Merge branch 'master' into master2

This commit is contained in:
Manish Kumar
2017-12-30 13:22:00 +05:30
committed by GitHub
80 changed files with 995 additions and 241 deletions
+3 -3
View File
@@ -9,10 +9,10 @@ env:
before_install:
- sudo systemctl stop apt-daily.service apt-daily.timer
- sudo systemctl disable apt-daily.service apt-daily.timer
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get update -qq
- sudo rm -f /var/lib/dpkg/lock && sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo rm -f /var/lib/dpkg/lock && sudo apt-get update -qq
- printenv
- sudo apt-get install -qq libopenblas-dev liblapack-dev g++ libboost-all-dev
- sudo rm -f /var/lib/dpkg/lock && sudo apt-get install -qq libopenblas-dev liblapack-dev g++ libboost-all-dev
- sudo wget https://launchpadlibrarian.net/260609315/fix-std-vector-load.diff -O /usr/include/fix-std-vector-load.diff
- cd /usr/include && sudo patch -p1 < fix-std-vector-load.diff && sudo rm fix-std-vector-load.diff && cd -
- sudo pip install cython setuptools numpy pandas
+4 -3
View File
@@ -126,7 +126,7 @@ if(BUILD_WITH_COVERAGE)
endif()
# For clock_gettime().
if (UNIX AND NOT APPLE)
if (UNIX AND NOT APPLE AND NOT HAIKU)
set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} "rt")
endif ()
@@ -528,11 +528,12 @@ if (PKG_CONFIG_FOUND)
# So, we have to parse our list of library directories, libraries, and include
# directories in order to get the correct line to give to pkg-config.
# Next, adapt the list of include directories.
list(REMOVE_DUPLICATES MLPACK_INCLUDE_DIRS)
foreach (incldir ${MLPACK_INCLUDE_DIRS})
# Filter out some obviously unnecessary directories.
if (NOT "${incldir}" STREQUAL "/usr/include")
set(MLPACK_INCLUDE_DIRS_STRING "${MLPACK_INCLUDE_DIRS_STRING}
-I${incldir}")
set(MLPACK_INCLUDE_DIRS_STRING
"${MLPACK_INCLUDE_DIRS_STRING} -I${incldir}")
endif ()
endforeach ()
# Add the install directory too.
+3 -1
View File
@@ -60,6 +60,7 @@ class CLIOption
* @param input Whether or not the option is an input option.
* @param noTranspose If the parameter is a matrix and this is true, then the
* matrix will not be transposed on loading.
* @param testName Is not used and added for compatibility reasons.
*/
CLIOption(const N defaultValue,
const std::string& identifier,
@@ -68,7 +69,8 @@ class CLIOption
const std::string& cppName,
const bool required = false,
const bool input = true,
const bool noTranspose = false)
const bool noTranspose = false,
const std::string& /*testName*/ = "")
{
// Create the ParamData object to give to CLI.
util::ParamData data;
+4 -2
View File
@@ -33,7 +33,8 @@ class PyOption
public:
/**
* Construct a PyOption object. When constructed, it will register itself
* with CLI.
* with CLI. The testName parameter is not used and added for compatibility
* reasons.
*/
PyOption(const T defaultValue,
const std::string& identifier,
@@ -42,7 +43,8 @@ class PyOption
const std::string& cppName,
const bool required = false,
const bool input = true,
const bool noTranspose = false)
const bool noTranspose = false,
const std::string& /*testName*/ = "")
{
// Create the ParamData object to give to CLI.
util::ParamData data;
@@ -52,7 +52,7 @@ PARAM_MODEL_OUT(GaussianKernel, "model_out", "Output model, with twice the "
"bandwidth.", "");
PARAM_DOUBLE_OUT("model_bw_out", "The bandwidth of the model.");
void mlpackMain()
static void mlpackMain()
{
const string s = CLI::GetParam<string>("string_in");
const int i = CLI::GetParam<int>("int_in");
+6 -3
View File
@@ -53,6 +53,8 @@ class TestOption
* @param input Whether or not the option is an input option.
* @param noTranspose If the parameter is a matrix and this is true, then the
* matrix will not be transposed on loading.
* @param testName Name of the test (used for identifiying which binding test
* this option belongs to)
*/
TestOption(const N defaultValue,
const std::string& identifier,
@@ -61,7 +63,8 @@ class TestOption
const std::string& cppName,
const bool required = false,
const bool input = true,
const bool noTranspose = false)
const bool noTranspose = false,
const std::string& testName = "")
{
// Create the ParamData object to give to CLI.
util::ParamData data;
@@ -81,7 +84,7 @@ class TestOption
const std::string tname = data.tname;
CLI::RestoreSettings(programName, false);
CLI::RestoreSettings(testName, false);
// Set some function pointers that we need.
CLI::GetSingleton().functionMap[tname]["GetPrintableParam"] =
@@ -94,7 +97,7 @@ class TestOption
if (!input)
CLI::SetPassed(identifier);
CLI::StoreSettings(programName);
CLI::StoreSettings(testName);
CLI::ClearSettings();
}
};
@@ -3,6 +3,8 @@ set(SOURCES
adam_impl.hpp
adam_update.hpp
adamax_update.hpp
amsgrad_update.hpp
nadam_update.hpp
)
set(DIR_SRCS)
+22 -8
View File
@@ -4,11 +4,13 @@
* @author Vasanth Kalingeri
* @author Marcus Edel
* @author Vivek Pal
* @author Sourabh Varshney
*
* Adam and AdaMax optimizer. Adam is an an algorithm for first-order gradient-
* -based optimization of stochastic objective functions, based on adaptive
* estimates of lower-order moments. AdaMax is simply a variant of Adam based
* on the infinity norm.
* Adam, AdaMax, AMSGrad and Nadam optimizers. Adam is an an algorithm for
* first-order gradient-based optimization of stochastic objective functions,
* based on adaptive estimates of lower-order moments. AdaMax is simply a
* variant of Adam based on the infinity norm. AMSGrad is another variant of
* Adam with guaranteed convergence.
*
* 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
@@ -23,6 +25,8 @@
#include <mlpack/core/optimizers/sgd/sgd.hpp>
#include "adam_update.hpp"
#include "adamax_update.hpp"
#include "amsgrad_update.hpp"
#include "nadam_update.hpp"
namespace mlpack {
namespace optimization {
@@ -31,7 +35,8 @@ namespace optimization {
* Adam is an optimizer that computes individual adaptive learning rates for
* different parameters from estimates of first and second moments of the
* gradients. AdaMax is a variant of Adam based on the infinity norm as given
* in the section 7 of the following paper.
* in the section 7 of the following paper. Nadam is an optimizer that
* combines the Adam and NAG.
*
* For more information, see the following.
*
@@ -43,11 +48,16 @@ namespace optimization {
* year = {2014},
* url = {http://arxiv.org/abs/1412.6980}
* }
* @article{
* title = {On the convergence of Adam and beyond},
* url = {https://openreview.net/pdf?id=ryQu7f-RZ}
* year = {2018}
* }
* @endcode
*
*
* For Adam and AdaMax to work, a DecomposableFunctionType template parameter
* is required. This class must implement the following function:
* For Adam, AdaMax, AMSGrad and Nadam to work, a DecomposableFunctionType
* template parameter is required. This class must implement the following
* function:
*
* size_t NumFunctions();
* double Evaluate(const arma::mat& coordinates,
@@ -166,6 +176,10 @@ using Adam = AdamType<AdamUpdate>;
using AdaMax = AdamType<AdaMaxUpdate>;
using AMSGrad = AdamType<AMSGradUpdate>;
using Nadam = AdamType<NadamUpdate>;
} // namespace optimization
} // namespace mlpack
@@ -5,7 +5,7 @@
* @author Marcus Edel
* @author Vivek Pal
*
* Implementation of the Adam and AdaMax optimizer.
* Implementation of the Adam, AdaMax, AMSGrad and Nadam 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
@@ -0,0 +1,145 @@
/**
* @file amsgrad_update.hpp
* @author Haritha Nair
*
* Implementation of AMSGrad optimizer. AMSGrad is an exponential moving average
* optimizer that dynamically adapts over time with guaranteed convergence.
*
* 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_AMS_GRAD_AMS_GRAD_UPDATE_HPP
#define MLPACK_CORE_OPTIMIZERS_AMS_GRAD_AMS_GRAD_UPDATE_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace optimization {
/**
* AMSGrad is an exponential moving average variant which along with having
* benefits of optimizers like Adam and RMSProp, also guarantees convergence.
* Unlike Adam, it uses maximum of past squared gradients rather than their
* exponential average for updation.
*
* For more information, see the following.
*
* @code
* @article{
* title = {On the convergence of Adam and beyond},
* url = {https://openreview.net/pdf?id=ryQu7f-RZ}
* year = {2018}
* }
* @endcode
*/
class AMSGradUpdate
{
public:
/**
* Construct the AMSGrad update policy with the given parameters.
*
* @param epsilon The epsilon value used to initialise the squared gradient
* parameter.
* @param beta1 The smoothing parameter.
* @param beta2 The second moment coefficient.
*/
AMSGradUpdate(const double epsilon = 1e-8,
const double beta1 = 0.9,
const double beta2 = 0.999) :
epsilon(epsilon),
beta1(beta1),
beta2(beta2),
iteration(0)
{
// Nothing to do.
}
/**
* The Initialize method is called by SGD Optimizer method before the start of
* the iteration update process.
*
* @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)
{
m = arma::zeros<arma::mat>(rows, cols);
v = arma::zeros<arma::mat>(rows, cols);
vImproved = arma::zeros<arma::mat>(rows, cols);
}
/**
* Update step for AMSGrad.
*
* @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)
{
// Increment the iteration counter variable.
++iteration;
// And update the iterate.
m *= beta1;
m += (1 - beta1) * gradient;
v *= beta2;
v += (1 - beta2) * (gradient % gradient);
const double biasCorrection1 = 1.0 - std::pow(beta1, iteration);
const double biasCorrection2 = 1.0 - std::pow(beta2, iteration);
// Element wise maximum of past and present squared gradients.
vImproved = arma::max(vImproved, v);
iterate -= (stepSize * std::sqrt(biasCorrection2) / biasCorrection1) *
m / (arma::sqrt(vImproved) + epsilon);
}
//! Get the value used to initialise the squared gradient parameter.
double Epsilon() const { return epsilon; }
//! Modify the value used to initialise the squared gradient parameter.
double& Epsilon() { return epsilon; }
//! Get the smoothing parameter.
double Beta1() const { return beta1; }
//! Modify the smoothing parameter.
double& Beta1() { return beta1; }
//! Get the second moment coefficient.
double Beta2() const { return beta2; }
//! Modify the second moment coefficient.
double& Beta2() { return beta2; }
private:
// The epsilon value used to initialise the squared gradient parameter.
double epsilon;
// The smoothing parameter.
double beta1;
// The second moment coefficient.
double beta2;
// The exponential moving average of gradient values.
arma::mat m;
// The exponential moving average of squared gradient values.
arma::mat v;
// The optimal sqaured gradient value.
arma::mat vImproved;
// The number of iterations.
double iteration;
};
} // namespace optimization
} // namespace mlpack
#endif
@@ -0,0 +1,173 @@
/**
* @file nadam_update.hpp
* @author Sourabh Varshney
*
* Nadam update rule. Nadam is an optimizer that combines the effect of Adam
* and NAG to the gradient descent to improve its Performance.
*
* 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_ADAM_NADAM_UPDATE_HPP
#define MLPACK_CORE_OPTIMIZERS_ADAM_NADAM_UPDATE_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace optimization {
/**
* Nadam is an optimizer that combines the Adam and NAG.
*
* For more information, see the following.
*
* @code
* @techreport{Dozat2015,
* title = {Incorporating Nesterov momentum into Adam},
* author = {Timothy Dozat},
* institution = {Stanford University},
* address = {Stanford},
* year = {2015},
* url = {https://openreview.net/pdf?id=OM0jvwB8jIp57ZJjtNEZ}
* }
* @endcode
*/
class NadamUpdate
{
public:
/**
* Construct the Nadam update policy with the given parameters.
*
* @param epsilon The epsilon value used to initialise the squared gradient
* parameter.
* @param beta1 The smoothing parameter.
* @param beta2 The second moment coefficient
* @param scheduleDecay The decay parameter for decay coefficients
*/
NadamUpdate(const double epsilon = 1e-8,
const double beta1 = 0.9,
const double beta2 = 0.99,
const double scheduleDecay = 4e-3)
:epsilon(epsilon),
beta1(beta1),
beta2(beta2),
scheduleDecay(scheduleDecay),
iteration(0),
cumBeta1(1)
{
// Nothing to do.
}
/**
* The Initialize method is called by SGD Optimizer method before the start
* of the iteration update process.
*
* @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)
{
m = arma::zeros<arma::mat>(rows, cols);
v = arma::zeros<arma::mat>(rows, cols);
}
/**
* Update step for Nadam.
*
* @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)
{
// Increment the iteration counter variable.
++iteration;
// And update the iterate.
m *= beta1;
m += (1 - beta1) * gradient;
v *= beta2;
v += (1 - beta2) * gradient % gradient;
double beta1T = beta1 * (1 - (0.5 *
std::pow(0.96, iteration * scheduleDecay)));
double beta1T1 = beta1 * (1 - (0.5 *
std::pow(0.96, (iteration + 1) * scheduleDecay)));
cumBeta1 *= beta1T;
const double biasCorrection1 = 1.0 - cumBeta1;
const double biasCorrection2 = 1.0 - std::pow(beta2, iteration);
const double biasCorrection3 = 1.0 - (cumBeta1 * beta1T1);
/* Note :- arma::sqrt(v) + epsilon * sqrt(biasCorrection2) is approximated
* as arma::sqrt(v) + epsilon
*/
iterate -= (stepSize * (((1 - beta1T) / biasCorrection1) * gradient
+ (beta1T1 / biasCorrection3) * m) * sqrt(biasCorrection2))
/ (arma::sqrt(v) + epsilon);
}
//! Get the value used to initialise the squared gradient parameter.
double Epsilon() const { return epsilon; }
//! Modify the value used to initialise the squared gradient parameter.
double& Epsilon() { return epsilon; }
//! Get the value of the cumulative product of decay coefficients
double CumBeta1() const { return cumBeta1; }
//! Modify the value of the cumulative product of decay coefficients
double& CumBeta1() { return cumBeta1; }
//! Get the smoothing parameter.
double Beta1() const { return beta1; }
//! Modify the smoothing parameter.
double& Beta1() { return beta1; }
//! Get the second moment coefficient.
double Beta2() const { return beta2; }
//! Modify the second moment coefficient.
double& Beta2() { return beta2; }
//! Get the decay parameter for decay coefficients
double ScheduleDecay() const { return scheduleDecay; }
//! Modify the decay parameter for decay coefficients
double& ScheduleDecay() { return scheduleDecay; }
private:
// The epsilon value used to initialise the squared gradient parameter.
double epsilon;
// The smoothing parameter.
double beta1;
// The second moment coefficient.
double beta2;
// The exponential moving average of gradient values.
arma::mat m;
// The exponential moving average of squared gradient values.
arma::mat v;
// The cumulative product of decay coefficients
double cumBeta1;
// The decay parameter for decay coefficients
double scheduleDecay;
// The number of iterations.
double iteration;
};
} // namespace optimization
} // namespace mlpack
#endif
@@ -32,7 +32,7 @@ class FullSelection
* @param iterate starting point.
*/
template<typename DecomposableFunctionType>
const double Select(DecomposableFunctionType& function,
double Select(DecomposableFunctionType& function,
const size_t batchSize,
const arma::mat& iterate)
{
@@ -47,7 +47,7 @@ class RandomSelection
* @param iterate starting point.
*/
template<typename DecomposableFunctionType>
const double Select(DecomposableFunctionType& function,
double Select(DecomposableFunctionType& function,
const size_t batchSize,
const arma::mat& iterate)
{
+8 -2
View File
@@ -102,8 +102,14 @@ double SGD<UpdatePolicyType, DecayPolicyType>::Optimize(
function.Shuffle();
}
// Find the effective batch size (the last batch may be smaller).
const size_t effectiveBatchSize = std::min(batchSize,
// Find the effective batch size; we have to take the minimum of three
// things:
// - the batch size can't be larger than the user-specified batch size;
// - the batch size can't be larger than the number of iterations left
// before actualMaxIterations is hit;
// - the batch size can't be larger than the number of functions left.
const size_t effectiveBatchSize = std::min(
std::min(batchSize, actualMaxIterations - i),
numFunctions - currentFunction);
function.Gradient(iterate, currentFunction, gradient, effectiveBatchSize);
@@ -108,8 +108,14 @@ double SPALeRASGD<DecayPolicyType>::Optimize(DecomposableFunctionType& function,
function.Shuffle();
}
// Find the effective batch size (the last batch may be smaller).
const size_t effectiveBatchSize = std::min(batchSize,
// Find the effective batch size; we have to take the minimum of three
// things:
// - the batch size can't be larger than the user-specified batch size;
// - the batch size can't be larger than the number of iterations left
// before actualMaxIterations is hit;
// - the batch size can't be larger than the number of functions left.
const size_t effectiveBatchSize = std::min(
std::min(batchSize, actualMaxIterations - i),
numFunctions - currentFunction);
function.Gradient(iterate, currentFunction, gradient, effectiveBatchSize);
@@ -94,7 +94,7 @@ CosineTree::CosineTree(const arma::mat& dataset,
// Initialize Monte Carlo error estimate for comparison.
double monteCarloError = root.FrobNormSquared();
while (treeQueue.top() &&
while (treeQueue.size() > 0 &&
(monteCarloError > epsilon * root.FrobNormSquared()))
{
// Pop node from queue with highest projection error.
+5 -9
View File
@@ -46,11 +46,12 @@ using Option = mlpack::bindings::cli::CLIOption<T>;
}
}
static const std::string testName = "";
#include <mlpack/core/util/param.hpp>
#include <mlpack/bindings/cli/parse_command_line.hpp>
#include <mlpack/bindings/cli/end_program.hpp>
void mlpackMain(); // This is typically defined after this include.
static void mlpackMain(); // This is typically defined after this include.
int main(int argc, char** argv)
{
@@ -91,19 +92,13 @@ using Option = mlpack::bindings::tests::TestOption<T>;
}
}
// testName symbol should be defined in each binding test file
#include <mlpack/core/util/param.hpp>
#undef PROGRAM_INFO
#define PROGRAM_INFO(NAME, DESC) static mlpack::util::ProgramDoc \
cli_programdoc_dummy_object = mlpack::util::ProgramDoc(NAME, \
[]() { return DESC; }); \
namespace mlpack { \
namespace bindings { \
namespace tests { \
std::string programName = NAME; \
} \
} \
}
[]() { return DESC; });
#elif(BINDING_TYPE == BINDING_TYPE_PYX) // This is a Python binding.
@@ -126,6 +121,7 @@ using Option = mlpack::bindings::python::PyOption<T>;
}
}
static const std::string testName = "";
#include <mlpack/core/util/param.hpp>
#undef PROGRAM_INFO
+28 -22
View File
@@ -1012,53 +1012,55 @@ using DatasetInfo = DatasetMapper<IncrementPolicy, std::string>;
#define PARAM_IN(T, ID, DESC, ALIAS, DEF, REQ) \
static mlpack::util::Option<T> \
JOIN(cli_option_dummy_object_in_, __COUNTER__) \
(DEF, ID, DESC, ALIAS, #T, REQ, true, false);
(DEF, ID, DESC, ALIAS, #T, REQ, true, false, testName);
#define PARAM_OUT(T, ID, DESC, ALIAS, DEF, REQ) \
static mlpack::util::Option<T> \
JOIN(cli_option_dummy_object_out_, __COUNTER__) \
(DEF, ID, DESC, ALIAS, #T, REQ, false, false);
(DEF, ID, DESC, ALIAS, #T, REQ, false, false, testName);
#define PARAM_MATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::mat> \
JOIN(cli_option_dummy_matrix_, __COUNTER__) \
(arma::mat(), ID, DESC, ALIAS, "arma::mat", REQ, IN, !TRANS);
(arma::mat(), ID, DESC, ALIAS, "arma::mat", \
REQ, IN, !TRANS, testName);
#define PARAM_UMATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::Mat<size_t>> \
JOIN(cli_option_dummy_umatrix_, __COUNTER__) \
(arma::Mat<size_t>(), ID, DESC, ALIAS, "arma::Mat<size_t>", REQ, IN, \
!TRANS);
(arma::Mat<size_t>(), ID, DESC, ALIAS, "arma::Mat<size_t>", \
REQ, IN, !TRANS, testName);
#define PARAM_COL(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::vec> \
JOIN(cli_option_dummy_col_, __COUNTER__) \
(arma::vec(), ID, DESC, ALIAS, "arma::vec", REQ, IN, !TRANS);
(arma::vec(), ID, DESC, ALIAS, "arma::vec", \
REQ, IN, !TRANS, testName);
#define PARAM_UCOL(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::Col<size_t>> \
JOIN(cli_option_dummy_ucol_, __COUNTER__) \
(arma::Col<size_t>(), ID, DESC, ALIAS, "arma::Col<size_t>", REQ, IN, \
!TRANS);
(arma::Col<size_t>(), ID, DESC, ALIAS, "arma::Col<size_t>", \
REQ, IN, !TRANS, testName);
#define PARAM_ROW(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::rowvec> \
JOIN(cli_option_dummy_row_, __COUNTER__) \
(arma::rowvec(), ID, DESC, ALIAS, "arma::rowvec", REQ, IN, !TRANS);
(arma::rowvec(), ID, DESC, ALIAS, "arma::rowvec", \
REQ, IN, !TRANS, testName);
#define PARAM_UROW(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::Row<size_t>> \
JOIN(cli_option_dummy_urow_, __COUNTER__) \
(arma::Row<size_t>(), ID, DESC, ALIAS, "arma::Row<size_t>", REQ, IN, \
!TRANS);
(arma::Row<size_t>(), ID, DESC, ALIAS, "arma::Row<size_t>", \
REQ, IN, !TRANS, testName);
// There are no uses of required models, so that is not an option to this
// macro (it would be easy to add).
#define PARAM_MODEL(TYPE, ID, DESC, ALIAS, REQ, IN) \
static mlpack::util::Option<TYPE> \
JOIN(cli_option_dummy_model_, __COUNTER__) \
(TYPE(), ID, DESC, ALIAS, #TYPE, REQ, IN);
(TYPE(), ID, DESC, ALIAS, #TYPE, REQ, IN, false, testName);
#else
// We have to do some really bizarre stuff since __COUNTER__ isn't defined. I
// don't think we can absolutely guarantee success, but it should be "good
@@ -1067,50 +1069,54 @@ using DatasetInfo = DatasetMapper<IncrementPolicy, std::string>;
#define PARAM_IN(T, ID, DESC, ALIAS, DEF, REQ) \
static mlpack::util::Option<T> \
JOIN(JOIN(cli_option_dummy_object_in_, __LINE__), opt) \
(DEF, ID, DESC, ALIAS, #T, REQ, true, false);
(DEF, ID, DESC, ALIAS, #T, REQ, true, false, testName);
#define PARAM_OUT(T, ID, DESC, ALIAS, DEF, REQ) \
static mlpack::util::Option<T> \
JOIN(JOIN(cli_option_dummy_object_out_, __LINE__), opt) \
(DEF, ID, DESC, ALIAS, #T, REQ, false, false);
(DEF, ID, DESC, ALIAS, #T, REQ, false, false, testName);
#define PARAM_MATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::mat> \
JOIN(JOIN(cli_option_dummy_object_matrix_, __LINE__), opt) \
(arma::mat(), ID, DESC, ALIAS, "arma::mat", REQ, IN, !TRANS);
(arma::mat(), ID, DESC, ALIAS, "arma::mat", REQ, IN, !TRANS, \
testName);
#define PARAM_UMATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::Mat<size_t>> \
JOIN(JOIN(cli_option_dummy_object_umatrix_, __LINE__), opt) \
(arma::Mat<size_t>(), ID, DESC, ALIAS, "arma::Mat<size_t>", REQ, IN, \
!TRANS);
!TRANS, testName);
#define PARAM_COL(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::vec> \
JOIN(cli_option_dummy_object_col_, __LINE__) \
(arma::vec(), ID, DESC, ALIAS, "arma::vec", REQ, IN, !TRANS);
(arma::vec(), ID, DESC, ALIAS, "arma::vec", REQ, IN, !TRANS, \
testName);
#define PARAM_UCOL(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::Col<size_t>> \
JOIN(cli_option_dummy_object_ucol_, __LINE__) \
(arma::Col<size_t>(), ID, DESC, ALIAS, "arma::Col<size_t>", REQ, IN, \
!TRANS);
!TRANS, testName);
#define PARAM_ROW(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::rowvec> \
JOIN(cli_option_dummy_object_row_, __LINE__) \
(arma::rowvec(), ID, DESC, ALIAS, "arma::rowvec", REQ, IN, !TRANS);
(arma::rowvec(), ID, DESC, ALIAS, "arma::rowvec", REQ, IN, !TRANS, \
testName);
#define PARAM_UROW(ID, DESC, ALIAS, REQ, TRANS, IN) \
static mlpack::util::Option<arma::Row<size_t>> \
JOIN(cli_option_dummy_object_urow_, __LINE__) \
(arma::Row<size_t>(), ID, DESC, ALIAS, "arma::Row<size_t>", REQ, IN, \
!TRANS);
!TRANS, testName);
#define PARAM_MODEL(TYPE, ID, DESC, ALIAS, REQ, IN) \
static mlpack::util::Option<TYPE> \
JOIN(JOIN(cli_option_dummy_object_model_, __LINE__), opt) \
(TYPE(), ID, DESC, ALIAS, #TYPE, REQ, IN);
(TYPE(), ID, DESC, ALIAS, #TYPE, REQ, IN, false, \
testName);
#endif
#endif
@@ -111,7 +111,7 @@ PARAM_MODEL_IN(AdaBoostModel, "input_model", "Input AdaBoost model.", "m");
PARAM_MODEL_OUT(AdaBoostModel, "output_model", "Output trained AdaBoost model.",
"M");
void mlpackMain()
static void mlpackMain()
{
// Check input parameters and issue warnings/errors as necessary.
@@ -80,7 +80,7 @@ void FastLSTM<InputDataType, OutputDataType>::ResetCell(const size_t size)
gradientStep = batchSize * size - 1;
const size_t rhoBatchSize = size * batchSize;
if (gate.is_empty() || gate.n_cols < rhoBatchSize)
if (gate.is_empty() || gate.n_cols != rhoBatchSize)
{
gate.set_size(4 * outSize, rhoBatchSize);
gateActivation.set_size(outSize * 3, rhoBatchSize);
@@ -197,7 +197,7 @@ void FastLSTM<InputDataType, OutputDataType>::Backward(
backwardStep - batchStep, 3 * outSize - 1, backwardStep) %
cellActivationError;
if (backwardStep != 0)
if (backwardStep > batchStep)
{
prevError.submat(2 * outSize, 0, 3 * outSize - 1, batchStep) =
cell.cols((backwardStep - batchSize) - batchStep,
@@ -258,13 +258,13 @@ void FastLSTM<InputDataType, OutputDataType>::Gradient(
gradient.n_elem - 1, 0) = arma::vectorise(prevError *
outParameter.cols(gradientStep - batchStep, gradientStep).t());
if (gradientStep == 0)
if (gradientStep > batchStep)
{
gradientStep = batchSize * bpttSteps - 1;
gradientStep -= batchSize;
}
else
{
gradientStep -= batchSize;
gradientStep = batchSize * bpttSteps - 1;
}
}
+49 -4
View File
@@ -69,7 +69,7 @@ GRU<InputDataType, OutputDataType>::GRU(
allZeros = arma::zeros<arma::mat>(outSize, batchSize);
outParameter.push_back(std::move(arma::mat(allZeros.memptr(),
allZeros.n_rows, allZeros.n_cols, false, true)));
allZeros.n_rows, allZeros.n_cols, false, true)));
prevOutput = outParameter.begin();
backIterator = outParameter.end();
@@ -96,6 +96,21 @@ void GRU<InputDataType, OutputDataType>::Forward(
{
batchSize = input.n_cols;
prevError.resize(3 * outSize, batchSize);
allZeros.zeros(outSize, batchSize);
// Batch size better not change during an iteration...
if (outParameter.size() > 1)
{
Log::Fatal << "GRU<>::Forward(): batch size cannot change during a "
<< "forward pass!" << std::endl;
}
outParameter.clear();
outParameter.push_back(std::move(arma::mat(allZeros.memptr(),
allZeros.n_rows, allZeros.n_cols, false, true)));
prevOutput = outParameter.begin();
backIterator = outParameter.end();
gradIterator = outParameter.end();
}
// Process the input linearly(zt, rt, ot).
@@ -157,13 +172,13 @@ void GRU<InputDataType, OutputDataType>::Forward(
if (!deterministic)
{
outParameter.push_back(std::move(arma::mat(allZeros.memptr(),
allZeros.n_rows, allZeros.n_cols, false, true)));
allZeros.n_rows, allZeros.n_cols, false, true)));
prevOutput = --outParameter.end();
}
else
{
*prevOutput = std::move(arma::mat(allZeros.memptr(),
allZeros.n_rows, allZeros.n_cols, false, true));
allZeros.n_rows, allZeros.n_cols, false, true));
}
}
else if (!deterministic)
@@ -196,6 +211,21 @@ void GRU<InputDataType, OutputDataType>::Backward(
{
batchSize = input.n_cols;
prevError.resize(3 * outSize, batchSize);
allZeros.zeros(outSize, batchSize);
// Batch size better not change during an iteration...
if (outParameter.size() > 1)
{
Log::Fatal << "GRU<>::Forward(): batch size cannot change during a "
<< "forward pass!" << std::endl;
}
outParameter.clear();
outParameter.push_back(std::move(arma::mat(allZeros.memptr(),
allZeros.n_rows, allZeros.n_cols, false, true)));
prevOutput = outParameter.begin();
backIterator = outParameter.end();
gradIterator = outParameter.end();
}
if ((outParameter.size() - backwardStep - 1) % rho != 0 && backwardStep != 0)
@@ -214,7 +244,7 @@ void GRU<InputDataType, OutputDataType>::Backward(
hiddenStateModule));
// Delta ot.
arma::mat dOt = gy % (arma::ones<arma::vec>(outSize) -
arma::mat dOt = gy % (arma::ones<arma::mat>(outSize, batchSize) -
boost::apply_visitor(outputParameterVisitor, inputGateModule));
// Delta of input gate.
@@ -297,6 +327,21 @@ void GRU<InputDataType, OutputDataType>::Gradient(
{
batchSize = input.n_cols;
prevError.resize(3 * outSize, batchSize);
allZeros.zeros(outSize, batchSize);
// Batch size better not change during an iteration...
if (outParameter.size() > 1)
{
Log::Fatal << "GRU<>::Forward(): batch size cannot change during a "
<< "forward pass!" << std::endl;
}
outParameter.clear();
outParameter.push_back(std::move(arma::mat(allZeros.memptr(),
allZeros.n_rows, allZeros.n_cols, false, true)));
prevOutput = outParameter.begin();
backIterator = outParameter.end();
gradIterator = outParameter.end();
}
if (gradIterator == outParameter.end())
+13 -11
View File
@@ -188,12 +188,12 @@ void LSTM<InputDataType, OutputDataType>::Forward(
if (forwardStep > 0)
{
inputGate.cols(forwardStep, forwardStep + batchStep) +=
cell2GateInputWeight % cell.cols(forwardStep - batchSize,
forwardStep - batchSize + batchStep);
arma::repmat(cell2GateInputWeight, 1, batchSize) %
cell.cols(forwardStep - batchSize, forwardStep - batchSize + batchStep);
forgetGate.cols(forwardStep, forwardStep + batchStep) +=
cell2GateForgetWeight % cell.cols(forwardStep - batchSize,
forwardStep - batchSize + batchStep);
arma::repmat(cell2GateForgetWeight, 1, batchSize) %
cell.cols(forwardStep - batchSize, forwardStep - batchSize + batchStep);
}
inputGateActivation.cols(forwardStep, forwardStep + batchStep) = 1.0 /
@@ -283,7 +283,7 @@ void LSTM<InputDataType, OutputDataType>::Backward(
cellError += inputCellError;
}
if (backwardStep != 0)
if (backwardStep > batchStep)
{
forgetGateError = cell.cols((backwardStep - batchSize) - batchStep,
(backwardStep - batchSize)) % cellError % (forgetGateActivation.cols(
@@ -305,7 +305,7 @@ void LSTM<InputDataType, OutputDataType>::Backward(
backwardStep - batchStep, backwardStep), 2));
inputCellError = forgetGateActivation.cols(backwardStep - batchStep,
backwardStep) %cellError + forgetGateError.each_col() %
backwardStep) % cellError + forgetGateError.each_col() %
cell2GateForgetWeight + inputGateError.each_col() % cell2GateInputWeight;
g = input2GateInputWeight.t() * inputGateError +
@@ -395,15 +395,17 @@ void LSTM<InputDataType, OutputDataType>::Gradient(
offset += cell2GateOutputWeight.n_elem;
// Cell2GateForgetWeight and cell2GateInputWeight gradients.
if (gradientStep != 0)
if (gradientStep > batchStep)
{
gradient.submat(offset, 0, offset + cell2GateForgetWeight.n_elem - 1, 0) =
arma::sum(forgetGateError % cell.cols(gradientStep - batchStep -
batchSize, gradientStep - batchSize), 1);
arma::sum(forgetGateError %
cell.cols((gradientStep - batchSize) - batchStep,
(gradientStep - batchSize)), 1);
gradient.submat(offset + cell2GateForgetWeight.n_elem, 0, offset +
cell2GateForgetWeight.n_elem + cell2GateInputWeight.n_elem - 1, 0) =
arma::sum(inputGateError % cell.cols(gradientStep - batchStep -
batchSize, gradientStep - batchSize), 1);
arma::sum(inputGateError %
cell.cols((gradientStep - batchSize) - batchStep,
(gradientStep - batchSize)), 1);
}
else
{
+8 -1
View File
@@ -222,7 +222,14 @@ class RNN
size_t& Rho() { return rho; }
/**
* Reset the module infomration (weights/parameters).
* Reset the state of the network. This ensures that all internally-held
* gradients are set to 0, all memory cells are reset, and the parameters
* matrix is the right size.
*/
void Reset();
/**
* Reset the module information (weights/parameters).
*/
void ResetParameters();
+11 -4
View File
@@ -102,7 +102,6 @@ void RNN<OutputLayerType, InitializationRuleType>::Train(
if (!reset)
{
ResetParameters();
reset = true;
}
// Train the model.
@@ -139,7 +138,6 @@ void RNN<OutputLayerType, InitializationRuleType>::Train(
if (!reset)
{
ResetParameters();
reset = true;
}
OptimizerType optimizer;
@@ -207,7 +205,6 @@ double RNN<OutputLayerType, InitializationRuleType>::Evaluate(
if (parameter.is_empty())
{
ResetParameters();
reset = true;
}
if (deterministic != this->deterministic)
@@ -272,7 +269,6 @@ void RNN<OutputLayerType, InitializationRuleType>::Gradient(
if (parameter.is_empty())
{
ResetParameters();
reset = true;
}
gradient = arma::zeros<arma::mat>(parameter.n_rows, parameter.n_cols);
@@ -337,6 +333,17 @@ void RNN<OutputLayerType, InitializationRuleType>::ResetParameters()
// Reset the network parameter with the given initialization rule.
NetworkInitialization<InitializationRuleType> networkInit(initializeRule);
networkInit.Initialize(network, parameter);
reset = true;
}
template<typename OutputLayerType, typename InitializationRuleType>
void RNN<OutputLayerType, InitializationRuleType>::Reset()
{
ResetParameters();
ResetCells();
currentGradient.zeros();
ResetGradients(currentGradient);
}
template<typename OutputLayerType, typename InitializationRuleType>
@@ -141,7 +141,7 @@ PARAM_MODEL_IN(ApproxKFNModel, "input_model", "File containing input model.",
PARAM_MODEL_OUT(ApproxKFNModel, "output_model", "File to save output model to.",
"M");
void mlpackMain()
static void mlpackMain()
{
// We have to pass either a reference set or an input model.
RequireOnlyOnePassed({ "reference", "input_model" });
+1 -1
View File
@@ -263,7 +263,7 @@ void AssembleFactorizerType(const std::string& algorithm,
}
}
void mlpackMain()
static void mlpackMain()
{
if (CLI::GetParam<int>("seed") == 0)
math::RandomSeed(std::time(NULL));
+1 -1
View File
@@ -112,7 +112,7 @@ void RunDBSCAN(RangeSearchType rs = RangeSearchType())
CLI::GetParam<arma::Row<size_t>>("assignments") = std::move(assignments);
}
void mlpackMain()
static void mlpackMain()
{
RequireAtLeastOnePassed({ "assignments", "centroids" }, false,
"no output will be saved");
@@ -103,7 +103,7 @@ PARAM_MODEL_OUT(DSModel, "output_model", "Output decision stump model to save.",
PARAM_INT_IN("bucket_size", "The minimum number of training points in each "
"decision stump bucket.", "b", 6);
void mlpackMain()
static void mlpackMain()
{
// Check that the parameters are reasonable.
RequireOnlyOnePassed({ "training", "input_model" }, true);
@@ -115,7 +115,7 @@ PARAM_MODEL_IN(DecisionTreeModel, "input_model", "Pre-trained decision tree, "
PARAM_MODEL_OUT(DecisionTreeModel, "output_model", "Output for trained decision"
" tree.", "M");
void mlpackMain()
static void mlpackMain()
{
// Check parameters.
RequireOnlyOnePassed({ "training", "input_model" }, true);
+1 -1
View File
@@ -100,7 +100,7 @@ PARAM_FLAG("volume_regularization", "This flag gives the used the option to use"
*/
void mlpackMain()
static void mlpackMain()
{
// Validate input parameters.
RequireOnlyOnePassed({ "training", "input_model" }, true);
+1 -1
View File
@@ -72,7 +72,7 @@ using namespace mlpack::metric;
using namespace mlpack::util;
using namespace std;
void mlpackMain()
static void mlpackMain()
{
RequireAtLeastOnePassed({ "output" }, false, "no output will be saved");
+1 -1
View File
@@ -83,7 +83,7 @@ PARAM_FLAG("single", "If true, single-tree search is used (as opposed to "
PARAM_MATRIX_OUT("kernels", "Output matrix of kernels.", "p");
PARAM_UMATRIX_OUT("indices", "Output matrix of indices.", "i");
void mlpackMain()
static void mlpackMain()
{
// Validate command-line parameters.
RequireOnlyOnePassed({ "reference", "input_model" }, true);
+1 -1
View File
@@ -42,7 +42,7 @@ PARAM_MATRIX_OUT("output", "Matrix to save output samples in.", "o");
PARAM_INT_IN("seed", "Random seed. If 0, 'std::time(NULL)' is used.", "s", 0);
void mlpackMain()
static void mlpackMain()
{
// Parameter sanity checks.
RequireAtLeastOnePassed({ "output" }, false, "no results will be saved");
@@ -41,7 +41,7 @@ PARAM_MATRIX_IN_REQ("input", "Input matrix to calculate probabilities of.",
PARAM_MATRIX_OUT("output", "Matrix to store calculated probabilities in.", "o");
void mlpackMain()
static void mlpackMain()
{
RequireAtLeastOnePassed({ "output" }, false, "no results will be saved");
+1 -1
View File
@@ -121,7 +121,7 @@ PARAM_MODEL_IN(GMM, "input_model", "Initial input GMM model to start training "
"with.", "m");
PARAM_MODEL_OUT(GMM, "output_model", "Output for trained GMM model.", "M");
void mlpackMain()
static void mlpackMain()
{
// Check parameters and load data.
if (CLI::GetParam<int>("seed") != 0)
+1 -1
View File
@@ -92,7 +92,7 @@ struct Generate
}
};
void mlpackMain()
static void mlpackMain()
{
RequireAtLeastOnePassed({ "output", "state" }, false, "no output will be "
"saved");
+1 -1
View File
@@ -76,7 +76,7 @@ struct Loglik
}
};
void mlpackMain()
static void mlpackMain()
{
// Load model, and calculate the log-likelihood of the sequence.
CLI::GetParam<HMMModel>("input_model").PerformAction<Loglik>((void*) NULL);
+1 -1
View File
@@ -340,7 +340,7 @@ struct Train
}
};
void mlpackMain()
static void mlpackMain()
{
// Set random seed.
if (CLI::GetParam<int>("seed") != 0)
+1 -1
View File
@@ -82,7 +82,7 @@ struct Viterbi
}
};
void mlpackMain()
static void mlpackMain()
{
RequireAtLeastOnePassed({ "output" }, false, "no results will be saved");
@@ -109,7 +109,7 @@ PARAM_INT_IN("observations_before_binning", "If the 'domingos' split strategy "
// Convenience typedef.
typedef tuple<DatasetInfo, arma::mat> TupleType;
void mlpackMain()
static void mlpackMain()
{
// Check input parameters for validity.
const string numericSplitStrategy =
@@ -164,7 +164,7 @@ void RunKPCA(arma::mat& dataset,
}
}
void mlpackMain()
static void mlpackMain()
{
RequireAtLeastOnePassed({ "output" }, false, "no output will be saved");
+1 -1
View File
@@ -140,7 +140,7 @@ template<typename InitialPartitionPolicy,
template<class, class> class LloydStepType>
void RunKMeans(const InitialPartitionPolicy& ipp);
void mlpackMain()
static void mlpackMain()
{
// Initialize random seed.
if (CLI::GetParam<int>("seed") != 0)
+1 -1
View File
@@ -101,7 +101,7 @@ PARAM_DOUBLE_IN("lambda2", "Regularization parameter for l2-norm penalty.", "L",
PARAM_FLAG("use_cholesky", "Use Cholesky decomposition during computation "
"rather than explicitly computing the full Gram matrix.", "c");
void mlpackMain()
static void mlpackMain()
{
double lambda1 = CLI::GetParam<double>("lambda1");
double lambda2 = CLI::GetParam<double>("lambda2");
@@ -85,7 +85,7 @@ PARAM_COL_OUT("output_predictions", "If --test_file is specified, this "
PARAM_DOUBLE_IN("lambda", "Tikhonov regularization for ridge regression. If 0,"
" the method reduces to linear regression.", "l", 0.0);
void mlpackMain()
static void mlpackMain()
{
const double lambda = CLI::GetParam<double>("lambda");
@@ -93,7 +93,7 @@ PARAM_MATRIX_OUT("codes", "Output codes matrix.", "c");
PARAM_INT_IN("seed", "Random seed. If 0, 'std::time(NULL)' is used.", "s", 0);
void mlpackMain()
static void mlpackMain()
{
if (CLI::GetParam<int>("seed") != 0)
RandomSeed((size_t) CLI::GetParam<int>("seed"));
@@ -133,7 +133,7 @@ PARAM_DOUBLE_IN("decision_boundary", "Decision boundary for prediction; if the "
"logistic function for a point is less than the boundary, the class is "
"taken to be 0; otherwise, the class is 1.", "d", 0.5);
void mlpackMain()
static void mlpackMain()
{
// Collect command-line options.
const double lambda = CLI::GetParam<double>("lambda");
@@ -162,8 +162,8 @@ void mlpackMain()
ReportIgnoredParam({{ "test", false }}, "output_probabilities");
// Tolerance needs to be positive.
RequireParamValue<double>("tolerance", [](double x) { return x > 0.0; },
true, "tolerance must be positive");
RequireParamValue<double>("tolerance", [](double x) { return x >= 0.0; },
true, "tolerance must be positive or zero");
// Optimizer has to be L-BFGS or SGD.
RequireParamInSet<string>("optimizer", { "lbfgs", "sgd" },
+1 -1
View File
@@ -82,7 +82,7 @@ PARAM_INT_IN("bucket_size", "The size of a bucket in the second level hash.",
"B", 500);
PARAM_INT_IN("seed", "Random seed. If 0, 'std::time(NULL)' is used.", "s", 0);
void mlpackMain()
static void mlpackMain()
{
if (CLI::GetParam<int>("seed") != 0)
math::RandomSeed((size_t) CLI::GetParam<int>("seed"));
@@ -66,7 +66,7 @@ PARAM_DOUBLE_IN("radius", "If the distance between two centroids is less than "
"the given radius, one will be removed. A radius of 0 or less means an "
"estimate will be calculated and used for the radius.", "r", 0);
void mlpackMain()
static void mlpackMain()
{
const double radius = CLI::GetParam<double>("radius");
const int maxIterations = CLI::GetParam<int>("max_iterations");
+1 -1
View File
@@ -105,7 +105,7 @@ PARAM_UROW_OUT("output", "The matrix in which the predicted labels for the"
PARAM_MATRIX_OUT("output_probs", "The matrix in which the predicted probability"
" of labels for the test set will be written.", "p");
void mlpackMain()
static void mlpackMain()
{
// Check input parameters.
RequireOnlyOnePassed({ "training", "input_model" }, true);
+1 -1
View File
@@ -124,7 +124,7 @@ using namespace mlpack::optimization;
using namespace mlpack::util;
using namespace std;
void mlpackMain()
static void mlpackMain()
{
if (CLI::GetParam<int>("seed") != 0)
math::RandomSeed((size_t) CLI::GetParam<int>("seed"));
@@ -95,7 +95,7 @@ PARAM_DOUBLE_IN("percentage", "If specified, will do approximate furthest "
"neighbors will be at least (p*100) % of the distance as the true furthest "
"neighbor.", "p", 1);
void mlpackMain()
static void mlpackMain()
{
if (CLI::GetParam<int>("seed") != 0)
math::RandomSeed((size_t) CLI::GetParam<int>("seed"));
@@ -99,7 +99,7 @@ PARAM_STRING_IN("algorithm", "Type of neighbor search: 'naive', 'single_tree', "
PARAM_DOUBLE_IN("epsilon", "If specified, will do approximate nearest neighbor "
"search with given relative error.", "e", 0);
void mlpackMain()
static void mlpackMain()
{
if (CLI::GetParam<int>("seed") != 0)
math::RandomSeed((size_t) CLI::GetParam<int>("seed"));
+1 -1
View File
@@ -76,7 +76,7 @@ PARAM_DOUBLE_IN("min_residue", "The minimum root mean square residue allowed "
PARAM_STRING_IN("update_rules", "Update rules for each iteration; ( multdist | "
"multdiv | als ).", "u", "multdist");
void mlpackMain()
static void mlpackMain()
{
// Initialize random seed.
if (CLI::GetParam<int>("seed") != 0)
+3 -2
View File
@@ -99,7 +99,7 @@ void RunPCA(arma::mat& dataset,
dataset.n_rows << " dimensions)." << endl;
}
void mlpackMain()
static void mlpackMain()
{
// Load input dataset.
arma::mat& dataset = CLI::GetParam<arma::mat>("input");
@@ -119,7 +119,8 @@ void mlpackMain()
error << "cannot be greater than existing dimensionality (" << dataset.n_rows
<< ")";
RequireParamValue<int>("new_dimensionality",
[dataset](int x) { return x <= dataset.n_rows; }, true, error.str());
[dataset](int x) { return x <= (int) dataset.n_rows; }, true,
error.str());
RequireParamValue<double>("var_to_retain",
[](double x) { return x >= 0.0 && x <= 1.0; }, true,
@@ -118,7 +118,7 @@ PARAM_MATRIX_IN("test", "A matrix containing the test set.", "T");
PARAM_UROW_OUT("output", "The matrix in which the predicted labels for the"
" test set will be written.", "o");
void mlpackMain()
static void mlpackMain()
{
// First, get all parameters and validate them.
const size_t maxIterations = (size_t) CLI::GetParam<int>("max_iterations");
@@ -54,7 +54,7 @@ using namespace mlpack::util;
using namespace arma;
using namespace std;
void mlpackMain()
static void mlpackMain()
{
const size_t dimension = (size_t) CLI::GetParam<int>("dimension");
const double threshold = CLI::GetParam<double>("threshold");
@@ -153,7 +153,7 @@ double StandardError(const size_t size, const double& fStd)
return fStd / sqrt(size);
}
void mlpackMain()
static void mlpackMain()
{
const size_t dimension = static_cast<size_t>(CLI::GetParam<int>("dimension"));
const size_t precision = static_cast<size_t>(CLI::GetParam<int>("precision"));
@@ -53,7 +53,7 @@ using namespace arma;
using namespace std;
using namespace data;
void mlpackMain()
static void mlpackMain()
{
const string inputFile = CLI::GetParam<string>("input_file");
const string outputFile = CLI::GetParam<string>("output_file");
@@ -71,7 +71,7 @@ using namespace mlpack::util;
using namespace arma;
using namespace std;
void mlpackMain()
static void mlpackMain()
{
// Parse command line options.
const double testRatio = CLI::GetParam<double>("test_ratio");
+1 -1
View File
@@ -57,7 +57,7 @@ using namespace mlpack::util;
using namespace std;
using namespace arma;
void mlpackMain()
static void mlpackMain()
{
// Set random seed.
if (CLI::GetParam<int>("seed") != 0)
@@ -68,7 +68,7 @@ PARAM_MODEL_IN(RandomForestModel, "input_model", "Pre-trained random forest to "
PARAM_MODEL_OUT(RandomForestModel, "output_model", "Model to save trained "
"random forest to.", "M");
void mlpackMain()
static void mlpackMain()
{
// Check for incompatible input parameters.
RequireOnlyOnePassed({ "training", "input_model" }, true);
@@ -91,7 +91,7 @@ PARAM_FLAG("naive", "If true, O(n^2) naive mode is used for computation.", "N");
PARAM_FLAG("single_mode", "If true, single-tree search is used (as opposed to "
"dual-tree search).", "S");
void mlpackMain()
static void mlpackMain()
{
if (CLI::GetParam<int>("seed") != 0)
math::RandomSeed((size_t) CLI::GetParam<int>("seed"));
+1 -1
View File
@@ -96,7 +96,7 @@ PARAM_FLAG("first_leaf_exact", "The flag to trigger sampling only after "
PARAM_INT_IN("single_sample_limit", "The limit on the maximum number of "
"samples (and hence the largest node you can approximate).", "z", 20);
void mlpackMain()
static void mlpackMain()
{
if (CLI::GetParam<int>("seed") != 0)
math::RandomSeed((size_t) CLI::GetParam<int>("seed"));
@@ -115,7 +115,7 @@ void TestClassifyAcc(const size_t numClasses, const Model& model);
template<typename Model>
unique_ptr<Model> TrainSoftmax(const size_t maxIterations);
void mlpackMain()
static void mlpackMain()
{
const int maxIterations = CLI::GetParam<int>("max_iterations");
@@ -12,7 +12,6 @@
*/
#include "sparse_coding.hpp"
#include <mlpack/core/math/lin_alg.hpp>
#include <mlpack/core/util/param.hpp>
namespace mlpack {
namespace sparse_coding {
@@ -96,7 +96,7 @@ PARAM_MATRIX_OUT("codes", "Matrix to save the output sparse codes of the test "
PARAM_MATRIX_IN("test", "Optional matrix to be encoded by trained model.", "T");
void mlpackMain()
static void mlpackMain()
{
if (CLI::GetParam<int>("seed") != 0)
RandomSeed((size_t) CLI::GetParam<int>("seed"));
+1
View File
@@ -123,6 +123,7 @@ add_executable(mlpack_test
union_find_test.cpp
vantage_point_tree_test.cpp
main_tests/decision_tree_test.cpp
main_tests/linear_regression_test.cpp
main_tests/pca_test.cpp
main_tests/preprocess_binarize_test.cpp
main_tests/preprocess_imputer_test.cpp
+152 -1
View File
@@ -2,8 +2,9 @@
* @file adam_test.cpp
* @author Vasanth Kalingeri
* @author Vivek Pal
* @author Sourabh Varshney
*
* Tests the Adam and AdaMax optimizer.
* Tests the Adam, AdaMax, AMSGrad and Nadam 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
@@ -62,6 +63,22 @@ BOOST_AUTO_TEST_CASE(SimpleAdaMaxTestFunction)
BOOST_REQUIRE_SMALL(coordinates[2], 0.1);
}
/**
* Tests the AMSGrad optimizer using a simple test function.
*/
BOOST_AUTO_TEST_CASE(SimpleAMSGradTestFunction)
{
SGDTestFunction f;
AMSGrad optimizer(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
BOOST_REQUIRE_SMALL(coordinates[0], 0.1);
BOOST_REQUIRE_SMALL(coordinates[1], 0.1);
BOOST_REQUIRE_SMALL(coordinates[2], 0.1);
}
/**
* Run Adam on logistic regression and make sure the results are acceptable.
*/
@@ -178,4 +195,138 @@ BOOST_AUTO_TEST_CASE(AdaMaxLogisticRegressionTest)
BOOST_REQUIRE_CLOSE(testAcc, 100.0, 0.6); // 0.6% error tolerance.
}
/**
* Run AMSGrad on logistic regression and make sure the results are acceptable.
*/
BOOST_AUTO_TEST_CASE(AMSGradLogisticRegressionTest)
{
// Generate a two-Gaussian dataset.
GaussianDistribution g1(arma::vec("1.0 1.0 1.0"), arma::eye<arma::mat>(3, 3));
GaussianDistribution g2(arma::vec("9.0 9.0 9.0"), arma::eye<arma::mat>(3, 3));
arma::mat data(3, 1000);
arma::Row<size_t> responses(1000);
for (size_t i = 0; i < 500; ++i)
{
data.col(i) = g1.Random();
responses[i] = 0;
}
for (size_t i = 500; i < 1000; ++i)
{
data.col(i) = g2.Random();
responses[i] = 1;
}
// Shuffle the dataset.
arma::uvec indices = arma::shuffle(arma::linspace<arma::uvec>(0,
data.n_cols - 1, data.n_cols));
arma::mat shuffledData(3, 1000);
arma::Row<size_t> shuffledResponses(1000);
for (size_t i = 0; i < data.n_cols; ++i)
{
shuffledData.col(i) = data.col(indices[i]);
shuffledResponses[i] = responses[indices[i]];
}
// Create a test set.
arma::mat testData(3, 1000);
arma::Row<size_t> testResponses(1000);
for (size_t i = 0; i < 500; ++i)
{
testData.col(i) = g1.Random();
testResponses[i] = 0;
}
for (size_t i = 500; i < 1000; ++i)
{
testData.col(i) = g2.Random();
testResponses[i] = 1;
}
AMSGrad amsgrad(1e-3, 1, 0.9, 0.999, 1e-8, 500000, 1e-11, true);
LogisticRegression<> lr(shuffledData, shuffledResponses, amsgrad, 0.5);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses);
BOOST_REQUIRE_CLOSE(acc, 100.0, 0.3); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses);
BOOST_REQUIRE_CLOSE(testAcc, 100.0, 0.6); // 0.6% error tolerance.
}
/**
* Tests the Nadam optimizer using a simple test function.
*/
BOOST_AUTO_TEST_CASE(SimpleNadamTestFunction)
{
SGDTestFunction f;
Nadam optimizer(1e-3, 1, 0.9, 0.99, 1e-8, 500000, 1e-9, true);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
BOOST_REQUIRE_SMALL(coordinates[0], 0.1);
BOOST_REQUIRE_SMALL(coordinates[1], 0.1);
BOOST_REQUIRE_SMALL(coordinates[2], 0.1);
}
/**
* Run Nadam on logistic regression and make sure the results are acceptable.
*/
BOOST_AUTO_TEST_CASE(NadamLogisticRegressionTest)
{
// Generate a two-Gaussian dataset.
GaussianDistribution g1(arma::vec("1.0 1.0 1.0"),
arma::eye<arma::mat>(3, 3));
GaussianDistribution g2(arma::vec("9.0 9.0 9.0"),
arma::eye<arma::mat>(3, 3));
arma::mat data(3, 1000);
arma::Row<size_t> responses(1000);
for (size_t i = 0; i < 500; ++i)
{
data.col(i) = g1.Random();
responses[i] = 0;
}
for (size_t i = 500; i < 1000; ++i)
{
data.col(i) = g2.Random();
responses[i] = 1;
}
// Shuffle the dataset.
arma::uvec indices = arma::shuffle(arma::linspace<arma::uvec>(0,
data.n_cols - 1, data.n_cols));
arma::mat shuffledData(3, 1000);
arma::Row<size_t> shuffledResponses(1000);
for (size_t i = 0; i < data.n_cols; ++i)
{
shuffledData.col(i) = data.col(indices[i]);
shuffledResponses[i] = responses[indices[i]];
}
// Create a test set.
arma::mat testData(3, 1000);
arma::Row<size_t> testResponses(1000);
for (size_t i = 0; i < 500; ++i)
{
testData.col(i) = g1.Random();
testResponses[i] = 0;
}
for (size_t i = 500; i < 1000; ++i)
{
testData.col(i) = g2.Random();
testResponses[i] = 1;
}
Nadam nadam;
LogisticRegression<> lr(shuffledData, shuffledResponses, nadam, 0.5);
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses);
BOOST_REQUIRE_CLOSE(acc, 100.0, 0.3); // 0.3% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses);
BOOST_REQUIRE_CLOSE(testAcc, 100.0, 0.6); // 0.6% error tolerance.
}
BOOST_AUTO_TEST_SUITE_END();
+2
View File
@@ -22,6 +22,8 @@ using Option = mlpack::bindings::cli::CLIOption<T>;
} // namespace util
} // namespace mlpack
static const std::string testName = "";
#include <mlpack/core/util/param.hpp>
#include <mlpack/bindings/cli/parse_command_line.hpp>
#include <mlpack/bindings/cli/end_program.hpp>
+81 -58
View File
@@ -47,37 +47,49 @@ BOOST_AUTO_TEST_CASE(CNEXORTest)
arma::mat train("1, 0, 0, 1; 1, 0, 1, 0");
arma::mat labels("1, 1, 2, 2");
// network with 2 input 2 hidden and 2 output layer
FFN<NegativeLogLikelihood<> > network;
network.Add<Linear<> >(2, 2);
network.Add<SigmoidLayer<> >();
network.Add<Linear<> >(2, 2);
network.Add<LogSoftMax<> >();
// CNE object.
CNE opt(60, 5000, 0.1, 0.02, 0.2, 0.1, -1);
// Training the network with CNE
network.Train(train, labels, opt);
// Predicting for the same train data
arma::mat predictionTemp;
network.Predict(train, predictionTemp);
arma::mat prediction = arma::zeros<arma::mat>(1, predictionTemp.n_cols);
for (size_t i = 0; i < predictionTemp.n_cols; ++i)
// CNE may fail to find a good optimum. But if it can succeed one out of 6
// times I think that is sufficient to say it is working.
size_t successes = 0;
for (size_t trial = 0; trial < 6; ++trial)
{
prediction(i) = arma::as_scalar(arma::find(
arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1;
// Build a network with 2 input, 2 hidden, and 2 output layers.
FFN<NegativeLogLikelihood<> > network;
network.Add<Linear<> >(2, 2);
network.Add<SigmoidLayer<> >();
network.Add<Linear<> >(2, 2);
network.Add<LogSoftMax<> >();
// CNE object.
CNE opt(60, 5000, 0.1, 0.02, 0.2, 0.1, -1);
// Training the network with CNE
network.Train(train, labels, opt);
// Predicting for the same train data
arma::mat predictionTemp;
network.Predict(train, predictionTemp);
arma::mat prediction = arma::zeros<arma::mat>(1, predictionTemp.n_cols);
for (size_t i = 0; i < predictionTemp.n_cols; ++i)
{
prediction(i) = arma::as_scalar(arma::find(
arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1;
}
// 1 means 0 and 2 means 1 as the output to XOR.
if ((prediction[0] == 1) &&
(prediction[1] == 1) &&
(prediction[2] == 2) &&
(prediction[3] == 2))
{
++successes;
break;
}
}
// 1 means 0 and 2 means 1 as the output to XOR
BOOST_REQUIRE_EQUAL(1, prediction[0]);
BOOST_REQUIRE_EQUAL(1, prediction[1]);
BOOST_REQUIRE_EQUAL(2, prediction[2]);
BOOST_REQUIRE_EQUAL(2, prediction[3]);
BOOST_REQUIRE_GT(successes, 0);
}
/**
@@ -127,7 +139,7 @@ BOOST_AUTO_TEST_CASE(CNELogisticRegressionTest)
testResponses[i] = 1;
}
CNE opt(30, 500, 0.2, 0.2, 0.3, 65, -1);
CNE opt(200, 10000, 0.2, 0.2, 0.3, 65, -1);
LogisticRegression<> lr(shuffledData, shuffledResponses, opt, 0.5);
@@ -159,41 +171,52 @@ BOOST_AUTO_TEST_CASE(VanillaNetworkWithCNETest)
data::Load("iris_test_labels.csv", testLabels, true);
testLabels += 1;
// Create vanilla network with 4 input, 4 hidden and 3 output nodes.
FFN<NegativeLogLikelihood<> > model;
model.Add<Linear<> >(trainData.n_rows, 4);
model.Add<SigmoidLayer<> >();
model.Add<Linear<> >(4, 3);
model.Add<LogSoftMax<> >();
// Creating CNE object.
// The tolerance and objectiveChange are not taken into consideration.
CNE opt(30, 200, 0.2, 0.2, 0.3, -1, -1);
model.Train(trainData, trainLabels, opt);
arma::mat predictionTemp;
model.Predict(testData, predictionTemp);
arma::mat prediction = arma::zeros<arma::mat>(1, predictionTemp.n_cols);
for (size_t i = 0; i < predictionTemp.n_cols; ++i)
// Training the network may fail, so we will try a few times.
size_t successes = 0;
for (size_t trial = 0; trial < 4; ++trial)
{
prediction(i) = arma::as_scalar(arma::find(
arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1;
}
// Create vanilla network with 4 input, 4 hidden and 3 output nodes.
FFN<NegativeLogLikelihood<> > model;
model.Add<Linear<> >(trainData.n_rows, 4);
model.Add<SigmoidLayer<> >();
model.Add<Linear<> >(4, 3);
model.Add<LogSoftMax<> >();
size_t error = 0;
for (size_t i = 0; i < testData.n_cols; i++)
{
if (int(arma::as_scalar(prediction.col(i))) ==
int(arma::as_scalar(testLabels.col(i))))
// Creating CNE object.
// The tolerance and objectiveChange are not taken into consideration.
CNE opt(30, 200, 0.2, 0.2, 0.3, -1, -1);
model.Train(trainData, trainLabels, opt);
arma::mat predictionTemp;
model.Predict(testData, predictionTemp);
arma::mat prediction = arma::zeros<arma::mat>(1, predictionTemp.n_cols);
for (size_t i = 0; i < predictionTemp.n_cols; ++i)
{
error++;
prediction(i) = arma::as_scalar(arma::find(
arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1;
}
size_t error = 0;
for (size_t i = 0; i < testData.n_cols; i++)
{
if (int(arma::as_scalar(prediction.col(i))) ==
int(arma::as_scalar(testLabels.col(i))))
{
error++;
}
}
double classificationError = 1 - double(error) / testData.n_cols;
if (classificationError <= 0.1)
{
++successes;
break;
}
}
double classificationError = 1 - double(error) / testData.n_cols;
BOOST_REQUIRE_LE(classificationError, 0.1);
BOOST_REQUIRE_GT(successes, 0);
}
BOOST_AUTO_TEST_SUITE_END();
+3 -3
View File
@@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE(regularizedOMP)
mat B1 = 0.1 * eye(k, k);
mat B2 = 100 * randn(k, k);
mat A = join_horiz(B1, B2); // The dictionary is input as columns of A.
vec b(k); // Vector to be sparsely approximated.
vec b(k, arma::fill::zeros); // Vector to be sparsely approximated.
b(0) = 1;
b(1) = 1;
vec lambda(A.n_cols);
@@ -98,8 +98,8 @@ BOOST_AUTO_TEST_CASE(PruneSupportOMP)
int k = 3;
mat B1;
B1 << 1 << 0 << 1 << endr
<< 0 << 1 << 1 << endr
<< 0 << 0 << 1 << endr;
<< 0 << 1 << 1 << endr
<< 0 << 0 << 1 << endr;
mat B2 = randu(k, k);
mat A = join_horiz(B1, B2); // The dictionary is input as columns of A.
vec b;
@@ -0,0 +1,70 @@
/**
* @file linear_regression_test.cpp
* @author Eugene Freyman
*
* Test mlpackMain() of linear_regression_main.cpp.
*/
#include <string>
#define BINDING_TYPE BINDING_TYPE_TEST
static const std::string testName = "LinearRegression";
#include <mlpack/core.hpp>
#include <mlpack/core/util/mlpack_main.hpp>
#include <mlpack/methods/linear_regression/linear_regression_main.cpp>
#include <boost/test/unit_test.hpp>
#include "../test_tools.hpp"
using namespace mlpack;
// Utility function to set a parameter and mark it as passed, using copy
// semantics.
template<typename T>
void SetInputParam(const std::string& name, const T& value)
{
CLI::GetParam<T>(name) = value;
CLI::SetPassed(name);
}
// Utility function to set a parameter and mark it as passed, using move
// semantics.
template<typename T>
void SetInputParam(const std::string& name, T&& value)
{
CLI::GetParam<T>(name) = std::move(value);
CLI::SetPassed(name);
}
struct LinearRegressionTestFixture
{
public:
LinearRegressionTestFixture()
{
// Cache in the options for this program.
CLI::RestoreSettings(testName);
}
~LinearRegressionTestFixture()
{
// Clear the settings.
CLI::ClearSettings();
}
};
BOOST_FIXTURE_TEST_SUITE(LinearRegressionMainTest, LinearRegressionTestFixture);
BOOST_AUTO_TEST_CASE(LinearRegressionWrongResponseSizeTest)
{
arma::mat x = arma::randu<arma::mat>(5, 5);
arma::rowvec y = arma::randu<arma::rowvec>(4);
SetInputParam("training", std::move(x));
SetInputParam("training_responses", std::move(y));
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
BOOST_AUTO_TEST_SUITE_END();
+5 -11
View File
@@ -4,7 +4,11 @@
*
* Test mlpackMain() of pca_main.cpp.
*/
#include <string>
#define BINDING_TYPE BINDING_TYPE_TEST
static const std::string testName = "PrincipalComponentAnalysis";
#include <mlpack/core.hpp>
#include <mlpack/core/util/mlpack_main.hpp>
#include <mlpack/methods/pca/pca_main.cpp>
@@ -14,16 +18,6 @@
using namespace mlpack;
namespace mlpack {
namespace bindings {
namespace tests {
extern std::string programName;
}
}
}
// Utility function to set a parameter and mark it as passed, using copy
// semantics.
template<typename T>
@@ -48,7 +42,7 @@ struct PCATestFixture
PCATestFixture()
{
// Cache in the options for this program.
CLI::RestoreSettings(mlpack::bindings::tests::programName);
CLI::RestoreSettings(testName);
}
~PCATestFixture()
+3 -3
View File
@@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE(MomentumSGDSpeedUpTestFunction)
arma::mat coordinates = f.GetInitialPoint();
double result = s.Optimize(f, coordinates);
BOOST_REQUIRE_CLOSE(result, -1.0, 0.05);
BOOST_REQUIRE_CLOSE(result, -1.0, 0.15);
BOOST_REQUIRE_SMALL(coordinates[0], 1e-3);
BOOST_REQUIRE_SMALL(coordinates[1], 1e-7);
BOOST_REQUIRE_SMALL(coordinates[2], 1e-7);
@@ -65,12 +65,12 @@ BOOST_AUTO_TEST_CASE(GeneralizedRosenbrockTest)
// Create the generalized Rosenbrock function.
GeneralizedRosenbrockFunction f(i);
MomentumUpdate momentumUpdate(0.4);
MomentumSGD s(0.001, 1, 0, 1e-15, true, momentumUpdate);
MomentumSGD s(0.0008, 1, 0, 1e-15, true, momentumUpdate);
arma::mat coordinates = f.GetInitialPoint();
double result = s.Optimize(f, coordinates);
BOOST_REQUIRE_SMALL(result, 1e-10);
BOOST_REQUIRE_SMALL(result, 1e-4);
for (size_t j = 0; j < i; ++j)
BOOST_REQUIRE_CLOSE(coordinates[j], (double) 1.0, 1e-3);
}
+18 -11
View File
@@ -230,21 +230,28 @@ BOOST_AUTO_TEST_CASE(QUICPCADimensionalityReductionTest)
data::Load("test_data_3_1000.csv", data);
data1 = data;
arma::mat backupData(data);
// It isn't guaranteed that the QUIC-SVD will match with the exact SVD method,
// starting with random samples. If this works 1 of 5 times, I'm fine with
// that. All I want to know is that the QUIC-SVD method is able to solve the
// that. All I want to know is that the QUIC-SVD method is able to solve the
// task and is at least as good as the exact method (plus a little bit for
// noise).
size_t successes = 0;
for (size_t trial = 0; trial < 5; ++trial)
{
if (trial > 0)
{
data = backupData;
data1 = backupData;
}
PCAType<ExactSVDPolicy> exactPCA;
const double varRetainedExact = exactPCA.Apply(data, 1);
PCAType<QUICSVDPolicy> quicPCA;
const double varRetainedQUIC = quicPCA.Apply(data1, 1);
if (std::abs(varRetainedExact - varRetainedQUIC) < 0.2)
{
++successes;
@@ -294,21 +301,21 @@ BOOST_AUTO_TEST_CASE(PCAScalingTest)
// The first two components of the eigenvector with largest eigenvalue should
// be somewhere near sqrt(2) / 2. The third component should be close to
// zero. There is noise, of course...
BOOST_REQUIRE_CLOSE(std::abs(eigvec(0, 0)), sqrt(2) / 2, 0.2);
BOOST_REQUIRE_CLOSE(std::abs(eigvec(1, 0)), sqrt(2) / 2, 0.2);
BOOST_REQUIRE_SMALL(eigvec(2, 0), 0.08); // Large tolerance for noise.
BOOST_REQUIRE_CLOSE(std::abs(eigvec(0, 0)), sqrt(2) / 2, 0.35);
BOOST_REQUIRE_CLOSE(std::abs(eigvec(1, 0)), sqrt(2) / 2, 0.35);
BOOST_REQUIRE_SMALL(eigvec(2, 0), 0.1); // Large tolerance for noise.
// The second component should be focused almost entirely in the third
// dimension.
BOOST_REQUIRE_SMALL(eigvec(0, 1), 0.08);
BOOST_REQUIRE_SMALL(eigvec(1, 1), 0.08);
BOOST_REQUIRE_CLOSE(std::abs(eigvec(2, 1)), 1.0, 0.2);
BOOST_REQUIRE_SMALL(eigvec(0, 1), 0.1);
BOOST_REQUIRE_SMALL(eigvec(1, 1), 0.1);
BOOST_REQUIRE_CLOSE(std::abs(eigvec(2, 1)), 1.0, 0.35);
// The third component should have the same absolute value characteristics as
// the first (plus 20% tolerance).
BOOST_REQUIRE_CLOSE(std::abs(eigvec(0, 0)), sqrt(2) / 2, 0.2);
BOOST_REQUIRE_CLOSE(std::abs(eigvec(1, 0)), sqrt(2) / 2, 0.2);
BOOST_REQUIRE_SMALL(eigvec(2, 0), 0.08); // Large tolerance for noise.
BOOST_REQUIRE_CLOSE(std::abs(eigvec(0, 0)), sqrt(2) / 2, 0.35);
BOOST_REQUIRE_CLOSE(std::abs(eigvec(1, 0)), sqrt(2) / 2, 0.35);
BOOST_REQUIRE_SMALL(eigvec(2, 0), 0.1); // Large tolerance for noise.
// The eigenvalues should sum to three.
BOOST_REQUIRE_CLOSE(accu(eigval), 3.0, 0.1); // 10% tolerance.
+22 -11
View File
@@ -29,18 +29,29 @@ BOOST_AUTO_TEST_CASE(QUICSVDReconstructionError)
arma::mat dataset;
data::Load("test_data_3_1000.csv", dataset);
// Obtain the SVD using default parameters.
arma::mat u, v, sigma;
svd::QUIC_SVD quicsvd(dataset, u, v, sigma);
// The QUIC-SVD procedure can fail---the Monte Carlo error calculation is
// random. Therefore we simply require at least one success.
size_t successes = 0;
for (size_t i = 0; i < 3; ++i)
{
// Obtain the SVD using default parameters.
Log::Info.ignoreInput = false;
Log::Warn.ignoreInput = false;
arma::mat u, v, sigma;
svd::QUIC_SVD quicsvd(dataset, u, v, sigma);
// Reconstruct the matrix using the SVD.
arma::mat reconstruct;
reconstruct = u * sigma * v.t();
// Reconstruct the matrix using the SVD.
arma::mat reconstruct;
reconstruct = u * sigma * v.t();
// The relative reconstruction error should be small.
double relativeError = arma::norm(dataset - reconstruct, "frob") /
arma::norm(dataset, "frob");
BOOST_REQUIRE_SMALL(relativeError, 1e-5);
// The relative reconstruction error should be small.
double relativeError = arma::norm(dataset - reconstruct, "frob") /
arma::norm(dataset, "frob");
if (relativeError < 1e-5)
++successes;
}
BOOST_REQUIRE_GT(successes, 0);
}
/**
@@ -71,7 +82,7 @@ BOOST_AUTO_TEST_CASE(QUICSVDSingularValueError)
// The sigular value error should be small.
double error = arma::norm(s1 - s3);
BOOST_REQUIRE_SMALL(error, 0.05);
BOOST_REQUIRE_SMALL(error, 0.1);
}
BOOST_AUTO_TEST_CASE(QUICSVDSameDimensionTest)
+4 -4
View File
@@ -224,7 +224,7 @@ BOOST_AUTO_TEST_CASE(UnweightedCategoricalLearningTest)
arma::Row<size_t> testLabels = l.subvec(2000, 3999);
// Train a random forest and a decision tree.
RandomForest<> rf(trainingData, di, trainingLabels, 5, 10 /* 10 trees */, 5);
RandomForest<> rf(trainingData, di, trainingLabels, 5, 15 /* 15 trees */, 5);
DecisionTree<> dt(trainingData, di, trainingLabels, 5, 5);
// Get performance statistics on test data.
@@ -238,7 +238,7 @@ BOOST_AUTO_TEST_CASE(UnweightedCategoricalLearningTest)
size_t rfCorrect = arma::accu(rfPredictions == testLabels);
size_t dtCorrect = arma::accu(dtPredictions == testLabels);
BOOST_REQUIRE_GE(rfCorrect, dtCorrect);
BOOST_REQUIRE_GE(rfCorrect, dtCorrect - 30);
BOOST_REQUIRE_GE(rfCorrect, size_t(0.7 * testData.n_cols));
}
@@ -281,7 +281,7 @@ BOOST_AUTO_TEST_CASE(WeightedCategoricalLearningTest)
arma::Row<size_t> fullLabels = arma::join_rows(trainingLabels, randomLabels);
// Build a random forest and a decision tree.
RandomForest<> rf(fullData, di, fullLabels, 5, 10 /* 10 trees */, 5);
RandomForest<> rf(fullData, di, fullLabels, 5, 15 /* 15 trees */, 5);
DecisionTree<> dt(fullData, di, fullLabels, 5, 5);
// Get performance statistics on test data.
@@ -295,7 +295,7 @@ BOOST_AUTO_TEST_CASE(WeightedCategoricalLearningTest)
size_t rfCorrect = arma::accu(rfPredictions == testLabels);
size_t dtCorrect = arma::accu(dtPredictions == testLabels);
BOOST_REQUIRE_GE(rfCorrect, dtCorrect);
BOOST_REQUIRE_GE(rfCorrect, dtCorrect - 30);
BOOST_REQUIRE_GE(rfCorrect, size_t(0.7 * testData.n_cols));
}
+83 -5
View File
@@ -67,13 +67,13 @@ void GenerateNoisySines(arma::mat& data,
BOOST_AUTO_TEST_CASE(SequenceClassificationTest)
{
// It isn't guaranteed that the recurrent network will converge in the
// specified number of iterations using random weights. If this works 1 of 5
// specified number of iterations using random weights. If this works 1 of 6
// times, I'm fine with that. All I want to know is that the network is able
// to escape from local minima and to solve the task.
size_t successes = 0;
const size_t rho = 10;
for (size_t trial = 0; trial < 5; ++trial)
for (size_t trial = 0; trial < 6; ++trial)
{
// Generate 12 (2 * 6) noisy sines. A single sine contains rho
// points/features.
@@ -287,7 +287,8 @@ void GenerateNextReber(const arma::Mat<char>& transitions,
* @param nextReber All reachable next symbols.
*/
void GenerateNextRecursiveReber(const arma::Mat<char>& transitions,
const std::string& reber, std::string& nextReber)
const std::string& reber,
std::string& nextReber)
{
size_t state = 0;
size_t numPs = 0;
@@ -457,7 +458,7 @@ void ReberGrammarTestNetwork(const size_t hiddenSize = 4,
MomentumSGD opt(0.06, 50, 2, -50000);
arma::mat inputTemp, labelsTemp;
for (size_t i = 0; i < (iterations + offset); i++)
for (size_t iteration = 0; iteration < (iterations + offset); iteration++)
{
for (size_t j = 0; j < trainReberGrammarCount; j++)
{
@@ -672,7 +673,7 @@ void DistractedSequenceRecallTestNetwork(
// We increase the number of iterations (training) if the first run didn't
// pass.
arma::mat inputTemp, labelsTemp;
for (size_t i = 0; i < (9 + offset); i++)
for (size_t iteration = 0; iteration < (9 + offset); iteration++)
{
for (size_t j = 0; j < trainDistractedSequenceCount; j++)
{
@@ -743,6 +744,83 @@ BOOST_AUTO_TEST_CASE(GRUDistractedSequenceRecallTest)
DistractedSequenceRecallTestNetwork<GRU<> >(4, 8);
}
/**
* Create a simple recurrent neural network for the noisy sines task, and
* require that it produces the exact same network for a few batch sizes.
*/
template<typename RecurrentLayerType>
void BatchSizeTest()
{
const size_t rho = 10;
// Generate 12 (2 * 6) noisy sines. A single sine contains rho
// points/features.
arma::mat input, labelsTemp;
GenerateNoisySines(input, labelsTemp, rho, 6);
arma::mat labels = arma::zeros<arma::mat>(rho, labelsTemp.n_cols);
for (size_t i = 0; i < labelsTemp.n_cols; ++i)
{
const int value = arma::as_scalar(arma::find(
arma::max(labelsTemp.col(i)) == labelsTemp.col(i), 1)) + 1;
labels.col(i).fill(value);
}
RNN<> model(rho);
model.Add<Linear<>>(1, 10);
model.Add<SigmoidLayer<>>();
model.Add<RecurrentLayerType>(10, 10);
model.Add<SigmoidLayer<>>();
model.Add<Linear<>>(10, 10);
model.Add<SigmoidLayer<>>();
model.Reset();
arma::mat initParams = model.Parameters();
StandardSGD opt(1e-5, 1, 5, -100, false);
model.Train(input, labels, opt);
// This is trained with one point.
arma::mat outputParams = model.Parameters();
model.Reset();
model.Parameters() = initParams;
opt.BatchSize() = 2;
model.Train(input, labels, opt);
CheckMatrices(outputParams, model.Parameters(), 1);
model.Parameters() = initParams;
opt.BatchSize() = 5;
model.Train(input, labels, opt);
CheckMatrices(outputParams, model.Parameters(), 1);
}
/**
* Ensure LSTMs work with larger batch sizes.
*/
BOOST_AUTO_TEST_CASE(LSTMBatchSizeTest)
{
BatchSizeTest<LSTM<>>();
}
/**
* Ensure fast LSTMs work with larger batch sizes.
*/
BOOST_AUTO_TEST_CASE(FastLSTMBatchSizeTest)
{
BatchSizeTest<FastLSTM<>>();
}
/**
* Ensure GRUs work with larger batch sizes.
*/
BOOST_AUTO_TEST_CASE(GRUBatchSizeTest)
{
BatchSizeTest<GRU<>>();
}
/**
* Make sure the RNN can be properly serialized.
*/
+2 -2
View File
@@ -79,10 +79,10 @@ BOOST_AUTO_TEST_CASE(LogisticRegressionTest)
// Ensure that the error is close to zero.
const double acc = lr.ComputeAccuracy(data, responses);
BOOST_REQUIRE_CLOSE(acc, 100.0, 0.3); // 0.3% error tolerance.
BOOST_REQUIRE_CLOSE(acc, 100.0, 0.5); // 0.5% error tolerance.
const double testAcc = lr.ComputeAccuracy(testData, testResponses);
BOOST_REQUIRE_CLOSE(testAcc, 100.0, 0.6); // 0.6% error tolerance.
BOOST_REQUIRE_CLOSE(testAcc, 100.0, 0.8); // 0.8% error tolerance.
}
}
+1 -1
View File
@@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(SVDBatchMomentumTest)
const double momentumRMSE = amf2.Apply(cleanedData, 2, m1, m2);
BOOST_REQUIRE_LE(momentumRMSE, regularRMSE + 0.05);
BOOST_REQUIRE_LE(momentumRMSE, regularRMSE + 0.08);
}
/**