Creating polyalgorithms by chaining solvers using remake
The general framework of using multiple solvers to use exploration-convergence alternations is commonly known as polyalgorithms. In the past Optimization.jl has provided a PolyOpt
solver in OptimizationPolyalgorithms.jl
which combined Adam from Optimisers.jl with BFGS from Optim.jl. With the large number of choices available through the interface unique combinations of solvers can be effective for specific problems.
In this tutorial we will demonstrate how to use the remake
function to chain together solvers to create your own polyalgorithms.
The SciML interface provides a remake
function which allows you to recreate the OptimizationProblem
from a previously defined OptimizationProblem
with different initial guess for the optimization variables.
Let's look at a 10 dimensional schwefel function in the hypercube $x_i \in [-500, 500]$.
using Optimization, Random
using OptimizationBBO, ReverseDiff
Random.seed!(122333)
function f_schwefel(x, p = [418.9829])
result = p[1] * length(x)
for i in 1:length(x)
result -= x[i] * sin(sqrt(abs(x[i])))
end
return result
end
optf = OptimizationFunction(f_schwefel, Optimization.AutoReverseDiff(compile = true))
x0 = ones(10) .* 200.0
prob = OptimizationProblem(
optf, x0, [418.9829], lb = fill(-500.0, 10), ub = fill(500.0, 10))
@show f_schwefel(x0)
2189.853687755758
Our polyalgorithm strategy will to use BlackBoxOptim's global optimizers for efficient exploration of the parameter space followed by a quasi-Newton LBFGS method to (hopefully) converge to the global optimum.
res1 = solve(prob, BBO_adaptive_de_rand_1_bin(), maxiters = 4000)
@show res1.objective
592.7339938425041
This is a good start can we converge to the global optimum?
prob = remake(prob, u0 = res1.minimizer)
res2 = solve(prob, Optimization.LBFGS(), maxiters = 100)
@show res2.objective
118.4384618901176
Yay! We have found the global optimum (this is known to be at $x_i = 420.9687$).