-
Notifications
You must be signed in to change notification settings - Fork 1
add a user define option for threshold in bregman #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/bregman.jl
Outdated
@@ -124,7 +126,7 @@ function bregman(funobj::Function, x::AbstractArray{T}, options::BregmanParams, | |||
# Update z variable | |||
@. z = z + d | |||
# Get λ at first iteration | |||
i == 1 && (λ = abs(T(quantile(abs.(z), options.quantile)))) | |||
i == 1 && (sol.λ = λ = isnothing(options.lambda) ? abs(T(quantile(abs.(z), options.quantile))) : abs(T(options.lambda))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a lot of if in one line but I guess.
I'm still waiting on an answer as to why you would ever end up with a complex-valued x
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that will be easy if I want to solve AC'x=b
where x is the complex curvelet coefficients. It is easier for me to take this form if I want to do weightings on x
later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not the right way to use this as you are not solving the correct problem. You are always solving the L1-l2
elastic net on the curvelet coefficient so x
is your image and is real. if you give z as the input and C' instead of C you are solving sparsity in the image domain.
If you want to do weighting you need to provide W*C
instead of C
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I see your point. However, I think they are different ways to form the optimization problem. Either way works because they should be mathematically equivalent to solve for either the image or its curvelet coefficients. So I still think a PR to fix the support of complex number is needed. Any thought?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either way does not work. You are confusing mathematical equivalence and implementation equivalence you can't make a program magically understand a change of variable (which is what you are doing). The documentation fo this implementation is very explicit about what it solves.
I don't have an issue with complex number supports but you are not doing what you think you are doing and it has to be for the case where x
is complex, the actual primal x
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem of provide W*C instead of C
is that its adjoint is not inverse. Then during soft-thresholding we have to do a W inverse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because you are trying to do a weighted l1 which is a different problem. You could add weighted l1 with the standard identity as default but again you need to be careful about what problem you are solving.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I agree what you are saying now but we don't have to add anything new: just solve AC'Wx = b
and use the identity as the sparsity transform will do the work. The solution is C'WX
in the end. That's much simpler than adding a weighted l1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not the same as you will computethe threshold on W*z
not on z
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No we don't have to. The forward and adjoint of W
can already bump the entries on support 2 times so these entries are much easier to pass the threshold
src/bregman.jl
Outdated
@@ -124,15 +127,29 @@ function bregman(funobj::Function, x::AbstractArray{T}, options::BregmanParams, | |||
# Update z variable | |||
@. z = z + d | |||
# Get λ at first iteration | |||
i == 1 && (λ = abs(T(quantile(abs.(z), options.quantile)))) | |||
if i == 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very ugly, it takes more space than the actual algorithm, make a proper function with dispatch for this.
src/bregman.jl
Outdated
if length(λ) == 1 | ||
@printf("%10d %15.5e %15.5e %15.5e %15.5e \n",i, t, obj_fun, f, λ) | ||
else | ||
@printf("%10d %15.5e %15.5e %15.5e %5s \n",i, t, obj_fun, f, "vector") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's not informative, choose a value like min/max/mean/ or tuple or something to give proper information
examples/denoising.jl
Outdated
@@ -20,11 +20,11 @@ imgn= img .+ .01f0*randn(Float32, size(img)) | |||
b = A*vec(imgn) | |||
|
|||
# setup bregamn | |||
opt = bregman_options(maxIter=200, verbose=2, quantile=.5, alpha=1, antichatter=true) | |||
opt2 = bregman_options(maxIter=200, verbose=2, quantile=.5, alpha=1, antichatter=true, spg=true) | |||
opt = bregman_options(maxIter=200, verbose=2, alpha=1, antichatter=true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really don't like this. Now there is options all over the place that completely defeat the purpose. And why is the TD moved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remove TD so that it's optional (default is identity matrix)
What do you mean "Now there is options all over the place that completely defeat the purpose"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
like do you mean I should move these lambda, lambdafunc etc inside the bregmanparams?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now there is the options and the additional kwargs. Like user have to set options then have to put new ones separately like lambda. I still think its a bit messy. Put back the old basic interface and use dispatch to properly set the other cases in a clean way not adding 50 kwargs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't dispatch over a quantile or a pre-set threshold. They are both a single number. Any thought?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
99% of what you added can be easily done via simple dispatch rather than all these additional keyword arguments on top of the options, for exampel would have takien you one line to define
bregman(A, x, b) = bregman(A, LinearAlgebra.I, x::Array{T}, b)
And everything satays clean an easy to use. Try to make an effort making it user friendly not "works for me" friendly. All the rest is the same can be easily done via dispatch and/or options preprocessing and setup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok thanks for your suggestion on this LinearAlgebra.I
thing. I agree this works in a more reasonable structure.
What's your take on this threshold thing? Following your suggestion, I should add it in the bregmanparams, right? Since a pre-set threshold and a quantile are both single value. Can't dispatch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Options are all kwargs so you can filter then and do so pre-setup based on input
Now previous functionality still works |
@@ -20,11 +20,11 @@ imgn= img .+ .01f0*randn(Float32, size(img)) | |||
b = A*vec(imgn) | |||
|
|||
# setup bregamn | |||
opt = bregman_options(maxIter=200, verbose=2, quantile=.5, alpha=1, antichatter=true) | |||
opt2 = bregman_options(maxIter=200, verbose=2, quantile=.5, alpha=1, antichatter=true, spg=true) | |||
opt = bregman_options(maxIter=200, verbose=2, quantile=.5, alpha=1, antichatter=true, TD=W) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
at that point let's just put A and x and b in options too........
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the bregman function itself should show A
and b
(or the function to calculate function value and gradient) since we are solving a linear system. In terms of the sparsifying transform ... I slightly prefer putting it into the options (since we have different "options" for sparsifying transform)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mind moving TD to the options but this still needs cleanup
src/bregman.jl
Outdated
bregman_options(;verbose=1, progTol=1e-8, maxIter=20, store_trace=false, antichatter=true, quantile=.95, alpha=.5, spg=false) = | ||
BregmanParams(verbose, progTol, maxIter, store_trace, antichatter, quantile, alpha, spg) | ||
bregman_options(;verbose=1, progTol=1e-8, maxIter=20, store_trace=false, antichatter=true, alpha=.5, spg=false, TD=LinearAlgebra.I, quantile=.95, λ=nothing, λfunc=nothing) = | ||
BregmanParams(verbose, progTol, maxIter, store_trace, antichatter, alpha, spg, TD, quantile, λ, λfunc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is still messy
- Some of these options are not compatible
- You wouldn't need to check all these
if options.x
below if you just properly filter the input options to setup the problem
src/bregman.jl
Outdated
λfunc = z->quantile(abs.(z), options.quantile) | ||
end | ||
end | ||
return bregman(funobj, x, options, λfunc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now you have to call the algo with λfunc
both in options
and as an input which you wuldn't with properly setup options
src/bregman.jl
Outdated
end | ||
|
||
function bregman(funobj::Function, TD, x::AbstractArray{T}, options=bregman_options()) where {T} | ||
options.TD = TD |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mutating structure and objects is in general very bad practice coding-wise, so this needs a proper deprecation warning.
src/bregman.jl
Outdated
@@ -124,16 +160,14 @@ function bregman(funobj::Function, x::AbstractArray{T}, options::BregmanParams, | |||
# Update z variable | |||
@. z = z + d | |||
# Get λ at first iteration | |||
i == 1 && (λ = abs(T(quantile(abs.(z), options.quantile)))) | |||
(i == 1) && (sol.λ = λ = abs.(T.(λfunc(z)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or you can just use sol.λ
everywhere
src/bregman.jl
Outdated
""" | ||
function bregman(funobj::Function, x::AbstractArray{T}, options::BregmanParams, TD=nothing) where {T} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No blank line between docstring and function
src/bregman.jl
Outdated
""" | ||
function bregman(A, TD, x::Array{T}, b, options) where {T} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No blank line between docstring and code
src/bregman.jl
Outdated
|
||
""" | ||
bregman(A, TD, x, b, options) | ||
bregman(A, x, b; options) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TD isn't defined anymore in problem def line 47
src/bregman.jl
Outdated
end | ||
|
||
""" | ||
bregman_options(;verbose=1, optTol=1e-6, progTol=1e-8, maxIter=20 | ||
store_trace=false, linesearch=false, alpha=.25, spg=false) | ||
store_trace=false, λ=.2, alpha=.25, spg=false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where does .2 comes from
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just to inform user that you can do something like this
test/test_bregman.jl
Outdated
@@ -5,9 +5,9 @@ using LinearAlgebra | |||
|
|||
N1 = 100 | |||
N2 = div(N1, 2) + 5 | |||
A = randn(N1, N2) | |||
A = randn(ComplexF32, N1, N2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want to add a case add an extra one do not modify an existing one especially if you are disabling options
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
test/test_bregman.jl
Outdated
@@ -20,8 +20,8 @@ function obj(x) | |||
return fun, grad | |||
end | |||
|
|||
opt = bregman_options(maxIter=200, progTol=0, verbose=2) | |||
sol = bregman(obj, 1 .+ randn(N2), opt) | |||
opt = bregman_options(maxIter=200, progTol=0, verbose=2, antichatter=false) # anti chatter now only works with real number |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to raise a proper error if attempted. Why isn't it supported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anti-chatter needs to record number of -1/1 when the gradient fluctuates. If things are complex then there is no -1/1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes there is no sign
in complex which is why there is a different thresholding function for this case so the anti-chatter should follow it and use the angle instead of sign but I think it should follow
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm in anti-chatter there is a sum of -1/1. How do we do it with angle? A sum of unit vectors with different angles? And then do inner product to calculate the scaling of gradient?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably something like that. I don't mind it leaving it as a todo and see if can make something like that work, would assume it would by summing the angles. But would adda warning or error if someone tries it so that it's readable not a lengthy error trace
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gotcha make sense
src/bregman.jl
Outdated
""" | ||
function bregman(A, TD, x::Array{T}, b, options) where {T} | ||
function bregman(A, x::AbstractArray{T}, b::AbstractArray{T}, options::BregmanParams) where {T} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No! There is defaults for a reason
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly there
src/bregman.jl
Outdated
if ~isnothing(λ) | ||
λfunc = z->λ | ||
else | ||
λfunc = z->SlimOptim.quantile(abs.(z), quantile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Statistics.
src/bregman.jl
Outdated
""" | ||
function bregman(A, TD, x::Array{T}, b, options) where {T} | ||
function bregman(A, x::AbstractArray{T}, b::AbstractArray{T}, options::BregmanParams=bregman_options()) where {T} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AbstractVector no? May wanna add it to obj below as well
src/bregman.jl
Outdated
@@ -97,7 +116,7 @@ function bregman(funobj::Function, x::AbstractArray{T}, options::BregmanParams, | |||
# Result structure | |||
sol = breglog(x, z) | |||
# Initialize λ | |||
λ = abs(T(0)) | |||
sol.λ = abs(T(0)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't this be done in options init now?
test/test_bregman.jl
Outdated
@@ -36,3 +36,35 @@ part_nz = i -> norm(sol.x[i], 1)/N2 | |||
@test part_nz(inds) < 1f-1 | |||
@test part_n(ninds) < 1f-1 | |||
@test sol.residual/sol.r_trace[1] < 1f-1 | |||
|
|||
# test complex | |||
A = randn(ComplexF32, N1, N2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For T in [float, complex]...
src/bregman.jl
Outdated
norm(x - sol.x) < options.progTol && (@printf("Step size below progTol\n"); break;) | ||
update!(sol; iter=i, ϕ=obj_fun, residual=f, x=x, z=z, g=g, store_trace=options.store_trace) | ||
end | ||
return sol | ||
end | ||
|
||
function bregman(funobj::Function, x::AbstractArray{T}, options::BregmanParams, TD) where {T} | ||
@warn "deprecation warning: TD should be put in BregmanParams when version >= 0.1.8; now overwritting TD in BregmanParams" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add new syntax explicitly to message
No description provided.