Closed ghost closed 1 year ago
When you call algorithm.run(...)
, the first argument is the termination condition. By default, it is the number of function evaluations: algorithm.run(10000)
. But you can also pass in a TerminationCondition
type. For example, algorithm.run(MaxTime(60))
would run for 1 minute (approximately). For function tolerance, you would need to subclass TerminationCondition
and implement that check.
I am also keen to see an, easy to implement, example of this stopping condition. Something like: the algorithm proceeds until the best solution during the evolution process doesn't change to a better value after a predefined number of generations.
This is a sample implementation:
import random
from platypus import Problem, Real, NSGAII, SPEA2, GAOperator, SBX, PM, TerminationCondition, ProcessPoolEvaluator
import sys
num_vars = 2
num_objs = 1
num_cons = 2
class EarlyStopping(TerminationCondition):
def __init__(self, min_iterations, max_iterations, tolerance, patience):
"""
Parameters:
min_iterations (int): Run optimizer for at least this many iterations
max_iterations (int): Do not run optimizer for more than this many iterations
tolerance (float): Maximum change able to tolerate in function objective to declare convergence
patience (int): Tolerance should be satisfied for steps = patience before early stopping
"""
super(EarlyStopping, self).__init__()
self.min_iterations = min_iterations
self.max_iterations = max_iterations
self.tolerance = tolerance
self.patience = patience
self.current_patience = 0
self.last_iter_obj_value = 1e10 #sys.float_info.max
self.iteration = -1
def initialize(self, algorithm):
pass
def shouldTerminate(self, algorithm):
self.iteration += 1
if self.iteration < self.min_iterations:
return False
elif self.iteration >= self.max_iterations:
return True
else:
for p in algorithm.population:
if p.feasible:
self.current_iter_obj_value = p.objectives[0]
break
print("iteration", self.iteration, "obj", p.objectives[0])
if abs(self.current_iter_obj_value - self.last_iter_obj_value) <= self.tolerance:
self.current_patience += 1
else:
self.current_patience = 0
self.last_iter_obj_value = self.current_iter_obj_value
if self.current_patience == self.patience:
return True
return False
# convex problem objective = ((x-5)/4)^2 + ((y-3)/2)^2 with constraint x >= 10 and y>=4. So solution is (10, 4)
def convex_objective(x):
x0 = x[0]
x1 = x[1]
return ((x0-5)/4)**2 + ((x1-3)/2) ** 2, (x[0] - 10, x[1] - 4)
problem = Problem(num_vars, num_objs, num_cons)
problem.types[:] = Real(0, 50)
problem.directions[:] = Problem.MINIMIZE
problem.constraints[:] = '>=0'
problem.function = convex_objective
def run_opt():
iteration_history = []
random.seed(24837102)
earlystop = EarlyStopping(1, 2, 1e-2, 30)
with ProcessPoolEvaluator(8) as evaluator:
algorithm = SPEA2(problem
, population_size=100
, variator=GAOperator(SBX(probability=0.9
, distribution_index=20)
, PM(probability=0.1
, distribution_index=10))
, evaluator=evaluator
, archive=iteration_history)
algorithm.run(earlystop)
return algorithm, iteration_history, earlystop
alg, hist, earlystop = run_opt()
print("Converged in {0} iterations".format(earlystop.count))
print("solution", alg.population[0])
print("iteration_history", hist)
This issue is stale and will be closed soon. If you feel this issue is still relevant, please comment to keep it active. Please also consider working on a fix and submitting a PR.
Hey guys,
First of all thanks for providing such a valuable opensource code. Can you please let me know if there are any stopping criteria available like these:
Function tolerance: The algorithm stops if the average relative change in the best fitness function value over lets say 200000 generations is less than or equal to Function tolerance.
Time limit: To stop the optimization process after lets say 10 hours.
I think it is now obvious what programming language I am used to ;)
Thank you in advance.