Skip to content

CMA stop conditions #401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 76 additions & 7 deletions include/ensmallen_bits/cmaes/cmaes_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,18 @@ CMAES<SelectionPolicyType, TransformationPolicyType>::CMAES(const size_t lambda,
const size_t maxIterations,
const double tolerance,
const SelectionPolicyType& selectionPolicy,
double stepSizeIn) :
double stepSizeIn,
const double minObjective = std::numeric_limits<double>::lowest(),
const int maxFunctionEvaluations = std::numeric_limits<int>::max()):
lambda(lambda),
batchSize(batchSize),
maxIterations(maxIterations),
tolerance(tolerance),
selectionPolicy(selectionPolicy),
transformationPolicy(transformationPolicy),
stepSize(stepSizeIn)
stepSize(stepSizeIn),
minObjective(minObjective),
maxFunctionEvaluations(maxFunctionEvaluations)
{ /* Nothing to do. */ }

template<typename SelectionPolicyType, typename TransformationPolicyType>
Expand All @@ -49,13 +53,16 @@ CMAES<SelectionPolicyType, TransformationPolicyType>::CMAES(const size_t lambda,
const size_t maxIterations,
const double tolerance,
const SelectionPolicyType& selectionPolicy,
double stepSizeIn) :
double stepSizeIn,
const double minObjective = std::numeric_limits<double>::lowest(),
const int maxFunctionEvaluations = std::numeric_limits<int>::max()):
lambda(lambda),
batchSize(batchSize),
maxIterations(maxIterations),
tolerance(tolerance),
selectionPolicy(selectionPolicy),
stepSize(stepSizeIn)
stepSize(stepSizeIn),
minObjective(minObjective)
{
Warn << "This is a deprecated constructor and will be removed in a "
"future version of ensmallen" << std::endl;
Expand Down Expand Up @@ -89,9 +96,12 @@ typename MatType::elem_type CMAES<SelectionPolicyType,
// Find the number of functions to use.
const size_t numFunctions = function.NumFunctions();

// Initialize the counter for the number of function evaluations.
size_t numFunctionEvaluations = 0;

// Population size.
if (lambda == 0)
lambda = (4 + std::round(3 * std::log(iterate.n_elem))) * 10;
lambda = (4 + std::round(3 * std::log(iterate.n_elem)));

// Parent weights.
const size_t mu = std::round(lambda / 2);
Expand All @@ -109,7 +119,7 @@ typename MatType::elem_type CMAES<SelectionPolicyType,
else
sigma(0) = stepSize;

const double cs = (muEffective + 2) / (iterate.n_elem + muEffective + 5);
const double cs = (muEffective + 2) / (iterate.n_elem + muEffective + 3);
const double ds = 1 + cs + 2 * std::max(std::sqrt((muEffective - 1) /
(iterate.n_elem + 1)) - 1, 0.0);
const double enn = std::sqrt(iterate.n_elem) * (1.0 - 1.0 /
Expand Down Expand Up @@ -151,6 +161,7 @@ typename MatType::elem_type CMAES<SelectionPolicyType,
terminate |= Callback::Evaluate(*this, function, transformedIterate,
objective, callbacks...);
}
numFunctionEvaluations += numFunctions;

ElemType overallObjective = currentObjective;
ElemType lastObjective = std::numeric_limits<ElemType>::max();
Expand Down Expand Up @@ -186,6 +197,10 @@ typename MatType::elem_type CMAES<SelectionPolicyType,
size_t patience = 10 + (30 * iterate.n_elem / lambda) + 1;
size_t steps = 0;

// The min and max objective values in the range. For early termination.
double minObjectiveInPatience = std::numeric_limits<double>::infinity();
double maxObjectiveInPatience = -std::numeric_limits<double>::infinity();

for (size_t i = 1; (i != maxIterations) && !terminate; ++i)
{
// To keep track of where we are.
Expand Down Expand Up @@ -235,6 +250,8 @@ typename MatType::elem_type CMAES<SelectionPolicyType,
transformationPolicy.Transform(mPosition[idx1]), terminate,
callbacks...);

numFunctionEvaluations += lambda; // I think, not totally sure

// Update best parameters.
if (currentObjective < overallObjective)
{
Expand Down Expand Up @@ -274,6 +291,17 @@ typename MatType::elem_type CMAES<SelectionPolicyType,
return overallObjective;
}

// Terminate if sigma/sigma0 is above 10^4 * max(D)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Terminate if sigma/sigma0 is above 10^4 * max(D)
// Terminate if sigma/sigma0 is above 10^4 * max(D).

To be consistent with the style.

if (sigma(idx1) / sigma(0) > 1e4 * std::max(eigvalZero, eigval))
{
Info << "The step size ratio is too large; "
<< "terminating with failure." << std::endl;

iterate = transformationPolicy.Transform(iterate);
Callback::EndOptimization(*this, function, iterate, callbacks...);
return overallObjective;
}

// Update covariance matrix.
if ((psNorm / sqrt(1 - std::pow(1 - cs, 2 * i))) < h)
{
Expand Down Expand Up @@ -340,6 +368,9 @@ typename MatType::elem_type CMAES<SelectionPolicyType,
}
}

minObjectiveInPatience = std::min(minObjectiveInPatience, currentObjective);
maxObjectiveInPatience = std::max(maxObjectiveInPatience, currentObjective);

// Output current objective function.
Info << "CMA-ES: iteration " << i << ", objective " << overallObjective
<< "." << std::endl;
Expand All @@ -354,7 +385,8 @@ typename MatType::elem_type CMAES<SelectionPolicyType,
return overallObjective;
}

if (std::abs(lastObjective - overallObjective) < tolerance)
if ((std::abs(lastObjective - overallObjective) < tolerance) &&
(maxObjectiveInPatience - minObjectiveInPatience < tolerance))
{
if (steps > patience) {
Info << "CMA-ES: minimized within tolerance " << tolerance << "; "
Expand All @@ -366,9 +398,46 @@ typename MatType::elem_type CMAES<SelectionPolicyType,
}
}
else {
minObjectiveInPatience = std::numeric_limits<double>::infinity();
maxObjectiveInPatience = -std::numeric_limits<double>::infinity();
steps = 0;
}

// Other termination criteria.
// Terminate if the objective is less than the minimum objective.
if (overallObjective < minObjective)
{
Info << "CMA-ES: minimized below minObjective " << minObjective << "; "
<< "terminating optimization." << std::endl;

iterate = transformationPolicy.Transform(iterate);
Callback::EndOptimization(*this, function, iterate, callbacks...);
return overallObjective;
}

// Terminate if the maximum number of function evaluations has been reached.
if (numFunctionEvaluations >= maxFunctionEvaluations)
{
Info << "CMA-ES: maximum number of function evaluations ("
<< maxFunctionEvaluations << ") reached; "
<< "terminating optimization." << std::endl;

iterate = transformationPolicy.Transform(iterate);
Callback::EndOptimization(*this, function, iterate, callbacks...);
return overallObjective;
}

// Check if the condition number of the covariance matrix is too high.
if (eigval(eigval.n_elem - 1) / eigval(0) > 1e14) // TODO: Probably put this into a parameter
{
Info << "CMA-ES: covariance matrix condition number is too high; "
<< "terminating with failure." << std::endl;

iterate = transformationPolicy.Transform(iterate);
Callback::EndOptimization(*this, function, iterate, callbacks...);
return overallObjective;
}

steps++;

lastObjective = overallObjective;
Expand Down