The runtime of rosenbrock is totally negligble in Julia:
julia> @btime rosenbrock($x2) # result of running optimization
1.354 ns (0 allocations: 0 bytes)
7.645688055381766e-21
but it may take close to a microseond or per call in Python?
Also, FWIW, I once tried to lean up Optim for use on cheap functions in simulations. Things aren’t in a pretty state at the moment, but, setup (note this “once differentiable” object uses ForwardDiff):
using BenchmarkTools, DifferentiableObjects # https://github.com/chriselrod/DifferentiableObjects.jl
using TriangularMatrices
# This should really be StaticArrays, but in a rush job I didn't make things as generic as I should have.
# I'll get around to making it appropriately generic within a couple months
# https://github.com/chriselrod/TriangularMatrices.jl
rosenbrock(x) = (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2
x = RecursiveVector{Float64,2}() .= 0; # basically, an MVector
od = OnceDifferentiable(rosenbrock, deepcopy(x));
Results:
julia> optimize_light(od, x, BFGS())
([1.0, 1.0], 7.645688055381766e-21)
julia> x
2-element RecursiveVector{Float64,2}:
0.0
0.0
julia> @benchmark optimize_light($od, $x, BFGS())
BenchmarkTools.Trial:
memory estimate: 14.08 KiB
allocs estimate: 313
--------------
minimum time: 10.747 μs (0.00% GC)
median time: 11.165 μs (0.00% GC)
mean time: 18.872 μs (37.76% GC)
maximum time: 51.231 ms (99.95% GC)
--------------
samples: 10000
evals/sample: 1
Also, you should definitely give BackTracking a try:
julia> using LineSearches
julia> @benchmark optimize_light($od, $x, BFGS(;linesearch = BackTracking()))
BenchmarkTools.Trial:
memory estimate: 3.02 KiB
allocs estimate: 83
--------------
minimum time: 5.105 μs (0.00% GC)
median time: 5.244 μs (0.00% GC)
mean time: 6.884 μs (20.84% GC)
maximum time: 9.548 ms (99.93% GC)
--------------
samples: 10000
evals/sample: 6
I’ve found it to be much faster than the default line search HagerZhang in my problems (but slightly less reliable when the parameter space is poorly behaved).
Anyway, for most problems, the actual function calls dominate runtime. This I think is overall a major advantage of Julia – you’re optimizing Julia functions, not Python functions.
And it also means the performance benefits of leaning out Optim, like you see above, are negligible for most problems.
Final aside: would be nice to take advantage of GitHub - yuyichao/FunctionWrappers.jl
to get type stability, without having to recompile for different objectives.