import numpy as np
from math import inf
from spotpython.fun.objectivefunctions import Analytical
from spotpython.spot import Spot
from scipy.optimize import shgo
from scipy.optimize import direct
from scipy.optimize import differential_evolution
from scipy.optimize import dual_annealing
from scipy.optimize import basinhopping
from spotpython.utils.init import fun_control_init, design_control_init, optimizer_control_init
15 Sequential Parameter Optimization: Using scipy
Optimizers
As a default optimizer, spotpython
uses differential_evolution
from the scipy.optimize
package. Alternatively, any other optimizer from the scipy.optimize
package can be used. This chapter describes how different optimizers from the scipy optimize
package can be used on the surrogate. The optimization algorithms are available from https://docs.scipy.org/doc/scipy/reference/optimize.html
15.1 The Objective Function Branin
The spotpython
package provides several classes of objective functions. We will use an analytical objective function, i.e., a function that can be described by a (closed) formula. Here we will use the Branin function. The 2-dim Branin function is \[
y = a (x_2 - b x_1^2 + c x_1 - r) ^2 + s (1 - t) \cos(x_1) + s,
\] where values of \(a\), \(b\), \(c\), \(r\), \(s\) and \(t\) are: \(a = 1\), \(b = 5.1 / (4\pi^2)\), \(c = 5 / \pi\), \(r = 6\), \(s = 10\) and \(t = 1 / (8\pi)\).
It has three global minima: \(f(x) = 0.397887\) at \((-\pi, 12.275)\), \((\pi, 2.275)\), and \((9.42478, 2.475)\).
Input Domain: This function is usually evaluated on the square \(x_1 \in [-5, 10] \times x_2 \in [0, 15]\).
from spotpython.fun.objectivefunctions import Analytical
= np.array([-5,-0])
lower = np.array([10,15])
upper = Analytical(seed=123).fun_branin fun
15.2 The Optimizer
Differential Evolution (DE) from the scikit.optimize
package, see https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html#scipy.optimize.differential_evolution is the default optimizer for the search on the surrogate. Other optimiers that are available in spotpython
, see https://docs.scipy.org/doc/scipy/reference/optimize.html#global-optimization.
dual_annealing
direct
shgo
basinhopping
These optimizers can be selected as follows:
from scipy.optimize import differential_evolution
= differential_evolution optimizer
As noted above, we will use differential_evolution
. The optimizer can use 1000
evaluations. This value will be passed to the differential_evolution
method, which has the argument maxiter
(int). It defines the maximum number of generations over which the entire differential evolution population is evolved, see https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html#scipy.optimize.differential_evolution
Similar to the one-dimensional case, which is discussed in Section 12.25, we can use TensorBoard to monitor the progress of the optimization. We will use a similar code, only the prefix is different:
=fun_control_init(
fun_control= lower,
lower = upper,
upper = 20,
fun_evals = "04_DE_"
PREFIX )
= Spot(fun=fun,
spot_de =fun_control)
fun_control spot_de.run()
Anisotropic model: n_theta set to 2
Anisotropic model: n_theta set to 2
spotpython tuning: 3.8004506840294194 [######----] 55.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.8004506840294194 [######----] 60.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.159565441942571 [######----] 65.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.134679102336346 [#######---] 70.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.060135205103653 [########--] 75.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 2.90563997499389 [########--] 80.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.4456698307125606 [########--] 85.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.421388624512117 [#########-] 90.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.40011963854874466 [##########] 95.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.3981258100809235 [##########] 100.00% Done...
Experiment saved to 04_DE__res.pkl
<spotpython.spot.spot.Spot at 0x1600c2300>
15.2.1 TensorBoard
If the prefix
argument in fun_control_init()
is not None
(as above, where the prefix
was set to 04_DE_
) , we can start TensorBoard in the background with the following command:
tensorboard --logdir="./runs"
We can access the TensorBoard web server with the following URL:
http://localhost:6006/
The TensorBoard plot illustrates how spotpython
can be used as a microscope for the internal mechanisms of the surrogate-based optimization process. Here, one important parameter, the learning rate \(\theta\) of the Kriging surrogate is plotted against the number of optimization steps.
15.3 Print the Results
spot_de.print_results()
min y: 0.3981258100809235
x0: 3.1365073110744954
x1: 2.2682783594995963
[['x0', np.float64(3.1365073110744954)],
['x1', np.float64(2.2682783594995963)]]
15.4 Show the Progress
=True) spot_de.plot_progress(log_y
spot_de.surrogate.plot()
15.5 Exercises
15.5.1 dual_annealing
- Describe the optimization algorithm, see scipy.optimize.dual_annealing.
- Use the algorithm as an optimizer on the surrogate.
We can run spotpython with the dual_annealing
optimizer as follows:
= Spot(fun=fun,
spot_da =fun_control,
fun_control=dual_annealing)
optimizer
spot_da.run()
spot_da.print_results()=True)
spot_da.plot_progress(log_y spot_da.surrogate.plot()
Anisotropic model: n_theta set to 2
Anisotropic model: n_theta set to 2
spotpython tuning: 3.8004590707154895 [######----] 55.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.8004590707154895 [######----] 60.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.1596655918260073 [######----] 65.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.142644614299817 [#######---] 70.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.059310353246632 [########--] 75.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 2.910687165654897 [########--] 80.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.4451365537588803 [########--] 85.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.422797397289699 [#########-] 90.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.3991731495275026 [##########] 95.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.3981358951826284 [##########] 100.00% Done...
Experiment saved to 04_DE__res.pkl
min y: 0.3981358951826284
x0: 3.1355708107484257
x1: 2.2710730566490436
15.5.2 direct
- Describe the optimization algorithm
- Use the algorithm as an optimizer on the surrogate
We can run spotpython with the direct
optimizer as follows:
= Spot(fun=fun,
spot_di =fun_control,
fun_control=direct)
optimizer
spot_di.run()
spot_di.print_results()=True)
spot_di.plot_progress(log_y spot_di.surrogate.plot()
Anisotropic model: n_theta set to 2
Anisotropic model: n_theta set to 2
spotpython tuning: 3.808603529901438 [######----] 55.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.808603529901438 [######----] 60.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.19804562480188 [######----] 65.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.17767194117126 [#######---] 70.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.165751373773567 [########--] 75.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.133265047041581 [########--] 80.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.1024264122901313 [########--] 85.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.5157442227491682 [#########-] 90.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.4602369731562064 [##########] 95.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.4007432998173748 [##########] 100.00% Done...
Experiment saved to 04_DE__res.pkl
min y: 0.4007432998173748
x0: 3.1172839506172827
x1: 2.2896662094192957
15.5.3 shgo
- Describe the optimization algorithm
- Use the algorithm as an optimizer on the surrogate
We can run spotpython with the direct
optimizer as follows:
= Spot(fun=fun,
spot_sh =fun_control,
fun_control=shgo)
optimizer
spot_sh.run()
spot_sh.print_results()=True)
spot_sh.plot_progress(log_y spot_sh.surrogate.plot()
Anisotropic model: n_theta set to 2
Anisotropic model: n_theta set to 2
spotpython tuning: 3.8004561983162244 [######----] 55.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.8004561983162244 [######----] 60.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.1596084688768897 [######----] 65.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.134328088792513 [#######---] 70.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.046748037985717 [########--] 75.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 2.9040930518989256 [########--] 80.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.4478684866072875 [########--] 85.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.4215898119407626 [#########-] 90.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.3995512640374308 [##########] 95.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.39815654235438735 [##########] 100.00% Done...
Experiment saved to 04_DE__res.pkl
min y: 0.39815654235438735
x0: 3.135708577708246
x1: 2.2694462408595184
15.5.4 basinhopping
- Describe the optimization algorithm
- Use the algorithm as an optimizer on the surrogate
We can run spotpython with the direct
optimizer as follows:
= Spot(fun=fun,
spot_bh =fun_control,
fun_control=basinhopping)
optimizer
spot_bh.run()
spot_bh.print_results()=True)
spot_bh.plot_progress(log_y spot_bh.surrogate.plot()
Anisotropic model: n_theta set to 2
Anisotropic model: n_theta set to 2
spotpython tuning: 3.800515912225105 [######----] 55.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.800515912225105 [######----] 60.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.1598057167066838 [######----] 65.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.1343867161541867 [#######---] 70.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 3.049792079644357 [########--] 75.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 2.905212399616701 [########--] 80.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 2.905212399616701 [########--] 85.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.4905152146959697 [#########-] 90.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.432559107080257 [##########] 95.00%
Anisotropic model: n_theta set to 2
spotpython tuning: 0.3990757838695238 [##########] 100.00% Done...
Experiment saved to 04_DE__res.pkl
min y: 0.3990757838695238
x0: 3.1270452453270146
x1: 2.2732417517803016
15.5.5 Performance Comparison
Compare the performance and run time of the 5 different optimizers:
differential_evolution
dual_annealing
direct
shgo
basinhopping
.
The Branin function has three global minima:
- \(f(x) = 0.397887\) at
- \((-\pi, 12.275)\),
- \((\pi, 2.275)\), and
- \((9.42478, 2.475)\).
- Which optima are found by the optimizers?
- Does the
seed
argument infun = Analytical(seed=123).fun_branin
change this behavior?
15.6 Jupyter Notebook
- The Jupyter-Notebook of this chapter is available on GitHub in the Hyperparameter-Tuning-Cookbook Repository