|
| 1 | +--- |
| 2 | +author: "Jonathan Bieler, Chris Rackauckas" |
| 3 | +title: "Black-Box Global Optimizer Benchmarks" |
| 4 | +--- |
| 5 | + |
| 6 | + |
| 7 | +In this benchmark we will run the [BlackboxGlobalOptimization.jl](https://github.com/jonathanBieler/BlackBoxOptimizationBenchmarking.jl) |
| 8 | +benchmarks, a set of global optimization benchmarks on the [Optimization.jl](https://github.com/SciML/Optimization.jl) |
| 9 | +interface that test a wide variety of behaviors. This tests time and iterations vs accuracy, |
| 10 | +i.e. for a given amount of time to the optimizer, what percentage of problems from the set is |
| 11 | +it able to solve. This gives a global view of which methods are the most efficient at finding |
| 12 | +difficult global optima. |
| 13 | + |
| 14 | +## Setup |
| 15 | + |
| 16 | +```julia |
| 17 | +using BlackBoxOptimizationBenchmarking, Plots, Optimization, Memoize, Statistics |
| 18 | +import BlackBoxOptimizationBenchmarking.Chain |
| 19 | +const BBOB = BlackBoxOptimizationBenchmarking |
| 20 | + |
| 21 | +using OptimizationBBO, OptimizationOptimJL, OptimizationEvolutionary, OptimizationNLopt |
| 22 | +using OptimizationMetaheuristics, OptimizationNOMAD, OptimizationPRIMA, OptimizationOptimisers |
| 23 | +``` |
| 24 | + |
| 25 | + |
| 26 | +```julia |
| 27 | +chain = (t; isboxed=false) -> Chain( |
| 28 | + BenchmarkSetup(t, isboxed = isboxed), |
| 29 | + BenchmarkSetup(NelderMead(), isboxed = false), |
| 30 | + 0.9 |
| 31 | +) |
| 32 | + |
| 33 | +test_functions = BBOB.list_functions() |
| 34 | +dimension = 3 |
| 35 | +run_length = round.(Int, 10 .^ LinRange(1,5,30)) |
| 36 | + |
| 37 | +@memoize run_bench(algo) = BBOB.benchmark(setup[algo], test_functions, run_length, Ntrials=40, dimension = dimension) |
| 38 | +``` |
| 39 | + |
| 40 | +``` |
| 41 | +run_bench (generic function with 1 method) |
| 42 | +``` |
| 43 | + |
| 44 | + |
| 45 | + |
| 46 | +```julia |
| 47 | +setup = Dict( |
| 48 | + "NelderMead" => NelderMead(), |
| 49 | + #Optim.BFGS(), |
| 50 | + #"NLopt.GN_MLSL_LDS" => chain(NLopt.GN_MLSL_LDS(), isboxed=true), # gives me errors |
| 51 | + "NLopt.GN_CRS2_LM()" => chain(NLopt.GN_CRS2_LM(), isboxed=true), |
| 52 | + "NLopt.GN_DIRECT()" => chain(NLopt.GN_DIRECT(), isboxed=true), |
| 53 | + "NLopt.GN_ESCH()" => chain(NLopt.GN_ESCH(), isboxed=true), |
| 54 | + "OptimizationEvolutionary.GA()" => chain(OptimizationEvolutionary.GA(), isboxed=true), |
| 55 | + "OptimizationEvolutionary.DE()" => chain(OptimizationEvolutionary.DE(), isboxed=true), |
| 56 | + "OptimizationEvolutionary.ES()" => chain(OptimizationEvolutionary.ES(), isboxed=true), |
| 57 | + "Optim.SAMIN" => chain(SAMIN(verbosity=0), isboxed=true), |
| 58 | + "BBO_adaptive_de_rand_1_bin" => chain(BBO_adaptive_de_rand_1_bin(), isboxed=true), |
| 59 | + "BBO_adaptive_de_rand_1_bin_radiuslimited" => chain(BBO_adaptive_de_rand_1_bin_radiuslimited(), isboxed=true), # same as BBO_adaptive_de_rand_1_bin |
| 60 | + "BBO_separable_nes" => chain(BBO_separable_nes(), isboxed=true), |
| 61 | + "BBO_de_rand_2_bin" => chain(BBO_de_rand_2_bin(), isboxed=true), |
| 62 | + #"BBO_xnes" => chain(BBO_xnes(), isboxed=true), # good but slow |
| 63 | + #"BBO_dxnes" => chain(BBO_dxnes(), isboxed=true), |
| 64 | + "OptimizationMetaheuristics.ECA" => chain(OptimizationMetaheuristics.ECA(), isboxed=true), |
| 65 | + #"OptimizationMetaheuristics.CGSA" => () -> chain(OptimizationMetaheuristics.CGSA(), isboxed=true), #give me strange results |
| 66 | + "OptimizationMetaheuristics.DE" => chain(OptimizationMetaheuristics.DE(), isboxed=true), |
| 67 | + "Optimisers.AdamW" => chain(Optimisers.AdamW(), isboxed=false), |
| 68 | + "Optimisers.RMSProp" => chain(Optimisers.RMSProp(), isboxed=false), |
| 69 | + # "NOMADOpt" => chain(NOMADOpt()), too much printing |
| 70 | + # "OptimizationPRIMA.UOBYQA()" => chain(OptimizationPRIMA.UOBYQA()), :StackOverflowError? |
| 71 | + # "OptimizationPRIMA.NEWUOA()" => OptimizationPRIMA.UOBYQA(), |
| 72 | + # |
| 73 | +) |
| 74 | +``` |
| 75 | + |
| 76 | +``` |
| 77 | +Dict{String, Any} with 16 entries: |
| 78 | + "OptimizationEvolutionar… => Chain(GA → NelderMead)… |
| 79 | + "BBO_separable_nes" => Chain(BBO_separable_nes → NelderMead)… |
| 80 | + "NelderMead" => NelderMead{AffineSimplexer, AdaptiveParamete |
| 81 | +rs}(… |
| 82 | + "BBO_adaptive_de_rand_1_… => Chain(BBO_adaptive_de_rand_1_bin → NelderMea |
| 83 | +d)… |
| 84 | + "BBO_adaptive_de_rand_1_… => Chain(BBO_adaptive_de_rand_1_bin_radiuslimit |
| 85 | +ed →… |
| 86 | + "BBO_de_rand_2_bin" => Chain(BBO_de_rand_2_bin → NelderMead)… |
| 87 | + "NLopt.GN_DIRECT()" => Chain(Algorithm → NelderMead)… |
| 88 | + "NLopt.GN_ESCH()" => Chain(Algorithm → NelderMead)… |
| 89 | + "OptimizationMetaheurist… => Chain(Algorithm → NelderMead)… |
| 90 | + "OptimizationEvolutionar… => Chain(ES → NelderMead)… |
| 91 | + "Optimisers.AdamW" => Chain(AdamW → NelderMead)… |
| 92 | + "OptimizationEvolutionar… => Chain(DE → NelderMead)… |
| 93 | + "Optimisers.RMSProp" => Chain(RMSProp → NelderMead)… |
| 94 | + "OptimizationMetaheurist… => Chain(Algorithm → NelderMead)… |
| 95 | + "NLopt.GN_CRS2_LM()" => Chain(Algorithm → NelderMead)… |
| 96 | + "Optim.SAMIN" => Chain(SAMIN → NelderMead)… |
| 97 | +``` |
| 98 | + |
| 99 | + |
| 100 | + |
| 101 | + |
| 102 | + |
| 103 | +## Test one optimizer |
| 104 | + |
| 105 | +```julia |
| 106 | +@time b = BBOB.benchmark( |
| 107 | + chain(OptimizationMetaheuristics.CGSA(), isboxed=true), |
| 108 | + test_functions[1:10], 100:500:10_000, Ntrials=10, dimension = 3 |
| 109 | +) |
| 110 | + |
| 111 | +plot(b) |
| 112 | +``` |
| 113 | + |
| 114 | +``` |
| 115 | +11.445198 seconds (72.19 M allocations: 6.253 GiB, 5.34% gc time, 45.68% c |
| 116 | +ompilation time: 4% of which was recompilation) |
| 117 | +``` |
| 118 | + |
| 119 | + |
| 120 | + |
| 121 | + |
| 122 | + |
| 123 | + |
| 124 | +## Test one test function (Rastrigin) |
| 125 | + |
| 126 | +```julia |
| 127 | +Δf = 1e-6 |
| 128 | +f = test_functions[3] |
| 129 | + |
| 130 | +single_setup = BenchmarkSetup(NLopt.GN_CRS2_LM(), isboxed=true) |
| 131 | + |
| 132 | +sol = [BBOB.solve_problem(single_setup, f, 3, 5_000) for in in 1:10] |
| 133 | +@info [sol.objective < Δf + f.f_opt for sol in sol] |
| 134 | + |
| 135 | +p = plot(f, size = (600,600), zoom = 1.5) |
| 136 | +for sol in sol |
| 137 | + scatter!(sol.u[1:1], sol.u[2:2], label="", c="blue", marker = :xcross, markersize=5, markerstrokewidth=0) |
| 138 | +end |
| 139 | +p |
| 140 | +``` |
| 141 | + |
| 142 | + |
| 143 | + |
| 144 | + |
| 145 | + |
| 146 | +## Test all |
| 147 | + |
| 148 | +```julia |
| 149 | +results = Array{BBOB.BenchmarkResults}(undef, length(setup)) |
| 150 | + |
| 151 | +Threads.@threads for (i,algo) in collect(enumerate(keys(setup))) |
| 152 | + results[i] = run_bench(algo) |
| 153 | +end |
| 154 | + |
| 155 | +results |
| 156 | +``` |
| 157 | + |
| 158 | +``` |
| 159 | +16-element Vector{BlackBoxOptimizationBenchmarking.BenchmarkResults}: |
| 160 | + BenchmarkResults : |
| 161 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 162 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 163 | +Success rate : [0.0, 0.0, 0.0, 0.0, 0.0025, 0.00125, 0.0125, 0.015, 0.02625 |
| 164 | +, 0.03 … 0.525, 0.5225, 0.53125, 0.53125, 0.52625, 0.52375, 0.5425, 0.526 |
| 165 | +25, 0.52875, 0.53125] |
| 166 | + BenchmarkResults : |
| 167 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 168 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 169 | +Success rate : [0.01875, 0.03, 0.0425, 0.04625, 0.05, 0.0525, 0.07125, 0.10 |
| 170 | +375, 0.17625, 0.27625 … 0.63375, 0.6275, 0.64, 0.66125, 0.665, 0.65375, 0 |
| 171 | +.64, 0.6475, 0.66, 0.6475] |
| 172 | + BenchmarkResults : |
| 173 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 174 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 175 | +Success rate : [0.01625, 0.03, 0.04, 0.04625, 0.05, 0.05625, 0.08125, 0.146 |
| 176 | +25, 0.25625, 0.35625 … 0.53875, 0.5375, 0.52875, 0.5425, 0.53375, 0.5275, |
| 177 | + 0.53875, 0.5425, 0.53375, 0.53125] |
| 178 | + BenchmarkResults : |
| 179 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 180 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 181 | +Success rate : [0.00125, 0.005, 0.005, 0.00875, 0.01, 0.02, 0.02875, 0.0412 |
| 182 | +5, 0.04625, 0.05 … 0.8375, 0.92, 0.92875, 0.93875, 0.95875, 0.97375, 0.99 |
| 183 | +, 0.99875, 0.99875, 0.99625] |
| 184 | + BenchmarkResults : |
| 185 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 186 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 187 | +Success rate : [0.00125, 0.0025, 0.005, 0.01, 0.01875, 0.0175, 0.0375, 0.04 |
| 188 | +, 0.0475, 0.05 … 0.855, 0.92375, 0.945, 0.95875, 0.95875, 0.96375, 0.9662 |
| 189 | +5, 0.96, 0.95625, 0.965] |
| 190 | + BenchmarkResults : |
| 191 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 192 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 193 | +Success rate : [0.00125, 0.00375, 0.00625, 0.005, 0.01625, 0.0225, 0.0275, |
| 194 | +0.04125, 0.04875, 0.04875 … 0.7675, 0.84, 0.89125, 0.905, 0.91625, 0.9337 |
| 195 | +5, 0.93875, 0.94875, 0.96375, 0.96375] |
| 196 | + BenchmarkResults : |
| 197 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 198 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 199 | +Success rate : [0.0, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05 |
| 200 | +… 0.6, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7] |
| 201 | + BenchmarkResults : |
| 202 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 203 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 204 | +Success rate : [0.0, 0.0025, 0.00125, 0.0025, 0.00375, 0.0125, 0.0175, 0.03 |
| 205 | +, 0.0475, 0.05 … 0.57875, 0.59, 0.62875, 0.63, 0.6375, 0.635, 0.63875, 0. |
| 206 | +6525, 0.6425, 0.64] |
| 207 | + BenchmarkResults : |
| 208 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 209 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 210 | +Success rate : [0.0425, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.1 |
| 211 | + … 0.5, 0.5, 0.5, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55] |
| 212 | + BenchmarkResults : |
| 213 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 214 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 215 | +Success rate : [0.0, 0.0, 0.0, 0.0, 0.005, 0.0025, 0.0075, 0.01, 0.0175, 0. |
| 216 | +02875 … 0.52, 0.525, 0.5275, 0.54, 0.535, 0.53375, 0.5275, 0.54125, 0.538 |
| 217 | +75, 0.53875] |
| 218 | + BenchmarkResults : |
| 219 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 220 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 221 | +Success rate : [0.0, 0.0, 0.00125, 0.0, 0.0, 0.00125, 0.00875, 0.01375, 0.0 |
| 222 | +275, 0.0325 … 0.53, 0.5275, 0.53375, 0.53375, 0.53625, 0.545, 0.54125, 0. |
| 223 | +5525, 0.54375, 0.5575] |
| 224 | + BenchmarkResults : |
| 225 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 226 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 227 | +Success rate : [0.0, 0.0, 0.0, 0.0, 0.00125, 0.0, 0.0075, 0.0175, 0.03125, |
| 228 | +0.035 … 0.5225, 0.51375, 0.52625, 0.54, 0.54375, 0.53, 0.54, 0.53625, 0.5 |
| 229 | +3625, 0.53625] |
| 230 | + BenchmarkResults : |
| 231 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 232 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 233 | +Success rate : [0.0, 0.0, 0.0, 0.0, 0.00625, 0.00375, 0.01125, 0.00875, 0.0 |
| 234 | +225, 0.0375 … 0.52125, 0.52125, 0.52125, 0.52875, 0.53625, 0.5275, 0.5525 |
| 235 | +, 0.545, 0.53875, 0.54875] |
| 236 | + BenchmarkResults : |
| 237 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 238 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 239 | +Success rate : [0.045, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.1 |
| 240 | + … 0.5, 0.5, 0.5, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55, 0.55] |
| 241 | + BenchmarkResults : |
| 242 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 243 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 244 | +Success rate : [0.00125, 0.00125, 0.005, 0.00875, 0.015, 0.04125, 0.04125, |
| 245 | +0.0475, 0.05, 0.05 … 0.80125, 0.785, 0.79625, 0.77625, 0.8, 0.79625, 0.79 |
| 246 | +625, 0.8, 0.79125, 0.79875] |
| 247 | + BenchmarkResults : |
| 248 | +Run length : [10, 14, 19, 26, 36, 49, 67, 92, 127, 174 … 5736, 7880, 1082 |
| 249 | +6, 14874, 20434, 28072, 38566, 52983, 72790, 100000] |
| 250 | +Success rate : [0.00125, 0.01, 0.01125, 0.02, 0.0375, 0.03875, 0.0475, 0.04 |
| 251 | +875, 0.05125, 0.05 … 0.64, 0.73625, 0.80125, 0.7775, 0.8175, 0.83875, 0.8 |
| 252 | +175, 0.8125, 0.82125, 0.82625] |
| 253 | +``` |
| 254 | + |
| 255 | + |
| 256 | + |
| 257 | +```julia |
| 258 | +labels = collect(keys(setup)) |
| 259 | +idx = sortperm([b.success_rate[end] for b in results], rev=true) |
| 260 | + |
| 261 | +p = plot(xscale = :log10, legend = :outerright, size = (700,350), margin=10Plots.px, dpi=200) |
| 262 | +for i in idx |
| 263 | + plot!(results[i], label = labels[i], showribbon=false, lw=2.5, xlim = (1,1e5), x = :run_length) |
| 264 | +end |
| 265 | +p |
| 266 | +``` |
| 267 | + |
| 268 | + |
| 269 | + |
| 270 | +```julia |
| 271 | +success_rate_per_function = reduce(hcat, b.success_rate_per_function for b in results) |
| 272 | + |
| 273 | +idx = sortperm(mean(success_rate_per_function, dims=1)[:], rev=false) |
| 274 | +idxfunc = sortperm(mean(success_rate_per_function, dims=2)[:], rev=true) |
| 275 | +idxfunc = 1:length(test_functions) |
| 276 | + |
| 277 | +p = heatmap( |
| 278 | + string.(test_functions)[idxfunc], labels[idx], success_rate_per_function[idxfunc, idx]', |
| 279 | + cmap = :RdYlGn, |
| 280 | + xticks = :all, |
| 281 | + yticks = :all, |
| 282 | + xrotation = 45, |
| 283 | + dpi = 200, |
| 284 | +) |
| 285 | +``` |
| 286 | + |
| 287 | + |
| 288 | + |
| 289 | +```julia |
| 290 | +labels = collect(keys(setup)) |
| 291 | +idx = sortperm([b.distance_to_minimizer[end] for b in results], rev=false) |
| 292 | + |
| 293 | +p = plot(xscale = :log10, legend = :outerright, size = (900,500), margin=10Plots.px, ylim = (0,5)) |
| 294 | +for i in idx |
| 295 | + plot!( |
| 296 | + results[i].run_length, results[i].distance_to_minimizer, label = labels[i], |
| 297 | + showribbon=false, lw=2, xlim = (1,1e5), |
| 298 | + xlabel = "Iterations", ylabel = "Mean distance to minimum" |
| 299 | + ) |
| 300 | +end |
| 301 | +p |
| 302 | +``` |
| 303 | + |
| 304 | + |
| 305 | + |
| 306 | +```julia |
| 307 | +ref = findfirst("NelderMead" .== labels) |
| 308 | +runtimes = getfield.(results, :runtime) |
| 309 | +runtimes = runtimes ./ runtimes[ref] |
| 310 | + |
| 311 | +bar( |
| 312 | + labels, runtimes, xrotation = :45, xticks = :all, ylabel = "Run time relative to NM", |
| 313 | + yscale = :log10, yticks = [0.1,1,10,100], |
| 314 | + legend = false, margin = 25Plots.px |
| 315 | +) |
| 316 | +``` |
| 317 | + |
| 318 | + |
0 commit comments