PyBorg is a new secondary implementation of Borg, written entirely in Python using the Platypus optimization library. PyBorg was developed by Andrew Dircks based on the original implementation in C and it is intended primarily as a learning tool as it is less efficient than the original C version (which you can still use with Python but through the use of the plugin “wrapper” also found in the package). PyBorg can be found in the same repository where the original Borg can be downloaded, for which you can request access here: http://borgmoea.org/#contact
This blogpost is intended to demonstrate this new implementation. To follow along, first you need to either clone or download the BitBucket repository after you gain access.
Setting up the required packages is easy. In your terminal, navigate to the Python directory in the repository and install all prerequisites using
python setup.py install. This will install all requirements (i.e. the Platypus library, numpy, scipy and six) for you in your current environment.
You can test that everything works fine by running the optimization on the DTLZ2 test function, found in
dtlz2.py. The script creates an instance of the problem (as it is already defined in the Platypus library), sets it up as a ploblem for Borg to optimize and runs the algorithm for 10,000 function evaluations:
# define a DTLZ2 problem instance from the Platypus library nobjs = 3 problem = DTLZ2(nobjs) # define and run the Borg algorithm for 10000 evaluations algorithm = BorgMOEA(problem, epsilons=0.1) algorithm.run(10000)
A handy 3D scatter plot is also generated to show the optimization results.
The repository also comes with two other scripts
The first demonstrates how to use the Platypus hypervolume indicator at a specified runtime frequency to get learn about its progress as the algorithm goes through function evaluations:
The latter provides more advanced functionality that allows you define custom parameters for Borg. It also includes a function to generate runtime data from the run. Both scripts are useful to diagnose how your algorithm is performing on any given problem.
The rest of this post is a demo of how you can use PyBorg with your own Python model and all of the above. I’ll be using a model I’ve used before, which can be found here, and I’ll formulate it so it only uses the first three objectives for the purposes of demonstration.
The first thing you need to do to optimize your problem is to define it. This is done very simply in the exact same way you’d do it on Project Platypus, using the Problem class:
from fishery import fish_game from platypus import Problem, Real from pyborg import BorgMOEA # define a problem nVars = 6 nObjs = 3 problem = Problem(nVars, nObjs) # first input is no of decision variables, second input is no of objectives problem.types[:] = Real(0, 1) #defines the type and bounds of each decision variable problem.function = fish_game #defines the model function
This assumes that all decision variables are of the same type and range, but you can also define them individually using, e.g.,
Then you define the problem for the algorithm and set the number of function evaluations:
algorithm = BorgMOEA(problem, epsilons=0.001) #epsilons for each objective algorithm.run(10000) # number of function evaluations
If you’d like to also produce a runtime file you can use the
detailed_run function included in the demo (in the files referenced above), which wraps the algorithm and runs it in intervals so the progress can be monitored. You can combine it with
runtime_hypervolume to also track your hypervolume indicator. To use it you need to define the total number of function evaluations, the frequency with which you’d like the progress to be monitored and the name of the output file. If you’d like to calculate the Hypervolume (you first need to import it from platypus) you also need to either provide a known reference set or define maximum and minimum values for your solutions.
maxevals = 10000 frequency = 100 output = "fishery.data" hv = Hypervolume(minimum=[-6000, 0, 0], maximum=[0, 1, 100]) nfe, hyp = detailed_run(algorithm, maxevals, frequency, output, hv)
My full script can be found below. The
detailed_run function is an edited version of the default that comes in the demo to also include the hypervolume calculation.
from fishery import fish_game from platypus import Problem, Real, Hypervolume from pyborg import BorgMOEA from runtime_diagnostics import detailed_run # define a problem nVars = 6 # no. of decision variables to be optimized nObjs = 3 problem = Problem(nVars, nObjs) # first input is no of decision variables, second input is no of objectives problem.types[:] = Real(0, 1) problem.function = fish_game # define and run the Borg algorithm for 10000 evaluations algorithm = BorgMOEA(problem, epsilons=0.001) #algorithm.run(10000) # define detailed_run parameters maxevals = 10000 frequency = 100 output = "fishery.data" hv = Hypervolume(minimum=[-6000, 0, 0], maximum=[0, 1, 100]) nfe, hyp = detailed_run(algorithm, maxevals, frequency, output, hv) # plot the results using matplotlib import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.scatter([s.objectives for s in algorithm.result], [s.objectives for s in algorithm.result], [s.objectives for s in algorithm.result]) ax.set_xlabel('Objective 1') ax.set_ylabel('Objective 2') ax.set_zlabel('Objective 3') ax.scatter(-6000, 0, 0, marker="*", c='orange', s=50) plt.show() plt.plot(nfe, hyp) plt.title('PyBorg Runtime Hypervolume Fish game') plt.xlabel('Number of Function Evaluations') plt.ylabel('Hypervolume') plt.show()
It produces the following two figures: