Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ version = "1.14.0"


[deps]
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
EnumX = "4e289a0a-7415-4d19-859d-a7e5c4648b56"
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
Expand All @@ -25,6 +26,7 @@ MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
OptimMOIExt = "MathOptInterface"

[compat]
ADTypes = "1.11.0"
Compat = "3.2.0, 3.3.0, 3.4.0, 3.5.0, 3.6.0, 4"
EnumX = "1.0.4"
FillArrays = "0.6.2, 0.7, 0.8, 0.9, 0.10, 0.11, 0.12, 0.13, 1"
Expand All @@ -44,7 +46,6 @@ Test = "<0.0.1, 1.6"
julia = "1.10"

[extras]
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
Expand All @@ -59,4 +60,4 @@ StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test", "Distributions", "MathOptInterface", "Measurements", "OptimTestProblems", "Random", "RecursiveArrayTools", "StableRNGs", "LineSearches", "NLSolversBase", "PositiveFactorizations", "ReverseDiff", "ADTypes"]
test = ["Test", "Distributions", "MathOptInterface", "Measurements", "OptimTestProblems", "Random", "RecursiveArrayTools", "StableRNGs", "LineSearches", "NLSolversBase", "PositiveFactorizations", "ReverseDiff"]
1 change: 1 addition & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[deps]
ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
Expand Down
2 changes: 1 addition & 1 deletion docs/src/examples/ipnewton_basics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ using Test #src
@test Optim.converged(res) #src
@test Optim.minimum(res) ≈ 0.25 #src

# Like the rest of Optim, you can also use `autodiff=:forward` and just pass in
# Like the rest of Optim, you can also use `autodiff=ADTypes.AutoForwardDiff()` and just pass in
# `fun`.

# If we only want to set lower bounds, use `ux = fill(Inf, 2)`
Expand Down
5 changes: 3 additions & 2 deletions docs/src/examples/maxlikenlm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using Optim, NLSolversBase
using LinearAlgebra: diag
using ForwardDiff
using ADTypes: AutoForwardDiff

#md # !!! tip
#md # Add Optim with the following command at the Julia command prompt:
Expand Down Expand Up @@ -152,7 +153,7 @@ end
func = TwiceDifferentiable(
vars -> Log_Likelihood(x, y, vars[1:nvar], vars[nvar+1]),
ones(nvar + 1);
autodiff = :forward,
autodiff = AutoForwardDiff(),
);

