Merge branch 'master' into master

This commit is contained in:
Namrata Mukhija
2018-04-23 12:39:20 +05:30
committed by GitHub
21 changed files with 1209 additions and 58 deletions
+1
View File
@@ -242,6 +242,7 @@
* - Moksh Jain <mokshjn00@gmail.com>
* - Manthan-R-Sheth <manthanrsheth96@gmail.com>
* - Namrata Mukhija <namratamukhija@gmail.com>
* - Rohan Raj <rajrohan1108@gmail.com>
*/
// First, include all of the prerequisites.
@@ -3,8 +3,10 @@
set(SOURCES
const_init.hpp
gaussian_init.hpp
he_init.hpp
init_rules_traits.hpp
kathirvalavakumar_subavathi_init.hpp
lecun_normal_init.hpp
network_init.hpp
nguyen_widrow_init.hpp
oivs_init.hpp
@@ -0,0 +1,106 @@
/**
* @file he_init.hpp
* @author Dakshit Agrawal
* @author Prabhat Sharma
*
* Intialization rule given by He et. al. for neural networks. The He
* initialization initializes weights of the neural network to better
* suit the rectified activation units.
*
* 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_METHODS_ANN_INIT_RULES_HE_INIT_HPP
#define MLPACK_METHODS_ANN_INIT_RULES_HE_INIT_HPP
#include <mlpack/prereqs.hpp>
#include <mlpack/core/math/random.hpp>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
/**
* This class is used to initialize weight matrix with the He
* initialization rule given by He et. al. for neural networks. The He
* initialization initializes weights of the neural network to better
* suit the rectified activation units.
*
* For more information, the following paper can be referred to:
*
* @code
* @article{Delving2015,
* title = {Delving Deep into Rectifiers: Surpassing Human-Level Performance
* on ImageNet Classification},
* author = {Kaiming He and Xiangyu Zhang and Shaoqing Ren and Jian Sun},
* journal = {2015 IEEE International Conference on Computer Vision (ICCV)},
* year = {2015},
* pages = {1026-1034}
* }
* @endcode
*
*/
class HeInitialization
{
public:
/**
* Initialize the HeInitialization object.
*/
HeInitialization()
{
// Nothing to do here.
}
/**
* Initialize the elements of the weight matrix with the He initialization
* rule.
*
* @param W Weight matrix to initialize.
* @param rows Number of rows.
* @param cols Number of columns.
*/
void Initialize(arma::mat& W, const size_t rows, const size_t cols)
{
// He initialization rule says to initialize weights with random
// values taken from a gaussian distribution with mean = 0 and
// standard deviation = sqrt(2/rows), i.e. variance = (2/rows).
const double variance = 2.0 / (double)rows;
if (W.is_empty())
{
W.set_size(rows, cols);
}
// Multipling a random variable X with variance V(X) by some factor c,
// then the variance V(cX) = (c^2) * V(X).
W.imbue( [&]() { return sqrt(variance) * arma::randn(); } );
}
/**
* Initialize the elements of the specified weight 3rd order tensor
* with He initialization rule.
*
* @param W Weight matrix to initialize.
* @param rows Number of rows.
* @param cols Number of columns.
* @param slice Numbers of slices.
*/
void Initialize(arma::cube & W,
const size_t rows,
const size_t cols,
const size_t slices)
{
if (W.is_empty())
W.set_size(rows, cols, slices);
for (size_t i = 0; i < slices; i++)
Initialize(W.slice(i), rows, cols);
}
}; // class HeInitialization
} // namespace ann
} // namespace mlpack
#endif
@@ -0,0 +1,112 @@
/**
* @file lecun_normal_init.hpp
* @author Dakshit Agrawal
* @author Prabhat Sharma
*
* Intialization rule given by Lecun et. al. for neural networks and
* also mentioned in Self Normalizing Networks.
*
* 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_METHODS_ANN_INIT_RULES_LECUN_NORMAL_INIT_HPP
#define MLPACK_METHODS_ANN_INIT_RULES_LECUN_NORMAL_INIT_HPP
#include <mlpack/prereqs.hpp>
#include <mlpack/core/math/random.hpp>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
/**
* This class is used to initialize weight matrix with the Lecun Normalization
* initialization rule.
*
* For more information, the following papers can be referred to:
*
* @code
* @inproceedings{Klambauer2017,
* itle = {Self-Normalizing Neural Networks.},
* author = {Klambauer, Günter and Unterthiner, Thomas
* and Mayr, Andreas and Hochreiter, Sepp},
* pages = {972-981},
* year = {2017}
* }
*
* @inproceedings{LeCun1998,
* title = {Efficient BackProp},
* author = {LeCun, Yann and Bottou, L{\'e}on and Orr, Genevieve B.
* and M\"{u}ller, Klaus-Robert},
* year = {1998},
* pages = {9--50}
* }
* @endcode
*
*/
class LecunNormalInitialization
{
public:
/**
* Initialize the LecunNormalInitialization object.
*/
LecunNormalInitialization()
{
// Nothing to do here.
}
/**
* Initialize the elements of the weight matrix with the Lecun
* Normal initialization rule.
*
* @param W Weight matrix to initialize.
* @param rows Number of rows.
* @param cols Number of columns.
*/
void Initialize(arma::mat& W,
const size_t rows,
const size_t cols)
{
// He initialization rule says to initialize weights with random
// values taken from a gaussian distribution with mean = 0 and
// standard deviation = sqrt(1 / rows), i.e. variance = (1 / rows).
const double variance = 1.0 / ((double) rows);
if (W.is_empty())
{
W.set_size(rows, cols);
}
// Multipling a random variable X with variance V(X) by some factor c,
// then the variance V(cX) = (c ^ 2) * V(X).
W.imbue( [&]() { return sqrt(variance) * arma::randn(); } );
}
/**
* Initialize the elements of the specified weight 3rd order tensor
* with Lecun Normal initialization rule.
*
* @param W Weight matrix to initialize.
* @param rows Number of rows.
* @param cols Number of columns.
* @param slice Numbers of slices.
*/
void Initialize(arma::cube & W,
const size_t rows,
const size_t cols,
const size_t slices)
{
if (W.is_empty())
W.set_size(rows, cols, slices);
for (size_t i = 0; i < slices; i++)
Initialize(W.slice(i), rows, cols);
}
}; // class LecunNormalInitialization
} // namespace ann
} // namespace mlpack
#endif
@@ -30,6 +30,8 @@ set(SOURCES
elu_impl.hpp
fast_lstm.hpp
fast_lstm_impl.hpp
flexible_relu.hpp
flexible_relu_impl.hpp
glimpse.hpp
glimpse_impl.hpp
gru.hpp
+10 -22
View File
@@ -3,7 +3,7 @@
* @author Marcus Edel
*
* Definition of the Dropout class, which implements a regularizer that
* randomly sets units to zero. Preventing units from co-adapting.
* randomly sets units to zero preventing units from co-adapting.
*
* 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
@@ -18,12 +18,12 @@
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
/**
* The dropout layer is a regularizer that randomly with probability ratio
* The dropout layer is a regularizer that randomly with probability 'ratio'
* sets input values to zero and scales the remaining elements by factor 1 /
* (1 - ratio). If rescale is true the input is scaled with 1 / (1-p) when
* deterministic is false. In the deterministic mode (during testing), the layer
* just scales the output.
* (1 - ratio) rather than during test time so as to keep the expected sum same.
* In the deterministic mode (during testing), there is no change in the input.
*
* Note: During training you should set deterministic to false and during
* testing you should set deterministic to true.
@@ -47,21 +47,17 @@ namespace ann /** Artificial Neural Network. */ {
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
*/
template <
typename InputDataType = arma::mat,
typename OutputDataType = arma::mat
>
template<typename InputDataType = arma::mat,
typename OutputDataType = arma::mat>
class Dropout
{
public:
/**
* Create the Dropout object using the specified ratio and rescale
* parameter.
* Create the Dropout object using the specified ratio parameter.
*
* @param ratio The probability of setting a value to zero.
* @param rescale If true the input is rescaled when deterministic is False.
*/
Dropout(const double ratio = 0.5, const bool rescale = true);
Dropout(const double ratio = 0.5);
/**
* Ordinary feed forward pass of the dropout layer.
@@ -85,7 +81,7 @@ class Dropout
arma::Mat<eT>&& g);
//! Get the input parameter.
InputDataType const& InputParameter() const { return inputParameter; }
InputDataType const& InputParameter() const { return inputParameter; }
//! Modify the input parameter.
InputDataType& InputParameter() { return inputParameter; }
@@ -114,11 +110,6 @@ class Dropout
scale = 1.0 / (1.0 - ratio);
}
//! The value of the rescale parameter.
bool Rescale() const {return rescale; }
//! Modify the value of the rescale parameter.
bool& Rescale() {return rescale; }
/**
* Serialize the layer.
*/
@@ -146,9 +137,6 @@ class Dropout
//! If true dropout and scaling is disabled, see notes above.
bool deterministic;
//! If true the input is rescaled when deterministic is False.
bool rescale;
}; // class Dropout
} // namespace ann
+5 -14
View File
@@ -21,11 +21,10 @@ namespace ann /** Artificial Neural Network. */ {
template<typename InputDataType, typename OutputDataType>
Dropout<InputDataType, OutputDataType>::Dropout(
const double ratio, const bool rescale) :
const double ratio) :
ratio(ratio),
scale(1.0 / (1.0 - ratio)),
deterministic(true),
rescale(rescale)
deterministic(false)
{
// Nothing to do here.
}
@@ -40,21 +39,14 @@ void Dropout<InputDataType, OutputDataType>::Forward(
// (during testing).
if (deterministic)
{
if (!rescale)
{
output = input;
}
else
{
output = input * scale;
}
output = input;
}
else
{
// Scale with input / (1 - ratio) and set values to zero with probability
// ratio.
// 'ratio'.
mask = arma::randu<arma::Mat<eT> >(input.n_rows, input.n_cols);
mask.transform( [&](double val) { return (val > ratio); } );
mask.transform([&](double val) { return (val > ratio); });
output = input % mask * scale;
}
}
@@ -76,7 +68,6 @@ void Dropout<InputDataType, OutputDataType>::serialize(
const unsigned int /* version */)
{
ar & BOOST_SERIALIZATION_NVP(ratio);
ar & BOOST_SERIALIZATION_NVP(rescale);
// Reset scale.
scale = 1.0 / (1.0 - ratio);
@@ -0,0 +1,175 @@
/**
* @file flexible_relu.hpp
* @author Aarush Gupta
* @author Manthan-R-Sheth
*
* Definition of FlexibleReLU layer as described by
* Suo Qiu, Xiangmin Xu and Bolun Cai in
* "FReLU: Flexible Rectified Linear Units for Improving Convolutional
* Neural Networks", 2018
*
* 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_METHODS_ANN_LAYER_FLEXIBLERELU_HPP
#define MLPACK_METHODS_ANN_LAYER_FLEXIBLERELU_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace ann /**Artificial Neural Network*/ {
/**
* The FlexibleReLU activation function, defined by
*
* @f{eqnarray*}{
* f(x) &=& \max(0,x)+alpha \\
* f'(x) &=& \left\{
* \begin(array){lr}
* 1 & : x > 0 \\
* 0 & : x \le 0
* \end{array}
* \right
* @f}
*
* For more information, read the following paper:
*
* @code
* @article{Qiu2018,
* author = {Suo Qiu, Xiangmin Xu and Bolun Cai},
* title = {FReLU: Flexible Rectified Linear Units for Improving
* Convolutional Neural Networks}
* journal = {arxiv preprint},
* URL = {https://arxiv.org/abs/1706.08098},
* year = {2018}
* }
* @endcode
*
* @tparam InputDataType Type of the input data (arma::colvec, arma::mar,
* arma::sp_mat or arma::cube)
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube)
*/
template <
typename InputDataType = arma::mat,
typename OutputDataType = arma::mat
>
class FlexibleReLU
{
public:
/**
*
* Create the FlexibleReLU object using the specified parameters.
* The non zero parameter can be adjusted by specifying the parameter
* alpha which controls the range of the relu function. (Default alpha = 0)
* This parameter is trainable.
*
* @param alpha Parameter for adjusting the range of the relu function.
*
*/
FlexibleReLU(const double alpha = 0);
/**
* Reset the layer parameter.
*/
void Reset();
/**
* Ordinary feed forward pass of a neural network, evaluating the function
* f(x) by propagating the activity forward through f.
*
* @param input Input data used for evaluating the specified function.
* @param output Resulting output activation.
*/
template<typename InputType, typename OutputType>
void Forward(const InputType&& input, OutputType&& output);
/**
* Ordinary feed backward pass of a neural network, calculating the function
* f(x) by propagating x backwards through f. Using the results from the feed
* forward pass.
*
* @param input The propagated input activation.
* @param gy The backpropagated error.
* @param g The calculated gradient.
*/
template<typename DataType>
void Backward(const DataType&& input, DataType&& gy, DataType&& g);
/**
* Calculate the gradient using the output delta and the input activation.
*
* @param input The input parameter used for calculating the gradient.
* @param error The calculated error.
* @param gradient The calculated gradient.
*/
template<typename eT>
void Gradient(const arma::Mat<eT>&& input,
arma::Mat<eT>&& error,
arma::Mat<eT>&& gradient);
//! Get the parameters.
OutputDataType const& Parameters() const { return alpha; }
//! Modify the parameters.
OutputDataType& Parameters() { return alpha; }
//! Get the input parameter.
InputDataType const& InputParameter() const { return inputParameter; }
//! Modify the input parameter.
InputDataType& InputParameter() { return inputParameter; }
//! Get the output parameter.
OutputDataType const& OutputParameter() const { return outputParameter; }
//! Modify the output parameter.
OutputDataType& OutputParameter() { return outputParameter; }
//! Get the delta.
OutputDataType const& Delta() const { return delta; }
//! Modify the delta.
OutputDataType& Delta() { return delta;}
//! Get the gradient.
OutputDataType const& Gradient() const { return gradient; }
//! Modify the gradient.
OutputDataType& Gradient() { return gradient; }
//! Get the parameter controlling the range of the relu function.
double const& Alpha() const { return alpha; }
//! Modify the parameter controlling the range of the relu function.
double& Alpha() { return alpha; }
/**
* Serialize the layer.
*/
template<typename Archive>
void serialize(Archive& ar, const unsigned int /* version*/);
private:
//! Locally-stored delta object.
OutputDataType delta;
//! Locally-stored input parameter object.
InputDataType inputParameter;
//! Locally-stored output parameter object.
OutputDataType outputParameter;
//! Parameter object.
OutputDataType alpha;
//! Locally-stored gradient object.
OutputDataType gradient;
//! Parameter controlling the range of the rectifier function
double userAlpha;
}; // class FlexibleReLU
} // namespace ann
} // namespace mlpack
// Include implementation
#include "flexible_relu_impl.hpp"
#endif
@@ -0,0 +1,86 @@
/**
* @file flexible_relu_impl.hpp
* @author Aarush Gupta
* @author Manthan-R-Sheth
*
* Implementation of FlexibleReLU layer as described by
* Suo Qiu, Xiangmin Xu and Bolun Cai in
* "FReLU: Flexible Rectified Linear Units for Improving Convolutional
* Neural Networks", 2018
*
* 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_METHODS_ANN_LAYER_FLEXIBLERELU_IMPL_HPP
#define MLPACK_METHODS_ANN_LAYER_FLEXIBLERELU_IMPL_HPP
#include "flexible_relu.hpp"
#include<algorithm>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
template<typename InputDataType, typename OutputDataType>
FlexibleReLU<InputDataType, OutputDataType>::FlexibleReLU(
const double alpha) : userAlpha(alpha)
{
this->alpha.set_size(1, 1);
this->alpha(0) = userAlpha;
}
template<typename InputDataType, typename OutputDataType>
void FlexibleReLU<InputDataType, OutputDataType>::Reset()
{
//! Set value of alpha to the one given by user.
alpha(0) = userAlpha;
}
template<typename InputDataType, typename OutputDataType>
template<typename InputType, typename OutputType>
void FlexibleReLU<InputDataType, OutputDataType>::Forward(
const InputType&& input, OutputType&& output)
{
output = arma::clamp(input, 0.0, DBL_MAX) + alpha(0);
}
template<typename InputDataType, typename OutputDataType>
template<typename DataType>
void FlexibleReLU<InputDataType, OutputDataType>::Backward(
const DataType&& input, DataType&& gy, DataType&& g)
{
//! Compute the first derivative of FlexibleReLU function.
g = gy % arma::clamp(arma::sign(input), 0.0, 1.0);
}
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void FlexibleReLU<InputDataType, OutputDataType>::Gradient(
const arma::Mat<eT>&& input,
arma::Mat<eT>&& error,
arma::Mat<eT>&& gradient)
{
if (gradient.n_elem == 0)
{
gradient.set_size(1, 1);
}
gradient(0) = arma::accu(error) / input.n_cols;
}
template<typename InputDataType, typename OutputDataType>
template<typename Archive>
void FlexibleReLU<InputDataType, OutputDataType>::serialize(
Archive& ar,
const unsigned int /* version*/)
{
ar & BOOST_SERIALIZATION_NVP(alpha);
}
} // namespace ann
} // namespace mlpack
#endif
@@ -27,6 +27,7 @@
#include <mlpack/methods/ann/layer/hard_tanh.hpp>
#include <mlpack/methods/ann/layer/join.hpp>
#include <mlpack/methods/ann/layer/leaky_relu.hpp>
#include <mlpack/methods/ann/layer/flexible_relu.hpp>
#include <mlpack/methods/ann/layer/log_softmax.hpp>
#include <mlpack/methods/ann/layer/lookup.hpp>
#include <mlpack/methods/ann/layer/mean_squared_error.hpp>
@@ -126,6 +127,7 @@ using LayerTypes = boost::variant<
Dropout<arma::mat, arma::mat>*,
AlphaDropout<arma::mat, arma::mat>*,
ELU<arma::mat, arma::mat>*,
FlexibleReLU<arma::mat, arma::mat>*,
Glimpse<arma::mat, arma::mat>*,
HardTanH<arma::mat, arma::mat>*,
Join<arma::mat, arma::mat>*,
+2 -2
View File
@@ -103,7 +103,7 @@ class LeakyReLU
private:
/**
* Computes the LeakReLU function
* Computes the LeakyReLU function
*
* @param x Input data.
* @return f(x).
@@ -114,7 +114,7 @@ class LeakyReLU
}
/**
* Computes the Leaky ReLU function using a dense matrix as input.
* Computes the LeakyReLU function using a dense matrix as input.
*
* @param x Input data.
* @param y The resulting output activation.
+15 -6
View File
@@ -201,6 +201,7 @@ double RNN<OutputLayerType, InitializationRuleType, CustomLayers...>::Evaluate(
ResetCells();
double performance = 0;
size_t responseSeq = 0;
for (size_t seqNum = 0; seqNum < rho; ++seqNum)
{
@@ -208,8 +209,10 @@ double RNN<OutputLayerType, InitializationRuleType, CustomLayers...>::Evaluate(
arma::mat stepData(predictors.slice(seqNum).colptr(begin),
predictors.n_rows, batchSize, false, true);
Forward(std::move(stepData));
arma::mat respData(responses.slice(seqNum).colptr(begin),
responses.n_rows, batchSize, false, true);
if (!single)
{
responseSeq = seqNum;
}
if (!deterministic)
{
@@ -222,7 +225,7 @@ double RNN<OutputLayerType, InitializationRuleType, CustomLayers...>::Evaluate(
performance += outputLayer.Forward(std::move(boost::apply_visitor(
outputParameterVisitor, network.back())),
std::move(arma::mat(responses.slice(seqNum).colptr(begin),
std::move(arma::mat(responses.slice(responseSeq).colptr(begin),
responses.n_rows, batchSize, false, true)));
}
@@ -283,19 +286,25 @@ void RNN<OutputLayerType, InitializationRuleType, CustomLayers...>::Gradient(
{
error.zeros();
}
else if (single && seqNum == 0)
{
outputLayer.Backward(std::move(boost::apply_visitor(
outputParameterVisitor, network.back())),
std::move(arma::mat(responses.slice(0).colptr(begin),
responses.n_rows, batchSize, false, true)), std::move(error));
}
else
{
outputLayer.Backward(std::move(boost::apply_visitor(
outputParameterVisitor, network.back())),
std::move(arma::mat(responses.slice(rho - seqNum - 1).colptr(begin),
responses.n_rows, batchSize, false, true)),
std::move(error));
responses.n_rows, batchSize, false, true)), std::move(error));
}
Backward();
Gradient(std::move(
arma::mat(predictors.slice(rho - seqNum - 1).colptr(begin),
predictors.n_rows, batchSize, false, true)));
predictors.n_rows, batchSize, false, true)));
gradient += currentGradient;
}
}
@@ -3,6 +3,7 @@
set(SOURCES
mountain_car.hpp
cart_pole.hpp
acrobat.hpp
)
# Add directory name to sources.
@@ -0,0 +1,345 @@
/**
* @file acrobat.hpp
* @author Rohan Raj
*
* This file is an implementation of Acrobat task:
* https://gym.openai.com/envs/Acrobot-v1/
*
* 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_METHODS_RL_ENVIRONMENT_ACROBAT_HPP
#define MLPACK_METHODS_RL_ENVIRONMENT_ACROBAT_HPP
#include <mlpack/core.hpp>
namespace mlpack{
namespace rl{
/**
* Implementation of Acrobat game. Acrobot is a 2-link pendulum with only the
* second joint actuated. Intitially, both links point downwards. The goal is
* to swing the end-effector at a height at least the length of one link above
* the base. Both links can swing freely and can pass by each other, i.e.,
* they don't collide when they have the same angle.
*/
class Acrobat
{
public:
/*
* Implementation of Acrobat State. Each State is a tuple vector
* (theta1, thetha2, angular velocity 1, angular velocity 2).
*/
class State
{
public:
/**
* Construct a state instance.
*/
State(): data(dimension) { /* nothing to do here */ }
/**
* Construct a state instance from given data.
*
* @param data Data for the theta and angular velocity of two links.
*/
State(const arma::colvec& data) : data(data)
{ /* nothing to do here */ }
//! Modify the state representation.
arma::colvec& Data() { return data; }
//! Get value of theta (one).
double Theta1() const { return data[0]; }
//! Modify value of theta (one).
double& Theta1() { return data[0]; }
//! Get value of theta (two).
double Theta2() const { return data[1]; }
//! Modify value of theta (two).
double& Theta2() { return data[1]; }
//! Get value of Angular velocity (one).
double AngularVelocity1() const { return data[2]; }
//! Modify the angular velocity (one).
double& AngularVelocity1() { return data[2]; }
//! Get value of Angular velocity (two).
double AngularVelocity2() const { return data[3]; }
//! Modify the angular velocity (two).
double& AngularVelocity2() { return data[3]; }
//! Encode the state to a column vector.
const arma::colvec& Encode() const { return data; }
//! Dimension of the encoded state.
static constexpr size_t dimension = 4;
private:
//! Locally-Stored (theta1, theta2, angular velocity 1, angular velocity2).
arma::colvec data;
};
/*
* Implementation of action for Acrobat
*/
enum Action
{
negativeTorque,
zeroTorque,
positiveTorque,
// Track the size of the action space.
size
};
/**
* Construct a Acrobat instance using the given constants.
*
* @param gravity The gravity parameter.
* @param linkLength1 The length of link 1.
* @param linkLength2 The length of link 2.
* @param linkMass1 The mass of link 1.
* @param linkMass2 The mass of link 2.
* @param linkCom1 The position of the center of mass of link 1.
* @param linkCom2 The position of the center of mass of link 2.
* @param linkMoi The moments of inertia for both link.
* @param maxVel1 The max angular velocity of link1.
* @param maxVel2 The max angular velocity of link2.
* @param dt The differential value.
*/
Acrobat(const double gravity = 9.81,
const double linkLength1 = 1.0,
const double linkLength2 = 1.0,
const double linkMass1 = 1.0,
const double linkMass2 = 1.0,
const double linkCom1 = 0.5,
const double linkCom2 = 0.5,
const double linkMoi = 1.0,
const double maxVel1 = 4 * M_PI,
const double maxVel2 = 9 * M_PI,
const double dt = 0.2) :
gravity(gravity),
linkLength1(linkLength1),
linkLength2(linkLength2),
linkMass1(linkMass1),
linkMass2(linkMass2),
linkCom1(linkCom1),
linkCom2(linkCom2),
linkMoi(linkMoi),
maxVel1(maxVel1),
maxVel2(maxVel2),
dt(dt)
{ /* Nothing to do here */ }
/**
* Dynamics of the Acrobat System. To get reward and next state based on
* current state and current action. Always return -1 reward.
*
* @param state The current State.
* @param action The action taken.
* @param nextState The next state.
* @return reward, it's always -1.0.
*/
double Sample(const State& state,
const Action& action,
State& nextState) const
{
// Make a vector to estimate nextstate.
arma::colvec currentState = {state.Theta1(), state.Theta2(),
state.AngularVelocity1(), state.AngularVelocity2()};
arma::colvec currentNextState = Rk4(currentState, Torque(action));
nextState.Theta1() = Wrap(currentNextState[0], -M_PI, M_PI);
nextState.Theta2() = Wrap(currentNextState[1], -M_PI, M_PI);
//! The value of angular velocity is bounded in min and max value.
nextState.AngularVelocity1() = std::min(
std::max(currentNextState[2], -maxVel1), maxVel1);
nextState.AngularVelocity2() = std::min(
std::max(currentNextState[3], -maxVel2), maxVel2);
return -1.0;
};
/**
* Dynamics of the Acrobat System. To get reward and next state based on
* current state and current action. This function calls the Sample function
* to estimate the next state return reward for taking a particular action.
*
* @param state The current State.
* @param action The action taken.
* @param nextState The next state.
*/
double Sample(const State& state, const Action& action) const
{
State nextState;
return Sample(state, action, nextState);
}
/**
* This function does random initialization of state space.
*/
State InitialSample() const
{
return State((arma::randu<arma::colvec>(4) - 0.5) / 5.0);
}
/**
* This function checks if the acrobat has reached the terminal state.
*
* @param state The current State.
*/
bool IsTerminal(const State& state) const
{
return bool (-std::cos(state.Theta1())-std::cos(state.Theta1() +
state.Theta2()) > 1.0);
}
/**
* This is the ordinary differential equations required for estimation of
* nextState through RK4 method.
*
* @param state Current State.
* @param torque The torque Applied.
*/
arma::colvec Dsdt(arma::colvec state, const double torque) const
{
const double m1 = linkMass1;
const double m2 = linkMass2;
const double l1 = linkLength1;
const double lc1 = linkCom1;
const double lc2 = linkCom2;
const double I1 = linkMoi;
const double I2 = linkMoi;
const double g = gravity;
const double a = torque;
const double theta1 = state[0];
const double theta2 = state[1];
arma::colvec values(4);
values[0] = state[2];
values[1] = state[3];
const double d1 = m1 * std::pow(lc1, 2) + m2 * (std::pow(l1, 2) +
std::pow(lc2, 2) + 2 * l1 * lc2 * std::cos(theta2)) + I1 + I2;
const double d2 = m2 * (std::pow(lc2, 2) + l1 * lc2 * std::cos(theta2)) +
I2;
const double phi2 = m2 * lc2 * g * std::cos(theta1 + theta2 - M_PI / 2.);
const double phi1 = - m2 * l1 * lc2 * std::pow(values[1], 2) *
std::sin(theta2) - 2 * m2 * l1 * lc2 * values[1] * values[0] *
std::sin(theta2) + (m1 * lc1 + m2 * l1) * g *
std::cos(theta1 - M_PI / 2) + phi2;
values[3] = (a + d2 / d1 * phi1 - m2 * l1 * lc2 * std::pow(values[0], 2) *
std::sin(theta2) - phi2) / (m2 * std::pow(lc2, 2) + I2 -
std::pow(d2, 2) / d1);
values[2] = -(d2 * values[3] + phi1) / d1;
return values;
};
/**
* Wrap funtion is required to truncate the angle value from -180 to 180.
* This function will make sure that value will always be between minimum
* to maximum.
*
* @param value Scalar value to wrap.
* @param minimum Minimum range of wrap.
* @param maximum Maximum range of wrap.
*/
double Wrap(double value,
const double minimum,
const double maximum) const
{
const double diff = maximum - minimum;
if (value > maximum)
{
value = value - diff;
}
else if (value < minimum)
{
value = value + diff;
}
return value;
};
/**
* This function calculates the torque for a particular action.
* 0 : negative torque, 1 : zero torque, 2 : positive torque.
*
* @param Action action taken.
*/
double Torque(const Action& action) const
{
// Add noise to the Torque Torque is action number - 1. {0,1,2} -> {-1,0,1}.
return double(action - 1) + mlpack::math::Random(-0.1, 0.1);
}
/**
*
* This function calls the RK4 iterative method to estimate the next state
* based on given ordinary differential equation.
*
* @param state The current State.
* @param torque The torque applied.
*/
arma::colvec Rk4(const arma::colvec state, const double torque) const
{
arma::colvec k1 = Dsdt(state, torque);
arma::colvec k2 = Dsdt(state + dt * k1 / 2, torque);
arma::colvec k3 = Dsdt(state + dt * k2 / 2, torque);
arma::colvec k4 = Dsdt(state + dt * k3, torque);
arma::colvec nextState = state + dt * (k1 + 2 * k2 + 2 * k3 + k4) / 6;
return nextState;
};
private:
//! Locally-stored gravity.
double gravity;
//! Locally-stored length of link 1.
double linkLength1;
//! Locally-stored length of link 2.
double linkLength2;
//! Locally-stored mass of link 1.
double linkMass1;
//! Locally-stored mass of link 2.
double linkMass2;
//! Locally-stored position of link 1.
double linkCom1;
//! Locally-stored position of link 2.
double linkCom2;
//! Locally-stored moment of intertia value.
double linkMoi;
//! Locally-stored max angular velocity of link1.
double maxVel1;
//! Locally-stored max angular velocity of link2.
double maxVel2;
//! Locally-stored dt for RK4 method.
double dt;
}; // class Acrobat
} // namespace rl
} // namespace mlpack
#endif
+65 -9
View File
@@ -319,10 +319,8 @@ BOOST_AUTO_TEST_CASE(JacobianConstantLayerTest)
*/
BOOST_AUTO_TEST_CASE(SimpleDropoutLayerTest)
{
// Initialize the probability of setting a value to zero and the scale
// parameter.
// Initialize the probability of setting a value to zero.
const double p = 0.2;
const double scale = 1.0 / (1.0 - p);
// Initialize the input parameter.
arma::mat input(1000, 1);
@@ -345,14 +343,8 @@ BOOST_AUTO_TEST_CASE(SimpleDropoutLayerTest)
// Test the Forward function.
module.Deterministic() = true;
module.Rescale() = false;
module.Forward(std::move(input), std::move(output));
BOOST_REQUIRE_EQUAL(arma::accu(input), arma::accu(output));
// Test the Forward function.
module.Rescale() = true;
module.Forward(std::move(input), std::move(output));
BOOST_REQUIRE_CLOSE(arma::accu(input) * scale, arma::accu(output), 1e-3);
}
/**
@@ -707,6 +699,70 @@ BOOST_AUTO_TEST_CASE(JacobianLeakyReLULayerTest)
}
}
/**
* Jacobian FlexibleReLU module test.
*/
BOOST_AUTO_TEST_CASE(JacobianFlexibleReLULayerTest)
{
for (size_t i = 0; i < 5; i++)
{
const size_t inputElements = math::RandInt(2, 1000);
arma::mat input;
input.set_size(inputElements, 1);
FlexibleReLU<> module;
double error = JacobianTest(module, input);
BOOST_REQUIRE_LE(error, 1e-5);
}
}
/**
* Flexible ReLU layer numerically gradient test.
*/
BOOST_AUTO_TEST_CASE(GradientFlexibleReLULayerTest)
{
// Add function gradient instantiation.
struct GradientFunction
{
GradientFunction()
{
input = arma::randu(2, 1);
target = arma::mat("1");
model = new FFN<NegativeLogLikelihood<>, RandomInitialization>(
NegativeLogLikelihood<>(), RandomInitialization(0.1, 0.5));
model->Predictors() = input;
model->Responses() = target;
model->Add<LinearNoBias<> >(2, 5);
model->Add<FlexibleReLU<> >(0.05);
model->Add<LogSoftMax<> >();
}
~GradientFunction()
{
delete model;
}
double Gradient(arma::mat& gradient) const
{
arma::mat output;
double error = model->Evaluate(model->Parameters(), 0, 1);
model->Gradient(model->Parameters(), 0, gradient, 1);
return error;
}
arma::mat& Parameters() { return model->Parameters(); }
FFN<NegativeLogLikelihood<>, RandomInitialization>* model;
arma::mat input, target;
} function;
BOOST_REQUIRE_LE(CheckGradient(function), 1e-4);
}
/**
* Jacobian MultiplyConstant module test.
*/
+1 -1
View File
@@ -157,7 +157,7 @@ BOOST_AUTO_TEST_CASE(MatRowColIteratorDecrementOperatorTest)
// Check that postfix-- does not decrement the position when position is
// pointing to the beginning.
(void) it2--;
auto junk = it2--; (void)(junk);
BOOST_REQUIRE_EQUAL(it1.row(), it2.row());
BOOST_REQUIRE_EQUAL(it1.col(), it2.col());
+2 -2
View File
@@ -16,7 +16,7 @@
#include <mlpack/methods/ann/layer/layer.hpp>
#include <mlpack/methods/reinforcement_learning/async_learning.hpp>
#include <mlpack/methods/reinforcement_learning/environment/cart_pole.hpp>
#include <mlpack/core/optimizers/adam/adam_update.hpp>
#include <mlpack/core/optimizers/sgd/update_policies/vanilla_update.hpp>
#include <mlpack/methods/reinforcement_learning/policy/greedy_policy.hpp>
#include <mlpack/methods/reinforcement_learning/policy/aggregated_policy.hpp>
#include <mlpack/methods/reinforcement_learning/training_config.hpp>
@@ -35,7 +35,7 @@ BOOST_AUTO_TEST_SUITE(AsyncLearningTest);
BOOST_AUTO_TEST_CASE(OneStepQLearningTest)
{
/**
* This is for the Travis CI server, in your own machine you shuold use more
* This is for the Travis CI server, in your own machine you should use more
* threads.
*/
#ifdef HAS_OPENMP
+51
View File
@@ -24,6 +24,8 @@
#include <mlpack/methods/ann/init_rules/const_init.hpp>
#include <mlpack/methods/ann/init_rules/gaussian_init.hpp>
#include <mlpack/methods/ann/init_rules/glorot_init.hpp>
#include <mlpack/methods/ann/init_rules/he_init.hpp>
#include <mlpack/methods/ann/init_rules/lecun_normal_init.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
@@ -328,5 +330,54 @@ BOOST_AUTO_TEST_CASE(GlorotInitNormalTest)
BOOST_REQUIRE_EQUAL(weights3d.n_slices, 2);
}
/**
* Simple test of the HeInitialization class.
*/
BOOST_AUTO_TEST_CASE(HeInitTest)
{
const size_t rows = 4;
const size_t cols = 4;
const size_t slices = 2;
arma::mat weights;
arma::cube weights3d;
HeInitialization initializer;
initializer.Initialize(weights, rows, cols);
initializer.Initialize(weights3d, rows, cols, slices);
BOOST_REQUIRE_EQUAL(weights.n_rows, rows);
BOOST_REQUIRE_EQUAL(weights.n_cols, cols);
BOOST_REQUIRE_EQUAL(weights3d.n_rows, rows);
BOOST_REQUIRE_EQUAL(weights3d.n_cols, cols);
BOOST_REQUIRE_EQUAL(weights3d.n_slices, slices);
}
/**
* Simple test of the LecunNormalInitialization class.
*/
BOOST_AUTO_TEST_CASE(LecunNormalInitTest)
{
const size_t rows = 4;
const size_t cols = 4;
const size_t slices = 2;
arma::mat weights;
arma::cube weights3d;
LecunNormalInitialization initializer;
initializer.Initialize(weights, rows, cols);
initializer.Initialize(weights3d, rows, cols, slices);
BOOST_REQUIRE_EQUAL(weights.n_rows, rows);
BOOST_REQUIRE_EQUAL(weights.n_cols, cols);
BOOST_REQUIRE_EQUAL(weights3d.n_rows, rows);
BOOST_REQUIRE_EQUAL(weights3d.n_cols, cols);
BOOST_REQUIRE_EQUAL(weights3d.n_slices, slices);
}
BOOST_AUTO_TEST_SUITE_END();
+70 -2
View File
@@ -1,6 +1,7 @@
/**
* @file q_learning_test.hpp
* @author Shangtong Zhang
* @author Rohan Raj
*
* Test for Q-Learning implementation
*
@@ -17,6 +18,7 @@
#include <mlpack/methods/ann/layer/layer.hpp>
#include <mlpack/methods/reinforcement_learning/q_learning.hpp>
#include <mlpack/methods/reinforcement_learning/environment/mountain_car.hpp>
#include <mlpack/methods/reinforcement_learning/environment/acrobat.hpp>
#include <mlpack/methods/reinforcement_learning/environment/cart_pole.hpp>
#include <mlpack/methods/reinforcement_learning/policy/greedy_policy.hpp>
#include <mlpack/core/optimizers/adam/adam_update.hpp>
@@ -60,7 +62,7 @@ BOOST_AUTO_TEST_CASE(CartPoleWithDQN)
// Set up DQN agent.
QLearning<CartPole, decltype(model), AdamUpdate, decltype(policy)>
agent(std::move(config), std::move(model), std::move(policy),
std::move(replayMethod));
std::move(replayMethod));
arma::running_stat<double> averageReturn;
size_t episodes = 0;
@@ -133,7 +135,7 @@ BOOST_AUTO_TEST_CASE(CartPoleWithDoubleDQN)
// Set up the DQN agent.
QLearning<CartPole, decltype(model), RMSPropUpdate, decltype(policy)>
agent(std::move(config), std::move(model), std::move(policy),
std::move(replayMethod));
std::move(replayMethod));
arma::running_stat<double> averageReturn;
@@ -170,4 +172,70 @@ BOOST_AUTO_TEST_CASE(CartPoleWithDoubleDQN)
BOOST_REQUIRE(converged);
}
//! Test DQN in Acrobat task.
BOOST_AUTO_TEST_CASE(AcrobatWithDQN)
{
// Set up the network.
FFN<MeanSquaredError<>, GaussianInitialization> model(MeanSquaredError<>(),
GaussianInitialization(0, 0.001));
model.Add<Linear<>>(4, 64);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(64, 32);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(32, 3);
// Set up the policy and replay method.
GreedyPolicy<Acrobat> policy(1.0, 1000, 0.1);
RandomReplay<Acrobat> replayMethod(20, 10000);
TrainingConfig config;
config.StepSize() = 0.01;
config.Discount() = 0.99;
config.TargetNetworkSyncInterval() = 100;
config.ExplorationSteps() = 100;
config.DoubleQLearning() = false;
config.StepLimit() = 400;
// Set up DQN agent.
QLearning<Acrobat, decltype(model), AdamUpdate, decltype(policy)>
agent(std::move(config), std::move(model), std::move(policy),
std::move(replayMethod));
arma::running_stat<double> averageReturn;
size_t episodes = 0;
bool converged = true;
while (true)
{
double episodeReturn = agent.Episode();
averageReturn(episodeReturn);
episodes += 1;
if (episodes > 1000)
{
Log::Debug << "Acrobat with DQN failed." << std::endl;
converged = false;
break;
}
/**
* I am using a thresold of -380 to check convegence.
*/
Log::Debug << "Average return: " << averageReturn.mean()
<< " Episode return: " << episodeReturn << std::endl;
if (averageReturn.mean() > -380.00)
{
agent.Deterministic() = true;
arma::running_stat<double> testReturn;
for (size_t i = 0; i < 20; ++i)
testReturn(agent.Episode());
Log::Debug << "Average return in deterministic test: "
<< testReturn.mean() << std::endl;
break;
}
}
BOOST_REQUIRE(converged);
}
BOOST_AUTO_TEST_SUITE_END();
+138
View File
@@ -12,9 +12,11 @@
#include <mlpack/core.hpp>
#include <mlpack/core/optimizers/sgd/sgd.hpp>
#include <mlpack/core/optimizers/rmsprop/rmsprop.hpp>
#include <mlpack/methods/ann/layer/layer.hpp>
#include <mlpack/methods/ann/rnn.hpp>
#include <mlpack/core/data/binarize.hpp>
#include <mlpack/core/math/random.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
@@ -24,6 +26,7 @@
using namespace mlpack;
using namespace mlpack::ann;
using namespace mlpack::optimization;
using namespace mlpack::math;
BOOST_AUTO_TEST_SUITE(RecurrentNetworkTest);
@@ -1085,4 +1088,139 @@ BOOST_AUTO_TEST_CASE(CustomRecursiveReberGrammarTest)
ReberGrammarTestCustomNetwork(16, true);
}
/**
* @brief Generates noisy sine wave and outputs the data and the labels that
* can be used directly for training and testing with RNN.
*
* @param data The data points as output
* @param labels The expected values as output
* @param rho The size of the sequence of each data point
* @param outputSteps How many output steps to consider for every rho inputs
* @param dataPoints The number of generated data points. The actual generated
* data points may be more than this to adjust to the outputSteps. But at
* the minimum these many data points will be generated.
* @param gain The gain on the amplitude
* @param freq The frquency of the sine wave
* @param phase The phase shift if any
* @param noisePercent The percent noise to induce
* @param numCycles How many full size wave cycles required. All the data
* points will be fit into these cycles.
* @param normalize Whether to normalise the data. This may be required for some
* layers like LSTM. Default is true.
*/
void GenerateNoisySinRNN(arma::cube& data,
arma::cube& labels,
size_t rho,
size_t outputSteps = 1,
const int dataPoints = 100,
const double gain = 1.0,
const int freq = 10,
const double phase = 0,
const int noisePercent = 20,
const double numCycles = 6.0,
const bool normalize = true)
{
int points = dataPoints;
int r = dataPoints % rho;
if (r == 0)
{
points += outputSteps;
}
else
{
points += rho - r + outputSteps;
}
arma::colvec x(points);
int i = 0;
double interval = numCycles / freq / points;
x.for_each([&i, gain, freq, phase, noisePercent, interval]
(arma::colvec::elem_type& val) {
double t = interval * (i++);
val = gain * ::sin(2 * M_PI * freq * t + phase) +
(noisePercent * gain / 100 * Random(0.0, 0.1));
});
arma::colvec y = x;
if (normalize)
y = arma::normalise(x);
// Now break this into columns of rho size slices.
size_t numColumns = y.n_elem / rho;
data = arma::cube(1, numColumns, rho);
labels = arma::cube(outputSteps, numColumns, 1);
for (size_t i = 0; i < numColumns; ++i)
{
data.tube(0, i) = y.rows(i * rho, i * rho + rho - 1);
labels.subcube(0, i, 0, outputSteps - 1, i, 0) =
y.rows(i * rho + rho, i * rho + rho + outputSteps - 1);
}
}
/**
* @brief RNNSineTest Test a simple RNN using noisy sine. Use single output
* for multiple inputs.
* @param hiddenUnits No of units in the hiddenlayer.
* @param rho The input sequence length.
* @param numEpochs The number of epochs to run.
* @return The mean squared error of the prediction.
*/
double RNNSineTest(size_t hiddenUnits, size_t rho, size_t numEpochs = 100)
{
RNN<MeanSquaredError<> > net(rho, true);
net.Add<LinearNoBias<> >(1, hiddenUnits);
net.Add<LSTM<> >(hiddenUnits, hiddenUnits);
net.Add<LinearNoBias<> >(hiddenUnits, 1);
RMSProp opt(0.005, 100, 0.9, 1e-08, 50000, 1e-5);
// Generate data
arma::cube data;
arma::cube labels;
GenerateNoisySinRNN(data, labels, rho, 1, 2000, 20.0, 200, 0.0, 45, 20);
// Break into training and test sets. Simply split along columns.
size_t trainCols = data.n_cols * 0.8; // Take 20% out for testing.
size_t testCols = data.n_cols - trainCols;
arma::cube testData = data.subcube(0, data.n_cols - testCols, 0,
data.n_rows - 1, data.n_cols - 1, data.n_slices - 1);
arma::cube testLabels = labels.subcube(0, labels.n_cols - testCols, 0,
labels.n_rows - 1, labels.n_cols - 1, labels.n_slices - 1);
for (size_t i = 0; i < numEpochs; ++i)
{
net.Train(data.subcube(0, 0, 0, data.n_rows - 1, trainCols - 1,
data.n_slices - 1), labels.subcube(0, 0, 0, labels.n_rows - 1,
trainCols - 1, labels.n_slices - 1), opt);
}
// Well now it should be trained. Do the test here.
arma::cube prediction;
net.Predict(testData, prediction);
// The prediction must really follow the test data. So convert both the test
// data and the pediction to vectors and compare the two.
arma::colvec testVector = arma::vectorise(testData);
arma::colvec predVector = arma::vectorise(prediction);
// Adjust the vectors for comparison, as the prediction is one step ahead.
testVector = testVector.rows(1, testVector.n_rows - 1);
predVector = predVector.rows(0, predVector.n_rows - 2);
double error = std::sqrt(arma::sum(arma::square(testVector - predVector))) /
testVector.n_rows;
return error;
}
/**
* Test RNN using multiple timestep input and single output.
*/
BOOST_AUTO_TEST_CASE(MultiTimestepTest)
{
double err = RNNSineTest(4, 10, 20);
BOOST_REQUIRE_LE(err, 1e-02);
}
BOOST_AUTO_TEST_SUITE_END();
+18
View File
@@ -14,6 +14,7 @@
#include <mlpack/methods/reinforcement_learning/environment/mountain_car.hpp>
#include <mlpack/methods/reinforcement_learning/environment/cart_pole.hpp>
#include <mlpack/methods/reinforcement_learning/environment/acrobat.hpp>
#include <mlpack/methods/reinforcement_learning/replay/random_replay.hpp>
#include <mlpack/methods/reinforcement_learning/policy/greedy_policy.hpp>
@@ -25,6 +26,23 @@ using namespace mlpack::rl;
BOOST_AUTO_TEST_SUITE(RLComponentsTest)
/**
* Constructs a Acrobat instance and check if the main rountine works as
* it should be.
*/
BOOST_AUTO_TEST_CASE(SimpleAcrobatTest)
{
const Acrobat task = Acrobat();
Acrobat::State state = task.InitialSample();
Acrobat::Action action = Acrobat::Action::negativeTorque;
double reward = task.Sample(state, action);
BOOST_REQUIRE_EQUAL(reward, -1.0);
BOOST_REQUIRE(!task.IsTerminal(state));
BOOST_REQUIRE_EQUAL(3, Acrobat::Action::size);
}
/**
* Constructs a MountainCar instance and check if the main rountine works as
* it should be.