Yabox: Yet another black-box optimization library for Python - https://github.com/pablormier/yabox

This notebook compares the performance of the Differential Evolution (DE) algorithm and the DE with parallel evaluation (PDE) implemented in Yabox against the default Scipy's implementation over a collection of common optimization functions.

Author: Pablo Rodríguez-Mier, @pablormier

Imports & boilerplate code


In [ ]:
%matplotlib inline
import matplotlib.pyplot as plt
import sys
from time import time

# Load Yabox (from local)
# Comment this line to use the installed version
sys.path.insert(0, '../')

import yabox as yb

import scipy as sp
import numpy as np

# Import the DE implementations
from yabox.algorithms import DE, PDE
from yabox.utils import benchmark
from scipy.optimize import differential_evolution as SDE

In [ ]:
print('Yabox version: ', yb.__version__)
print('Scipy version: ', sp.__version__)

Default config

The initialization of the population in all cases (Yabox/Scipy) is random and the schema used is rand/1/bin


In [ ]:
config = dict(
    # Runs per method and function, average the final results
    runs = 1,
    # Time limit for each method (in seconds)
    stop_after = 30,
    # Max number of iterations
    maxiters = 1000000,
    # Use a constant mutation factor (0-1)
    mutation = 0.5,
    # Recombination probability (0-1)
    recombination = 0.5,
    # Number of individuals in the population. NOTE: Since Scipy uses num_individuals = dimensions * popsize
    # Select a size for popsize and a set of dimensions to test so that popsize / dimensions in every case 
    # produces an integer number
    popsize = 64,
    # Methods to be tested
    methods = ['yabox_de', 'yabox_pde', 'scipy_de']    
)

Evaluation

In order to evaluate the performance of each implementation, I used 5 different multi-dimensional functions commonly used for benchmarking black-box optimization algorithms. All tests have been taken on a Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz.

Benchmark 1 - Ackley function

"The Ackley function is widely used for testing optimization algorithms. In its two-dimensional form, as shown in the plot above, it is characterized by a nearly flat outer region, and a large hole at the centre. The function poses a risk for optimization algorithms, particularly hillclimbing algorithms, to be trapped in one of its many local minima."

Global minimum:

$ f(\mathbf{x^*}) = 0, \text{at}~\mathbf{x^*} = (0, \dots, 0) $


In [ ]:
from yabox.problems import Ackley
Ackley().plot3d();

In [ ]:
# Run the set of benchmarks on Ackley using the config defined at the beginning of this notebook
ackley_data = benchmark.test(Ackley, config)

# Plot the performance of each algorithm (execution time vs. fitness)
benchmark.plot_results(ackley_data)

In [ ]:
benchmark.plot_results(ackley_data, use_time=False)

In [ ]:
benchmark.plot_time_per_iteration(ackley_data)

Benchmark 2 - Rastrigin function

"The Rastrigin function has several local minima. It is highly multimodal, but locations of the minima are regularly distributed. It is shown in the plot in its two-dimensional form."

Global minimum:

$ f(\mathbf{x^*}) = 0, \text{at}~\mathbf{x^*} = (0, \dots, 0) $


In [ ]:
from yabox.problems import Rastrigin
Rastrigin().plot3d();

In [ ]:
rastrigin_data = benchmark.test(Rastrigin, config)
benchmark.plot_results(rastrigin_data)

In [ ]:
benchmark.plot_results(rastrigin_data, use_time=False)

In [ ]:
benchmark.plot_time_per_iteration(rastrigin_data)

Benchmark 3 - Schwefel function

"The Schwefel function is complex, with many local minima. The plot shows the two-dimensional form of the function."

Global minimum:

$ f(\mathbf{x^*}) = 0, \text{at}~\mathbf{x^*} = (420.9687, \dots, 420.9687) $


In [ ]:
from yabox.problems import Schwefel
Schwefel().plot3d();

In [ ]:
schwefel_data = benchmark.test(Schwefel, config)
benchmark.plot_results(schwefel_data)

In [ ]:
benchmark.plot_results(schwefel_data, use_time=False)

In [ ]:
benchmark.plot_time_per_iteration(schwefel_data)

Benchmark 4 - Michalewicz function

"The Michalewicz function has d! local minima, and it is multimodal. The parameter m defines the steepness of they valleys and ridges; a larger m leads to a more difficult search. The recommended value of m is m = 10."


In [ ]:
from yabox.problems import Michalewicz
Michalewicz().plot3d();

In [ ]:
michalewicz_data = benchmark.test(Michalewicz, config)
benchmark.plot_results(michalewicz_data)

Benchmark 5 - Griewank function

"The Griewank function has many widespread local minima, which are regularly distributed."

Global minimum:

$ f(\mathbf{x^*}) = 0, \text{at}~\mathbf{x^*} = (0, \dots, 0) $


In [ ]:
from yabox.problems import Griewank
Griewank().plot3d();

In [ ]:
griewank_data = benchmark.test(Griewank, config)
benchmark.plot_results(griewank_data)