Add AdaDelta policy class
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
set(DIRS
|
||||
adadelta
|
||||
ada_delta
|
||||
ada_grad
|
||||
adam
|
||||
aug_lagrangian
|
||||
|
||||
+1
@@ -1,6 +1,7 @@
|
||||
set(SOURCES
|
||||
ada_delta.hpp
|
||||
ada_delta_impl.hpp
|
||||
ada_delta_update.hpp
|
||||
)
|
||||
|
||||
set(DIR_SRCS)
|
||||
+27
-36
@@ -2,10 +2,11 @@
|
||||
* @file ada_delta.hpp
|
||||
* @author Ryan Curtin
|
||||
* @author Vasanth Kalingeri
|
||||
* @author Abhinav Moudgil
|
||||
*
|
||||
* Implementation of the Adadelta optimizer. Adadelta is an optimizer that
|
||||
* Implementation of the AdaDelta optimizer. AdaDelta is an optimizer that
|
||||
* dynamically adapts over time using only first order information.
|
||||
* Additionally, Adadelta requires no manual tuning of a learning rate.
|
||||
* Additionally, AdaDelta requires no manual tuning of a learning rate.
|
||||
*
|
||||
* mlpack is free software; you may redistribute it and/or modify it under the
|
||||
* terms of the 3-clause BSD license. You should have received a copy of the
|
||||
@@ -16,12 +17,14 @@
|
||||
#define __MLPACK_CORE_OPTIMIZERS_ADADELTA_ADA_DELTA_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
#include <mlpack/core/optimizers/sgd/sgd.hpp>
|
||||
#include "ada_delta_update.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace optimization {
|
||||
|
||||
/**
|
||||
* Adadelta is an optimizer that uses two ideas to improve upon the two main
|
||||
* AdaDelta is an optimizer that uses two ideas to improve upon the two main
|
||||
* drawbacks of the Adagrad method:
|
||||
*
|
||||
* - Accumulate Over Window
|
||||
@@ -38,7 +41,6 @@ namespace optimization {
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
|
||||
* For AdaDelta to work, a DecomposableFunctionType template parameter is
|
||||
* required. This class must implement the following function:
|
||||
*
|
||||
@@ -81,6 +83,7 @@ class AdaDelta
|
||||
* function is visited in linear order.
|
||||
*/
|
||||
AdaDelta(DecomposableFunctionType& function,
|
||||
const double stepSize = 1.0,
|
||||
const double rho = 0.95,
|
||||
const double eps = 1e-6,
|
||||
const size_t maxIterations = 100000,
|
||||
@@ -95,57 +98,46 @@ class AdaDelta
|
||||
* @param iterate Starting point (will be modified).
|
||||
* @return Objective value of the final point.
|
||||
*/
|
||||
double Optimize(arma::mat& iterate);
|
||||
double Optimize(arma::mat& iterate) { return optimizer.Optimize(iterate); }
|
||||
|
||||
//! Get the instantiated function to be optimized.
|
||||
const DecomposableFunctionType& Function() const { return function; }
|
||||
const DecomposableFunctionType& Function() const { return optimizer.Function(); }
|
||||
//! Modify the instantiated function.
|
||||
DecomposableFunctionType& Function() { return function; }
|
||||
DecomposableFunctionType& Function() { return optimizer.Function(); }
|
||||
|
||||
//! Get the step size.
|
||||
double StepSize() const { return optimizer.StepSize(); }
|
||||
//! Modify the step size.
|
||||
double& StepSize() { return optimizer.StepSize(); }
|
||||
|
||||
//! Get the smoothing parameter.
|
||||
double Rho() const { return rho; }
|
||||
double Rho() const { return optimizer.UpdatePolicy().Rho(); }
|
||||
//! Modify the smoothing parameter.
|
||||
double& Rho() { return rho; }
|
||||
double& Rho() { return optimizer.UpdatePolicy().Rho(); }
|
||||
|
||||
//! Get the value used to initialise the mean squared gradient parameter.
|
||||
double Epsilon() const { return eps; }
|
||||
double Epsilon() const { return optimizer.UpdatePolicy().Epsilon(); }
|
||||
//! Modify the value used to initialise the mean squared gradient parameter.
|
||||
double& Epsilon() { return eps; }
|
||||
double& Epsilon() { return optimizer.UpdatePolicy().Epsilon(); }
|
||||
|
||||
//! Get the maximum number of iterations (0 indicates no limit).
|
||||
size_t MaxIterations() const { return maxIterations; }
|
||||
size_t MaxIterations() const { return optimizer.MaxIterations(); }
|
||||
//! Modify the maximum number of iterations (0 indicates no limit).
|
||||
size_t& MaxIterations() { return maxIterations; }
|
||||
size_t& MaxIterations() { return optimizer.MaxIterations(); }
|
||||
|
||||
//! Get the tolerance for termination.
|
||||
double Tolerance() const { return tolerance; }
|
||||
double Tolerance() const { return optimizer.Tolerance(); }
|
||||
//! Modify the tolerance for termination.
|
||||
double& Tolerance() { return tolerance; }
|
||||
double& Tolerance() { return optimizer.Tolerance(); }
|
||||
|
||||
//! Get whether or not the individual functions are shuffled.
|
||||
bool Shuffle() const { return shuffle; }
|
||||
bool Shuffle() const { return optimizer.Shuffle(); }
|
||||
//! Modify whether or not the individual functions are shuffled.
|
||||
bool& Shuffle() { return shuffle; }
|
||||
bool& Shuffle() { return optimizer.Shuffle(); }
|
||||
|
||||
private:
|
||||
//! The instantiated function.
|
||||
DecomposableFunctionType& function;
|
||||
|
||||
//! The smoothing parameter.
|
||||
double rho;
|
||||
|
||||
//! The value used to initialise the mean squared gradient parameter.
|
||||
double eps;
|
||||
|
||||
//! The maximum number of allowed iterations.
|
||||
size_t maxIterations;
|
||||
|
||||
//! The tolerance for termination.
|
||||
double tolerance;
|
||||
|
||||
//! Controls whether or not the individual functions are shuffled when
|
||||
//! iterating.
|
||||
bool shuffle;
|
||||
//! The Stochastic Gradient Descent object with AdaDelta policy.
|
||||
SGD<DecomposableFunctionType, AdaDeltaUpdate> optimizer;
|
||||
};
|
||||
|
||||
} // namespace optimization
|
||||
@@ -155,4 +147,3 @@ class AdaDelta
|
||||
#include "ada_delta_impl.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @file ada_delta_impl.hpp
|
||||
* @author Ryan Curtin
|
||||
* @author Vasanth Kalingeri
|
||||
* @author Abhinav Moudgil
|
||||
*
|
||||
* Implementation of the AdaDelta optimizer.
|
||||
*
|
||||
* mlpack is free software; you may redistribute it and/or modify it under the
|
||||
* terms of the 3-clause BSD license. You should have received a copy of the
|
||||
* 3-clause BSD license along with mlpack. If not, see
|
||||
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
|
||||
*/
|
||||
#ifndef MLPACK_CORE_OPTIMIZERS_ADADELTA_ADA_DELTA_IMPL_HPP
|
||||
#define MLPACK_CORE_OPTIMIZERS_ADADELTA_ADA_DELTA_IMPL_HPP
|
||||
|
||||
#include "ada_delta.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace optimization {
|
||||
|
||||
template<typename DecomposableFunctionType>
|
||||
AdaDelta<DecomposableFunctionType>::AdaDelta(DecomposableFunctionType& function,
|
||||
const double stepSize,
|
||||
const double rho,
|
||||
const double epsilon,
|
||||
const size_t maxIterations,
|
||||
const double tolerance,
|
||||
const bool shuffle) :
|
||||
optimizer(function,
|
||||
stepSize,
|
||||
maxIterations,
|
||||
tolerance,
|
||||
shuffle,
|
||||
AdaDeltaUpdate(rho, epsilon))
|
||||
{ /* Nothing to do. */ }
|
||||
|
||||
} // namespace optimization
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @file ada_delta_update.hpp
|
||||
* @author Abhinav Moudgil
|
||||
*
|
||||
* AdaDelta update for Stochastic Gradient Descent.
|
||||
*
|
||||
* mlpack is free software; you may redistribute it and/or modify it under the
|
||||
* terms of the 3-clause BSD license. You should have received a copy of the
|
||||
* 3-clause BSD license along with mlpack. If not, see
|
||||
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
|
||||
*/
|
||||
#ifndef MLPACK_CORE_OPTIMIZERS_SGD_ADA_DELTA_UPDATE_HPP
|
||||
#define MLPACK_CORE_OPTIMIZERS_SGD_ADA_DELTA_UPDATE_HPP
|
||||
|
||||
#include <mlpack/prereqs.hpp>
|
||||
|
||||
namespace mlpack {
|
||||
namespace optimization {
|
||||
|
||||
/**
|
||||
* Implementation of the AdaDelta update policy. AdaDelta is an optimizer that
|
||||
* uses two ideas to improve upon the two main drawbacks of the AdaGrad method:
|
||||
*
|
||||
* - Accumulate Over Window
|
||||
* - Correct Units with Hessian Approximation
|
||||
*
|
||||
* For more information, see the following.
|
||||
*
|
||||
* @code
|
||||
* @article{Zeiler2012,
|
||||
* author = {Matthew D. Zeiler},
|
||||
* title = {{ADADELTA:} An Adaptive Learning Rate Method},
|
||||
* journal = {CoRR},
|
||||
* year = {2012}
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
class AdaDeltaUpdate
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct the AdaDelta update policy with given rho and epsilon parameters.
|
||||
*
|
||||
* @param rho The smoothing parameter.
|
||||
* @param epsilon The epsilon value used to initialise the squared gradient parameter.
|
||||
*/
|
||||
AdaDeltaUpdate(const double rho = 0.95, const double epsilon = 1e-8) :
|
||||
rho(rho),
|
||||
epsilon(epsilon)
|
||||
{ /* Do nothing. */ };
|
||||
|
||||
/**
|
||||
* The Initialize method is called by SGD Optimizer method before the start of the
|
||||
* iteration update process. In AdaDelta update policy, the mean squared and the delta
|
||||
* mean squared gradient matrices are initialized to the zeros matrix with the same
|
||||
* size as gradient matrix (see mlpack::optimization::SGD::Optimizer )
|
||||
*
|
||||
* @param rows number of rows in the gradient matrix.
|
||||
* @param cols number of columns in the gradient matrix.
|
||||
*/
|
||||
void Initialize(const size_t rows,
|
||||
const size_t cols)
|
||||
{
|
||||
// Initialize empty matrices for mean sum of squares of parameter gradient.
|
||||
meanSquaredGradient = arma::zeros<arma::mat>(rows, cols);
|
||||
meanSquaredGradientDx = arma::zeros<arma::mat>(rows, cols);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update step for SGD. The AdaDelta update dynamically adapts over time using only
|
||||
* first order information. Additionally, AdaDelta requires no manual tuning
|
||||
* of a learning rate.
|
||||
*
|
||||
* @param iterate Parameters that minimize the function.
|
||||
* @param stepSize Step size to be used for the given iteration.
|
||||
* @param gradient The gradient matrix.
|
||||
*/
|
||||
void Update(arma::mat& iterate,
|
||||
const double stepSize,
|
||||
const arma::mat& gradient)
|
||||
{
|
||||
// Accumulate gradient.
|
||||
meanSquaredGradient *= rho;
|
||||
meanSquaredGradient += (1 - rho) * (gradient % gradient);
|
||||
arma::mat dx = arma::sqrt((meanSquaredGradientDx + eps) /
|
||||
(meanSquaredGradient + eps)) % gradient;
|
||||
|
||||
// Accumulate updates.
|
||||
meanSquaredGradientDx *= rho;
|
||||
meanSquaredGradientDx += (1 - rho) * (dx % dx);
|
||||
|
||||
// Apply update.
|
||||
iterate -= (stepSize * dx);
|
||||
}
|
||||
|
||||
//! Get the smoothing parameter.
|
||||
double Rho() const { return rho; }
|
||||
//! Modify the smoothing parameter.
|
||||
double& Rho() { return rho; }
|
||||
|
||||
//! Get the value used to initialise the mean squared gradient parameter.
|
||||
double Epsilon() const { return epsilon; }
|
||||
//! Modify the value used to initialise the mean squared gradient parameter.
|
||||
double& Epsilon() { return epsilon; }
|
||||
|
||||
private:
|
||||
// The smoothing parameter.
|
||||
double rho;
|
||||
// The epsilon value used to initialise the mean squared gradient parameter.
|
||||
double epsilon;
|
||||
// The mean squared gradient matrix.
|
||||
arma::mat meanSquaredGradient;
|
||||
// The delta mean squared gradient matrix.
|
||||
arma::mat meanSquaredGradientDx;
|
||||
};
|
||||
|
||||
} // namespace optimization
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -1,141 +0,0 @@
|
||||
/**
|
||||
* @file ada_delta_impl.hpp
|
||||
* @author Ryan Curtin
|
||||
* @author Vasanth Kalingeri
|
||||
*
|
||||
* Implementation of the Adadelta optimizer.
|
||||
*
|
||||
* mlpack is free software; you may redistribute it and/or modify it under the
|
||||
* terms of the 3-clause BSD license. You should have received a copy of the
|
||||
* 3-clause BSD license along with mlpack. If not, see
|
||||
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
|
||||
*/
|
||||
#ifndef __MLPACK_CORE_OPTIMIZERS_ADADELTA_ADA_DELTA_IMPL_HPP
|
||||
#define __MLPACK_CORE_OPTIMIZERS_ADADELTA_ADA_DELTA_IMPL_HPP
|
||||
|
||||
#include "ada_delta.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace optimization {
|
||||
|
||||
template<typename DecomposableFunctionType>
|
||||
AdaDelta<DecomposableFunctionType>::AdaDelta(DecomposableFunctionType& function,
|
||||
const double rho,
|
||||
const double eps,
|
||||
const size_t maxIterations,
|
||||
const double tolerance,
|
||||
const bool shuffle) :
|
||||
function(function),
|
||||
rho(rho),
|
||||
eps(eps),
|
||||
maxIterations(maxIterations),
|
||||
tolerance(tolerance),
|
||||
shuffle(shuffle)
|
||||
{ /* Nothing to do. */ }
|
||||
|
||||
//! Optimize the function (minimize).
|
||||
template<typename DecomposableFunctionType>
|
||||
double AdaDelta<DecomposableFunctionType>::Optimize(arma::mat& iterate)
|
||||
{
|
||||
// Find the number of functions to use.
|
||||
const size_t numFunctions = function.NumFunctions();
|
||||
|
||||
// This is used only if shuffle is true.
|
||||
arma::Col<size_t> visitationOrder;
|
||||
if (shuffle)
|
||||
visitationOrder = arma::shuffle(arma::linspace<arma::Col<size_t>>(0,
|
||||
(numFunctions - 1), numFunctions));
|
||||
|
||||
// To keep track of where we are and how things are going.
|
||||
size_t currentFunction = 0;
|
||||
double overallObjective = 0;
|
||||
double lastObjective = DBL_MAX;
|
||||
|
||||
// Calculate the first objective function.
|
||||
for (size_t i = 0; i < numFunctions; ++i)
|
||||
overallObjective += function.Evaluate(iterate, i);
|
||||
|
||||
// Now iterate!
|
||||
arma::mat gradient(iterate.n_rows, iterate.n_cols);
|
||||
|
||||
// Leaky sum of squares of parameter gradient.
|
||||
arma::mat meanSquaredGradient = arma::zeros<arma::mat>(iterate.n_rows,
|
||||
iterate.n_cols);
|
||||
|
||||
// Leaky sum of squares of parameter gradient.
|
||||
arma::mat meanSquaredGradientDx = arma::zeros<arma::mat>(iterate.n_rows,
|
||||
iterate.n_cols);
|
||||
|
||||
for (size_t i = 1; i != maxIterations; ++i, ++currentFunction)
|
||||
{
|
||||
// Is this iteration the start of a sequence?
|
||||
if ((currentFunction % numFunctions) == 0)
|
||||
{
|
||||
// Output current objective function.
|
||||
Log::Info << "AdaDelta: iteration " << i << ", objective "
|
||||
<< overallObjective << "." << std::endl;
|
||||
|
||||
if (std::isnan(overallObjective) || std::isinf(overallObjective))
|
||||
{
|
||||
Log::Warn << "AdaDelta: converged to " << overallObjective
|
||||
<< "; terminating with failure. Try a smaller step size?"
|
||||
<< std::endl;
|
||||
return overallObjective;
|
||||
}
|
||||
|
||||
if (std::abs(lastObjective - overallObjective) < tolerance)
|
||||
{
|
||||
Log::Info << "AdaDelta: minimized within tolerance " << tolerance
|
||||
<< "; terminating optimization." << std::endl;
|
||||
return overallObjective;
|
||||
}
|
||||
|
||||
// Reset the counter variables.
|
||||
lastObjective = overallObjective;
|
||||
overallObjective = 0;
|
||||
currentFunction = 0;
|
||||
|
||||
if (shuffle) // Determine order of visitation.
|
||||
visitationOrder = arma::shuffle(visitationOrder);
|
||||
}
|
||||
|
||||
// Evaluate the gradient for this iteration.
|
||||
if (shuffle)
|
||||
function.Gradient(iterate, visitationOrder[currentFunction], gradient);
|
||||
else
|
||||
function.Gradient(iterate, currentFunction, gradient);
|
||||
|
||||
// Accumulate gradient.
|
||||
meanSquaredGradient *= rho;
|
||||
meanSquaredGradient += (1 - rho) * (gradient % gradient);
|
||||
arma::mat dx = arma::sqrt((meanSquaredGradientDx + eps) /
|
||||
(meanSquaredGradient + eps)) % gradient;
|
||||
|
||||
// Accumulate updates.
|
||||
meanSquaredGradientDx *= rho;
|
||||
meanSquaredGradientDx += (1 - rho) * (dx % dx);
|
||||
|
||||
// Apply update.
|
||||
iterate -= dx;
|
||||
|
||||
// Now add that to the overall objective function.
|
||||
if (shuffle)
|
||||
overallObjective += function.Evaluate(iterate,
|
||||
visitationOrder[currentFunction]);
|
||||
else
|
||||
overallObjective += function.Evaluate(iterate, currentFunction);
|
||||
}
|
||||
|
||||
Log::Info << "AdaDelta: maximum iterations (" << maxIterations
|
||||
<< ") reached; terminating optimization." << std::endl;
|
||||
// Calculate final objective.
|
||||
overallObjective = 0;
|
||||
for (size_t i = 0; i < numFunctions; ++i)
|
||||
overallObjective += function.Evaluate(iterate, i);
|
||||
return overallObjective;
|
||||
}
|
||||
|
||||
} // namespace optimization
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -2,6 +2,7 @@
|
||||
* @file ada_delta_test.cpp
|
||||
* @author Marcus Edel
|
||||
* @author Vasanth Kalingeri
|
||||
* @author Abhinav Moudgil
|
||||
*
|
||||
* Tests the AdaDelta optimizer
|
||||
*
|
||||
@@ -12,7 +13,7 @@
|
||||
*/
|
||||
#include <mlpack/core.hpp>
|
||||
|
||||
#include <mlpack/core/optimizers/adadelta/ada_delta.hpp>
|
||||
#include <mlpack/core/optimizers/ada_delta/ada_delta.hpp>
|
||||
#include <mlpack/core/optimizers/sgd/test_function.hpp>
|
||||
#include <mlpack/methods/logistic_regression/logistic_regression.hpp>
|
||||
|
||||
@@ -36,7 +37,7 @@ BOOST_AUTO_TEST_SUITE(AdaDeltaTest);
|
||||
BOOST_AUTO_TEST_CASE(SimpleAdaDeltaTestFunction)
|
||||
{
|
||||
SGDTestFunction f;
|
||||
AdaDelta<SGDTestFunction> optimizer(f, 0.99, 1e-8, 5000000, 1e-9, true);
|
||||
AdaDelta<SGDTestFunction> optimizer(f, 1.0, 0.99, 1e-8, 5000000, 1e-9, true);
|
||||
|
||||
arma::mat coordinates = f.GetInitialPoint();
|
||||
optimizer.Optimize(coordinates);
|
||||
|
||||
Reference in New Issue
Block a user