RL-informed Evolution Strategies (PPO-ES)¶
The Proximal Policy Optimization algorithm starts the search to collect some individuals given a fitness function through a RL environment. In the second step, the best PPO individuals are used to guide evolution strategies (ES), where RL individuals are randomly introduced into the ES population to enrich their diversity. The user first runs PPO search followed by ES, the best results of both stages are reported to the user.
Original papers:
Radaideh, M. I., & Shirvan, K. (2021). Rule-based reinforcement learning methodology to inform evolutionary algorithms for constrained optimization of engineering applications. Knowledge-Based Systems, 217, 106836.
Radaideh, M. I., Forget, B., & Shirvan, K. (2021). Large-scale design optimisation of boiling water reactor bundles with neuroevolution. Annals of Nuclear Energy, 160, 108355.
What can you use?¶
Multi processing: ✔️
Discrete spaces: ✔️
Continuous spaces: ✔️
Mixed Discrete/Continuous spaces: ✔️
Parameters¶
-
class
neorl.hybrid.ppoes.
PPOES
(mode, fit, env, bounds, npop=60, npop_rl=6, init_pop_rl=True, hyperparam={}, seed=None)[source]¶ A PPO-informed ES Neuroevolution module
- Parameters
mode – (str) problem type, either
min
for minimization problem ormax
for maximizationfit – (function) the fitness function to be used with ES
env – (NEORL environment or Gym environment) The environment to learn with PPO, either use NEORL method
CreateEnvironment
(see below) or construct your custom Gym environment.bounds – (dict) input parameter type and lower/upper bounds in dictionary form. Example:
bounds={'x1': ['int', 1, 4], 'x2': ['float', 0.1, 0.8], 'x3': ['float', 2.2, 6.2]}
npop – (int): population size of ES
npop_rl – (int): number of RL/PPO individuals to use in ES population (
npop_rl < npop
)init_pop_rl – (bool) flag to initialize ES population with PPO individuals
hyperparam – (dict) dictionary of ES hyperparameters (
cxpb
,cxmode
,mutpb
,alpha
,mu
,smin
,smax
) and PPO hyperparameters (n_steps
,gamma
,learning_rate
,ent_coef
,vf_coef
,lam
,cliprange
,max_grad_norm
,nminibatches
,noptephocs
)seed – (int) random seed for sampling
-
evolute
(ngen, ncores=1, verbose=False)[source]¶ This function evolutes the ES algorithm for number of generations with guidance from RL individuals.
- Parameters
ngen – (int) number of generations to evolute
ncores – (int) number of parallel processors to use with ES
verbose – (bool) print statistics to screen
- Returns
(tuple) (best individual, best fitness, and a list of fitness history)
-
learn
(total_timesteps, rl_filter=100, verbose=False)[source]¶ This function starts the learning of PPO algorithm for number of timesteps to create individuals for evolutionary search
- Parameters
total_timesteps – (int) number of timesteps to run
rl_filter – (int) number of top individuals to keep from the full RL search
verbose – (bool) print statistics to screen
- Returns
(dataframe) dataframe of individuals/fitness sorted from best to worst
-
class
neorl.rl.make_env.
CreateEnvironment
(method, fit, bounds, ncores=1, mode='max', episode_length=50)[source] A module to construct a fitness environment for certain algorithms that follow reinforcement learning approach of optimization
- Parameters
method – (str) the supported algorithms, choose either:
dqn
,ppo
,acktr
,acer
,a2c
.fit – (function) the fitness function
bounds – (dict) input parameter type and lower/upper bounds in dictionary form. Example:
bounds={'x1': ['int', 1, 4], 'x2': ['float', 0.1, 0.8], 'x3': ['float', 2.2, 6.2]}
ncores – (int) number of parallel processors
mode – (str) problem type, either
min
for minimization problem ormax
for maximization (RL is default tomax
)episode_length – (int): number of individuals to evaluate before resetting the environment to random initial guess.
Example¶
Train a PPO-ES agent to optimize the 5-D sphere function
from neorl import PPOES
from neorl import CreateEnvironment
def Sphere(individual):
"""Sphere test objective function.
F(x) = sum_{i=1}^d xi^2
d=1,2,3,...
Range: [-100,100]
Minima: 0
"""
y=sum(x**2 for x in individual)
return y
#Setup the parameter space (d=5)
nx=5
BOUNDS={}
for i in range(1,nx+1):
BOUNDS['x'+str(i)]=['float', -100, 100]
if __name__=='__main__': #use this block for parallel PPO!
#create an enviroment class for RL/PPO
env=CreateEnvironment(method='ppo', fit=Sphere, ncores=1,
bounds=BOUNDS, mode='min', episode_length=50)
#change hyperparameters of PPO/ES if you like (defaults should be good to start with)
h={'cxpb': 0.8,
'mutpb': 0.2,
'n_steps': 24,
'lam': 1.0}
#Important: `mode` in CreateEnvironment and `mode` in PPOES must be consistent
#fit is needed to be passed again for ES, must be same as the one used in env
ppoes=PPOES(mode='min', fit=Sphere,
env=env, npop_rl=4, init_pop_rl=True,
bounds=BOUNDS, hyperparam=h, seed=1)
#first run RL for some timesteps
rl=ppoes.learn(total_timesteps=2000, verbose=True)
#second run ES, which will use RL data for guidance
ppoes_x, ppoes_y, ppoes_hist=ppoes.evolute(ngen=20, ncores=1, verbose=True) #ncores for ES