# The above statment accepts 4 inputs: the x matrix, the dependent
Expand All @@ -163,7 +164,7 @@ func = TwiceDifferentiable(
# the error variance.
#
# The `ones(nvar+1)` are the starting values for the parameters and
# the `autodiff=:forward` command performs forward mode automatic
# the `autodiff=ADTypes.AutoForwardDiff()` command performs forward mode automatic
# differentiation.
#
# The actual optimization of the likelihood function is accomplished
Expand Down
14 changes: 7 additions & 7 deletions docs/src/user/gradientsandhessians.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ Automatic differentiation techniques are a middle ground between finite differen

Reverse-mode automatic differentiation can be seen as an automatic implementation of the adjoint method mentioned above, and requires a runtime comparable to only one evaluation of ``f``. It is however considerably more complex to implement, requiring to record the execution of the program to then run it backwards, and incurs a larger overhead.

Forward-mode automatic differentiation is supported through the [ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) package by providing the `autodiff=:forward` keyword to `optimize`.
More generic automatic differentiation is supported thanks to [DifferentiationInterface.jl](https://github.com/JuliaDiff/DifferentiationInterface.jl), by setting `autodiff` to any compatible backend object from [ADTypes.jl](https://github.com/SciML/ADTypes.jl).
For instance, the user can choose `autodiff=AutoReverseDiff()`, `autodiff=AutoEnzyme()`, `autodiff=AutoMooncake()` or `autodiff=AutoZygote()` for a reverse-mode gradient computation, which is generally faster than forward mode on large inputs.
Each of these choices requires loading the corresponding package beforehand.
Generic automatic differentiation is supported thanks to [DifferentiationInterface.jl](https://github.com/JuliaDiff/DifferentiationInterface.jl), by setting `autodiff` to any compatible backend object from [ADTypes.jl](https://github.com/SciML/ADTypes.jl).
For instance, forward-mode automatic differentiation through the [ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) package by providing the `autodiff=ADTypes.AutoForwardDiff()` keyword to `optimize`.
Additionally, the user can choose `autodiff=AutoReverseDiff()`, `autodiff=AutoEnzyme()`, `autodiff=AutoMooncake()` or `autodiff=AutoZygote()` for a reverse-mode gradient computation, which is generally faster than forward mode on large inputs.
Each of these choices requires loading the `ADTypes` package and the corresponding automatic differentiation package (e.g., `ForwardDiff` or `ReverseDiff`) beforehand.

## Example

Expand Down Expand Up @@ -66,14 +66,14 @@ julia> Optim.minimizer(optimize(f, initial_x, BFGS()))
```
Still looks good. Returning to automatic differentiation, let us try both solvers using this
method. We enable [forward mode](https://github.com/JuliaDiff/ForwardDiff.jl) automatic
differentiation by using the `autodiff = :forward` keyword.
differentiation by using the `autodiff = AutoForwardDiff()` keyword.
```jlcon
julia> Optim.minimizer(optimize(f, initial_x, BFGS(); autodiff = :forward))
julia> Optim.minimizer(optimize(f, initial_x, BFGS(); autodiff = AutoForwardDiff()))
2-element Array{Float64,1}:
1.0
1.0

julia> Optim.minimizer(optimize(f, initial_x, Newton(); autodiff = :forward))
julia> Optim.minimizer(optimize(f, initial_x, Newton(); autodiff = AutoForwardDiff()))
2-element Array{Float64,1}:
1.0
1.0
Expand Down
4 changes: 2 additions & 2 deletions docs/src/user/minimization.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ If we pass `f` alone, Optim will construct an approximate gradient for us using
```jl
optimize(f, x0, LBFGS())
```
For better performance and greater precision, you can pass your own gradient function. If your objective is written in all Julia code with no special calls to external (that is non-Julia) libraries, you can also use automatic differentiation, by using the `autodiff` keyword and setting it to `:forward`:
For better performance and greater precision, you can pass your own gradient function. If your objective is written in all Julia code with no special calls to external (that is non-Julia) libraries, you can also use automatic differentiation, by using the `autodiff` keyword and setting it to `AutoForwardDiff()`:
```julia
optimize(f, x0, LBFGS(); autodiff = :forward)
optimize(f, x0, LBFGS(); autodiff = AutoForwardDiff())
```

For the Rosenbrock example, the analytical gradient can be shown to be:
Expand Down
2 changes: 1 addition & 1 deletion ext/OptimMOIExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ function MOI.optimize!(model::Optimizer{T}) where {T}
inplace = true,
)
else
d = Optim.promote_objtype(method, initial_x, :finite, true, f, g!, h!)
d = Optim.promote_objtype(method, initial_x, Optim.DEFAULT_AD_TYPE, true, f, g!, h!)
options = Optim.Options(; Optim.default_options(method)..., options...)
if nl_constrained || has_bounds
if nl_constrained
Expand Down
2 changes: 2 additions & 0 deletions src/Optim.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ import NLSolversBase:
# var for NelderMead
import StatsBase: var

import ADTypes

import LinearAlgebra
import LinearAlgebra:
Diagonal,
Expand Down
25 changes: 14 additions & 11 deletions src/multivariate/optimize/interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ fallback_method(f) = NelderMead()
fallback_method(f, g!) = LBFGS()
fallback_method(f, g!, h!) = Newton()

# By default, use central finite difference method
const DEFAULT_AD_TYPE = ADTypes.AutoFiniteDiff(; fdtype = Val(:central))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One could consider switching to a different default AD backend (maybe ForwardDiff for univariate optimization and e.g. Mooncake - if at least all tests pass - for multivariate optimization problems? - but the choice for when to switch to which backend is likely also problem/dimension dependent, see also https://docs.sciml.ai/Optimization/stable/API/ad/#ad). But I think it would be better to make such more fundamental changes in a separate PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree both to switch to reverse mode for multivariate and forward for univariate, but also that it's probably a separate PR


function fallback_method(f::InplaceObjective)
if !(f.fdf isa Nothing)
if !(f.hv isa Nothing)
Expand Down Expand Up @@ -137,7 +140,7 @@ function optimize(
f,
initial_x::AbstractArray;
inplace = true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)
method = fallback_method(f)
d = promote_objtype(method, initial_x, autodiff, inplace, f)
Expand All @@ -149,7 +152,7 @@ function optimize(
f,
g,
initial_x::AbstractArray;
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
inplace = true,
)

Expand All @@ -166,7 +169,7 @@ function optimize(
h,
initial_x::AbstractArray;
inplace = true,
autodiff = :finite
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)
method = fallback_method(f, g, h)
d = promote_objtype(method, initial_x, autodiff, inplace, f, g, h)
Expand All @@ -189,7 +192,7 @@ function optimize(
initial_x::AbstractArray,
options::Options;
inplace = true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)
method = fallback_method(f)
d = promote_objtype(method, initial_x, autodiff, inplace, f)
Expand All @@ -201,7 +204,7 @@ function optimize(
initial_x::AbstractArray,
options::Options;
inplace = true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)

method = fallback_method(f, g)
Expand All @@ -215,7 +218,7 @@ function optimize(
initial_x::AbstractArray{T},
options::Options;
inplace = true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
) where {T}
method = fallback_method(f, g, h)
d = promote_objtype(method, initial_x, autodiff, inplace, f, g, h)
Expand All @@ -230,7 +233,7 @@ function optimize(
method::AbstractOptimizer,
options::Options = Options(; default_options(method)...);
inplace = true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)
d = promote_objtype(method, initial_x, autodiff, inplace, f)
optimize(d, initial_x, method, options)
Expand All @@ -242,7 +245,7 @@ function optimize(
method::AbstractOptimizer,
options::Options = Options(; default_options(method)...);
inplace = true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)

d = promote_objtype(method, initial_x, autodiff, inplace, f)
Expand All @@ -255,7 +258,7 @@ function optimize(
method::AbstractOptimizer,
options::Options = Options(; default_options(method)...);
inplace = true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)
d = promote_objtype(method, initial_x, autodiff, inplace, f, g)

Expand All @@ -269,7 +272,7 @@ function optimize(
method::AbstractOptimizer,
options::Options = Options(; default_options(method)...);
inplace = true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,

)
d = promote_objtype(method, initial_x, autodiff, inplace, f, g, h)
Expand All @@ -283,7 +286,7 @@ function optimize(
method::SecondOrderOptimizer,
options::Options = Options(; default_options(method)...);
inplace = true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
) where {D<:Union{NonDifferentiable,OnceDifferentiable}}
d = promote_objtype(method, initial_x, autodiff, inplace, d)
optimize(d, initial_x, method, options)
Expand Down
16 changes: 8 additions & 8 deletions src/multivariate/solvers/constrained/fminbox.jl
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ function optimize(
F::Fminbox = Fminbox(),
options::Options = Options();
inplace::Bool=true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)
if f isa NonDifferentiable
f = f.f
Expand All @@ -308,7 +308,7 @@ function optimize(
optimize(od, l, u, initial_x, F, options)
end

function optimize(f, l::Number, u::Number, initial_x::AbstractArray; autodiff = :finite)
function optimize(f, l::Number, u::Number, initial_x::AbstractArray; autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE)
T = eltype(initial_x)
optimize(
OnceDifferentiable(f, initial_x, zero(T); autodiff),
Expand All @@ -328,7 +328,7 @@ optimize(
mo::AbstractConstrainedOptimizer,
opt::Options = Options();
inplace::Bool=true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
) = optimize(
f,
Fill(T(l), size(initial_x)...),
Expand All @@ -347,7 +347,7 @@ function optimize(
mo::AbstractConstrainedOptimizer = Fminbox(),
opt::Options = Options();
inplace::Bool=true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)
T = eltype(initial_x)
optimize(f, T.(l), Fill(T(u), size(initial_x)...), initial_x, mo, opt; inplace, autodiff)
Expand All @@ -360,7 +360,7 @@ function optimize(
mo::AbstractConstrainedOptimizer=Fminbox(),
opt::Options = Options();
inplace::Bool=true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)
T = eltype(initial_x)
optimize(f, Fill(T(l), size(initial_x)...), T.(u), initial_x, mo, opt; inplace, autodiff)
Expand All @@ -373,7 +373,7 @@ function optimize(
initial_x::AbstractArray,
opt::Options;
inplace::Bool=true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)

T = eltype(initial_x)
Expand All @@ -397,7 +397,7 @@ function optimize(
initial_x::AbstractArray,
opt::Options;
inplace::Bool=true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)
T = eltype(initial_x)
optimize(f, g, T.(l), Fill(T(u), size(initial_x)...), initial_x, opt; inplace, autodiff)
Expand All @@ -411,7 +411,7 @@ function optimize(
initial_x::AbstractArray,
opt::Options;
inplace::Bool=true,
autodiff = :finite,
autodiff::ADTypes.AbstractADType = DEFAULT_AD_TYPE,
)
T= eltype(initial_x)
optimize(f, g, Fill(T(l), size(initial_x)...), T.(u), initial_x, opt, inplace, autodiff)
Expand Down
14 changes: 7 additions & 7 deletions test/general/objective_types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
@test_throws ErrorException OnceDifferentiable(x -> x, rand(10); autodiff = :wah)

for T in (OnceDifferentiable, TwiceDifferentiable)
odad1 = T(x -> 5.0, rand(1); autodiff = :finite)
odad2 = T(x -> 5.0, rand(1); autodiff = :forward)
odad1 = T(x -> 5.0, rand(1); autodiff = AutoFiniteDiff(; fdtype = Val(:central)))
odad2 = T(x -> 5.0, rand(1); autodiff = AutoForwardDiff())
odad3 = T(x -> 5.0, rand(1); autodiff = AutoReverseDiff())
Optim.gradient!(odad1, rand(1))
Optim.gradient!(odad2, rand(1))
Expand All @@ -17,8 +17,8 @@

for a in (1.0, 5.0)
xa = rand(1)
odad1 = OnceDifferentiable(x -> a * x[1], xa; autodiff = :finite)
odad2 = OnceDifferentiable(x -> a * x[1], xa; autodiff = :forward)
odad1 = OnceDifferentiable(x -> a * x[1], xa; autodiff = AutoFiniteDiff(; fdtype = Val(:central)))
odad2 = OnceDifferentiable(x -> a * x[1], xa; autodiff = AutoForwardDiff())
odad3 = OnceDifferentiable(x -> a * x[1], xa; autodiff = AutoReverseDiff())
Optim.gradient!(odad1, xa)
Optim.gradient!(odad2, xa)
Expand All @@ -29,8 +29,8 @@
end
for a in (1.0, 5.0)
xa = rand(1)
odad1 = OnceDifferentiable(x -> a * x[1]^2, xa; autodiff = :finite)
odad2 = OnceDifferentiable(x -> a * x[1]^2, xa; autodiff = :forward)
odad1 = OnceDifferentiable(x -> a * x[1]^2, xa; autodiff = AutoFiniteDiff(; fdtype = Val(:central)))
odad2 = OnceDifferentiable(x -> a * x[1]^2, xa; autodiff = AutoForwardDiff())
odad3 = OnceDifferentiable(x -> a * x[1]^2, xa; autodiff = AutoReverseDiff())
Optim.gradient!(odad1, xa)
Optim.gradient!(odad2, xa)
Expand All @@ -40,7 +40,7 @@
@test Optim.gradient(odad3) == 2.0 * a * xa
end
for dtype in (OnceDifferentiable, TwiceDifferentiable)
for autodiff in (:finite, :forward, AutoReverseDiff())
for autodiff in (AutoFiniteDiff(; fdtype = Val(:central)), AutoForwardDiff(), AutoReverseDiff())
differentiable = dtype(x -> sum(x), rand(2); autodiff = autodiff)
Optim.value(differentiable)
Optim.value!(differentiable, rand(2))
Expand Down
8 changes: 4 additions & 4 deletions test/multivariate/solvers/constrained/fminbox.jl
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
optimize(od, lb, ub, initial_x, Fminbox())
nd = NonDifferentiable(exponential, initial_x)
optimize(nd, lb, ub, initial_x, Fminbox(NelderMead()))
od_forward = OnceDifferentiable(exponential, initial_x; autodiff = :forward)
od_forward = OnceDifferentiable(exponential, initial_x; autodiff = AutoForwardDiff())
optimize(od_forward, lb, ub, initial_x, Fminbox())
optimize(exponential, lb, ub, initial_x, Fminbox())
optimize(exponential, exponential_gradient!, lb, ub, initial_x, Fminbox())
Expand All @@ -131,8 +131,8 @@
optimize(exponential, exponential_gradient!, lb, ub, initial_x)
@testset "inplace and autodiff keywords #616" begin
optimize(exponential, lb, ub, initial_x, Fminbox())
optimize(exponential, lb, ub, initial_x, Fminbox(); autodiff = :finite)
optimize(exponential, lb, ub, initial_x, Fminbox(); autodiff = :forward)
optimize(exponential, lb, ub, initial_x, Fminbox(); autodiff = AutoFiniteDiff(; fdtype = Val(:central)))
optimize(exponential, lb, ub, initial_x, Fminbox(); autodiff = AutoForwardDiff())
optimize(
exponential,
exponential_gradient,
Expand Down Expand Up @@ -196,7 +196,7 @@ end
[1.0],
Fminbox(m),
)
optimize(x -> sqrt(x[1]), [0.0], [10.0], [1.0], Fminbox(m); autodiff = :forwarddiff)
optimize(x -> sqrt(x[1]), [0.0], [10.0], [1.0], Fminbox(m); autodiff = AutoForwardDiff())
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ using Optim, Test
ux = fill(+1.2, dof)
dfc = TwiceDifferentiableConstraints(lx, ux)

res = optimize(df, dfc, x0, IPNewton(); autodiff = :forward)
res = optimize(df, dfc, x0, IPNewton(); autodiff = AutoForwardDiff())
res = optimize(df, dfc, x0, IPNewton())
end

Expand Down
Loading
Loading