comp-imaging / proximal Goto Github PK
View Code? Open in Web Editor NEWA domain-specific language for image optimization.
License: MIT License
A domain-specific language for image optimization.
License: MIT License
Thanks for your wonderful works. But the website: proximal-lang.org can't be reached.
It shows an error: DNS_PROBE_FINISHED_NXDOMAIN
Could you check this?
Thank you!
There are several instances of set_some_attribute
in the code, this is considered a Python anti-pattern, see e.g. this and this stackoverflow thread. These should perhaps be changed to either a property + setter pair, e.g. like Variable.value
currently does it:
@property
def value(self):
return self._value
@value.setter
def value(self, val):
"""Assign a value to the variable.
"""
self._value = val
or simply by removing the set_SOMEVARIABLE
method and setting the attribute as usual: object.some_attribute = new_value
.
It is often of interest to inspect partial results of a solver, perhaps for debugging or for somehow displaying partial results.
The solvers in Scipy provides a solution to this in allowing users to pass a callable
that is called with the current iterate, see e.g. scipy.optimize.minimize and scipy.optimize.fmin_bfgs. ODL does the same in all of its solvers and also provides some standardized callbacks, see odl.solvers.util.callback.
It would be nice if ProxImaL also had this functionality.
For my last project I had to perform an extensive hyperparameter optimisation during which I regularly ran out of memory. After spending some time to find the memory leak, I came across the CompGraph
class which has a self reference cycle. Such a cycle prevents a class from being deleted.
The problem is the self
injected into the other objects in those two lines:
self.forward_log = TimingsLog(self.nodes + [self])
self.adjoint_log = TimingsLog(self.nodes + [self])
To fix the problem I changed the code to [str(self)]
which then only injects a string. Since there is generally only one computational graph, time logging stills works (exact object references should only be necessary for graph elements which appear more than once). But there is probably a more elegant way to resolve this issue.
I'm trying to solve an implementation of the space-variant deconvolution algorithm presented in Flicker & Rigaut (2005) and reviewed here.
I have PSFs sampled over the field, which are centered and stacked in a matrix, of which we compute the SVD to get weights and kernels that form the low-rank approximation of the spatially varying blur forward model. (Image, im, weights, W, and kernels, U, are each vectors in R^n, n=1e7 (image of ~10million pixels)).
I construct my problem like so, but it is not able to return after 100s of minutes of runtime. It does not print any debug information either, despite the verbose flag, so I'm not sure what is going on.
P.S. I'm running Python 3.10.1 on a macOS Ventura on an M1 Max 64GB RAM
import proximal as px
def forward(im, G, W):
for i in range(15):
weight = W[i,:].reshape(*im.shape)
psf_mode = G[:,i].reshape(*im.shape)
im += px.conv(psf_mode, px.mul_elemwise(weight, im))
return im
def cost_function(x, im, U, W, mu):
im_blur = forward(x, U, W)
data_term = px.sum_squares(px.subsample(im_blur, steps=2) - im)
grad_term = mu*px.norm1(px.grad(im_blur)) + (1-mu)*px.sum_squares(px.grad(im_blur))
return data_term + grad_term + px.nonneg(im_blur)
x = px.Variable(im.shape)
prob = px.Problem(cost_function(x, im, U, W, mu=0.01))
prob.solve(solver='pc', max_iters=2, verbose=True, x0=im.copy())
Can you please tell me:
My compiler (MSVC) complains about WTARGET and HTARGET undeclared identifiers in fft2_r2c.cpp:
C:\WinPython\3.5.2.3-64bit-qt5\python-3.5.2.amd64\lib\site-packages\proximal\halide\src\fft2_r2c.cpp(52): error C2065: 'WTARGET': undeclared identifier
C:\WinPython\3.5.2.3-64bit-qt5\python-3.5.2.amd64\lib\site-packages\proximal\halide\src\fft2_r2c.cpp(52): error C2065: 'HTARGET': undeclared identifier
C:\WinPython\3.5.2.3-64bit-qt5\python-3.5.2.amd64\lib\site-packages\proximal\halide\src\fft2_r2c.cpp(56): error C2065: 'WTARGET': undeclared identifier
C:\WinPython\3.5.2.3-64bit-qt5\python-3.5.2.amd64\lib\site-packages\proximal\halide\src\fft2_r2c.cpp(56): error C2065: 'HTARGET': undeclared identifier
I didn't find references for these anywhere in the code, so I'm unsure about how to fix these.
msvc hack: Trass3r@639eeeb
Sometimes, it is desirable to apply operators to the input image, e.g. in optical flow.
I cannot figure out if this is even possible. I tried defining e.g. (this functional makes no sense, its just supposed to be a minimum example).
I = imread(...) # read input picture
x = Variable(*I.shape)
prob = Problem( grad(I) - grad(x)) + sum_squares(v1)
prob.solve()
but I end up with some error because the problem contains grad(I)
. The actual error differs, depending on what I'm actually trying to do in my functional.
I know that I could substitute grad(I-x)
above but that trick will not work for arbitrary combinations of the operators (I actually need something like sum_squares(mul_elemwise(grad(I,1),x))
).
So I guess the big question is: Is it currently possible in proximal to define problems by applying operators to input images, or do I need to make the appropriate transformations by hand?
Thanks in advance :)
Initializing a proximal.subsample
in 1d seems to have harsher requirements on the input than for example Variable
:
>>> x = proximal.Variable(4)
>>> proximal.subsample(x, 2) # this fails
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "e:\github\proximal\proximal\lin_ops\subsample.py", line 12, in __init__
shape = tuple([(dim - 1) // step + 1 for dim, step in zip(arg.shape, steps)])
TypeError: zip argument #2 must support iteration
>>> proximal.subsample(x, [2]) # this works
I tried to use the Halide implementation of proximal by setting implem=Impl['halide']
in the Problem
class, but I got a lot of errors if I try to use the ADMM algorithm. With the Pock-Chambolle algorithm, everything seems to work fine.
Any ideas what might be the cause of this? The first lines of the log seems to suggest that proximal is using halide types that do not exist but I somehow doubt that that is the problem^^
Btw, halide on its own is working fine for me, but running grep -r FuncRefVar
in the halide root directory does not yield any results.
I also tried changing the include-statements in funct.h
to point directly to Halide.h
(in case there was a search-path related problem, but that did not change the error output)
Estimated params [sigma = 1.000 | tau = 1.000 | theta = 1.000 | L_est = 1.0000]
0.0818989276886
In file included from /home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/complex.h:6:0,
from /home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/fft.h:14,
from /home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft2_r2c.cpp:11:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:11:5: error: ‘FuncRefVar’ in namespace ‘Halide’ does not name a type
Halide::FuncRefVar untyped;
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:17:23: error: ‘FuncRefVar’ in namespace ‘Halide’ does not name a type
FuncRefVarT(const Halide::FuncRefVar& untyped)
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:17:43: error: ISO C++ forbids declaration of ‘untyped’ with no type [-fpermissive]
FuncRefVarT(const Halide::FuncRefVar& untyped)
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In constructor ‘FuncRefVarT<T>::FuncRefVarT(const int&)’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:18:21: error: request for member ‘function’ in ‘untyped’, which is of non-class type ‘const int’
: T(untyped.function().has_pure_definition() ? T(Tuple(untyped)) : T()),
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:19:13: error: class ‘FuncRefVarT<T>’ does not have any field named ‘untyped’
untyped(untyped) {}
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In member function ‘FuncRefVarT<T>::Stage FuncRefVarT<T>::operator=(T)’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:21:35: error: ‘untyped’ was not declared in this scope
Stage operator=(T x) { return untyped = x; }
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In member function ‘FuncRefVarT<T>::Stage FuncRefVarT<T>::operator+=(T)’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:22:36: error: ‘untyped’ was not declared in this scope
Stage operator+=(T x) { return untyped = T(Tuple(untyped)) + x; }
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In member function ‘FuncRefVarT<T>::Stage FuncRefVarT<T>::operator-=(T)’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:23:36: error: ‘untyped’ was not declared in this scope
Stage operator-=(T x) { return untyped = T(Tuple(untyped)) - x; }
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In member function ‘FuncRefVarT<T>::Stage FuncRefVarT<T>::operator*=(T)’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:24:36: error: ‘untyped’ was not declared in this scope
Stage operator*=(T x) { return untyped = T(Tuple(untyped)) * x; }
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In member function ‘FuncRefVarT<T>::Stage FuncRefVarT<T>::operator/=(T)’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:25:36: error: ‘untyped’ was not declared in this scope
Stage operator/=(T x) { return untyped = T(Tuple(untyped)) / x; }
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: At global scope:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:30:5: error: ‘FuncRefExpr’ in namespace ‘Halide’ does not name a type
Halide::FuncRefExpr untyped;
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:36:24: error: ‘FuncRefExpr’ in namespace ‘Halide’ does not name a type
FuncRefExprT(const Halide::FuncRefExpr& untyped)
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:36:45: error: ISO C++ forbids declaration of ‘untyped’ with no type [-fpermissive]
FuncRefExprT(const Halide::FuncRefExpr& untyped)
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In constructor ‘FuncRefExprT<T>::FuncRefExprT(const int&)’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:37:30: error: class ‘FuncRefExprT<T>’ does not have any field named ‘untyped’
: T(Tuple(untyped)), untyped(untyped) {}
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In member function ‘FuncRefExprT<T>::Stage FuncRefExprT<T>::operator=(T)’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:39:35: error: ‘untyped’ was not declared in this scope
Stage operator=(T x) { return untyped = x; }
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In member function ‘FuncRefExprT<T>::Stage FuncRefExprT<T>::operator+=(T)’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:40:36: error: ‘untyped’ was not declared in this scope
Stage operator+=(T x) { return untyped = T(Tuple(untyped)) + x; }
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In member function ‘FuncRefExprT<T>::Stage FuncRefExprT<T>::operator-=(T)’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:41:36: error: ‘untyped’ was not declared in this scope
Stage operator-=(T x) { return untyped = T(Tuple(untyped)) - x;}
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In member function ‘FuncRefExprT<T>::Stage FuncRefExprT<T>::operator*=(T)’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:42:36: error: ‘untyped’ was not declared in this scope
Stage operator*=(T x) { return untyped = T(Tuple(untyped)) * x; }
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In member function ‘FuncRefExprT<T>::Stage FuncRefExprT<T>::operator/=(T)’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:43:36: error: ‘untyped’ was not declared in this scope
Stage operator/=(T x) { return untyped = T(Tuple(untyped)) / x; }
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft2_r2c.cpp: In member function ‘Halide::NamesInterface::Func fft2_r2c_gen::build()’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft2_r2c.cpp:52:71: error: ‘WTARGET’ was not declared in this scope
paddedInput = repeat_image( constant_exterior(input, 0.f), 0, WTARGET, 0, HTARGET);
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft2_r2c.cpp:52:83: error: ‘HTARGET’ was not declared in this scope
paddedInput = repeat_image( constant_exterior(input, 0.f), 0, WTARGET, 0, HTARGET);
^
In file included from /home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/complex.h:6:0,
from /home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/fft.h:14,
from /home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft2_r2c.cpp:11:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In instantiation of ‘FuncRefExprT<T> FuncT<T>::operator()(std::vector<Halide::Expr>) const [with T = ComplexExpr]’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/fft.h:150:53: required from here
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:74:92: error: could not convert ‘Halide::Func::operator()(std::vector<Halide::Expr>) const(std::vector<Halide::Expr>((*(const std::vector<Halide::Expr>*)(& vars))))’ from ‘Halide::FuncRef’ to ‘FuncRefExprT<ComplexExpr>’
FuncRefExprT<T> operator()(std::vector<Expr> vars) const { return Func::operator()(vars); }
^
In file included from /home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/complex.h:6:0,
from /home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/fft.h:14,
from /home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft2_r2c.cpp:11:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In instantiation of ‘FuncRefVarT<T> FuncT<T>::operator()(std::vector<Halide::Var>) const [with T = ComplexExpr]’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/fft.h:169:15: required from here
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:66:90: error: could not convert ‘Halide::Func::operator()(std::vector<Halide::Var>) const(std::vector<Halide::Var>((*(const std::vector<Halide::Var>*)(& vars))))’ from ‘Halide::FuncRef’ to ‘FuncRefVarT<ComplexExpr>’
FuncRefVarT<T> operator()(std::vector<Var> vars) const { return Func::operator()(vars); }
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In instantiation of ‘FuncRefVarT<T> FuncT<T>::operator()(FuncT<T>::Var) const [with T = ComplexExpr; FuncT<T>::Var = Halide::Var]’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/fft.h:301:12: required from here
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:60:71: error: could not convert ‘Halide::Func::operator()(Args&& ...) const [with Args = {Halide::Var&}; typename std::enable_if<Halide::Internal::all_are_convertible<Halide::Var, Args ...>::value, Halide::FuncRef>::type = Halide::FuncRef]((* & x))’ from ‘std::enable_if<true, Halide::FuncRef>::type {aka Halide::FuncRef}’ to ‘FuncRefVarT<ComplexExpr>’
FuncRefVarT<T> operator()(Var x) const { return Func::operator()(x); }
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In instantiation of ‘FuncRefExprT<T> FuncT<T>::operator()(FuncT<T>::Expr) const [with T = ComplexExpr; FuncT<T>::Expr = Halide::Expr]’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/fft.h:353:79: required from here
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:68:73: error: could not convert ‘Halide::Func::operator()(Halide::Expr, Args&& ...) const [with Args = {}; typename std::enable_if<Halide::Internal::all_are_convertible<Halide::Expr, Args ...>::value, Halide::FuncRef>::type = Halide::FuncRef](Halide::Expr((*(const Halide::Expr*)(& x))))’ from ‘std::enable_if<true, Halide::FuncRef>::type {aka Halide::FuncRef}’ to ‘FuncRefExprT<ComplexExpr>’
FuncRefExprT<T> operator()(Expr x) const { return Func::operator()(x); }
^
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h: In instantiation of ‘FuncRefVarT<T> FuncT<T>::operator()(FuncT<T>::Var, FuncT<T>::Var, FuncT<T>::Var) const [with T = ComplexExpr; FuncT<T>::Var = Halide::Var]’:
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft2_r2c.cpp:32:50: required from here
/home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/src/fft/funct.h:62:91: error: could not convert ‘Halide::Func::operator()(Args&& ...) const [with Args = {Halide::Var&, Halide::Var&, Halide::Var&}; typename std::enable_if<Halide::Internal::all_are_convertible<Halide::Var, Args ...>::value, Halide::FuncRef>::type = Halide::FuncRef]((* & x), (* & y), (* & z))’ from ‘std::enable_if<true, Halide::FuncRef>::type {aka Halide::FuncRef}’ to ‘FuncRefVarT<ComplexExpr>’
FuncRefVarT<T> operator()(Var x, Var y, Var z) const { return Func::operator()(x, y, z); }
^
/bin/sh: 1: /home/sebastian/anaconda2/lib/python2.7/site-packages/proximal/halide/build/gengen.XXXX: not found
Error genererator compilation:
Currently, when following the installation guide on windows (tested on win 7 and 10) the following error is given:
$ conda install numpy scipy pil pip opencv
Fetching package metadata: ....
Error: No packages found in current win-64 channels matching: opencv
You can search for this package on anaconda.org with
anaconda search -t conda opencv
This can be solved (according to this stackoverflow thread) by running
conda install -c https://conda.binstar.org/menpo opencv
After doing this, the installation works as expected. This tip may need to be added to the installation instructions.
Ok I tried to switch things over to github actions, got pretty far but ran into compilation issues. If you're able to take a look at all I'd really appreciate it!
Originally posted by @SteveDiamond in #54 (comment)
The problem: Github actions wants to test the ProxImaL project in the non-native Python environment, e.g. v3.7. However, the C++ build system detects the system python (v3.8) and then refuses to link the binaries.
Evidence: https://github.com/comp-imaging/ProxImaL/runs/2214159928#step:6:473
@SteveDiamond Possible solutions:
Symptom: Refer to the Address sanitizer report below.
Potential root cause: is the segfault related to halide/Halide#7606 ? I expect an runtime exception, not a segfault though.
Changes that triggers the segmentation fault: antonysigma@8f0cc04
diff --git a/proximal/halide/src/user-problem/meson.build b/proximal/halide/src/user-problem/meson.build
index 99004b7..b98c9e2 100644
--- a/proximal/halide/src/user-problem/meson.build
+++ b/proximal/halide/src/user-problem/meson.build
@@ -31,13 +31,11 @@ solver_bin = custom_target(
'-o', meson.current_build_dir(),
'-g', 'ladmm_iter',
'-e', 'static_library,h,stmt_html',
- 'target=host',
+ 'target=host-cuda-cuda_capability_75',
- '-p', 'autoschedule_mullapudi2016',
- 'autoscheduler=Mullapudi2016',
+ '-p', 'autoschedule_anderson2021',
+ 'autoscheduler=Anderson2021',
'autoscheduler.parallelism=4',
- 'autoscheduler.last_level_cache_size=6291000',
- 'autoscheduler.balance=40',
Environment: Ubuntu 20.04 w/ gcc toolchain, Halide 16.0.0
Logs detailing the segmentation fault:
env LD_LIBRARY_PATH=/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib /home/antony/Projects/ProxImaL/proximal/halide/build-clang/src/user-problem/solver-generator -o /home/antony/Projects/ProxImaL/proximal/halide/build-clang/src/user-problem -g ladmm_iter -e static_library,h,stmt_html target=host-cuda-cuda_capability_75 -p autoschedule_anderson2021 autoscheduler=Anderson2021 autoscheduler.parallelism=4 n_iter=1 mu=0.333 lmb=3.0
AddressSanitizer:DEADLYSIGNAL
=================================================================
==3232855==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000070 (pc 0x7fb6062507ce bp 0x000000000008 sp 0x7ffc51d9e8b0 T0)
==3232855==The signal is caused by a READ memory access.
==3232855==Hint: address points to the zero page.
#0 0x7fb6062507ce in Halide::Internal::Autoscheduler::LoopNest::compute_strides(Halide::Internal::Autoscheduler::LoadJacobian const&, int, Halide::Internal::Autoscheduler::FunctionDAG::Node const*, Halide::Internal::IntrusivePtr<Halide::Internal::Autoscheduler::BoundContents const> const&, Halide::Internal::Autoscheduler::ThreadInfo const&, bool) const (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x657ce)
#1 0x7fb606272f6c in void Halide::Internal::Autoscheduler::LoopNest::compute_num_mem_accesses_per_block<Halide::Internal::Autoscheduler::GlobalMem>(Halide::Internal::Autoscheduler::LoadJacobian const&, Halide::Internal::Autoscheduler::FunctionDAG::Node const*, Halide::Internal::IntrusivePtr<Halide::Internal::Autoscheduler::BoundContents const> const&, Halide::Internal::Autoscheduler::ThreadInfo const&, int, double, Halide::Internal::Autoscheduler::MemInfo<Halide::Internal::Autoscheduler::MemTraits<Halide::Internal::Autoscheduler::GlobalMem>::MemInfoType>&, bool) const (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x87f6c)
#2 0x7fb606273f9d in void Halide::Internal::Autoscheduler::LoopNest::compute_mem_load_features<Halide::Internal::Autoscheduler::GlobalMem>(Halide::Internal::Autoscheduler::LoadJacobian const&, int, Halide::Internal::Autoscheduler::FunctionDAG::Node const*, Halide::Internal::IntrusivePtr<Halide::Internal::Autoscheduler::BoundContents const> const&, bool, Halide::Internal::Autoscheduler::ThreadInfo const&, Halide::Internal::Autoscheduler::MemInfo<Halide::Internal::Autoscheduler::MemTraits<Halide::Internal::Autoscheduler::GlobalMem>::MemInfoType>&, double, bool) const (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x88f9d)
#3 0x7fb60625ca37 in Halide::Internal::Autoscheduler::LoopNest::compute_features(Halide::Internal::Autoscheduler::FunctionDAG const&, Halide::Internal::Autoscheduler::Anderson2021Params const&, Halide::Target const&, PerfectHashMap<Halide::Internal::Autoscheduler::FunctionDAG::Node::Stage, Halide::Internal::Autoscheduler::LoopNest::Sites, 4, PerfectHashMapAsserter> const&, long, long, Halide::Internal::Autoscheduler::LoopNest const*, Halide::Internal::Autoscheduler::LoopNest const*, Halide::Internal::Autoscheduler::LoopNest const&, Halide::Internal::Autoscheduler::GPULoopInfo, bool, PerfectHashMap<Halide::Internal::Autoscheduler::FunctionDAG::Node::Stage, long, 4, PerfectHashMapAsserter> const&, long*, long*, long*, PerfectHashMap<Halide::Internal::Autoscheduler::FunctionDAG::Node::Stage, Halide::Internal::ScheduleFeatures, 4, PerfectHashMapAsserter>*, Halide::Internal::Autoscheduler::Statistics&, bool) const (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x71a37)
#4 0x7fb60625b0ab in Halide::Internal::Autoscheduler::LoopNest::compute_features(Halide::Internal::Autoscheduler::FunctionDAG const&, Halide::Internal::Autoscheduler::Anderson2021Params const&, Halide::Target const&, PerfectHashMap<Halide::Internal::Autoscheduler::FunctionDAG::Node::Stage, Halide::Internal::Autoscheduler::LoopNest::Sites, 4, PerfectHashMapAsserter> const&, long, long, Halide::Internal::Autoscheduler::LoopNest const*, Halide::Internal::Autoscheduler::LoopNest const*, Halide::Internal::Autoscheduler::LoopNest const&, Halide::Internal::Autoscheduler::GPULoopInfo, bool, PerfectHashMap<Halide::Internal::Autoscheduler::FunctionDAG::Node::Stage, long, 4, PerfectHashMapAsserter> const&, long*, long*, long*, PerfectHashMap<Halide::Internal::Autoscheduler::FunctionDAG::Node::Stage, Halide::Internal::ScheduleFeatures, 4, PerfectHashMapAsserter>*, Halide::Internal::Autoscheduler::Statistics&, bool) const (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x700ab)
#5 0x7fb60625ac49 in Halide::Internal::Autoscheduler::LoopNest::compute_features(Halide::Internal::Autoscheduler::FunctionDAG const&, Halide::Internal::Autoscheduler::Anderson2021Params const&, Halide::Target const&, PerfectHashMap<Halide::Internal::Autoscheduler::FunctionDAG::Node::Stage, Halide::Internal::Autoscheduler::LoopNest::Sites, 4, PerfectHashMapAsserter> const&, long, long, Halide::Internal::Autoscheduler::LoopNest const*, Halide::Internal::Autoscheduler::LoopNest const*, Halide::Internal::Autoscheduler::LoopNest const&, Halide::Internal::Autoscheduler::GPULoopInfo, bool, PerfectHashMap<Halide::Internal::Autoscheduler::FunctionDAG::Node::Stage, long, 4, PerfectHashMapAsserter> const&, long*, long*, long*, PerfectHashMap<Halide::Internal::Autoscheduler::FunctionDAG::Node::Stage, Halide::Internal::ScheduleFeatures, 4, PerfectHashMapAsserter>*, Halide::Internal::Autoscheduler::Statistics&, bool) const (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x6fc49)
#6 0x7fb60628c1bd in Halide::Internal::Autoscheduler::State::compute_featurization(Halide::Internal::Autoscheduler::FunctionDAG const&, Halide::Internal::Autoscheduler::Anderson2021Params const&, Halide::Target const&, PerfectHashMap<Halide::Internal::Autoscheduler::FunctionDAG::Node::Stage, Halide::Internal::ScheduleFeatures, 4, PerfectHashMapAsserter>*, Halide::Internal::Autoscheduler::Statistics&, bool) const (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0xa11bd)
#7 0x7fb60628cec0 in Halide::Internal::Autoscheduler::State::calculate_cost(Halide::Internal::Autoscheduler::FunctionDAG const&, Halide::Internal::Autoscheduler::Anderson2021Params const&, Halide::Target const&, Halide::CostModel*, Halide::Internal::Autoscheduler::Statistics&, bool) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0xa1ec0)
#8 0x7fb60627c076 in Halide::Internal::Autoscheduler::SearchSpace::add_child(Halide::Internal::IntrusivePtr<Halide::Internal::Autoscheduler::State> const&, Halide::Internal::IntrusivePtr<Halide::Internal::Autoscheduler::LoopNest const> const&, std::function<void (Halide::Internal::IntrusivePtr<Halide::Internal::Autoscheduler::State>&&)>&) const (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x91076)
#9 0x7fb606281839 in Halide::Internal::Autoscheduler::SearchSpace::generate_children(Halide::Internal::IntrusivePtr<Halide::Internal::Autoscheduler::State> const&, std::function<void (Halide::Internal::IntrusivePtr<Halide::Internal::Autoscheduler::State>&&)>&, int, bool) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x96839)
#10 0x7fb60620926e in Halide::Internal::Autoscheduler::AutoSchedule::optimal_schedule_pass(int, int, int, Halide::Internal::Autoscheduler::ProgressBar&, std::unordered_set<unsigned long, std::hash<unsigned long>, std::equal_to<unsigned long>, std::allocator<unsigned long> >&) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x1e26e)
#11 0x7fb60620b144 in Halide::Internal::Autoscheduler::AutoSchedule::optimal_schedule(int) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x20144)
#12 0x7fb60620c0d2 in Halide::Internal::Autoscheduler::generate_schedule(std::vector<Halide::Internal::Function, std::allocator<Halide::Internal::Function> > const&, Halide::Target const&, Halide::Internal::Autoscheduler::Anderson2021Params const&, Halide::AutoSchedulerResults*) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x210d2)
#13 0x7fb606217f4b in Halide::Internal::Autoscheduler::Anderson2021::operator()(Halide::Pipeline const&, Halide::Target const&, Halide::AutoschedulerParams const&, Halide::AutoSchedulerResults*) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x2cf4b)
#14 0x7fb60ade3c82 in Halide::Pipeline::apply_autoscheduler(Halide::Target const&, Halide::AutoschedulerParams const&) const (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-15.0.0-x86-64-linux/lib/libHalide.so.16+0xd9fc82)
#15 0x7fb60a917e7c in Halide::Internal::AbstractGenerator::build_module(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libHalide.so.16+0x8d3e7c)
#16 0x7fb60ac39eaa in std::_Function_handler<Halide::Module (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Halide::Target const&), Halide::Internal::execute_generator(Halide::Internal::ExecuteGeneratorArgs const&)::'lambda2'(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Halide::Target const&)>::_M_invoke(std::_Any_data const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Halide::Target const&) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libHalide.so.16+0xbf5eaa)
#17 0x7fb60adad309 in Halide::compile_multitarget(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::map<Halide::OutputFileType, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<Halide::OutputFileType>, std::allocator<std::pair<Halide::OutputFileType const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&, std::vector<Halide::Target, std::allocator<Halide::Target> > const&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&, std::function<Halide::Module (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Halide::Target const&)> const&, std::function<std::unique_ptr<Halide::Internal::CompilerLogger, std::default_delete<Halide::Internal::CompilerLogger> > (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Halide::Target const&)> const&) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libHalide.so.16+0xd69309)
#18 0x7fb60ac42edf in Halide::Internal::execute_generator(Halide::Internal::ExecuteGeneratorArgs const&) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libHalide.so.16+0xbfeedf)
#19 0x7fb60ac444ed in Halide::Internal::(anonymous namespace)::generate_filter_main_inner(int, char**, Halide::Internal::GeneratorFactoryProvider const&) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libHalide.so.16+0xc004ed)
#20 0x7fb60ac4527f in Halide::Internal::generate_filter_main(int, char**, Halide::Internal::GeneratorFactoryProvider const&) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libHalide.so.16+0xc0127f)
#21 0x7fb60ac452ca in Halide::Internal::generate_filter_main(int, char**) (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libHalide.so.16+0xc012ca)
#22 0x7fb609acd082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16
#23 0x42329d in _start (/home/antony/Projects/ProxImaL/proximal/halide/build-clang/src/user-problem/solver-generator+0x42329d)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/home/antony/Projects/ProxImaL/proximal/halide/subprojects/Halide-16.0.0-x86-64-linux/lib/libautoschedule_anderson2021.so+0x657ce) in Halide::Internal::Autoscheduler::LoopNest::compute_strides(Halide::Internal::Autoscheduler::LoadJacobian const&, int, Halide::Internal::Autoscheduler::FunctionDAG::Node const*, Halide::Internal::IntrusivePtr<Halide::Internal::Autoscheduler::BoundContents const> const&, Halide::Internal::Autoscheduler::ThreadInfo const&, bool) const
==3232855==ABORTING
I've been looking some at the code now in order to get it working nicely with ODL, and one thing I've come to notice is that you do not seem to follow the official python style as given in PEP8. Python differs from most other languages in there being an official style guide that should be used with it, and it is highly recommended to follow it. Further, it is often easier to get started with style conformance early on in the project than waiting until later (trust me, we waited far to long before we did this in ODL).
There are several tools available in order to both check that your code is conforming (such as pytest pep8 and the built in pep8 checker for spyder) and also a few that can help you make the code conforming such as autopep8 and autoflakes.
Solving a problem with the least_squares
prox function in Halide implementation modus throws the following errors during compilation:
`../ProxImaL/build/lib/proximal/halide/src/fft2_r2c.cpp:52:71: error: use of undeclared identifier 'WTARGET'
paddedInput = repeat_image( constant_exterior(input, 0.f), 0, WTARGET, 0, HTARGET);
^
../ProxImaL/build/lib/proximal/halide/src/fft2_r2c.cpp:52:83: error: use of undeclared identifier 'HTARGET'
paddedInput = repeat_image( constant_exterior(input, 0.f), 0, WTARGET, 0, HTARGET);
^
../ProxImaL/build/lib/proximal/halide/src/fft2_r2c.cpp:56:43: error: use of undeclared identifier 'WTARGET'
Func fftIn = fft2_r2c(input_func, WTARGET, HTARGET);
^
../ProxImaL/build/lib/proximal/halide/src/fft2_r2c.cpp:56:52: error: use of undeclared identifier 'HTARGET'
Func fftIn = fft2_r2c(input_func, WTARGET, HTARGET);`
I resolved the error by adding the necessary flags to the compilation in sum_squares.py
:
hflags = ['-DWTARGET={0} -DHTARGET={1}'.format(self.freq_shape[1], self.freq_shape[0])]
and
Halide('fft2_r2c.cpp', compile_flags=hflags)
.
If this is a new and unknown error and my solution is correct I am happy to send a PR.
When running the tests without Halide installed several tests fail with messages similar to this:
g++.exe: error: ${HALIDE_PATH}/tools/GenGen.cpp: No such file or directory
g++.exe: error: ${HALIDE_PATH}/bin/libHalide.so: No such file or directory
'D:\Programming\ProxImaL\proximal\halide\build\gengen.XXXX' is not recognized as an internal or external command,
operable program or batch file.
Error genererator compilation:
Platform used is windows 10 with python 2.7.
Currently in test_prox_fn
the following line is run (among others):
x_var = cvx.Variable(10)
I assume that this is a copy-paste error and that the test should be for proximal.Variable
? Otherwise these need to be import guarded since cvxpy
is not a required dependency of proximal
and not having it currently causes the tests to crash.
Github CI reported python failure since ~2 weeks ago. Mitigation: refactor the code to use the new Numexpr APIs.
Error message:
test_prox_fn.py:240:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../prox_fns/prox_fn.py:102: in prox
rho_hat = ne.evaluate('(rho + 2 * gamma) / (alpha * beta**2)', global_dict=symbols)
../../sandbox/lib/python3.8/site-packages/numexpr/necompiler.py:941: in evaluate
return re_evaluate(local_dict=local_dict, _frame_depth=_frame_depth)
../../sandbox/lib/python3.8/site-packages/numexpr/necompiler.py:969: in re_evaluate
args = getArguments(argnames, local_dict, _frame_depth=_frame_depth)
E KeyError: 'alpha'
../../sandbox/lib/python3.8/site-packages/numexpr/necompiler.py:755: KeyError
ProxImalL currently has a few python2 only statements, mostly print x
. Is there a plan to start supporting Python3 as well?
Hi,
Using proximal, with an odl operator, I was able to implement robust horn-shunck optical flow in just a few lines of code. Amazing!
laplacian = odl.Laplacian(space)
# Convert laplacian to ProxImaL operator
proximal_lang_laplacian = odl.as_proximal_lang_operator(laplacian)
fx = np.gradient(image1)[1]
fy = np.gradient(image1)[0]
ft = image1 - image2
# Set up optimization problem
u = proximal.Variable(space.shape)
v = proximal.Variable(space.shape)
alpha = .07
funcs = [alpha * proximal.norm1(proximal_lang_laplacian(u)),
alpha * proximal.norm1(proximal_lang_laplacian(v)),
proximal.norm1(proximal.mul_elemwise(fx,u) + proximal.mul_elemwise(fy,v) - ft)]
This works great. However, I am trying to solve a slightly different problem:
laplacian = odl.Laplacian(space)
# Convert laplacian to ProxImaL operator
proximal_lang_laplacian = odl.as_proximal_lang_operator(laplacian)
fx = np.gradient(image1)[1]
fy = np.gradient(image1)[0]
ft = image1 - image2
# Set up optimization problem
u = proximal.Variable(space.shape)
v = proximal.Variable(space.shape)
w = proximal.Variable(space.shape)
alpha = .07
funcs = [alpha * proximal.norm1(proximal_lang_laplacian(u)),
alpha * proximal.norm1(proximal_lang_laplacian(v)),
alpha * proximal.norm1(proximal_lang_laplacian(w)),
proximal.norm1(proximal.mul_elemwise(fx,u) + proximal.mul_elemwise(fy,v) + w - ft)]
In short I have added the free variable w. After doing this, the results don't make sense. The regularization parameter alpha makes no difference. 0 to 1e40 all give the same results. And without regularization, the problem is ill-posed. My first thought was that the solver is unhappy that u and v are scaled, while w is not, but performing a proximal.mul_elemwise(np.ones_like(fy),w) does not improve things. Any ideas?
Currently when trying to use several variables at once:
>>> x = proximal.Variable(3)
>>> y = proximal.Variable(6)
>>> rhs = np.array([1, 2, 3])
>>> prob = proximal.Problem([proximal.sum_squares(x - rhs),
proximal.sum_squares(proximal.subsample(y, [2]) - x)])
>>> prob.solve()
errors are encountered. Is this type of problem intended to be supported in ProxImaL? If not, perhaps a check should be added to disallow it.
The Linear-ADMM Halide code can compile and generate baremetal code in Linux and Windows build environments. But the same code fails in MacOS+clang14 environment.
Error report:
[4/6] Generating src/user-problem/ladmm_iter.[ah] with a custom command (wrapped by meson to set env)
FAILED: src/user-problem/ladmm_iter.a src/user-problem/ladmm_iter.h
env LD_LIBRARY_PATH=/Users/runner/work/ProxImaL/ProxImaL/proximal/halide/subprojects/Halide-10.0.0-x86-64-osx/lib /Users/runner/work/ProxImaL/ProxImaL/proximal/halide/build/src/user-problem/solver-generator -o /Users/runner/work/ProxImaL/ProxImaL/proximal/halide/build/src/user-problem -g ladmm_iter -e static_library,h,stmt_html machine_params=12,6291000,40 target=host auto_schedule=true -s Mullapudi2016 -p autoschedule_mullapudi2016 n_iter=1 mu=0.333 lmb=3.0
Assertion failed: (_z.defined() && "FuncTuple z_new is not defined."), function iterate, file linearized-admm.h, line 92.
The assertion that failed:
// src/algorithm/linearlized-admm.h
// Update z_i for i = 0..N .
const FuncTuple<N> Kv2 = K.forward(v_new);
FuncTuple<N> z_new;
{
for (auto&& [_z_new, _Kv2, _u, prox] : zip_view{z_new, Kv2, u, psi_fns}) {
Func Kv_u{"Kv_u"};
const auto vars = (prox.n_dim == 4) ? Vars{x, y, c, k} : Vars{x, y, c};
Kv_u(vars) = _Kv2(vars) + _u(vars);
_z_new = prox(Kv_u, 1.0f / lmb);
assert(_z_new.defined() && "FuncTuple z_new is not defined.");
}
}
Build environment:
C++ compiler for the host machine: c++ (clang 14.0.0 "Apple clang version 14.0.0 (clang-1400.0.29.202)")
C++ linker for the host machine: c++ ld64 820.1
Host machine cpu family: x86_64
Host machine cpu: x86_64
Possible root cause: In gcc and msvc, the variable _z_new
is treated as C++ l-value (Func&
), but in clang-14, it is treated as r-value Func&&
. Thus, the z-update step appears to be immediately discarded, causing the ADMM iteration to fail during the codegen step.
Likely solution: Upgrade from Halide 10.0 to Halide >14.0, so as to match the MacOS+clang14 build environment.
Fork from other discussion:
Component level specification
We could achieve the same pattern with ProxImaL. In ideal world that would be like:
- Describe the Problem [ProxImaL]
- Compile to have the solver as Halide Kernel (C++ or Python). [ProxImaL ->Halide]
- Use Halide to build a scheduler or auto_schedule for {CUDA, OpenCL, x86, ...} [Halide]
I suggest that we fork out a separate Github issue to discuss this. @jrk and @SteveDiamond can chime in as well.
My first thought is that ProxImaL, just like FlexISP, generates a cyclic compute graph. The lack of compute cycles in Halide is a fundamental strength to customize the compute schedule (or weakness in your use-case?).
As the authors suggested in the original article, I think the ProxImaL project can still grow by
proximal.linops.*
nodes in the proximal.CompGraph
into a single Halide pipeline; andBut eventually the Halide-generate code will have to hand back control to the ADMM while
-loop to complete the "cycle". Whether the while
-loop has to be coded in C++ or to remain in Python, I do not know.
Originally posted by @antonysigma in #57 (comment)
If we remove the regularizer and nonnegativity condition from the example in the README, we get:
from proximal import *
import numpy as np
import scipy.misc
import matplotlib.pyplot as plt
# Generate data.
I = scipy.misc.ascent()
np.random.seed(1)
b = I + 10*np.random.randn(*I.shape)
# Construct and solve problem.
x = Variable( I.shape )
prob = Problem(sum_squares(x - b/255)) # REMOVED: + .1*norm1( grad(x) ) + nonneg(x)
prob.solve()
# Plot the original, noisy, and denoised images.
plt.figure(figsize=(15,8))
plt.subplot(131)
plt.gray()
plt.imshow(I)
plt.title('Original image')
plt.subplot(132)
plt.gray()
plt.imshow(b)
plt.title('Noisy image')
plt.subplot(133)
plt.gray()
plt.imshow(x.value*255) # x.value is the optimal value of x.
plt.title('Denoising results')
plt.show()
I get an error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "e:\github\proximal\proximal\algorithms\problem.py", line 96, in solve
prox_fns = absorb.absorb_all_lin_ops(prox_fns)
File "e:\github\proximal\proximal\algorithms\absorb.py", line 21, in absorb_all_lin_ops
ready = prox_funcs[:]
TypeError: 'sum_squares' object has no attribute '__getitem__'
The problem can be partially fixed by adding square brackets ([ ]
) around the argument to proximal.Problem
, but then another issue appears:
from proximal import *
import numpy as np
import scipy.misc
import matplotlib.pyplot as plt
# Generate data.
I = scipy.misc.ascent()
np.random.seed(1)
b = I + 10*np.random.randn(*I.shape)
# Construct and solve problem.
x = Variable( I.shape )
prob = Problem( [ sum_squares(x - b/255) ] ) # ADDED [ ]
prob.solve()
# Plot the original, noisy, and denoised images.
plt.figure(figsize=(15,8))
plt.subplot(131)
plt.gray()
plt.imshow(I)
plt.title('Original image')
plt.subplot(132)
plt.gray()
plt.imshow(b)
plt.title('Noisy image')
plt.subplot(133)
plt.gray()
plt.imshow(x.value*255) # x.value is the optimal value of x.
plt.title('Denoising results')
plt.show()
I get an error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "e:\github\proximal\proximal\algorithms\problem.py", line 123, in solve
Knorm = est_CompGraph_norm(K, try_fast_norm=self.try_fast_norm)
File "e:\github\proximal\proximal\lin_ops\comp_graph.py", line 273, in est_CompGraph_norm
Knorm = np.sqrt(eigs(A, k=1, M=None, sigma=None, which='LM', tol=tol)[0].real)
File "C:\Anaconda\lib\site-packages\scipy\sparse\linalg\eigen\arpack\arpack.py", line 1224, in eigs
% (k, n - 1))
ValueError: k=1 must be between 1 and ndim(A)-1=-1
Tried on windows 7 with python 2.7 and the latest version of proximal from master.
When writing some examples I have come to realize that we pretty much always write:
prob = proximal.Problem(...)
prob.solve()
Looking through the proximal
code base, the only place I see a divergence from this pattern is where the set_
methods are tested, never in use.
Is there a reason that the Problem
class exists? Why could the above not simply be written in a functional manner:
proximal.solve(...)
The same revision e0bbeba passes the Windows CI on July 14, but the same code fails since July 19.
CI success on July 14: https://github.com/comp-imaging/ProxImaL/actions/runs/5564437916
CI failure today: https://github.com/antonysigma/ProxImaL/actions/runs/5557095504/job/15213363734
Error message:
Run ninja -C proximal/halide/build ladmm-runtime
ninja: Entering directory `proximal/halide/build'
[1/6] Compiling C++ object src/user-problem/solver-generator.exe.p/.._.._subprojects_Halide-14.0.0-x86-64-windows_share_Halide_tools_GenGen.cpp.obj
cl : Command line warning D9002 : ignoring unknown option '-fno-rtti'
[2/6] Compiling C++ object src/user-problem/solver-generator.exe.p/linearized-admm-gen.cpp.obj
cl : Command line warning D9002 : ignoring unknown option '-fno-rtti'
[3/6] Linking target src/user-problem/solver-generator.exe
[4/6] Generating src/user-problem/ladmm_iter.[ah] with a custom command (wrapped by meson to set PATH, to set env)
FAILED: src/user-problem/ladmm_iter.lib src/user-problem/ladmm_iter.h
"C:\hostedtoolcache\windows\Python\3.8.10\x64\Scripts\meson" "--internal" "exe" "--unpickle" "D:\a\ProxImaL\ProxImaL\proximal\halide\build\meson-private\meson_exe_solver-generator_13344a9f4d4ac864c6273976ca7dedc4382aeada.dat"
Traceback (most recent call last):
File "C:\hostedtoolcache\windows\Python\3.8.10\x64\lib\runpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\hostedtoolcache\windows\Python\3.8.10\x64\lib\runpy.py", line 87, in _run_code
exec(code, run_globals)
File "C:\hostedtoolcache\windows\Python\3.8.10\x64\Scripts\meson.exe\__main__.py", line 7, in <module>
File "C:\hostedtoolcache\windows\Python\3.8.10\x64\lib\site-packages\mesonbuild\mesonmain.py", line 294, in main
return run(sys.argv[1:], launcher)
File "C:\hostedtoolcache\windows\Python\3.8.10\x64\lib\site-packages\mesonbuild\mesonmain.py", line 282, in run
return run_script_command(args[1], args[2:])
File "C:\hostedtoolcache\windows\Python\3.8.10\x64\lib\site-packages\mesonbuild\mesonmain.py", line 223, in run_script_command
return module.run(script_args)
File "C:\hostedtoolcache\windows\Python\3.8.10\x64\lib\site-packages\mesonbuild\scripts\meson_exe.py", line 122, in run
return run_exe(exe)
File "C:\hostedtoolcache\windows\Python\3.8.10\x64\lib\site-packages\mesonbuild\scripts\meson_exe.py", line 76, in run_exe
raise FileNotFoundError(p.returncode, strerror, cmd_args)
FileNotFoundError: [Errno 322122[57](https://github.com/antonysigma/ProxImaL/actions/runs/5557095504/job/15213363734#step:8:58)81] Failed to run due to missing DLLs, with path: D:\a\ProxImaL\ProxImaL\proximal\halide\subprojects\Halide-14.0.0-x86-64-windows\lib\Release;D:\a\ProxImaL\ProxImaL\proximal\halide\build\src/user-problem;D:/a/ProxImaL/ProxImaL/proximal/halide/subprojects/Halide-14.0.0-x86-64-windows/lib/Release: ['D:\\a\\ProxImaL\\ProxImaL\\proximal\\halide\\build\\src/user-problem\\solver-generator.exe', '-o', 'D:/a/ProxImaL/ProxImaL/proximal/halide/build/src/user-problem', '-g', 'ladmm_iter', '-e', 'static_library,h,stmt_html', 'machine_params=12,[62](https://github.com/antonysigma/ProxImaL/actions/runs/5557095504/job/15213363734#step:8:63)91000,40', 'target=host', 'auto_schedule=true', '-s', 'Mullapudi2016', '-p', 'autoschedule_mullapudi2016', 'n_iter=1', 'mu=0.333', 'lmb=3.0']
Several examples seem to be referring a data folder, this is however missing in the repository. See for example here.
Creating a Problem
with scale=True
causes a scaling of the prox functions with the operator norm Knorm
. This usually works fine, but when a problem is solved with an x0
initialisation other than None
(i.e. all zeros in x0
) the scaling of the parameters and the input do not match. From my understanding the initialisation x0
has to be scaled as well. For example with:
x0 = x0.copy() * np.sqrt(Knorm)
In which case the operator norm has to be passed to the solve function. Without this scaling my results were considerably worse. This effect is of course only observable if Knorm != 1.0
.
Note to self: The algorithm least_square(x, b)
has a direct frequency domain inversion method, utilizing the Halide-accelerated FFT interface. However, the current implementation requires context switch between Halide/C++ domain and Numpy/Python domain, introducing overhead.
The internal buffer lifetime, namely self.ftmp_halide
, could have been managed in the Halide/C++ domain to reduce code bloat.
Roadmap:
least_squares_direct(input, b, freq_diag, output)
self.ftmp_halide
.proximal/examples/test_deconv.py
.ProxImaL/proximal/prox_fns/sum_squares.py
Lines 198 to 231 in 44eef8c
Is it possible to apply two convolution filters to the variable X, compare the elements of the two arrays, and choose the larger value? And can ProximaL solve the problem?
Issue reported by @shnaqvi :
Traceback (most recent call last):
File "examples/test_deconv_sv_psf.py", line 75, in <module>
prob.solve(solver='pc', max_iters=2, verbose=True, x0=im.copy())
File "../../../../../.pyenv/versions/3.10.1/lib/python3.10/site-packages/proximal/algorithms/problem.py", line 156, in solve
Knorm = est_CompGraph_norm(K, try_fast_norm=self.try_fast_norm)
File "../../../../../.pyenv/versions/3.10.1/lib/python3.10/site-packages/proximal/lin_ops/comp_graph.py", line 433, in est_CompGraph_norm
return np.float(Knorm)
File "../../../../../.pyenv/versions/3.10.1/lib/python3.10/site-packages/numpy/__init__.py", line 305, in __getattr__
raise AttributeError(__former_attrs__[attr])
AttributeError: module 'numpy' has no attribute 'float'.
`np.float` was a deprecated alias for the builtin `float`. To avoid this error in existing code, use `float` by itself. Doing this will not modify any behavior and is safe. If you specifically wanted the numpy scalar type, use `np.float64` here.
The aliases was originally deprecated in NumPy 1.20; for more details and guidance see the original release note at:
https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations
However, the master
branch indicates the bug is already resolved:
ProxImaL/proximal/lin_ops/comp_graph.py
Line 433 in 3437814
Steps to reproduce:
>>> x = proximal.Variable((10, 10))
>>> funcs = [proximal.sum_squares(x), proximal.patch_NLM(x)]
>>> prob = proximal.Problem(funcs)
>>> prob.solve()
cv2.error: ..\..\..\modules\photo\src\denoising.cpp:91: error: (-5) Type of input image should be CV_8UC3! in function cv::fastNlMeansDenoisingColored
Python 2.7.12
Windows 10
cv2 2.4.11
Edit: Title changed, problem seems to be deeper.
Steps to reproduce:
>>> x = proximal.Variable([2, 2])
TypeError: can only concatenate list (not "tuple") to list
Hi,
before creating a pull request for this with the necessary clean-up actions, I'd like to hear the opinion of the authors about this. I created a port using pycuda to improve performance. Currently a subset of the linear operations, the group_norm1 prox function and the Pock Chambolle algorithm is supported. I observe a nice speedup of a factor 10 compared to the native python implementation (even using only a mobile graphics card). On my forked repository https://github.com/wiedemannc/ProxImaL, it is currently implemented on the branch 'matlab_code_generation' (I have to remove the matlab stuff before creating the pull request for it).
If there is interest for integration, I'd be up for cleaning things up and create a pull request for this.
Kind Regards
Christoph
As some core is based on C++ & Halide.
Is there a way to reproduce the results of the paper using only C++?
From my understanding the implem
parameter of the Problem
class should work as a global implementation flag for the entire computation graph. One either specifies the implementation modus for each component individually or with the implem
parameter of the Problem
class.
Currently this is not the case if the problem is not scaled. Additionally the implementation modus is not handled very consistently. For example copying a ProxFn
object does not include the implementation modus.
Is the current state intentionally or does it make sense to send a PR with change suggestions?
We should cache (K^TK)^{-1}K^Tb
when repeatedly solving ||Kx - b||^2 + (\rho/2)||x-v||^2
directly.
Hello everyone,
I am currently extending the 'Lin_Op' class by creating a new class 'matrix_nonsquared_mult2'. This operator should perform the following operation:
C * i - h
where:
As can be noted, unlike "mul_elemwise", the dimensions of my objects are all different, so creating this new class by just modifying the forward and adjoint methods of "mul_elemwise" wont be sufficient as some reshaping must be done.
I have defined the constructor so that shapes of both, operator "C" and variable "i" match during the execution of the "forward" method. By the point where the bug occurs, the "adjoint" method hasn't even been referenced yet.
The bug occurs during the execution of the "get_diag" method within my class, during the "partition/split" phase. Specifically, in the line:
self_diag = np.reshape(self.kernel, self.size)
The reason for the bug is that "self.kernel" contains, well, the 442x442 operator; but "self.size" contains the size of the 442x19800 variable. In the cases of "conv" and "mul_elemwise" modules such conflict never exists: In the first case the kernel is reshaped within the operator's constructor to match the variable size and then the operator acting on the input is a element-wise multiplication; while in the second case, both, kernel and input variable must have same dimensions from the beginning.
At the moment, I can't figure out how to make this to match. I have tried to store different shapes within the constructor of my class but then immediately the program breaks during the "absorption" stage at the "forward" method execution, since shapes do not match during the matrix-matrix multiplication. So, where should I do the reshaping and what are the correct shapes/sizes to store?? I think I don't really understand what is each shape or size for.
I would appreciate any suggestions or ideas. I attach the code below
Thank you in advance.
Javier
`class matrix_nonsquared_mult2(LinOp):
def __init__(self, kernel, arg, implem = None):
#assert arg.shape == kernel.shape #Now we must admit different dimensions
self.kernel = kernel
self.forward_kernel = kernel
shape = arg.shape
super(matrix_nonsquared_mult2, self).__init__([arg], shape, implem)
def init_kernel(self):
print('Kernel Initialization: matrix_nonsquared_mult2')
def forward(self, inputs, outputs):
"""The forward operator.
Reads from inputs and writes to outputs.
"""
self.forward_kernel
np.copyto(outputs[0], np.dot(self.kernel,inputs[0]))
def adjoint(self, inputs, outputs):
"""The adjoint operator.
Reads from inputs and writes to outputs.
"""
print('To be implemented...')
self.adjoint_kernel = self.forward_kernel.conj()
def is_diag(self, freq=False):
return not freq and self.input_nodes[0].is_diag(freq)
def get_diag(self, freq=False):
"""Returns the diagonal representation (A^TA)^(1/2).
Parameters
----------
freq : bool
Is the diagonal representation in the frequency domain?
Returns
-------
dict of variable to ndarray
The diagonal operator acting on each variable.
"""
assert not freq
var_diags = self.input_nodes[0].get_diag(freq)
self_diag = np.reshape(self.kernel, self.size)
for var in var_diags.keys():
var_diags[var] = var_diags[var]*self_diag
return var_diags
def norm_bound(self, input_mags):
"""Gives an upper bound on the magnitudes of the outputs given inputs.
Parameters
----------
input_mags : list
List of magnitudes of inputs.
Returns
-------
float
Magnitude of outputs.
"""
return np.max(np.abs(self.kernel))*input_mags[0]`
Error message:
% cd proximal/halide/
% meson setup build/
The Meson build system
Version: 1.2.0
Source dir: /Users/antony/Projects/ProxImaL/proximal/halide
Build dir: /Users/antony/Projects/ProxImaL/proximal/halide/build
Build type: native build
Project name: proximal-halide
Project version: undefined
C++ compiler for the host machine: c++ (clang 15.0.0 "Apple clang version 15.0.0 (clang-1500.0.40.1)")
C++ linker for the host machine: c++ ld64 1015.7
Host machine cpu family: aarch64
Host machine cpu: aarch64
meson.build:8:19: ERROR: Neither a subproject directory nor a halide-aarch64-darwin.wrap file was found.
A full log can be found at /Users/antony/Projects/ProxImaL/proximal/halide/build/meson-logs/meson-log.txt
Hi @SteveDiamond , I found a bug in linearized_admm.py
causing the algorithm to return exceptions. I documented it in the draft pull request: #62
Could you please suggest a permanent fix? In the meantime, I will find a quick fix to workaround the shape mismatch.
Regards,
Antony
Hello, I am recently trying to use ProxImaL library and wondering which version of Halide did you guys build on? The code corresponding to halide seems to not work with the current version of Halide. Thanks!
I've been trying to use patch_NLM
with a nontrivial data discrepancy term, but my results seem to always diverge. The call is basically, using this ODL branch:
import numpy as np
import odl
import proximal
# Create space, a square from [0, 0] to [100, 100] with (100 x 100) points
space = odl.uniform_discr([0, 0], [100, 100], [100, 100])
# Create odl operator for laplacian
laplacian = odl.Laplacian(space)
# Create right hand side
rhs = laplacian(odl.phantom.shepp_logan(space, modified=True))
rhs += odl.phantom.white_noise(space) * np.std(rhs) * 0.0 # disable noise
rhs.show('noisy data')
# Convert laplacian to cvx operator
norm_bound = odl.power_method_opnorm(laplacian, 10, rhs)
cvx_laplacian = odl.operator.oputils.as_cvx_operator(laplacian,
norm_bound=norm_bound)
# Convert to array
rhs_arr = rhs.asarray()
# Set up optimization problem
x = proximal.Variable(space.shape)
funcs = [proximal.sum_squares(cvx_laplacian(x) - rhs_arr),
0.01 * proximal.patch_NLM(x, sigma_fixed=0)]
prob = proximal.Problem(funcs)
# Solve the problem
prob.solve(verbose=True, max_iters=2000)
# Convert back to odl and display result
result_odl = space.element(x.value)
result_odl.show('result')
Which gives utter nonsense as a result, and it does not seem to converge when max_iters
is increased, nor does overestimating the norm_bound
help. Changing the scaling term 0.01´ in front of
patch_NLM` seems to have only minor impact.
It seems I am missing something, so adding an example of using this regularizer would be great!
http://www.proximal-lang.org/en/latest/install/index.html
Tested Miniconda3 (Python 3.5) on Win7.
pip install proximal
just like pillowIt might be better to recommend a normal python installation.
Also I wonder how https://github.com/comp-imaging/ProxImaL/blob/master/continuous_integration/install.sh is supposed to work for 3.5 if miniconda2 is downloaded.
(Adding the task dependencies for my own reminder.)
Halide::BoundaryConditions
calls to use the new APIs;Generator::*
related code to use Halide 16.0 APIs;algorithms/ladmm.py
, ensure all Numpy matrices are Fortran order by default; this avoids the frequent C-order to F-order typecasting overhead in the (L-)ADMM iterations;A_mask.cpython.so
writes to the output buffers in F-order, not some orphan buffers that are immediately destroyed. This should solve the convergence failure bugs whenever implem='Halide'
is defined.C++20
; this should cut the compile time in half thanks to new C++ Concepts
feature;ladmm-iter-gen.cpp
with the broadcast operator Halide::_
.Li2018
autoscheduler with Anderson2021
: the latter utilizes the GPU cache and shared memory in the SM far better.References:
halide/Halide#6856
halide/Halide#7459
When running pip install proximal
you get an error:
>>> import proximal
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "proximal/__init__.py", line 3, in <module>
from .prox_fns import *
File "proximal/prox_fns/__init__.py", line 1, in <module>
from .prox_fn import ProxFn
File "proximal/prox_fns/prox_fn.py", line 4, in <module>
from proximal.utils import Impl
File "proximal/utils/__init__.py", line 1, in <module>
from .utils import Impl
File "proximal/utils/utils.py", line 6, in <module>
import cv2
ImportError: No module named cv2
It seems some cv2
binding has to be added to the list of dependencies.
Edit:
I installed opencv-python via pip install opencv-python
and it works great for me. So that binding can be added.
While working with ProxImaL in Halide implementation modus I encountered multiple problems in halide.py
:
e.message
is not correctly transpiled to Python 3. The message
attribute is not removed even though it does not exist in Python 3 and therefore throws an error. I suggest to remove the messsage
attribute at all. "{0}".format(e)
should work in both Python versions.
From NumPy >= 1.10.0 the result of np.isfortran may wary. See the documentation in the link. I therefore suggest to replace np.isfortran(arg)
with arg.flags.f_contiguous
.
If an error occurs in the try
statement of the gengen
function before header_file
and object_file
are initialized the function will throw an error in the finally
statement. I suggest to initialize the two variables like the launcher_file
before the try
statement:
...
header_file = object_file = launcher_file = ''
try:
...
# Run generator
env = os.environ.copy()
if sys.platform == "linux" or sys.platform == "linux2":
cmd = '{0} {1} {2} -e o,h -o {3} {4}'.format(
generator, generator_flag, function_flag, builddir, target_flags)
elif sys.platform == "darwin":
cmd = 'export DYLD_LIBRARY_PATH={5} && {0} {1} {2} -e o,h -o {3} {4}'.format(
generator, generator_flag, function_flag, builddir, target_flags, env['HALIDE_PATH'] + '/bin/')
if verbose:
print('Calling generator')
print('\t' + cmd)
subprocess.call(cmd, shell=True)
It was a while since the last release and some bugfixes has been done since. How about a new release so users can get the newest version from pip
?
Working draft for debugging purpose: https://github.com/antonysigma/proximal/tree/debug-producer-error
Observations: when we define the Halide Func
and then return them as std::tuple
, the generator can capture the algorithm pipeline and schedule it with Mullapudi2016
autoscheduler. But not Anderson2021
. The autoscheduler reports:
Unhandled exception: Internal Error at .../autoschedulers/anderson2021/LoopNest.cpp:2747
triggered by user code at :
Condition failed: producer_store_instances > 0:
The same assertion failure happens with C++ structured bindings, as well as passing return values as function reference.
The offending line is shown below:
using Halide::Func
template<size_t N> using FuncTuple = std::array<Func, N>;
std::vector<Func> v_list(n_iter);
std::vector<FuncTuple<psi_size>> z_list(n_iter);
std::vector<FuncTuple<psi_size>> u_list(n_iter);
for (size_t i = 0; i < n_iter; i++) {
std::tie(v_list[i], z_list[i], u_list[i]) = algorithm::linearized_admm::iterate(
v, z_prev, u_prev, K, omega_fn, psi_fns, lmb, mu, input);
}
See also: #67 .
I suggest the following changes for the linear operation mul_elemwise
:
Is the current state intentionally or does it make sense to send a PR with change suggestions?
If implementation modus Halide is activated the patch_NLM.py
prox function uses an OpenCV CUDA implementation of the NLM denoiser. Besides checking for the correct dimensions I think the if statement should also check if CUDA is actually available. For this the cuda_available
variable from cuda_codegen.py
could be exported as a flag which is package-wide available.
Furthermore the compilation of the prox_NLM.cpp
throws multiple undefinied symbol
errors e.g.
...
OSError: XXX/python3.6/site-packages/proximal/halide/build/prox_NLM.so: undefined symbol: NLM_extern
which I resolved by adding the following compilation flags to patch_NLM.py
:
ext_libs = '-lopencv_core', '-lopencv_imgproc', '-lopencv_cudaarithm', '-lopencv_cudev', '-lopencv_photo', '-lm'
ext_srcs = ['external/external_NLM.cpp']
Halide('prox_NLM.cpp', external_source=ext_srcs, external_libs=ext_libs).prox_NLM(tmpin, 1. / rho, self.paramsh, self.tmpout)
Is this a known error?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.