From c3c71cfb9bc6b137bd7b9c5bd87047016d0b1a33 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Sat, 11 Nov 2017 23:04:49 +0100 Subject: [PATCH 001/113] Add Booth, Colville, Matyas, McCormick, Rastrigin, Sphere and Styblinski test function. --- .../core/optimizers/problems/CMakeLists.txt | 23 +++++ .../optimizers/problems/booth_function.cpp | 48 ++++++++++ .../optimizers/problems/booth_function.hpp | 77 ++++++++++++++++ .../optimizers/problems/colville_function.cpp | 56 ++++++++++++ .../optimizers/problems/colville_function.hpp | 78 ++++++++++++++++ .../optimizers/problems/matyas_function.cpp | 48 ++++++++++ .../optimizers/problems/matyas_function.hpp | 77 ++++++++++++++++ .../problems/mc_cormick_function.cpp | 48 ++++++++++ .../problems/mc_cormick_function.hpp | 77 ++++++++++++++++ .../problems/rastrigin_function.cpp | 68 ++++++++++++++ .../problems/rastrigin_function.hpp | 89 ++++++++++++++++++ .../optimizers/problems/sphere_function.cpp | 66 ++++++++++++++ .../optimizers/problems/sphere_function.hpp | 90 ++++++++++++++++++ .../problems/styblinski_tang_function.cpp | 62 +++++++++++++ .../problems/styblinski_tang_function.hpp | 91 +++++++++++++++++++ 15 files changed, 998 insertions(+) create mode 100644 src/mlpack/core/optimizers/problems/CMakeLists.txt create mode 100644 src/mlpack/core/optimizers/problems/booth_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/booth_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/colville_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/colville_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/matyas_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/matyas_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/mc_cormick_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/mc_cormick_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/rastrigin_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/rastrigin_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/sphere_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/sphere_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/styblinski_tang_function.hpp diff --git a/src/mlpack/core/optimizers/problems/CMakeLists.txt b/src/mlpack/core/optimizers/problems/CMakeLists.txt new file mode 100644 index 0000000000..ee14ded0d8 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/CMakeLists.txt @@ -0,0 +1,23 @@ +set(SOURCES + booth_function.hpp + booth_function.cpp + colville_function.hpp + colville_function.cpp + matyas_function.hpp + matyas_function.cpp + mc_cormick_function.hpp + mc_cormick_function.cpp + rastrigin_function.hpp + rastrigin_function.cpp + sphere_function.hpp + sphere_function.cpp + styblinski_tang_function.hpp + styblinski_tang_function.cpp +) + +set(DIR_SRCS) +foreach(file ${SOURCES}) + set(DIR_SRCS ${DIR_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${file}) +endforeach() + +set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) diff --git a/src/mlpack/core/optimizers/problems/booth_function.cpp b/src/mlpack/core/optimizers/problems/booth_function.cpp new file mode 100644 index 0000000000..1db6d8f1af --- /dev/null +++ b/src/mlpack/core/optimizers/problems/booth_function.cpp @@ -0,0 +1,48 @@ +/** + * @file booth_function.cpp + * @author Marcus Edel + * + * Implementation of the Booth function. + * + * 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. + */ +#include "booth_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +BoothFunction::BoothFunction() { /* Nothing to do here */ } + +void BoothFunction::Shuffle() { /* Nothing to do here */ } + +double BoothFunction::Evaluate(const arma::mat& coordinates, + const size_t /* begin */, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + const double objective = std::pow(x1 + 2 * x2 - 7, 2) + + std::pow(2 * x1 + x2 - 5, 2); + + return objective; +} + +void BoothFunction::Gradient(const arma::mat& coordinates, + const size_t /* begin */, + arma::mat& gradient, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + gradient.set_size(2, 1); + gradient(0) = 10 * x1 + 8 * x2 - 34; + gradient(1) = 8 * x1 + 10 * x2 - 38; +} diff --git a/src/mlpack/core/optimizers/problems/booth_function.hpp b/src/mlpack/core/optimizers/problems/booth_function.hpp new file mode 100644 index 0000000000..a67e3198eb --- /dev/null +++ b/src/mlpack/core/optimizers/problems/booth_function.hpp @@ -0,0 +1,77 @@ +/** + * @file booth_function.hpp + * @author Marcus Edel + * + * Definition of the Booth function. + * + * 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_PROBLEMS_BOOTH_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_BOOTH_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Booth function, defined by + * + * \f[ + * f(x) = (x_1 + 2x_2 - 7)^2 + (2x_1 + x_2 - 5)^2 + * \f] + * + * This should optimize to f(x) = 0, at x = [1, 3]. + * + * For more information, please refer to: + * + * @code + * @article{Jamil2013, + * title = {A Literature Survey of Benchmark Functions For Global + * Optimization Problems}, + * author = {Momin Jamil and Xin{-}She Yang}, + * journal = {CoRR}, + * year = {2013}, + * url = {http://arxiv.org/abs/1308.4008} + * } + * @endcode + */ +class BoothFunction +{ + public: + //! Initialize the BoothFunction. + BoothFunction(); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return 1; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return arma::mat("-5; 3"); } + + //! Evaluate a function for a particular batch-size + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + //! Evaluate the gradient of a function for a particular batch-size + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_BOOTH_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/colville_function.cpp b/src/mlpack/core/optimizers/problems/colville_function.cpp new file mode 100644 index 0000000000..8598bf2ff9 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/colville_function.cpp @@ -0,0 +1,56 @@ +/** + * @file colville_function.cpp + * @author Marcus Edel + * + * Implementation of the Coville function. + * + * 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. + */ +#include "colville_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +ColvilleFunction::ColvilleFunction() { /* Nothing to do here */ } + +void ColvilleFunction::Shuffle() { /* Nothing to do here */ } + +double ColvilleFunction::Evaluate(const arma::mat& coordinates, + const size_t /* begin */, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + const double x3 = coordinates(2); + const double x4 = coordinates(3); + + const double objective = 100 * std::pow(std::pow(x1, 2) - x2, 2) + + std::pow(x1 - 1, 2) + std::pow(x3 - 1, 2) + 90 * + std::pow(std::pow(x3, 2) - x4, 2) + 10.1 * (std::pow(x2 - 1, 2) + + std::pow(x4 - 1, 2)) + 19.8 * (x2 - 1) * (x4 - 1); + + return objective; +} + +void ColvilleFunction::Gradient(const arma::mat& coordinates, + const size_t /* begin */, + arma::mat& gradient, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + const double x3 = coordinates(2); + const double x4 = coordinates(3); + + gradient.set_size(4, 1); + gradient(0) = 2 * (200 * x1 * (std::pow(x1, 2) - x2) + x1 - 1); + gradient(1) = 19.8 * x4 - 200 * std::pow(x1, 2) + 220.2 * x2 - 40; + gradient(2) = 2 * (180 * x3 * (std::pow(x3, 2) - x4) + x3 - 1); + gradient(3) = 200.2 * x4 + 19.8 * x2 - 180 * std::pow(x3, 2) - 40; +} diff --git a/src/mlpack/core/optimizers/problems/colville_function.hpp b/src/mlpack/core/optimizers/problems/colville_function.hpp new file mode 100644 index 0000000000..4fc74836f9 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/colville_function.hpp @@ -0,0 +1,78 @@ +/** + * @file colville_function.hpp + * @author Marcus Edel + * + * Definition of the Colville function. + * + * 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_PROBLEMS_COLVILLE_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_COLVILLE_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Colville function, defined by + * + * \f[ + * f(x) = 100(x_1^2 - x_2)^2 + (x_1 - 1)^2 + (x_3 - 1)^2 + 90 * (x_3^2 - x_4)^2 + * + 10.1 * ((x_2-1)^2 + (x_4 - 1)^2) + 19.8 * (x_2 - 1) * (x_4 - 1) + * \f] + * + * This should optimize to f(x) = 0, at x = [1, 1, 1, 1]. + * + * For more information, please refer to: + * + * @code + * @article{Jamil2013, + * title = {A Literature Survey of Benchmark Functions For Global + * Optimization Problems}, + * author = {Momin Jamil and Xin{-}She Yang}, + * journal = {CoRR}, + * year = {2013}, + * url = {http://arxiv.org/abs/1308.4008} + * } + * @endcode + */ +class ColvilleFunction +{ + public: + //! Initialize the ColvilleFunction. + ColvilleFunction(); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return 4; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return arma::mat("-5; 3; 1; -9"); } + + //! Evaluate a function for a particular batch-size + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + //! Evaluate the gradient of a function for a particular batch-size + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_COLVILLE_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/matyas_function.cpp b/src/mlpack/core/optimizers/problems/matyas_function.cpp new file mode 100644 index 0000000000..21c84e4916 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/matyas_function.cpp @@ -0,0 +1,48 @@ +/** + * @file matyas_function.cpp + * @author Marcus Edel + * + * Implementation of the Matyas function. + * + * 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. + */ +#include "matyas_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +MatyasFunction::MatyasFunction() { /* Nothing to do here */ } + +void MatyasFunction::Shuffle() { /* Nothing to do here */ } + +double MatyasFunction::Evaluate(const arma::mat& coordinates, + const size_t /* begin */, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + const double objective = 0.26 * (pow(x1, 2) + std::pow(x2, 2)) - + 0.48 * x1 * x2; + + return objective; +} + +void MatyasFunction::Gradient(const arma::mat& coordinates, + const size_t /* begin */, + arma::mat& gradient, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + gradient.set_size(2, 1); + gradient(0) = 0.52 * x1 - 48 * x2; + gradient(1) = 0.52 * x2 - 0.48 * x1; +} diff --git a/src/mlpack/core/optimizers/problems/matyas_function.hpp b/src/mlpack/core/optimizers/problems/matyas_function.hpp new file mode 100644 index 0000000000..1a13c4f63c --- /dev/null +++ b/src/mlpack/core/optimizers/problems/matyas_function.hpp @@ -0,0 +1,77 @@ +/** + * @file matyas_function.hpp + * @author Marcus Edel + * + * Definition of the Matyas function. + * + * 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_PROBLEMS_MATYAS_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_MATYAS_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Matyas function, defined by + * + * \f[ + * f(x) = 0.26 * (x_1^2 + x_2^2) - 0.48 * x_1 * x_2 + * \f] + * + * This should optimize to f(x) = 0, at x = [0, 0]. + * + * For more information, please refer to: + * + * @code + * @article{Jamil2013, + * title = {A Literature Survey of Benchmark Functions For Global + * Optimization Problems}, + * author = {Momin Jamil and Xin{-}She Yang}, + * journal = {CoRR}, + * year = {2013}, + * url = {http://arxiv.org/abs/1308.4008} + * } + * @endcode + */ +class MatyasFunction +{ + public: + //! Initialize the MatyasFunction. + MatyasFunction(); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return 1; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return arma::mat("-3; 3"); } + + //! Evaluate a function for a particular batch-size + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + //! Evaluate the gradient of a function for a particular batch-size + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_MATYAS_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/mc_cormick_function.cpp b/src/mlpack/core/optimizers/problems/mc_cormick_function.cpp new file mode 100644 index 0000000000..0c46d091b6 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/mc_cormick_function.cpp @@ -0,0 +1,48 @@ +/** + * @file mc_cormick_function.cpp + * @author Marcus Edel + * + * Implementation of the McCormick function. + * + * 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. + */ +#include "mc_cormick_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +McCormickFunction::McCormickFunction() { /* Nothing to do here */ } + +void McCormickFunction::Shuffle() { /* Nothing to do here */ } + +double McCormickFunction::Evaluate(const arma::mat& coordinates, + const size_t /* begin */, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + const double objective = std::sin(x1 + x2) + std::pow(x1 - x2, 2) - + 1.5 * x1 + 2.5 * x2 + 1; + + return objective; +} + +void McCormickFunction::Gradient(const arma::mat& coordinates, + const size_t /* begin */, + arma::mat& gradient, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + gradient.set_size(2, 1); + gradient(0) = std::cos(x1 + x2) + 2 * x1 - 2 * x2 - 1.5; + gradient(1) = std::cos(x1 + x2) - 2 * x1 + 2 * x2 + 2.5; +} diff --git a/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp b/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp new file mode 100644 index 0000000000..76bacba9ac --- /dev/null +++ b/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp @@ -0,0 +1,77 @@ +/** + * @file mc_cormick_function.hpp + * @author Marcus Edel + * + * Definition of the McCormick function. + * + * 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_PROBLEMS_MC_CORMICK_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_MC_CORMICK_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The McCormick function, defined by + * + * \f[ + * f(x) = \sin(x_1 + x_2) + (x_1 - x_2)^2 - 1.5 * x_1 + 2.5 * x_2 + 1 + * \f] + * + * This should optimize to f(x) = -1.9133, at x = [-0.54719, -1.54719]. + * + * For more information, please refer to: + * + * @code + * @article{Jamil2013, + * title = {A Literature Survey of Benchmark Functions For Global + * Optimization Problems}, + * author = {Momin Jamil and Xin{-}She Yang}, + * journal = {CoRR}, + * year = {2013}, + * url = {http://arxiv.org/abs/1308.4008} + * } + * @endcode + */ +class McCormickFunction +{ + public: + //! Initialize the McCormickFunction. + McCormickFunction(); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return 1; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return arma::mat("-1; 2"); } + + //! Evaluate a function for a particular batch-size + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + //! Evaluate the gradient of a function for a particular batch-size + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_MC_CORMICK_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/rastrigin_function.cpp b/src/mlpack/core/optimizers/problems/rastrigin_function.cpp new file mode 100644 index 0000000000..75d3830bd5 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/rastrigin_function.cpp @@ -0,0 +1,68 @@ +/** + * @file rastrigin_function.cpp + * @author Marcus Edel + * + * Implementation of the Rastrigin function. + * + * 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. + */ +#include "rastrigin_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +RastriginFunction::RastriginFunction(const size_t n) : + n(n), + visitationOrder(arma::linspace >(0, n - 1, n)) + +{ + initialPoint.set_size(n, 1); + for (size_t i = 0; i < n; ++i) // Set to [4.13 -4.15 4.13 -4.15...]. + { + if (i % 2 == 1) + initialPoint(i) = -4.15; + else + initialPoint(i) = 4.13; + } +} + +void RastriginFunction::Shuffle() +{ + visitationOrder = arma::shuffle( + arma::linspace >(0, n - 1, n)); +} + +double RastriginFunction::Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const +{ + double objective = 0.0; + for (size_t j = begin; j < begin + batchSize; ++j) + { + const size_t p = visitationOrder[j]; + objective += std::pow(coordinates(p), 2) - 10.0 * + std::cos(2.0 * M_PI * coordinates(p)); + } + objective *= 10.0 * n; + + return objective; +} + +void RastriginFunction::Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const +{ + gradient.zeros(n, 1); + + for (size_t j = begin; j < begin + batchSize; ++j) + { + const size_t p = visitationOrder[j]; + gradient(p) += (10.0 * n) * (2 * (coordinates(p) + 10.0 * M_PI * + std::sin(2.0 * M_PI * coordinates(p)))); + } +} diff --git a/src/mlpack/core/optimizers/problems/rastrigin_function.hpp b/src/mlpack/core/optimizers/problems/rastrigin_function.hpp new file mode 100644 index 0000000000..9be30d24f8 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/rastrigin_function.hpp @@ -0,0 +1,89 @@ +/** + * @file rastrigin_function.hpp + * @author Marcus Edel + * + * Definition of the Rastrigin function. + * + * 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_PROBLEMS_RASTRIGIN_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_RASTRIGIN_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Rastrigin function, defined by + * + * \f[ + * f(x) = 10 * d * \sum_{i=1}^{d} x_i^2 - 10 * \cos(2 * \pi * x_i) + * \f] + * + * This should optimize to f(x) = 0 + * at x = [0, ..., 0]. + * + * For more information, please refer to: + * + * @code + * @article{Jamil2013, + * title = {Systems of extremal control}, + * author = {Rastrigin, L. A.}, + * journal = {Mir}, + * year = {1974} + * } + * @endcode + */ +class RastriginFunction +{ + public: + /* + * Initialize the RastriginFunction. + * + * @param n Number of dimensions for the function. + */ + RastriginFunction(const size_t n); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return n; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return initialPoint; } + + //! Evaluate a function for a particular batch-size + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + //! Evaluate the gradient of a function for a particular batch-size + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; + private: + //! Number of dimensions for the function. + size_t n; + + //! For shuffling. + arma::Row visitationOrder; + + //! Initial starting point. + arma::mat initialPoint; +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_RASTRIGIN_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/sphere_function.cpp b/src/mlpack/core/optimizers/problems/sphere_function.cpp new file mode 100644 index 0000000000..73561e375c --- /dev/null +++ b/src/mlpack/core/optimizers/problems/sphere_function.cpp @@ -0,0 +1,66 @@ +/** + * @file sphere_function.cpp + * @author Marcus Edel + * + * Implementation of the Sphere function. + * + * 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. + */ +#include "sphere_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +SphereFunction::SphereFunction(const size_t n) : + n(n), + visitationOrder(arma::linspace >(0, n - 1, n)) + +{ + initialPoint.set_size(n, 1); + + for (size_t i = 0; i < n; ++i) // Set to [-3.12 3.33 -3.12 3.33...]. + { + if (i % 2 == 1) + initialPoint(i) = 3.33; + else + initialPoint(i) = -3.12; + } +} + +void SphereFunction::Shuffle() +{ + visitationOrder = arma::shuffle( + arma::linspace >(0, n - 1, n)); +} + +double SphereFunction::Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const +{ + double objective = 0.0; + for (size_t j = begin; j < begin + batchSize; ++j) + { + const size_t p = visitationOrder[j]; + objective += std::pow(coordinates(p), 2); + } + + return objective; +} + +void SphereFunction::Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const +{ + gradient.zeros(n, 1); + + for (size_t j = begin; j < begin + batchSize; ++j) + { + const size_t p = visitationOrder[j]; + gradient(p) += 2.0 * coordinates[p]; + } +} diff --git a/src/mlpack/core/optimizers/problems/sphere_function.hpp b/src/mlpack/core/optimizers/problems/sphere_function.hpp new file mode 100644 index 0000000000..a7b9742fb5 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/sphere_function.hpp @@ -0,0 +1,90 @@ +/** + * @file sphere_function.hpp + * @author Marcus Edel + * + * Definition of the Sphere function. + * + * 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_PROBLEMS_SPHERE_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_SPHERE_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Sphere function, defined by + * + * \f[ + * f(x) = x^2 + * \f] + * + * This should optimize to f(x) = 0, at x = [0, ..., 0]. + * + * For more information, please refer to: + * + * @code + * @article{Jamil2013, + * title = {A Literature Survey of Benchmark Functions For Global + * Optimization Problems}, + * author = {Momin Jamil and Xin{-}She Yang}, + * journal = {CoRR}, + * year = {2013}, + * url = {http://arxiv.org/abs/1308.4008} + * } + * @endcode + */ +class SphereFunction +{ + public: + /* + * Initialize the SphereFunction. + * + * @param n Number of dimensions for the function. + */ + SphereFunction(const size_t n); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return n; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return initialPoint; } + + //! Evaluate a function for a particular batch-size + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + //! Evaluate the gradient of a function for a particular batch-size + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; + private: + //! Number of dimensions for the function. + size_t n; + + //! For shuffling. + arma::Row visitationOrder; + + //! Initial starting point. + arma::mat initialPoint; +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_SPHERE_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp b/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp new file mode 100644 index 0000000000..515089160b --- /dev/null +++ b/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp @@ -0,0 +1,62 @@ +/** + * @file styblinski_tang_function.cpp + * @author Marcus Edel + * + * Implementation of the Styblinski-Tang function. + * + * 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. + */ +#include "styblinski_tang_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +StyblinskiTangFunction::StyblinskiTangFunction(const size_t n) : + n(n), + visitationOrder(arma::linspace >(0, n - 1, n)) + +{ + initialPoint.set_size(n, 1); + initialPoint.fill(-4); +} + +void StyblinskiTangFunction::Shuffle() +{ + visitationOrder = arma::shuffle( + arma::linspace >(0, n - 1, n)); +} + +double StyblinskiTangFunction::Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const +{ + double objective = 0.0; + for (size_t j = begin; j < begin + batchSize; ++j) + { + const size_t p = visitationOrder[j]; + objective += std::pow(coordinates(p), 4) - 16 * + std::pow(coordinates(p), 2) + 5 * coordinates(p); + } + objective /= 2; + + return objective; +} + +void StyblinskiTangFunction::Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const +{ + gradient.zeros(n, 1); + + for (size_t j = begin; j < begin + batchSize; ++j) + { + const size_t p = visitationOrder[j]; + gradient(p) += 0.5 * (4 * std::pow(coordinates(p), 3) - + 32.0 * coordinates(p) + 5.0); + } +} diff --git a/src/mlpack/core/optimizers/problems/styblinski_tang_function.hpp b/src/mlpack/core/optimizers/problems/styblinski_tang_function.hpp new file mode 100644 index 0000000000..e5e9f145e4 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/styblinski_tang_function.hpp @@ -0,0 +1,91 @@ +/** + * @file styblinski_tang_function.hpp + * @author Marcus Edel + * + * Definition of the Styblinski-Tang function. + * + * 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_PROBLEMS_STYBLINSKI_TANG_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_STYBLINSKI_TANG_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Styblinski-Tang function, defined by + * + * \f[ + * f(x) = 0.5 * \sum_{i=1}^{d} x_i^4 - 16_i^2+5x_i + * \f] + * + * This should optimize to f(x) = -39.16599 * d + * at x = [-2.903534, ..., -2.903534]. + * + * For more information, please refer to: + * + * @code + * @article{Jamil2013, + * title = {A Literature Survey of Benchmark Functions For Global + * Optimization Problems}, + * author = {Momin Jamil and Xin{-}She Yang}, + * journal = {CoRR}, + * year = {2013}, + * url = {http://arxiv.org/abs/1308.4008} + * } + * @endcode + */ +class StyblinskiTangFunction +{ + public: + /* + * Initialize the StyblinskiTangFunction. + * + * @param n Number of dimensions for the function. + */ + StyblinskiTangFunction(const size_t n); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return n; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return initialPoint; } + + //! Evaluate a function for a particular batch-size + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + //! Evaluate the gradient of a function for a particular batch-size + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; + private: + //! Number of dimensions for the function. + size_t n; + + //! For shuffling. + arma::Row visitationOrder; + + //! Initial starting point. + arma::mat initialPoint; +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_STYBLINSKI_TANG_FUNCTION_HPP From 62374060d83735c53f3ad50e8db98bbdb0687a67 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Mon, 13 Nov 2017 22:55:40 +0100 Subject: [PATCH 002/113] Add Evaluate(const arma::mat& coordinates) and Gradient(const arma::mat& coordinates, arma::mat& gradient) interface. --- src/mlpack/core/optimizers/CMakeLists.txt | 1 + .../core/optimizers/problems/CMakeLists.txt | 10 ++++++ .../optimizers/problems/booth_function.cpp | 10 ++++++ .../optimizers/problems/booth_function.hpp | 32 +++++++++++++++-- .../optimizers/problems/colville_function.cpp | 17 ++++++++-- .../optimizers/problems/colville_function.hpp | 32 +++++++++++++++-- .../optimizers/problems/matyas_function.cpp | 10 ++++++ .../optimizers/problems/matyas_function.hpp | 32 +++++++++++++++-- .../problems/mc_cormick_function.cpp | 11 ++++++ .../problems/mc_cormick_function.hpp | 32 +++++++++++++++-- .../problems/rastrigin_function.cpp | 11 ++++++ .../problems/rastrigin_function.hpp | 32 +++++++++++++++-- .../optimizers/problems/sphere_function.cpp | 10 ++++++ .../optimizers/problems/sphere_function.hpp | 34 +++++++++++++++++-- .../problems/styblinski_tang_function.cpp | 11 ++++++ .../problems/styblinski_tang_function.hpp | 32 +++++++++++++++-- 16 files changed, 299 insertions(+), 18 deletions(-) diff --git a/src/mlpack/core/optimizers/CMakeLists.txt b/src/mlpack/core/optimizers/CMakeLists.txt index 1dd8bb4e51..eff611f365 100644 --- a/src/mlpack/core/optimizers/CMakeLists.txt +++ b/src/mlpack/core/optimizers/CMakeLists.txt @@ -11,6 +11,7 @@ set(DIRS iqn lbfgs line_search + problems proximal rmsprop sa diff --git a/src/mlpack/core/optimizers/problems/CMakeLists.txt b/src/mlpack/core/optimizers/problems/CMakeLists.txt index ee14ded0d8..654bf757bc 100644 --- a/src/mlpack/core/optimizers/problems/CMakeLists.txt +++ b/src/mlpack/core/optimizers/problems/CMakeLists.txt @@ -1,14 +1,24 @@ set(SOURCES booth_function.hpp booth_function.cpp + bukin_function.hpp + bukin_function.cpp colville_function.hpp colville_function.cpp + drop_wave_function.hpp + drop_wave_function.cpp + easom_function.hpp + easom_function.cpp + eggholder_function.hpp + eggholder_function.cpp matyas_function.hpp matyas_function.cpp mc_cormick_function.hpp mc_cormick_function.cpp rastrigin_function.hpp rastrigin_function.cpp + schwefel_function.hpp + schwefel_function.cpp sphere_function.hpp sphere_function.cpp styblinski_tang_function.hpp diff --git a/src/mlpack/core/optimizers/problems/booth_function.cpp b/src/mlpack/core/optimizers/problems/booth_function.cpp index 1db6d8f1af..95759b1dae 100644 --- a/src/mlpack/core/optimizers/problems/booth_function.cpp +++ b/src/mlpack/core/optimizers/problems/booth_function.cpp @@ -33,6 +33,11 @@ double BoothFunction::Evaluate(const arma::mat& coordinates, return objective; } +double BoothFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, 1); +} + void BoothFunction::Gradient(const arma::mat& coordinates, const size_t /* begin */, arma::mat& gradient, @@ -46,3 +51,8 @@ void BoothFunction::Gradient(const arma::mat& coordinates, gradient(0) = 10 * x1 + 8 * x2 - 34; gradient(1) = 8 * x1 + 10 * x2 - 38; } + +void BoothFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, 1); +} diff --git a/src/mlpack/core/optimizers/problems/booth_function.hpp b/src/mlpack/core/optimizers/problems/booth_function.hpp index a67e3198eb..1c2f90ad0e 100644 --- a/src/mlpack/core/optimizers/problems/booth_function.hpp +++ b/src/mlpack/core/optimizers/problems/booth_function.hpp @@ -58,16 +58,44 @@ class BoothFunction //! Get the starting point. arma::mat GetInitialPoint() const { return arma::mat("-5; 3"); } - //! Evaluate a function for a particular batch-size + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ double Evaluate(const arma::mat& coordinates, const size_t begin, const size_t batchSize) const; - //! Evaluate the gradient of a function for a particular batch-size + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ void Gradient(const arma::mat& coordinates, const size_t begin, arma::mat& gradient, const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); }; } // namespace test diff --git a/src/mlpack/core/optimizers/problems/colville_function.cpp b/src/mlpack/core/optimizers/problems/colville_function.cpp index 8598bf2ff9..96e4509014 100644 --- a/src/mlpack/core/optimizers/problems/colville_function.cpp +++ b/src/mlpack/core/optimizers/problems/colville_function.cpp @@ -37,10 +37,15 @@ double ColvilleFunction::Evaluate(const arma::mat& coordinates, return objective; } +double ColvilleFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, 1); +} + void ColvilleFunction::Gradient(const arma::mat& coordinates, - const size_t /* begin */, - arma::mat& gradient, - const size_t /* batchSize */) const + const size_t /* begin */, + arma::mat& gradient, + const size_t /* batchSize */) const { // For convenience; we assume these temporaries will be optimized out. const double x1 = coordinates(0); @@ -54,3 +59,9 @@ void ColvilleFunction::Gradient(const arma::mat& coordinates, gradient(2) = 2 * (180 * x3 * (std::pow(x3, 2) - x4) + x3 - 1); gradient(3) = 200.2 * x4 + 19.8 * x2 - 180 * std::pow(x3, 2) - 40; } + +void ColvilleFunction::Gradient(const arma::mat& coordinates, + arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, 1); +} diff --git a/src/mlpack/core/optimizers/problems/colville_function.hpp b/src/mlpack/core/optimizers/problems/colville_function.hpp index 4fc74836f9..34b328924e 100644 --- a/src/mlpack/core/optimizers/problems/colville_function.hpp +++ b/src/mlpack/core/optimizers/problems/colville_function.hpp @@ -59,16 +59,44 @@ class ColvilleFunction //! Get the starting point. arma::mat GetInitialPoint() const { return arma::mat("-5; 3; 1; -9"); } - //! Evaluate a function for a particular batch-size + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ double Evaluate(const arma::mat& coordinates, const size_t begin, const size_t batchSize) const; - //! Evaluate the gradient of a function for a particular batch-size + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ void Gradient(const arma::mat& coordinates, const size_t begin, arma::mat& gradient, const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); }; } // namespace test diff --git a/src/mlpack/core/optimizers/problems/matyas_function.cpp b/src/mlpack/core/optimizers/problems/matyas_function.cpp index 21c84e4916..bfe93fa42b 100644 --- a/src/mlpack/core/optimizers/problems/matyas_function.cpp +++ b/src/mlpack/core/optimizers/problems/matyas_function.cpp @@ -33,6 +33,11 @@ double MatyasFunction::Evaluate(const arma::mat& coordinates, return objective; } +double MatyasFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, 1); +} + void MatyasFunction::Gradient(const arma::mat& coordinates, const size_t /* begin */, arma::mat& gradient, @@ -46,3 +51,8 @@ void MatyasFunction::Gradient(const arma::mat& coordinates, gradient(0) = 0.52 * x1 - 48 * x2; gradient(1) = 0.52 * x2 - 0.48 * x1; } + +void MatyasFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, 1); +} diff --git a/src/mlpack/core/optimizers/problems/matyas_function.hpp b/src/mlpack/core/optimizers/problems/matyas_function.hpp index 1a13c4f63c..979e69119e 100644 --- a/src/mlpack/core/optimizers/problems/matyas_function.hpp +++ b/src/mlpack/core/optimizers/problems/matyas_function.hpp @@ -58,16 +58,44 @@ class MatyasFunction //! Get the starting point. arma::mat GetInitialPoint() const { return arma::mat("-3; 3"); } - //! Evaluate a function for a particular batch-size + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ double Evaluate(const arma::mat& coordinates, const size_t begin, const size_t batchSize) const; - //! Evaluate the gradient of a function for a particular batch-size + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ void Gradient(const arma::mat& coordinates, const size_t begin, arma::mat& gradient, const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); }; } // namespace test diff --git a/src/mlpack/core/optimizers/problems/mc_cormick_function.cpp b/src/mlpack/core/optimizers/problems/mc_cormick_function.cpp index 0c46d091b6..330c3bef99 100644 --- a/src/mlpack/core/optimizers/problems/mc_cormick_function.cpp +++ b/src/mlpack/core/optimizers/problems/mc_cormick_function.cpp @@ -33,6 +33,11 @@ double McCormickFunction::Evaluate(const arma::mat& coordinates, return objective; } +double McCormickFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, 1); +} + void McCormickFunction::Gradient(const arma::mat& coordinates, const size_t /* begin */, arma::mat& gradient, @@ -46,3 +51,9 @@ void McCormickFunction::Gradient(const arma::mat& coordinates, gradient(0) = std::cos(x1 + x2) + 2 * x1 - 2 * x2 - 1.5; gradient(1) = std::cos(x1 + x2) - 2 * x1 + 2 * x2 + 2.5; } + +void McCormickFunction::Gradient(const arma::mat& coordinates, + arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, 1); +} diff --git a/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp b/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp index 76bacba9ac..e98d506076 100644 --- a/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp +++ b/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp @@ -58,16 +58,44 @@ class McCormickFunction //! Get the starting point. arma::mat GetInitialPoint() const { return arma::mat("-1; 2"); } - //! Evaluate a function for a particular batch-size + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ double Evaluate(const arma::mat& coordinates, const size_t begin, const size_t batchSize) const; - //! Evaluate the gradient of a function for a particular batch-size + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ void Gradient(const arma::mat& coordinates, const size_t begin, arma::mat& gradient, const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); }; } // namespace test diff --git a/src/mlpack/core/optimizers/problems/rastrigin_function.cpp b/src/mlpack/core/optimizers/problems/rastrigin_function.cpp index 75d3830bd5..745cb1638d 100644 --- a/src/mlpack/core/optimizers/problems/rastrigin_function.cpp +++ b/src/mlpack/core/optimizers/problems/rastrigin_function.cpp @@ -52,6 +52,11 @@ double RastriginFunction::Evaluate(const arma::mat& coordinates, return objective; } +double RastriginFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, NumFunctions()); +} + void RastriginFunction::Gradient(const arma::mat& coordinates, const size_t begin, arma::mat& gradient, @@ -66,3 +71,9 @@ void RastriginFunction::Gradient(const arma::mat& coordinates, std::sin(2.0 * M_PI * coordinates(p)))); } } + +void RastriginFunction::Gradient(const arma::mat& coordinates, + arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, NumFunctions()); +} diff --git a/src/mlpack/core/optimizers/problems/rastrigin_function.hpp b/src/mlpack/core/optimizers/problems/rastrigin_function.hpp index 9be30d24f8..a062724a9a 100644 --- a/src/mlpack/core/optimizers/problems/rastrigin_function.hpp +++ b/src/mlpack/core/optimizers/problems/rastrigin_function.hpp @@ -61,16 +61,44 @@ class RastriginFunction //! Get the starting point. arma::mat GetInitialPoint() const { return initialPoint; } - //! Evaluate a function for a particular batch-size + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ double Evaluate(const arma::mat& coordinates, const size_t begin, const size_t batchSize) const; - //! Evaluate the gradient of a function for a particular batch-size + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ void Gradient(const arma::mat& coordinates, const size_t begin, arma::mat& gradient, const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); private: //! Number of dimensions for the function. size_t n; diff --git a/src/mlpack/core/optimizers/problems/sphere_function.cpp b/src/mlpack/core/optimizers/problems/sphere_function.cpp index 73561e375c..dd2f64cb6c 100644 --- a/src/mlpack/core/optimizers/problems/sphere_function.cpp +++ b/src/mlpack/core/optimizers/problems/sphere_function.cpp @@ -51,6 +51,11 @@ double SphereFunction::Evaluate(const arma::mat& coordinates, return objective; } +double SphereFunction::Evaluate(const arma::mat& coordinates) const +{ + Evaluate(coordinates, 0, NumFunctions()); +} + void SphereFunction::Gradient(const arma::mat& coordinates, const size_t begin, arma::mat& gradient, @@ -64,3 +69,8 @@ void SphereFunction::Gradient(const arma::mat& coordinates, gradient(p) += 2.0 * coordinates[p]; } } + +void SphereFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, 1); +} diff --git a/src/mlpack/core/optimizers/problems/sphere_function.hpp b/src/mlpack/core/optimizers/problems/sphere_function.hpp index a7b9742fb5..cdd172dde9 100644 --- a/src/mlpack/core/optimizers/problems/sphere_function.hpp +++ b/src/mlpack/core/optimizers/problems/sphere_function.hpp @@ -22,7 +22,7 @@ namespace test { * The Sphere function, defined by * * \f[ - * f(x) = x^2 + * f(x) = \sum_{i=1}^{d} x_i^2 * \f] * * This should optimize to f(x) = 0, at x = [0, ..., 0]. @@ -62,16 +62,44 @@ class SphereFunction //! Get the starting point. arma::mat GetInitialPoint() const { return initialPoint; } - //! Evaluate a function for a particular batch-size + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ double Evaluate(const arma::mat& coordinates, const size_t begin, const size_t batchSize) const; - //! Evaluate the gradient of a function for a particular batch-size + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ void Gradient(const arma::mat& coordinates, const size_t begin, arma::mat& gradient, const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); private: //! Number of dimensions for the function. size_t n; diff --git a/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp b/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp index 515089160b..fa6327160d 100644 --- a/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp +++ b/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp @@ -46,6 +46,11 @@ double StyblinskiTangFunction::Evaluate(const arma::mat& coordinates, return objective; } +double StyblinskiTangFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, 1); +} + void StyblinskiTangFunction::Gradient(const arma::mat& coordinates, const size_t begin, arma::mat& gradient, @@ -60,3 +65,9 @@ void StyblinskiTangFunction::Gradient(const arma::mat& coordinates, 32.0 * coordinates(p) + 5.0); } } + +void StyblinskiTangFunction::Gradient(const arma::mat& coordinates, + arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, 1); +} diff --git a/src/mlpack/core/optimizers/problems/styblinski_tang_function.hpp b/src/mlpack/core/optimizers/problems/styblinski_tang_function.hpp index e5e9f145e4..1dab305604 100644 --- a/src/mlpack/core/optimizers/problems/styblinski_tang_function.hpp +++ b/src/mlpack/core/optimizers/problems/styblinski_tang_function.hpp @@ -63,16 +63,44 @@ class StyblinskiTangFunction //! Get the starting point. arma::mat GetInitialPoint() const { return initialPoint; } - //! Evaluate a function for a particular batch-size + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ double Evaluate(const arma::mat& coordinates, const size_t begin, const size_t batchSize) const; - //! Evaluate the gradient of a function for a particular batch-size + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ void Gradient(const arma::mat& coordinates, const size_t begin, arma::mat& gradient, const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); private: //! Number of dimensions for the function. size_t n; From 8ce232a957a126ca419fd0efd83502290f20380b Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Tue, 14 Nov 2017 14:40:17 +0100 Subject: [PATCH 003/113] Add Bukin, DropWave, Easom, Eggholder, Schwefel test function. --- .../optimizers/problems/bukin_function.cpp | 51 ++++++++ .../optimizers/problems/bukin_function.hpp | 78 ++++++++++++ .../problems/drop_wave_function.cpp | 71 +++++++++++ .../problems/drop_wave_function.hpp | 105 ++++++++++++++++ .../optimizers/problems/easom_function.cpp | 67 ++++++++++ .../optimizers/problems/easom_function.hpp | 105 ++++++++++++++++ .../problems/eggholder_function.cpp | 71 +++++++++++ .../problems/eggholder_function.hpp | 106 ++++++++++++++++ .../optimizers/problems/schwefel_function.cpp | 74 +++++++++++ .../optimizers/problems/schwefel_function.hpp | 117 ++++++++++++++++++ 10 files changed, 845 insertions(+) create mode 100644 src/mlpack/core/optimizers/problems/bukin_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/bukin_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/drop_wave_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/drop_wave_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/easom_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/easom_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/eggholder_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/eggholder_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/schwefel_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/schwefel_function.hpp diff --git a/src/mlpack/core/optimizers/problems/bukin_function.cpp b/src/mlpack/core/optimizers/problems/bukin_function.cpp new file mode 100644 index 0000000000..77c5b94f01 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/bukin_function.cpp @@ -0,0 +1,51 @@ +/** + * @file bukin_function.cpp + * @author Marcus Edel + * + * Implementation of the Bukin function. + * + * 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. + */ +#include "bukin_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +BukinFunction::BukinFunction() { /* Nothing to do here */ } + +void BukinFunction::Shuffle() { /* Nothing to do here */ } + +double BukinFunction::Evaluate(const arma::mat& coordinates, + const size_t /* begin */, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + const double objective = 100 * std::sqrt(std::abs(x2 - 0.01 * + std::pow(x1, 2))) + 0.01 * std::abs(x1 + 10); + + return objective; +} + +void BukinFunction::Gradient(const arma::mat& coordinates, + const size_t /* begin */, + arma::mat& gradient, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + gradient.set_size(2, 1); + gradient(0) = (0.01 * (x1 + 10)) / std::abs(x1 + 10) - + (x1 * (x2 - 0.01 * std::pow(x2, 2))) / std::pow(std::abs(x2 - 0.01 * + std::pow(x2, 2)), 1.5); + gradient(1) = (50 * (x2 - 0.01 * std::pow(x1, 2))) / + std::pow(std::abs(x2 - 0.01 * std::pow(x1, 2)), 1.5); +} diff --git a/src/mlpack/core/optimizers/problems/bukin_function.hpp b/src/mlpack/core/optimizers/problems/bukin_function.hpp new file mode 100644 index 0000000000..5fc1491e0b --- /dev/null +++ b/src/mlpack/core/optimizers/problems/bukin_function.hpp @@ -0,0 +1,78 @@ +/** + * @file bukin_function.hpp + * @author Marcus Edel + * + * Definition of the Booth function. + * + * 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_PROBLEMS_BUKIN_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_BUKIN_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Bukin function, defined by + * + * \f[ + * f(x) = 100 * \sqrt(\left|x_2 - 0.01 * x_1^2 \right|) + + * 0.01 * \left|x_1 + 10 \right| + * \f] + * + * This should optimize to f(x) = 0, at x = [-10, 1]. + * + * For more information, please refer to: + * + * @code + * @article{Jamil2013, + * title = {A Literature Survey of Benchmark Functions For Global + * Optimization Problems}, + * author = {Momin Jamil and Xin{-}She Yang}, + * journal = {CoRR}, + * year = {2013}, + * url = {http://arxiv.org/abs/1308.4008} + * } + * @endcode + */ +class BukinFunction +{ + public: + //! Initialize the BukinFunction. + BukinFunction(); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return 1; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return arma::mat("-10; 2.0"); } + + //! Evaluate a function for a particular batch-size + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + //! Evaluate the gradient of a function for a particular batch-size + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_BUKIN_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/drop_wave_function.cpp b/src/mlpack/core/optimizers/problems/drop_wave_function.cpp new file mode 100644 index 0000000000..f69704468f --- /dev/null +++ b/src/mlpack/core/optimizers/problems/drop_wave_function.cpp @@ -0,0 +1,71 @@ +/** + * @file drop_wave_function.cpp + * @author Marcus Edel + * + * Implementation of the Drop-Wave function. + * + * 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. + */ +#include "drop_wave_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +DropWaveFunction::DropWaveFunction() { /* Nothing to do here */ } + +void DropWaveFunction::Shuffle() { /* Nothing to do here */ } + +double DropWaveFunction::Evaluate(const arma::mat& coordinates, + const size_t /* begin */, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + const double objective = -1.0 * (1.0 + std::cos(12.0 * + std::sqrt(std::pow(x1, 2) + std::pow(x2, 2)))) / + (0.5 * (std::pow(x1, 2) + std::pow(x2, 2)) + 2.0); + + return objective; +} + +double DropWaveFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, 1); +} + +void DropWaveFunction::Gradient(const arma::mat& coordinates, + const size_t /* begin */, + arma::mat& gradient, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + gradient.set_size(2, 1); + gradient(0) = (12.0 * x1 * std::sin(12.0 * std::sqrt(std::pow(x1, 2) + + std::pow(x2, 2)))) / (std::sqrt(std::pow(x1, 2) + std::pow(x2, 2)) * + (0.5 * (std::pow(x1, 2) + std::pow(x2, 2)) + 2)) - + (x1 * (-1.0 * std::cos(12.0 * std::sqrt(std::pow(x1, 2) + + std::pow(x2, 2))) -1.0)) / std::pow(0.5 * + (std::pow(x1, 2) + std::pow(x2, 2)) + 2, 2); + + gradient(1) = (12.0 * x2 * std::sin(12.0 * std::sqrt(std::pow(x1, 2) + + std::pow(x2, 2)))) / (std::sqrt(std::pow(x1, 2) + std::pow(x2, 2)) * + (0.5 * (std::pow(x1, 2) + std::pow(x2, 2)) + 2)) - + (x2 * (-1.0 * std::cos(12.0 * std::sqrt(std::pow(x1, 2) + + std::pow(x2, 2))) -1.0)) / std::pow(0.5 * + (std::pow(x1, 2) + std::pow(x2, 2)) + 2, 2); +} + +void DropWaveFunction::Gradient(const arma::mat& coordinates, + arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, 1); +} diff --git a/src/mlpack/core/optimizers/problems/drop_wave_function.hpp b/src/mlpack/core/optimizers/problems/drop_wave_function.hpp new file mode 100644 index 0000000000..e13ee71b56 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/drop_wave_function.hpp @@ -0,0 +1,105 @@ +/** + * @file drop_wave_function.hpp + * @author Marcus Edel + * + * Definition of the Drop-Wave function. + * + * 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_PROBLEMS_DROP_WAVE_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_DROP_WAVE_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Drop-Wave function, defined by + * + * \f[ + * f(x) = - (1 + \cos(12 * \sqrt(x_1^2 + x_2^2))) / (0.5 * (x_1^2 + x_2^2) + 2) + * \f] + * + * This should optimize to f(x) = 0, at x = [0, 0]. + * + * For more information, please refer to: + * + * @code + * @article{Jamil2013, + * title = {A Literature Survey of Benchmark Functions For Global + * Optimization Problems}, + * author = {Momin Jamil and Xin{-}She Yang}, + * journal = {CoRR}, + * year = {2013}, + * url = {http://arxiv.org/abs/1308.4008} + * } + * @endcode + */ +class DropWaveFunction +{ + public: + //! Initialize the DropWaveFunction. + DropWaveFunction(); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return 1; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return arma::mat("0.5; 0.5"); } + + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_DROP_WAVE_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/easom_function.cpp b/src/mlpack/core/optimizers/problems/easom_function.cpp new file mode 100644 index 0000000000..018ce1c0f9 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/easom_function.cpp @@ -0,0 +1,67 @@ +/** + * @file easom_function.cpp + * @author Marcus Edel + * + * Implementation of the Easom function. + * + * 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. + */ +#include "easom_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +EasomFunction::EasomFunction() { /* Nothing to do here */ } + +void EasomFunction::Shuffle() { /* Nothing to do here */ } + +double EasomFunction::Evaluate(const arma::mat& coordinates, + const size_t /* begin */, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + const double objective = -std::cos(x1) * std::cos(x2) * + std::exp(-1.0 * std::pow(x1 - M_PI, 2) - std::pow(x2 - M_PI, 2)); + + return objective; +} + +double EasomFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, 1); +} + +void EasomFunction::Gradient(const arma::mat& coordinates, + const size_t /* begin */, + arma::mat& gradient, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + gradient.set_size(2, 1); + gradient(0) = 2 * (x1 - M_PI) * + std::exp(-1.0 * std::pow(x1 - M_PI, 2) - std::pow(x2 - M_PI, 2)) * + std::cos(x1) * std::cos(x2) + + std::exp(-1.0 * std::pow(x1 - M_PI, 2) - std::pow(x2 - M_PI, 2)) * + std::sin(x1) * std::cos(x2); + + gradient(1) = 2 * (x2 - M_PI) * + std::exp(-1.0 * std::pow(x1 - M_PI, 2) - std::pow(x2 - M_PI, 2)) * + std::cos(x1) * std::cos(x2) + + std::exp(-1.0 * std::pow(x1 - M_PI, 2) - std::pow(x2 - M_PI, 2)) * + std::cos(x1) * std::sin(x2); +} + +void EasomFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, 1); +} diff --git a/src/mlpack/core/optimizers/problems/easom_function.hpp b/src/mlpack/core/optimizers/problems/easom_function.hpp new file mode 100644 index 0000000000..8043a92474 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/easom_function.hpp @@ -0,0 +1,105 @@ +/** + * @file easom_function.hpp + * @author Marcus Edel + * + * Definition of the Booth function. + * + * 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_PROBLEMS_EASOM_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_EASOM_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Easom function, defined by + * + * \f[ + * f(x) = -1.0 * \cos(x_1) * \cos(x_2) * \exp(-(x_1 - \pi)^2 - (x_2 - \pi)^2) + * \f] + * + * This should optimize to f(x) = -1, at x = [3.14, 3.14]. + * + * For more information, please refer to: + * + * @code + * @article{Jamil2013, + * title = {A Literature Survey of Benchmark Functions For Global + * Optimization Problems}, + * author = {Momin Jamil and Xin{-}She Yang}, + * journal = {CoRR}, + * year = {2013}, + * url = {http://arxiv.org/abs/1308.4008} + * } + * @endcode + */ +class EasomFunction +{ + public: + //! Initialize the EasomFunction. + EasomFunction(); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return 1; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return arma::mat("-90.0; 90.0"); } + + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_EASOM_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/eggholder_function.cpp b/src/mlpack/core/optimizers/problems/eggholder_function.cpp new file mode 100644 index 0000000000..783dd0276e --- /dev/null +++ b/src/mlpack/core/optimizers/problems/eggholder_function.cpp @@ -0,0 +1,71 @@ +/** + * @file eggholder_function.cpp + * @author Marcus Edel + * + * Implementation of the Eggholder function. + * + * 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. + */ +#include "eggholder_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +EggholderFunction::EggholderFunction() { /* Nothing to do here */ } + +void EggholderFunction::Shuffle() { /* Nothing to do here */ } + +double EggholderFunction::Evaluate(const arma::mat& coordinates, + const size_t /* begin */, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + const double objective = -1.0 * (x2 + 47) * std::sin(std::sqrt( + std::abs(x2 + x1 / 2 + 47))) - x1 * std::sin(std::sqrt( + std::abs(x1 - (x2 + 47)))); + + return objective; +} + +double EggholderFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, 1); +} + +void EggholderFunction::Gradient(const arma::mat& coordinates, + const size_t /* begin */, + arma::mat& gradient, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + gradient.set_size(2, 1); + gradient(0) = -1.0 * std::sin(std::sqrt(std::abs(x1 - x2 - 47))) - + (x1 * (x1 - x2 - 47) * std::cos(std::sqrt(std::abs(x1 - x2 - 47)))) / + std::pow(2 * std::abs(x1 - x2 - 47), 1.5) - + ((x1 + 47) * (x1 / 2 + x2 + 47) * + std::cos(std::sqrt(std::abs(x1 / 2 + x2 + 47)))) / + (4 * std::pow(std::abs(x1 / 2 + x2 + 47), 1.5)); + + gradient(1) = -1.0 * std::sin(std::sqrt(std::abs(x1 / 2 + x2 + 47))) - + (x1 * (x1 - x2 - 47) * std::cos(std::sqrt(std::abs(x1 - x2 - 47)))) / + std::pow(2 * std::abs(x1 - x2 - 47), 1.5) - + ((x1 + 47) * (x1 / 2 + x2 + 47) * + std::cos(std::sqrt(std::abs(x1 / 2 + x2 + 47)))) / + (4 * std::pow(std::abs(x1 / 2 + x2 + 47), 1.5)); +} + +void EggholderFunction::Gradient(const arma::mat& coordinates, + arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, 1); +} diff --git a/src/mlpack/core/optimizers/problems/eggholder_function.hpp b/src/mlpack/core/optimizers/problems/eggholder_function.hpp new file mode 100644 index 0000000000..cc4153fad5 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/eggholder_function.hpp @@ -0,0 +1,106 @@ +/** + * @file eggholder_function.hpp + * @author Marcus Edel + * + * Definition of the Eggholder function. + * + * 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_PROBLEMS_EGGHOLDER_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_EGGHOLDER_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Eggholder function, defined by + * + * \f[ + * f(x) = -(x_2 + 47) * \sin(\sqrt(\left|x_2 + x_1 / 2 + 47\right|)) - x_1 * + * \sin(\sqrt(\left|x_1-(x_2 + 47)\right|)) + * \f] + * + * This should optimize to f(x) = -959.6407, at x = [512, 404.2319]. + * + * For more information, please refer to: + * + * @code + * @article{Jamil2013, + * title = {A Literature Survey of Benchmark Functions For Global + * Optimization Problems}, + * author = {Momin Jamil and Xin{-}She Yang}, + * journal = {CoRR}, + * year = {2013}, + * url = {http://arxiv.org/abs/1308.4008} + * } + * @endcode + */ +class EggholderFunction +{ + public: + //! Initialize the EggholderFunction. + EggholderFunction(); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return 1; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return arma::mat("-333; -333"); } + + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_EGGHOLDER_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/schwefel_function.cpp b/src/mlpack/core/optimizers/problems/schwefel_function.cpp new file mode 100644 index 0000000000..fc1efe9e47 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/schwefel_function.cpp @@ -0,0 +1,74 @@ +/** + * @file schwefel_function.cpp + * @author Marcus Edel + * + * Implementation of the Schwefel function. + * + * 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. + */ +#include "schwefel_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +SchwefelFunction::SchwefelFunction(const size_t n) : + n(n), + visitationOrder(arma::linspace >(0, n - 1, n)) + +{ + initialPoint.set_size(n, 1); + initialPoint.fill(-300); +} + +void SchwefelFunction::Shuffle() +{ + visitationOrder = arma::shuffle( + arma::linspace >(0, n - 1, n)); +} + +double SchwefelFunction::Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const +{ + double objective = 0.0; + for (size_t j = begin; j < begin + batchSize; ++j) + { + const size_t p = visitationOrder[j]; + objective += coordinates(p) * std::sin(std::sqrt(std::abs(coordinates(p)))); + } + objective *= 418.9829 * n; + + return objective; +} + +double SchwefelFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, NumFunctions()); +} + +void SchwefelFunction::Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const +{ + gradient.zeros(n, 1); + + for (size_t j = begin; j < begin + batchSize; ++j) + { + const size_t p = visitationOrder[j]; + gradient(p) += (418.9829 * n) * (std::pow(coordinates(p), 2) * + std::cos(std::sqrt(std::abs(coordinates(p)))) / + (2 * std::pow(std::abs(coordinates(p)), 1.5)) + + std::sin(std::sqrt(std::abs(coordinates(p))))); + } +} + +void SchwefelFunction::Gradient(const arma::mat& coordinates, + arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, NumFunctions()); +} diff --git a/src/mlpack/core/optimizers/problems/schwefel_function.hpp b/src/mlpack/core/optimizers/problems/schwefel_function.hpp new file mode 100644 index 0000000000..69469ec4a4 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/schwefel_function.hpp @@ -0,0 +1,117 @@ +/** + * @file schwefel_function.hpp + * @author Marcus Edel + * + * Definition of the Schwefel function. + * + * 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_PROBLEMS_SCHWEFEL_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_SCHWEFEL_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Schwefel function, defined by + * + * \f[ + * f(x) = 418.9829 * d * \sum_{i=1}^{d} x_i * \sin(\sqrt(\left|x\right|)) + * \f] + * + * This should optimize to f(x) = 0 + * at x = [420.9687, ..., 420.9687]. + * + * For more information, please refer to: + * + * @code + * @article{Jamil2013, + * title = {Systems of extremal control}, + * author = {Rastrigin, L. A.}, + * journal = {Mir}, + * year = {1974} + * } + * @endcode + */ +class SchwefelFunction +{ + public: + /* + * Initialize the SchwefelFunction. + * + * @param n Number of dimensions for the function. + */ + SchwefelFunction(const size_t n); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return n; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return initialPoint; } + + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); + private: + //! Number of dimensions for the function. + size_t n; + + //! For shuffling. + arma::Row visitationOrder; + + //! Initial starting point. + arma::mat initialPoint; +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_SCHWEFEL_FUNCTION_HPP From b19339021e60b812d2a66c0d0f94de9fd3893ba3 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Tue, 14 Nov 2017 16:53:54 +0100 Subject: [PATCH 004/113] Use NumFunctions() instead of manually specified functions number. --- .../optimizers/problems/booth_function.cpp | 2 +- .../optimizers/problems/bukin_function.cpp | 10 ++++++ .../optimizers/problems/bukin_function.hpp | 32 +++++++++++++++++-- .../optimizers/problems/colville_function.cpp | 4 +-- .../optimizers/problems/colville_function.hpp | 2 +- .../optimizers/problems/easom_function.cpp | 4 +-- .../problems/eggholder_function.cpp | 4 +-- .../optimizers/problems/matyas_function.cpp | 4 +-- .../problems/mc_cormick_function.cpp | 4 +-- .../optimizers/problems/sphere_function.cpp | 4 +-- .../problems/styblinski_tang_function.cpp | 4 +-- 11 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/mlpack/core/optimizers/problems/booth_function.cpp b/src/mlpack/core/optimizers/problems/booth_function.cpp index 95759b1dae..18f928948b 100644 --- a/src/mlpack/core/optimizers/problems/booth_function.cpp +++ b/src/mlpack/core/optimizers/problems/booth_function.cpp @@ -35,7 +35,7 @@ double BoothFunction::Evaluate(const arma::mat& coordinates, double BoothFunction::Evaluate(const arma::mat& coordinates) const { - return Evaluate(coordinates, 0, 1); + return Evaluate(coordinates, 0, NumFunctions()); } void BoothFunction::Gradient(const arma::mat& coordinates, diff --git a/src/mlpack/core/optimizers/problems/bukin_function.cpp b/src/mlpack/core/optimizers/problems/bukin_function.cpp index 77c5b94f01..f4b772d750 100644 --- a/src/mlpack/core/optimizers/problems/bukin_function.cpp +++ b/src/mlpack/core/optimizers/problems/bukin_function.cpp @@ -33,6 +33,11 @@ double BukinFunction::Evaluate(const arma::mat& coordinates, return objective; } +double BukinFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, NumFunctions()); +} + void BukinFunction::Gradient(const arma::mat& coordinates, const size_t /* begin */, arma::mat& gradient, @@ -49,3 +54,8 @@ void BukinFunction::Gradient(const arma::mat& coordinates, gradient(1) = (50 * (x2 - 0.01 * std::pow(x1, 2))) / std::pow(std::abs(x2 - 0.01 * std::pow(x1, 2)), 1.5); } + +void BukinFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, NumFunctions()); +} diff --git a/src/mlpack/core/optimizers/problems/bukin_function.hpp b/src/mlpack/core/optimizers/problems/bukin_function.hpp index 5fc1491e0b..55885af625 100644 --- a/src/mlpack/core/optimizers/problems/bukin_function.hpp +++ b/src/mlpack/core/optimizers/problems/bukin_function.hpp @@ -59,16 +59,44 @@ class BukinFunction //! Get the starting point. arma::mat GetInitialPoint() const { return arma::mat("-10; 2.0"); } - //! Evaluate a function for a particular batch-size + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ double Evaluate(const arma::mat& coordinates, const size_t begin, const size_t batchSize) const; - //! Evaluate the gradient of a function for a particular batch-size + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ void Gradient(const arma::mat& coordinates, const size_t begin, arma::mat& gradient, const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); }; } // namespace test diff --git a/src/mlpack/core/optimizers/problems/colville_function.cpp b/src/mlpack/core/optimizers/problems/colville_function.cpp index 96e4509014..4ec8a14982 100644 --- a/src/mlpack/core/optimizers/problems/colville_function.cpp +++ b/src/mlpack/core/optimizers/problems/colville_function.cpp @@ -39,7 +39,7 @@ double ColvilleFunction::Evaluate(const arma::mat& coordinates, double ColvilleFunction::Evaluate(const arma::mat& coordinates) const { - return Evaluate(coordinates, 0, 1); + return Evaluate(coordinates, 0, NumFunctions()); } void ColvilleFunction::Gradient(const arma::mat& coordinates, @@ -63,5 +63,5 @@ void ColvilleFunction::Gradient(const arma::mat& coordinates, void ColvilleFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) { - Gradient(coordinates, 0, gradient, 1); + Gradient(coordinates, 0, gradient, NumFunctions()); } diff --git a/src/mlpack/core/optimizers/problems/colville_function.hpp b/src/mlpack/core/optimizers/problems/colville_function.hpp index 34b328924e..e1deb8c6a9 100644 --- a/src/mlpack/core/optimizers/problems/colville_function.hpp +++ b/src/mlpack/core/optimizers/problems/colville_function.hpp @@ -54,7 +54,7 @@ class ColvilleFunction void Shuffle(); //! Return 1 (the number of functions). - size_t NumFunctions() const { return 4; } + size_t NumFunctions() const { return 1; } //! Get the starting point. arma::mat GetInitialPoint() const { return arma::mat("-5; 3; 1; -9"); } diff --git a/src/mlpack/core/optimizers/problems/easom_function.cpp b/src/mlpack/core/optimizers/problems/easom_function.cpp index 018ce1c0f9..8427beb237 100644 --- a/src/mlpack/core/optimizers/problems/easom_function.cpp +++ b/src/mlpack/core/optimizers/problems/easom_function.cpp @@ -35,7 +35,7 @@ double EasomFunction::Evaluate(const arma::mat& coordinates, double EasomFunction::Evaluate(const arma::mat& coordinates) const { - return Evaluate(coordinates, 0, 1); + return Evaluate(coordinates, 0, NumFunctions()); } void EasomFunction::Gradient(const arma::mat& coordinates, @@ -63,5 +63,5 @@ void EasomFunction::Gradient(const arma::mat& coordinates, void EasomFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) { - Gradient(coordinates, 0, gradient, 1); + Gradient(coordinates, 0, gradient, NumFunctions()); } diff --git a/src/mlpack/core/optimizers/problems/eggholder_function.cpp b/src/mlpack/core/optimizers/problems/eggholder_function.cpp index 783dd0276e..4349583201 100644 --- a/src/mlpack/core/optimizers/problems/eggholder_function.cpp +++ b/src/mlpack/core/optimizers/problems/eggholder_function.cpp @@ -36,7 +36,7 @@ double EggholderFunction::Evaluate(const arma::mat& coordinates, double EggholderFunction::Evaluate(const arma::mat& coordinates) const { - return Evaluate(coordinates, 0, 1); + return Evaluate(coordinates, 0, NumFunctions()); } void EggholderFunction::Gradient(const arma::mat& coordinates, @@ -67,5 +67,5 @@ void EggholderFunction::Gradient(const arma::mat& coordinates, void EggholderFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) { - Gradient(coordinates, 0, gradient, 1); + Gradient(coordinates, 0, gradient, NumFunctions()); } diff --git a/src/mlpack/core/optimizers/problems/matyas_function.cpp b/src/mlpack/core/optimizers/problems/matyas_function.cpp index bfe93fa42b..6d4fef8de9 100644 --- a/src/mlpack/core/optimizers/problems/matyas_function.cpp +++ b/src/mlpack/core/optimizers/problems/matyas_function.cpp @@ -35,7 +35,7 @@ double MatyasFunction::Evaluate(const arma::mat& coordinates, double MatyasFunction::Evaluate(const arma::mat& coordinates) const { - return Evaluate(coordinates, 0, 1); + return Evaluate(coordinates, 0, NumFunctions()); } void MatyasFunction::Gradient(const arma::mat& coordinates, @@ -54,5 +54,5 @@ void MatyasFunction::Gradient(const arma::mat& coordinates, void MatyasFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) { - Gradient(coordinates, 0, gradient, 1); + Gradient(coordinates, 0, gradient, NumFunctions()); } diff --git a/src/mlpack/core/optimizers/problems/mc_cormick_function.cpp b/src/mlpack/core/optimizers/problems/mc_cormick_function.cpp index 330c3bef99..9ef4088d5c 100644 --- a/src/mlpack/core/optimizers/problems/mc_cormick_function.cpp +++ b/src/mlpack/core/optimizers/problems/mc_cormick_function.cpp @@ -35,7 +35,7 @@ double McCormickFunction::Evaluate(const arma::mat& coordinates, double McCormickFunction::Evaluate(const arma::mat& coordinates) const { - return Evaluate(coordinates, 0, 1); + return Evaluate(coordinates, 0, NumFunctions()); } void McCormickFunction::Gradient(const arma::mat& coordinates, @@ -55,5 +55,5 @@ void McCormickFunction::Gradient(const arma::mat& coordinates, void McCormickFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) { - Gradient(coordinates, 0, gradient, 1); + Gradient(coordinates, 0, gradient, NumFunctions()); } diff --git a/src/mlpack/core/optimizers/problems/sphere_function.cpp b/src/mlpack/core/optimizers/problems/sphere_function.cpp index dd2f64cb6c..12317336fc 100644 --- a/src/mlpack/core/optimizers/problems/sphere_function.cpp +++ b/src/mlpack/core/optimizers/problems/sphere_function.cpp @@ -53,7 +53,7 @@ double SphereFunction::Evaluate(const arma::mat& coordinates, double SphereFunction::Evaluate(const arma::mat& coordinates) const { - Evaluate(coordinates, 0, NumFunctions()); + return Evaluate(coordinates, 0, NumFunctions()); } void SphereFunction::Gradient(const arma::mat& coordinates, @@ -72,5 +72,5 @@ void SphereFunction::Gradient(const arma::mat& coordinates, void SphereFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) { - Gradient(coordinates, 0, gradient, 1); + Gradient(coordinates, 0, gradient, NumFunctions()); } diff --git a/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp b/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp index fa6327160d..c5b398da70 100644 --- a/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp +++ b/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp @@ -48,7 +48,7 @@ double StyblinskiTangFunction::Evaluate(const arma::mat& coordinates, double StyblinskiTangFunction::Evaluate(const arma::mat& coordinates) const { - return Evaluate(coordinates, 0, 1); + return Evaluate(coordinates, 0, NumFunctions()); } void StyblinskiTangFunction::Gradient(const arma::mat& coordinates, @@ -69,5 +69,5 @@ void StyblinskiTangFunction::Gradient(const arma::mat& coordinates, void StyblinskiTangFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) { - Gradient(coordinates, 0, gradient, 1); + Gradient(coordinates, 0, gradient, NumFunctions()); } From ce9c6cdc956e0e45fe7118fa2f2d7d9f4009af11 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Mon, 4 Dec 2017 23:09:27 +0100 Subject: [PATCH 005/113] Move the sgd test function into the problems folder. --- src/mlpack/core/optimizers/problems/CMakeLists.txt | 2 ++ src/mlpack/core/optimizers/problems/booth_function.hpp | 2 +- .../test_function.cpp => problems/sgd_test_function.cpp} | 4 ++-- .../test_function.hpp => problems/sgd_test_function.hpp} | 6 +++--- src/mlpack/core/optimizers/sgd/CMakeLists.txt | 2 -- src/mlpack/tests/ada_delta_test.cpp | 2 +- src/mlpack/tests/ada_grad_test.cpp | 2 +- src/mlpack/tests/adam_test.cpp | 2 +- src/mlpack/tests/gradient_clipping_test.cpp | 2 +- src/mlpack/tests/momentum_sgd_test.cpp | 2 +- src/mlpack/tests/rmsprop_test.cpp | 2 +- src/mlpack/tests/sgd_test.cpp | 2 +- src/mlpack/tests/smorms3_test.cpp | 2 +- 13 files changed, 16 insertions(+), 16 deletions(-) rename src/mlpack/core/optimizers/{sgd/test_function.cpp => problems/sgd_test_function.cpp} (97%) rename src/mlpack/core/optimizers/{sgd/test_function.hpp => problems/sgd_test_function.hpp} (92%) diff --git a/src/mlpack/core/optimizers/problems/CMakeLists.txt b/src/mlpack/core/optimizers/problems/CMakeLists.txt index 654bf757bc..96a1882ba9 100644 --- a/src/mlpack/core/optimizers/problems/CMakeLists.txt +++ b/src/mlpack/core/optimizers/problems/CMakeLists.txt @@ -19,6 +19,8 @@ set(SOURCES rastrigin_function.cpp schwefel_function.hpp schwefel_function.cpp + sgd_test_function.hpp + sgd_test_function.cpp sphere_function.hpp sphere_function.cpp styblinski_tang_function.hpp diff --git a/src/mlpack/core/optimizers/problems/booth_function.hpp b/src/mlpack/core/optimizers/problems/booth_function.hpp index 1c2f90ad0e..3977a0470a 100644 --- a/src/mlpack/core/optimizers/problems/booth_function.hpp +++ b/src/mlpack/core/optimizers/problems/booth_function.hpp @@ -56,7 +56,7 @@ class BoothFunction size_t NumFunctions() const { return 1; } //! Get the starting point. - arma::mat GetInitialPoint() const { return arma::mat("-5; 3"); } + arma::mat GetInitialPoint() const { return arma::mat("-9; -9"); } /* * Evaluate a function for a particular batch-size. diff --git a/src/mlpack/core/optimizers/sgd/test_function.cpp b/src/mlpack/core/optimizers/problems/sgd_test_function.cpp similarity index 97% rename from src/mlpack/core/optimizers/sgd/test_function.cpp rename to src/mlpack/core/optimizers/problems/sgd_test_function.cpp index 8415d98613..82d4862781 100644 --- a/src/mlpack/core/optimizers/sgd/test_function.cpp +++ b/src/mlpack/core/optimizers/problems/sgd_test_function.cpp @@ -1,5 +1,5 @@ /** - * @file test_function.cpp + * @file sgd_test_function.cpp * @author Ryan Curtin * * Implementation of very simple test function for stochastic gradient descent @@ -10,7 +10,7 @@ * 3-clause BSD license along with mlpack. If not, see * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ -#include "test_function.hpp" +#include "sgd_test_function.hpp" using namespace mlpack; using namespace mlpack::optimization; diff --git a/src/mlpack/core/optimizers/sgd/test_function.hpp b/src/mlpack/core/optimizers/problems/sgd_test_function.hpp similarity index 92% rename from src/mlpack/core/optimizers/sgd/test_function.hpp rename to src/mlpack/core/optimizers/problems/sgd_test_function.hpp index 3a566e0ea6..2709b597c7 100644 --- a/src/mlpack/core/optimizers/sgd/test_function.hpp +++ b/src/mlpack/core/optimizers/problems/sgd_test_function.hpp @@ -1,5 +1,5 @@ /** - * @file test_function.hpp + * @file sgd_test_function.hpp * @author Ryan Curtin * * Very simple test function for SGD. @@ -9,8 +9,8 @@ * 3-clause BSD license along with mlpack. If not, see * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ -#ifndef MLPACK_CORE_OPTIMIZERS_SGD_TEST_FUNCTION_HPP -#define MLPACK_CORE_OPTIMIZERS_SGD_TEST_FUNCTION_HPP +#ifndef MLPACK_CORE_OPTIMIZERS_PROBLEMS_SGD_TEST_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_SGD_TEST_FUNCTION_HPP #include diff --git a/src/mlpack/core/optimizers/sgd/CMakeLists.txt b/src/mlpack/core/optimizers/sgd/CMakeLists.txt index 1916ec0fdc..343d024d90 100644 --- a/src/mlpack/core/optimizers/sgd/CMakeLists.txt +++ b/src/mlpack/core/optimizers/sgd/CMakeLists.txt @@ -5,8 +5,6 @@ set(SOURCES update_policies/vanilla_update.hpp sgd.hpp sgd_impl.hpp - test_function.hpp - test_function.cpp ) set(DIR_SRCS) diff --git a/src/mlpack/tests/ada_delta_test.cpp b/src/mlpack/tests/ada_delta_test.cpp index bd14d7faeb..873f162278 100644 --- a/src/mlpack/tests/ada_delta_test.cpp +++ b/src/mlpack/tests/ada_delta_test.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/src/mlpack/tests/ada_grad_test.cpp b/src/mlpack/tests/ada_grad_test.cpp index 7362af4f36..484b6a7306 100644 --- a/src/mlpack/tests/ada_grad_test.cpp +++ b/src/mlpack/tests/ada_grad_test.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include "test_tools.hpp" diff --git a/src/mlpack/tests/adam_test.cpp b/src/mlpack/tests/adam_test.cpp index 9c954af6cf..06144e9fb2 100644 --- a/src/mlpack/tests/adam_test.cpp +++ b/src/mlpack/tests/adam_test.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/src/mlpack/tests/gradient_clipping_test.cpp b/src/mlpack/tests/gradient_clipping_test.cpp index dc8882a7cc..27b3960e0d 100644 --- a/src/mlpack/tests/gradient_clipping_test.cpp +++ b/src/mlpack/tests/gradient_clipping_test.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include "test_tools.hpp" diff --git a/src/mlpack/tests/momentum_sgd_test.cpp b/src/mlpack/tests/momentum_sgd_test.cpp index 42fd1d3499..2cd3a14ff2 100644 --- a/src/mlpack/tests/momentum_sgd_test.cpp +++ b/src/mlpack/tests/momentum_sgd_test.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include "test_tools.hpp" diff --git a/src/mlpack/tests/rmsprop_test.cpp b/src/mlpack/tests/rmsprop_test.cpp index 0fb51c24a0..7135d06c28 100644 --- a/src/mlpack/tests/rmsprop_test.cpp +++ b/src/mlpack/tests/rmsprop_test.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include diff --git a/src/mlpack/tests/sgd_test.cpp b/src/mlpack/tests/sgd_test.cpp index 77224adc78..d4e80e67dd 100644 --- a/src/mlpack/tests/sgd_test.cpp +++ b/src/mlpack/tests/sgd_test.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include "test_tools.hpp" diff --git a/src/mlpack/tests/smorms3_test.cpp b/src/mlpack/tests/smorms3_test.cpp index 30d307f952..de5c1f569c 100644 --- a/src/mlpack/tests/smorms3_test.cpp +++ b/src/mlpack/tests/smorms3_test.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include From 05b20d846d03dceafdd2588ead6438872f4a410e Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Mon, 11 Dec 2017 20:35:49 +0100 Subject: [PATCH 006/113] Adjust starting point. --- src/mlpack/core/optimizers/problems/mc_cormick_function.hpp | 2 +- src/mlpack/core/optimizers/problems/sphere_function.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp b/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp index e98d506076..56b31b2737 100644 --- a/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp +++ b/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp @@ -56,7 +56,7 @@ class McCormickFunction size_t NumFunctions() const { return 1; } //! Get the starting point. - arma::mat GetInitialPoint() const { return arma::mat("-1; 2"); } + arma::mat GetInitialPoint() const { return arma::mat("-2; 4"); } /* * Evaluate a function for a particular batch-size. diff --git a/src/mlpack/core/optimizers/problems/sphere_function.cpp b/src/mlpack/core/optimizers/problems/sphere_function.cpp index 12317336fc..1b25a1b8f2 100644 --- a/src/mlpack/core/optimizers/problems/sphere_function.cpp +++ b/src/mlpack/core/optimizers/problems/sphere_function.cpp @@ -25,9 +25,9 @@ SphereFunction::SphereFunction(const size_t n) : for (size_t i = 0; i < n; ++i) // Set to [-3.12 3.33 -3.12 3.33...]. { if (i % 2 == 1) - initialPoint(i) = 3.33; + initialPoint(i) = 5; else - initialPoint(i) = -3.12; + initialPoint(i) = -5; } } From c6cc315c687ffd5d6af14db040e97a272e847559 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Sat, 16 Dec 2017 14:26:29 +0100 Subject: [PATCH 007/113] Correct the gradient of Bukin function. --- src/mlpack/core/optimizers/problems/bukin_function.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/core/optimizers/problems/bukin_function.cpp b/src/mlpack/core/optimizers/problems/bukin_function.cpp index f4b772d750..6ec6edf2e1 100644 --- a/src/mlpack/core/optimizers/problems/bukin_function.cpp +++ b/src/mlpack/core/optimizers/problems/bukin_function.cpp @@ -49,8 +49,8 @@ void BukinFunction::Gradient(const arma::mat& coordinates, gradient.set_size(2, 1); gradient(0) = (0.01 * (x1 + 10)) / std::abs(x1 + 10) - - (x1 * (x2 - 0.01 * std::pow(x2, 2))) / std::pow(std::abs(x2 - 0.01 * - std::pow(x2, 2)), 1.5); + (x1 * (x2 - 0.01 * std::pow(x1, 2))) / std::pow(std::abs(x2 - 0.01 * + std::pow(x1, 2)), 1.5); gradient(1) = (50 * (x2 - 0.01 * std::pow(x1, 2))) / std::pow(std::abs(x2 - 0.01 * std::pow(x1, 2)), 1.5); } From 6342c8831d8752cbc29ab306c1c6ca97187102ba Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Sat, 16 Dec 2017 14:28:12 +0100 Subject: [PATCH 008/113] Adjust initial starting point. --- .../core/optimizers/problems/styblinski_tang_function.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp b/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp index c5b398da70..70473cece8 100644 --- a/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp +++ b/src/mlpack/core/optimizers/problems/styblinski_tang_function.cpp @@ -21,7 +21,7 @@ StyblinskiTangFunction::StyblinskiTangFunction(const size_t n) : { initialPoint.set_size(n, 1); - initialPoint.fill(-4); + initialPoint.fill(-5); } void StyblinskiTangFunction::Shuffle() From 2022164690869a04e74950928a95c7ae889ccf94 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Fri, 22 Dec 2017 22:46:44 +0100 Subject: [PATCH 009/113] Move and split the lbfgs test functions into the problems directory. --- .../core/optimizers/lbfgs/CMakeLists.txt | 2 - .../core/optimizers/lbfgs/test_functions.cpp | 284 ------------------ .../core/optimizers/lbfgs/test_functions.hpp | 174 ----------- .../core/optimizers/problems/CMakeLists.txt | 8 + src/mlpack/tests/cmaes_test.cpp | 2 +- src/mlpack/tests/gradient_clipping_test.cpp | 1 - src/mlpack/tests/gradient_descent_test.cpp | 3 +- src/mlpack/tests/lbfgs_test.cpp | 4 +- src/mlpack/tests/momentum_sgd_test.cpp | 2 +- src/mlpack/tests/parallel_sgd_test.cpp | 3 +- src/mlpack/tests/sa_test.cpp | 3 +- src/mlpack/tests/sgd_test.cpp | 2 +- 12 files changed, 20 insertions(+), 468 deletions(-) delete mode 100644 src/mlpack/core/optimizers/lbfgs/test_functions.cpp delete mode 100644 src/mlpack/core/optimizers/lbfgs/test_functions.hpp diff --git a/src/mlpack/core/optimizers/lbfgs/CMakeLists.txt b/src/mlpack/core/optimizers/lbfgs/CMakeLists.txt index f72f61f098..237f5ac579 100644 --- a/src/mlpack/core/optimizers/lbfgs/CMakeLists.txt +++ b/src/mlpack/core/optimizers/lbfgs/CMakeLists.txt @@ -2,8 +2,6 @@ set(SOURCES lbfgs_impl.hpp lbfgs.hpp lbfgs.cpp - test_functions.hpp - test_functions.cpp ) set(DIR_SRCS) diff --git a/src/mlpack/core/optimizers/lbfgs/test_functions.cpp b/src/mlpack/core/optimizers/lbfgs/test_functions.cpp deleted file mode 100644 index 2d0e0a3f50..0000000000 --- a/src/mlpack/core/optimizers/lbfgs/test_functions.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/** - * @file test_functions.cpp - * @author Ryan Curtin - * - * Implementations of the test functions defined in test_functions.hpp. - * - * 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. - */ -#include "test_functions.hpp" - -using namespace mlpack::optimization::test; - -// -// RosenbrockFunction implementation -// - -RosenbrockFunction::RosenbrockFunction() -{ - initialPoint.set_size(2, 1); - initialPoint[0] = -1.2; - initialPoint[1] = 1; -} - -/** - * Calculate the objective function. - */ -double RosenbrockFunction::Evaluate(const arma::mat& coordinates) -{ - double x1 = coordinates[0]; - double x2 = coordinates[1]; - - double objective = /* f1(x) */ 100 * std::pow(x2 - std::pow(x1, 2), 2) + - /* f2(x) */ std::pow(1 - x1, 2); - - return objective; -} - -/** - * Calculate the gradient. - */ -void RosenbrockFunction::Gradient(const arma::mat& coordinates, - arma::mat& gradient) -{ - // f'_{x1}(x) = -2 (1 - x1) + 400 (x1^3 - (x2 x1)) - // f'_{x2}(x) = 200 (x2 - x1^2) - - double x1 = coordinates[0]; - double x2 = coordinates[1]; - - gradient.set_size(2, 1); - gradient[0] = -2 * (1 - x1) + 400 * (std::pow(x1, 3) - x2 * x1); - gradient[1] = 200 * (x2 - std::pow(x1, 2)); -} - -const arma::mat& RosenbrockFunction::GetInitialPoint() const -{ - return initialPoint; -} - -// -// WoodFunction implementation -// - -WoodFunction::WoodFunction() -{ - initialPoint.set_size(4, 1); - initialPoint[0] = -3; - initialPoint[1] = -1; - initialPoint[2] = -3; - initialPoint[3] = -1; -} - -/** - * Calculate the objective function. - */ -double WoodFunction::Evaluate(const arma::mat& coordinates) -{ - // For convenience; we assume these temporaries will be optimized out. - double x1 = coordinates[0]; - double x2 = coordinates[1]; - double x3 = coordinates[2]; - double x4 = coordinates[3]; - - double objective = /* f1(x) */ 100 * std::pow(x2 - std::pow(x1, 2), 2) + - /* f2(x) */ std::pow(1 - x1, 2) + - /* f3(x) */ 90 * std::pow(x4 - std::pow(x3, 2), 2) + - /* f4(x) */ std::pow(1 - x3, 2) + - /* f5(x) */ 10 * std::pow(x2 + x4 - 2, 2) + - /* f6(x) */ (1.0 / 10.0) * std::pow(x2 - x4, 2); - - return objective; -} - -/** - * Calculate the gradient. - */ -void WoodFunction::Gradient(const arma::mat& coordinates, - arma::mat& gradient) -{ - // For convenience; we assume these temporaries will be optimized out. - double x1 = coordinates[0]; - double x2 = coordinates[1]; - double x3 = coordinates[2]; - double x4 = coordinates[3]; - - // f'_{x1}(x) = 400 (x1^3 - x2 x1) - 2 (1 - x1) - // f'_{x2}(x) = 200 (x2 - x1^2) + 20 (x2 + x4 - 2) + (1 / 5) (x2 - x4) - // f'_{x3}(x) = 360 (x3^3 - x4 x3) - 2 (1 - x3) - // f'_{x4}(x) = 180 (x4 - x3^2) + 20 (x2 + x4 - 2) - (1 / 5) (x2 - x4) - gradient.set_size(4, 1); - gradient[0] = 400 * (std::pow(x1, 3) - x2 * x1) - 2 * (1 - x1); - gradient[1] = 200 * (x2 - std::pow(x1, 2)) + 20 * (x2 + x4 - 2) + - (1.0 / 5.0) * (x2 - x4); - gradient[2] = 360 * (std::pow(x3, 3) - x4 * x3) - 2 * (1 - x3); - gradient[3] = 180 * (x4 - std::pow(x3, 2)) + 20 * (x2 + x4 - 2) - - (1.0 / 5.0) * (x2 - x4); -} - -const arma::mat& WoodFunction::GetInitialPoint() const -{ - return initialPoint; -} - -// -// GeneralizedRosenbrockFunction implementation -// - -GeneralizedRosenbrockFunction::GeneralizedRosenbrockFunction(int n) : - n(n), - visitationOrder(arma::linspace>(0, n - 2, n - 1)) -{ - initialPoint.set_size(n, 1); - for (int i = 0; i < n; i++) // Set to [-1.2 1 -1.2 1 ...]. - { - if (i % 2 == 1) - initialPoint[i] = -1.2; - else - initialPoint[i] = 1; - } -} - -/** - * Shuffle the data points. - */ -void GeneralizedRosenbrockFunction::Shuffle() -{ - visitationOrder = arma::shuffle(arma::linspace>(0, n - 2, - n - 1)); -} - -/** - * Calculate the objective function. - */ -double GeneralizedRosenbrockFunction::Evaluate(const arma::mat& coordinates) - const -{ - double fval = 0; - for (int i = 0; i < (n - 1); i++) - { - fval += 100 * std::pow(std::pow(coordinates[i], 2) - - coordinates[i + 1], 2) + std::pow(1 - coordinates[i], 2); - } - - return fval; -} - -/** - * Calculate the gradient. - */ -void GeneralizedRosenbrockFunction::Gradient(const arma::mat& coordinates, - arma::mat& gradient) const -{ - gradient.set_size(n); - for (int i = 0; i < (n - 1); i++) - { - gradient[i] = 400 * (std::pow(coordinates[i], 3) - coordinates[i] * - coordinates[i + 1]) + 2 * (coordinates[i] - 1); - - if (i > 0) - gradient[i] += 200 * (coordinates[i] - std::pow(coordinates[i - 1], 2)); - } - - gradient[n - 1] = 200 * (coordinates[n - 1] - - std::pow(coordinates[n - 2], 2)); -} - -//! Calculate the objective function of one of the individual functions. -double GeneralizedRosenbrockFunction::Evaluate(const arma::mat& coordinates, - const size_t i, - const size_t batchSize) const -{ - double objective = 0.0; - for (size_t j = i; j < i + batchSize; ++j) - { - const size_t p = visitationOrder[j]; - objective += 100 * std::pow((std::pow(coordinates[p], 2) - - coordinates[p + 1]), 2) + std::pow(1 - coordinates[p], 2); - } - - return objective; -} - -//! Calculate the gradient of one of the individual functions. -void GeneralizedRosenbrockFunction::Gradient(const arma::mat& coordinates, - const size_t i, - arma::mat& gradient, - const size_t batchSize) const -{ - gradient.zeros(n); - - for (size_t j = i; j < i + batchSize; ++j) - { - const size_t p = visitationOrder[j]; - gradient[p] = 400 * (std::pow(coordinates[p], 3) - coordinates[p] * - coordinates[p + 1]) + 2 * (coordinates[p] - 1); - gradient[p + 1] = 200 * (coordinates[p + 1] - std::pow(coordinates[p], 2)); - } -} - -void GeneralizedRosenbrockFunction::Gradient(const arma::mat& coordinates, - const size_t i, - arma::sp_mat& gradient) const -{ - gradient.set_size(n); - - const size_t p = visitationOrder[i]; - - gradient[p] = 400 * (std::pow(coordinates[p], 3) - coordinates[p] * - coordinates[p + 1]) + 2 * (coordinates[p] - 1); - gradient[p + 1] = 200 * (coordinates[p + 1] - std::pow(coordinates[p], 2)); -} - -const arma::mat& GeneralizedRosenbrockFunction::GetInitialPoint() const -{ - return initialPoint; -} - -// -// RosenbrockWoodFunction implementation -// - -RosenbrockWoodFunction::RosenbrockWoodFunction() : rf(4), wf() -{ - initialPoint.set_size(4, 2); - initialPoint.col(0) = rf.GetInitialPoint(); - initialPoint.col(1) = wf.GetInitialPoint(); -} - -/** - * Calculate the objective function. - */ -double RosenbrockWoodFunction::Evaluate(const arma::mat& coordinates) -{ - double objective = rf.Evaluate(coordinates.col(0)) + - wf.Evaluate(coordinates.col(1)); - - return objective; -} - -/*** - * Calculate the gradient. - */ -void RosenbrockWoodFunction::Gradient(const arma::mat& coordinates, - arma::mat& gradient) -{ - gradient.set_size(4, 2); - - arma::vec grf(4); - arma::vec gwf(4); - - rf.Gradient(coordinates.col(0), grf); - wf.Gradient(coordinates.col(1), gwf); - - gradient.col(0) = grf; - gradient.col(1) = gwf; -} - -const arma::mat& RosenbrockWoodFunction::GetInitialPoint() const -{ - return initialPoint; -} diff --git a/src/mlpack/core/optimizers/lbfgs/test_functions.hpp b/src/mlpack/core/optimizers/lbfgs/test_functions.hpp deleted file mode 100644 index 04f442b5be..0000000000 --- a/src/mlpack/core/optimizers/lbfgs/test_functions.hpp +++ /dev/null @@ -1,174 +0,0 @@ -/** - * @file test_functions.hpp - * @author Ryan Curtin - * - * A collection of functions to test optimizers (in this case, L-BFGS). These - * come from the following paper: - * - * "Testing Unconstrained Optimization Software" - * Jorge J. Moré, Burton S. Garbow, and Kenneth E. Hillstrom. 1981. - * ACM Trans. Math. Softw. 7, 1 (March 1981), 17-41. - * http://portal.acm.org/citation.cfm?id=355934.355936 - * - * 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_LBFGS_TEST_FUNCTIONS_HPP -#define MLPACK_CORE_OPTIMIZERS_LBFGS_TEST_FUNCTIONS_HPP - -#include - -// To fulfill the template policy class 'FunctionType', we must implement -// the following: -// -// FunctionType(); // constructor -// void Gradient(const arma::mat& coordinates, arma::mat& gradient); -// double Evaluate(const arma::mat& coordinates); -// const arma::mat& GetInitialPoint(); -// -// Note that we are using an arma::mat instead of the more intuitive and -// expected arma::vec. This is because L-BFGS will also optimize matrices. -// However, remember that an arma::vec is simply an (n x 1) arma::mat. You can -// use either internally but the L-BFGS method requires arma::mat& to be passed -// (C++ does not allow implicit reference casting to subclasses). - -namespace mlpack { -namespace optimization { -namespace test { - -/** - * The Rosenbrock function, defined by - * f(x) = f1(x) + f2(x) - * f1(x) = 100 (x2 - x1^2)^2 - * f2(x) = (1 - x1)^2 - * x_0 = [-1.2, 1] - * - * This should optimize to f(x) = 0, at x = [1, 1]. - * - * "An automatic method for finding the greatest or least value of a function." - * H.H. Rosenbrock. 1960. Comput. J. 3., 175-184. - */ -class RosenbrockFunction -{ - public: - RosenbrockFunction(); // initialize initial point - - double Evaluate(const arma::mat& coordinates); - void Gradient(const arma::mat& coordinates, arma::mat& gradient); - - const arma::mat& GetInitialPoint() const; - - private: - arma::mat initialPoint; -}; - -/** - * The Wood function, defined by - * f(x) = f1(x) + f2(x) + f3(x) + f4(x) + f5(x) + f6(x) - * f1(x) = 100 (x2 - x1^2)^2 - * f2(x) = (1 - x1)^2 - * f3(x) = 90 (x4 - x3^2)^2 - * f4(x) = (1 - x3)^2 - * f5(x) = 10 (x2 + x4 - 2)^2 - * f6(x) = (1 / 10) (x2 - x4)^2 - * x_0 = [-3, -1, -3, -1] - * - * This should optimize to f(x) = 0, at x = [1, 1, 1, 1]. - * - * "A comparative study of nonlinear programming codes." - * A.R. Colville. 1968. Rep. 320-2949, IBM N.Y. Scientific Center. - */ -class WoodFunction -{ - public: - WoodFunction(); // initialize initial point - - double Evaluate(const arma::mat& coordinates); - void Gradient(const arma::mat& coordinates, arma::mat& gradient); - - const arma::mat& GetInitialPoint() const; - - private: - arma::mat initialPoint; -}; - -/** - * The Generalized Rosenbrock function in n dimensions, defined by - * f(x) = sum_i^{n - 1} (f(i)(x)) - * f_i(x) = 100 * (x_i^2 - x_{i + 1})^2 + (1 - x_i)^2 - * x_0 = [-1.2, 1, -1.2, 1, ...] - * - * This should optimize to f(x) = 0, at x = [1, 1, 1, 1, ...]. - * - * This function can also be used for stochastic gradient descent (SGD) as a - * decomposable function (DecomposableFunctionType), so there are other - * overloads of Evaluate() and Gradient() implemented, as well as - * NumFunctions(). - * - * "An analysis of the behavior of a glass of genetic adaptive systems." - * K.A. De Jong. Ph.D. thesis, University of Michigan, 1975. - */ -class GeneralizedRosenbrockFunction -{ - public: - /*** - * Set the dimensionality of the extended Rosenbrock function. - * - * @param n Number of dimensions for the function. - */ - GeneralizedRosenbrockFunction(int n); - - void Shuffle(); - - double Evaluate(const arma::mat& coordinates) const; - void Gradient(const arma::mat& coordinates, arma::mat& gradient) const; - - size_t NumFunctions() const { return n - 1; } - double Evaluate(const arma::mat& coordinates, - const size_t i, - const size_t batchSize = 1) const; - void Gradient(const arma::mat& coordinates, - const size_t i, - arma::mat& gradient, - const size_t batchSize = 1) const; - - void Gradient(const arma::mat& coordinates, - const size_t i, - arma::sp_mat& gradient) const; - - const arma::mat& GetInitialPoint() const; - - private: - arma::mat initialPoint; - int n; // Dimensionality - arma::Row visitationOrder; // For shuffling. -}; - -/** - * The Generalized Rosenbrock function in 4 dimensions with the Wood Function in - * four dimensions. In this function we are actually optimizing a 2x4 matrix of - * coordinates, not a vector. - */ -class RosenbrockWoodFunction -{ - public: - RosenbrockWoodFunction(); // initialize initial point - - double Evaluate(const arma::mat& coordinates); - void Gradient(const arma::mat& coordinates, arma::mat& gradient); - - const arma::mat& GetInitialPoint() const; - - private: - arma::mat initialPoint; - GeneralizedRosenbrockFunction rf; - WoodFunction wf; -}; - -} // namespace test -} // namespace optimization -} // namespace mlpack - -#endif // MLPACK_CORE_OPTIMIZERS_LBFGS_TEST_FUNCTIONS_HPP diff --git a/src/mlpack/core/optimizers/problems/CMakeLists.txt b/src/mlpack/core/optimizers/problems/CMakeLists.txt index 96a1882ba9..873fdff9c3 100644 --- a/src/mlpack/core/optimizers/problems/CMakeLists.txt +++ b/src/mlpack/core/optimizers/problems/CMakeLists.txt @@ -11,12 +11,18 @@ set(SOURCES easom_function.cpp eggholder_function.hpp eggholder_function.cpp + generalized_rosenbrock_function.hpp + generalized_rosenbrock_function.cpp matyas_function.hpp matyas_function.cpp mc_cormick_function.hpp mc_cormick_function.cpp rastrigin_function.hpp rastrigin_function.cpp + rosenbrock_function.hpp + rosenbrock_wood_function.hpp + rosenbrock_wood_function.cpp + rosenbrock_function.cpp schwefel_function.hpp schwefel_function.cpp sgd_test_function.hpp @@ -25,6 +31,8 @@ set(SOURCES sphere_function.cpp styblinski_tang_function.hpp styblinski_tang_function.cpp + wood_function.hpp + wood_function.cpp ) set(DIR_SRCS) diff --git a/src/mlpack/tests/cmaes_test.cpp b/src/mlpack/tests/cmaes_test.cpp index 8a42919320..63606d2267 100644 --- a/src/mlpack/tests/cmaes_test.cpp +++ b/src/mlpack/tests/cmaes_test.cpp @@ -12,7 +12,7 @@ */ #include #include -#include +#include #include #include diff --git a/src/mlpack/tests/gradient_clipping_test.cpp b/src/mlpack/tests/gradient_clipping_test.cpp index 27b3960e0d..87afd669c5 100644 --- a/src/mlpack/tests/gradient_clipping_test.cpp +++ b/src/mlpack/tests/gradient_clipping_test.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/src/mlpack/tests/gradient_descent_test.cpp b/src/mlpack/tests/gradient_descent_test.cpp index 6c07fb35aa..12048d9d8a 100644 --- a/src/mlpack/tests/gradient_descent_test.cpp +++ b/src/mlpack/tests/gradient_descent_test.cpp @@ -11,7 +11,8 @@ */ #include #include -#include + +#include #include #include diff --git a/src/mlpack/tests/lbfgs_test.cpp b/src/mlpack/tests/lbfgs_test.cpp index 2e194f8079..f1eb863e97 100644 --- a/src/mlpack/tests/lbfgs_test.cpp +++ b/src/mlpack/tests/lbfgs_test.cpp @@ -12,7 +12,9 @@ */ #include #include -#include + +#include +#include #include #include "test_tools.hpp" diff --git a/src/mlpack/tests/momentum_sgd_test.cpp b/src/mlpack/tests/momentum_sgd_test.cpp index 2cd3a14ff2..0b4ddfa5d7 100644 --- a/src/mlpack/tests/momentum_sgd_test.cpp +++ b/src/mlpack/tests/momentum_sgd_test.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/mlpack/tests/parallel_sgd_test.cpp b/src/mlpack/tests/parallel_sgd_test.cpp index cc84ceea18..8e78551d17 100644 --- a/src/mlpack/tests/parallel_sgd_test.cpp +++ b/src/mlpack/tests/parallel_sgd_test.cpp @@ -13,7 +13,8 @@ #include #include #include -#include +#include + // We need some thorough testing #define private public #include diff --git a/src/mlpack/tests/sa_test.cpp b/src/mlpack/tests/sa_test.cpp index 5ada51d436..6a46f21b5a 100644 --- a/src/mlpack/tests/sa_test.cpp +++ b/src/mlpack/tests/sa_test.cpp @@ -12,7 +12,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/src/mlpack/tests/sgd_test.cpp b/src/mlpack/tests/sgd_test.cpp index d4e80e67dd..b4015daef0 100644 --- a/src/mlpack/tests/sgd_test.cpp +++ b/src/mlpack/tests/sgd_test.cpp @@ -11,7 +11,7 @@ */ #include #include -#include +#include #include #include From ca2709368d97dcf1c26d1cfa8cd5ca05efd7a5c5 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Fri, 22 Dec 2017 22:49:39 +0100 Subject: [PATCH 010/113] Add Rosenbrock, Wood, Generalized-Rosenbrock and Rosenbrock-Wood function. --- .../generalized_rosenbrock_function.cpp | 102 ++++++++++++++ .../generalized_rosenbrock_function.hpp | 124 ++++++++++++++++++ .../problems/rosenbrock_function.cpp | 60 +++++++++ .../problems/rosenbrock_function.hpp | 108 +++++++++++++++ .../problems/rosenbrock_wood_function.cpp | 64 +++++++++ .../problems/rosenbrock_wood_function.hpp | 101 ++++++++++++++ .../optimizers/problems/wood_function.cpp | 71 ++++++++++ .../optimizers/problems/wood_function.hpp | 112 ++++++++++++++++ 8 files changed, 742 insertions(+) create mode 100644 src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/rosenbrock_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/rosenbrock_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/rosenbrock_wood_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/rosenbrock_wood_function.hpp create mode 100644 src/mlpack/core/optimizers/problems/wood_function.cpp create mode 100644 src/mlpack/core/optimizers/problems/wood_function.hpp diff --git a/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.cpp b/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.cpp new file mode 100644 index 0000000000..c052d2f829 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.cpp @@ -0,0 +1,102 @@ +/** + * @file generalized_rosenbrock_function.cpp + * @author Ryan Curtin + * @author Marcus Edel + * + * Implementation of the Generalized-Rosenbrock function. + * + * 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. + */ +#include "generalized_rosenbrock_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +GeneralizedRosenbrockFunction::GeneralizedRosenbrockFunction(const size_t n) : + n(n), + visitationOrder(arma::linspace >(0, n - 1, n)) + +{ + initialPoint.set_size(n, 1); + for (size_t i = 0; i < n; i++) // Set to [-1.2 1 -1.2 1 ...]. + { + if (i % 2 == 1) + { + initialPoint(i) = -1.2; + } + else + { + initialPoint(i) = 1; + } + } +} + +void GeneralizedRosenbrockFunction::Shuffle() +{ + visitationOrder = arma::shuffle(arma::linspace>(0, n - 2, + n - 1)); +} + +double GeneralizedRosenbrockFunction::Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const +{ + double objective = 0.0; + for (size_t j = begin; j < begin + batchSize; ++j) + { + const size_t p = visitationOrder[j]; + objective += 100 * std::pow((std::pow(coordinates[p], 2) + - coordinates[p + 1]), 2) + std::pow(1 - coordinates[p], 2); + } + + return objective; +} + +double GeneralizedRosenbrockFunction::Evaluate(const arma::mat& coordinates) + const +{ + double fval = 0; + for (size_t i = 0; i < (n - 1); i++) + { + fval += 100 * std::pow(std::pow(coordinates[i], 2) - + coordinates[i + 1], 2) + std::pow(1 - coordinates[i], 2); + } + + return fval; +} + +void GeneralizedRosenbrockFunction::Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const +{ + gradient.zeros(n); + for (size_t j = begin; j < begin + batchSize; ++j) + { + const size_t p = visitationOrder[j]; + gradient[p] = 400 * (std::pow(coordinates[p], 3) - coordinates[p] * + coordinates[p + 1]) + 2 * (coordinates[p] - 1); + gradient[p + 1] = 200 * (coordinates[p + 1] - std::pow(coordinates[p], 2)); + } +} + +void GeneralizedRosenbrockFunction::Gradient(const arma::mat& coordinates, + arma::mat& gradient) const +{ + gradient.set_size(n); + for (size_t i = 0; i < (n - 1); i++) + { + gradient[i] = 400 * (std::pow(coordinates[i], 3) - coordinates[i] * + coordinates[i + 1]) + 2 * (coordinates[i] - 1); + + if (i > 0) + gradient[i] += 200 * (coordinates[i] - std::pow(coordinates[i - 1], 2)); + } + + gradient[n - 1] = 200 * (coordinates[n - 1] - + std::pow(coordinates[n - 2], 2)); +} diff --git a/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.hpp b/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.hpp new file mode 100644 index 0000000000..727fba124d --- /dev/null +++ b/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.hpp @@ -0,0 +1,124 @@ +/** + * @file generalized_rosenbrock_function.hpp + * @author Ryan Curtin + * @author Marcus Edel + * + * Definition of the Generalized Rosenbrock function. + * + * 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_PROBLEMS_GENERALIZED_ROSENBROCK_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_GENERALIZED_ROSENBROCK_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Generalized Rosenbrock function in n dimensions, defined by + * f(x) = sum_i^{n - 1} (f(i)(x)) + * f_i(x) = 100 * (x_i^2 - x_{i + 1})^2 + (1 - x_i)^2 + * x_0 = [-1.2, 1, -1.2, 1, ...] + * + * This should optimize to f(x) = 0, at x = [1, 1, 1, 1, ...]. + * + * This function can also be used for stochastic gradient descent (SGD) as a + * decomposable function (DecomposableFunctionType), so there are other + * overloads of Evaluate() and Gradient() implemented, as well as + * NumFunctions(). + * + * For more information, please refer to: + * + * @code + * @phdthesis{Jong1975, + * title = {Analysis of the behavior of a class of genetic adaptive + * systems}, + * author = {De Jong, Kenneth Alan}, + * school = {Queensland University of Technology}, + * year = {1975}, + * type = {{PhD} dissertation}, + * } + * @endcode + */ +class GeneralizedRosenbrockFunction +{ + public: + /* + * Initialize the GeneralizedRosenbrockFunction. + * + * @param n Number of dimensions for the function. + */ + GeneralizedRosenbrockFunction(const size_t n); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return n - 1; } + + //! Get the starting point. + const arma::mat& GetInitialPoint() const { return initialPoint;} + + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient) const; + + private: + //! Locally-stored Initial point. + arma::mat initialPoint; + + //! //! Number of dimensions for the function. + size_t n; + + //! For shuffling. + arma::Row visitationOrder; +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_GENERALIZED_ROSENBROCK_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/rosenbrock_function.cpp b/src/mlpack/core/optimizers/problems/rosenbrock_function.cpp new file mode 100644 index 0000000000..360712c39d --- /dev/null +++ b/src/mlpack/core/optimizers/problems/rosenbrock_function.cpp @@ -0,0 +1,60 @@ +/** + * @file rosenbrock_function.cpp + * @author Ryan Curtin + * @author Marcus Edel + * + * Implementation of the Rosenbrock function. + * + * 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. + */ +#include "rosenbrock_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +RosenbrockFunction::RosenbrockFunction() { /* Nothing to do here */ } + +void RosenbrockFunction::Shuffle() { /* Nothing to do here */ } + +double RosenbrockFunction::Evaluate(const arma::mat& coordinates, + const size_t /* begin */, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + const double objective = /* f1(x) */ 100 * std::pow(x2 - std::pow(x1, 2), 2) + + /* f2(x) */ std::pow(1 - x1, 2); + + return objective; +} + +double RosenbrockFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, NumFunctions()); +} + +void RosenbrockFunction::Gradient(const arma::mat& coordinates, + const size_t /* begin */, + arma::mat& gradient, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + + gradient.set_size(2, 1); + gradient(0) = -2 * (1 - x1) + 400 * (std::pow(x1, 3) - x2 * x1); + gradient(1) = 200 * (x2 - std::pow(x1, 2)); +} + +void RosenbrockFunction::Gradient(const arma::mat& coordinates, + arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, 1); +} diff --git a/src/mlpack/core/optimizers/problems/rosenbrock_function.hpp b/src/mlpack/core/optimizers/problems/rosenbrock_function.hpp new file mode 100644 index 0000000000..d5243b1333 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/rosenbrock_function.hpp @@ -0,0 +1,108 @@ +/** + * @file rosenbrock_function.hpp + * @author Ryan Curtin + * @author Marcus Edel + * + * Definition of the Rosenbrock function. + * + * 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_PROBLEMS_ROSENBROCK_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_ROSENBROCK_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Rosenbrock function, defined by: + * + * f(x) = f1(x) + f2(x) + * f1(x) = 100 (x2 - x1^2)^2 + * f2(x) = (1 - x1)^2 + * x_0 = [-1.2, 1] + * + * This should optimize to f(x) = 0, at x = [1, 1]. + * + * For more information, please refer to: + * + * @code + * @article{Rosenbrock1960, + * title = {An Automatic Method for Finding the Greatest or Least Value of a + * Function}, + * author = {Rosenbrock, H. H.}, + * journal = {The Computer Journal}, + * number = {3}, + * pages = {175--184}, + * year = {1960}, + * } + * @endcode + */ +class RosenbrockFunction +{ + public: + //! Initialize the RosenbrockFunction. + RosenbrockFunction(); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return 1; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return arma::mat("-9; -9"); } + + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_ROSENBROCK_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/rosenbrock_wood_function.cpp b/src/mlpack/core/optimizers/problems/rosenbrock_wood_function.cpp new file mode 100644 index 0000000000..4b62319d42 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/rosenbrock_wood_function.cpp @@ -0,0 +1,64 @@ +/** + * @file rosenbrock_wood_function.cpp + * @author Ryan Curtin + * @author Marcus Edel + * + * Implementation of the Rosenbrock-Wood function. + * + * 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. + */ +#include "rosenbrock_wood_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +RosenbrockWoodFunction::RosenbrockWoodFunction() : rf(4), wf() +{ + initialPoint.set_size(4, 2); + initialPoint.col(0) = rf.GetInitialPoint(); + initialPoint.col(1) = wf.GetInitialPoint(); +} + +void RosenbrockWoodFunction::Shuffle() { /* Nothing to do here */ } + +double RosenbrockWoodFunction::Evaluate(const arma::mat& coordinates, + const size_t /* begin */, + const size_t /* batchSize */) const +{ + const double objective = rf.Evaluate(coordinates.col(0)) + + wf.Evaluate(coordinates.col(1)); + + return objective; +} + +double RosenbrockWoodFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, NumFunctions()); +} + +void RosenbrockWoodFunction::Gradient(const arma::mat& coordinates, + const size_t /* begin */, + arma::mat& gradient, + const size_t /* batchSize */) const +{ + gradient.set_size(4, 2); + + arma::vec grf(4); + arma::vec gwf(4); + + rf.Gradient(coordinates.col(0), grf); + wf.Gradient(coordinates.col(1), gwf); + + gradient.col(0) = grf; + gradient.col(1) = gwf; +} + +void RosenbrockWoodFunction::Gradient(const arma::mat& coordinates, + arma::mat& gradient) +{ + Gradient(coordinates, 0, gradient, 1); +} diff --git a/src/mlpack/core/optimizers/problems/rosenbrock_wood_function.hpp b/src/mlpack/core/optimizers/problems/rosenbrock_wood_function.hpp new file mode 100644 index 0000000000..4f1c952a6c --- /dev/null +++ b/src/mlpack/core/optimizers/problems/rosenbrock_wood_function.hpp @@ -0,0 +1,101 @@ +/** + * @file rosenbrock_wood_function.hpp + * @author Ryan Curtin + * @author Marcus Edel + * + * Definition of the Rosenbrock-Wood function. + * + * 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_PROBLEMS_ROSENBROCK_WOOD_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_ROSENBROCK_WOOD_FUNCTION_HPP + +#include + +#include +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Generalized Rosenbrock function in 4 dimensions with the Wood Function in + * four dimensions. In this function we are actually optimizing a 2x4 matrix of + * coordinates, not a vector. + */ +class RosenbrockWoodFunction +{ + public: + //! Initialize the RosenbrockWoodFunction. + RosenbrockWoodFunction(); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return 1; } + + //! Get the starting point. + const arma::mat& GetInitialPoint() const { return initialPoint; } + + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient); + private: + //! Locally-stored initial point. + arma::mat initialPoint; + + //! Locally-stored Generalized-Rosenbrock function. + GeneralizedRosenbrockFunction rf; + + //! Locally-stored Wood function. + WoodFunction wf; +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_ROSENBROCK_WOOD_FUNCTION_HPP diff --git a/src/mlpack/core/optimizers/problems/wood_function.cpp b/src/mlpack/core/optimizers/problems/wood_function.cpp new file mode 100644 index 0000000000..07cb3a0aa5 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/wood_function.cpp @@ -0,0 +1,71 @@ +/** + * @file wood_function.cpp + * @author Ryan Curtin + * @author Marcus Edel + * + * Implementation of the Wood function. + * + * 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. + */ +#include "wood_function.hpp" + +using namespace mlpack; +using namespace mlpack::optimization; +using namespace mlpack::optimization::test; + +WoodFunction::WoodFunction() { /* Nothing to do here */ } + +void WoodFunction::Shuffle() { /* Nothing to do here */ } + +double WoodFunction::Evaluate(const arma::mat& coordinates, + const size_t /* begin */, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + const double x3 = coordinates(2); + const double x4 = coordinates(3); + + const double objective = /* f1(x) */ 100 * std::pow(x2 - std::pow(x1, 2), 2) + + /* f2(x) */ std::pow(1 - x1, 2) + + /* f3(x) */ 90 * std::pow(x4 - std::pow(x3, 2), 2) + + /* f4(x) */ std::pow(1 - x3, 2) + + /* f5(x) */ 10 * std::pow(x2 + x4 - 2, 2) + + /* f6(x) */ (1.0 / 10.0) * std::pow(x2 - x4, 2); + + return objective; +} + +double WoodFunction::Evaluate(const arma::mat& coordinates) const +{ + return Evaluate(coordinates, 0, NumFunctions()); +} + +void WoodFunction::Gradient(const arma::mat& coordinates, + const size_t /* begin */, + arma::mat& gradient, + const size_t /* batchSize */) const +{ + // For convenience; we assume these temporaries will be optimized out. + const double x1 = coordinates(0); + const double x2 = coordinates(1); + const double x3 = coordinates(2); + const double x4 = coordinates(3); + + gradient.set_size(4, 1); + gradient(0) = 400 * (std::pow(x1, 3) - x2 * x1) - 2 * (1 - x1); + gradient(1) = 200 * (x2 - std::pow(x1, 2)) + 20 * (x2 + x4 - 2) + + (1.0 / 5.0) * (x2 - x4); + gradient(2) = 360 * (std::pow(x3, 3) - x4 * x3) - 2 * (1 - x3); + gradient(3) = 180 * (x4 - std::pow(x3, 2)) + 20 * (x2 + x4 - 2) - + (1.0 / 5.0) * (x2 - x4); +} + +void WoodFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) const +{ + Gradient(coordinates, 0, gradient, 1); +} diff --git a/src/mlpack/core/optimizers/problems/wood_function.hpp b/src/mlpack/core/optimizers/problems/wood_function.hpp new file mode 100644 index 0000000000..f4f2b4d267 --- /dev/null +++ b/src/mlpack/core/optimizers/problems/wood_function.hpp @@ -0,0 +1,112 @@ +/** + * @file wood_function.hpp + * @author Ryan Curtin + * @author Marcus Edel + * + * Definition of the Wood function. + * + * 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_PROBLEMS_WOOD_FUNCTION_HPP +#define MLPACK_CORE_OPTIMIZERS_PROBLEMS_WOOD_FUNCTION_HPP + +#include + +namespace mlpack { +namespace optimization { +namespace test { + +/** + * The Wood function, defined by + * f(x) = f1(x) + f2(x) + f3(x) + f4(x) + f5(x) + f6(x) + * f1(x) = 100 (x2 - x1^2)^2 + * f2(x) = (1 - x1)^2 + * f3(x) = 90 (x4 - x3^2)^2 + * f4(x) = (1 - x3)^2 + * f5(x) = 10 (x2 + x4 - 2)^2 + * f6(x) = (1 / 10) (x2 - x4)^2 + * x_0 = [-3, -1, -3, -1] + * + * This should optimize to f(x) = 0, at x = [1, 1, 1, 1]. + * + * For more information, please refer to: + * + * @code + * @article{Grippo1989, + * title = {A truncated Newton method with nonmonotone line search for + * unconstrained optimization}, + * author = {Grippo, L. and Lampariello, F. and Lucidi, S.}, + * journal = {Journal of Optimization Theory and Applications}, + * year = {1989}, + * volume = {60}, + * number = {3}, + * pages = {401--419}, + * } + * @endcode + */ +class WoodFunction +{ + public: + //! Initialize the WoodFunction. + WoodFunction(); + + /** + * Shuffle the order of function visitation. This may be called by the + * optimizer. + */ + void Shuffle(); + + //! Return 1 (the number of functions). + size_t NumFunctions() const { return 1; } + + //! Get the starting point. + arma::mat GetInitialPoint() const { return arma::mat("-3; -1; -3; -1"); } + + /* + * Evaluate a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param batchSize Number of points to process. + */ + double Evaluate(const arma::mat& coordinates, + const size_t begin, + const size_t batchSize) const; + + /* + * Evaluate a function with the given coordinates. + * + * @param coordinates The function coordinates. + */ + double Evaluate(const arma::mat& coordinates) const; + + /* + * Evaluate the gradient of a function for a particular batch-size + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + * @param batchSize Number of points to process. + */ + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::mat& gradient, + const size_t batchSize) const; + + /* + * Evaluate the gradient of a function with the given coordinates. + * + * @param coordinates The function coordinates. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, arma::mat& gradient) const; +}; + +} // namespace test +} // namespace optimization +} // namespace mlpack + +#endif // MLPACK_CORE_OPTIMIZERS_PROBLEMS_WOOD_FUNCTION_HPP From f784f69c64b7c2e54a54d9b8621ec3c2e2679839 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Fri, 22 Dec 2017 23:10:59 +0100 Subject: [PATCH 011/113] Add default batch size to the Generalized-Rosenbrock function. --- .../optimizers/problems/generalized_rosenbrock_function.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.hpp b/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.hpp index 727fba124d..68d5f095c2 100644 --- a/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.hpp +++ b/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.hpp @@ -76,7 +76,7 @@ class GeneralizedRosenbrockFunction */ double Evaluate(const arma::mat& coordinates, const size_t begin, - const size_t batchSize) const; + const size_t batchSize = 1) const; /* * Evaluate a function with the given coordinates. @@ -96,7 +96,7 @@ class GeneralizedRosenbrockFunction void Gradient(const arma::mat& coordinates, const size_t begin, arma::mat& gradient, - const size_t batchSize) const; + const size_t batchSize = 1) const; /* * Evaluate the gradient of a function with the given coordinates. From 5c22688fce294a2af73c77e3be35785d1b4c9e00 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Sat, 23 Dec 2017 18:56:22 +0100 Subject: [PATCH 012/113] Minor style fixes. --- .../core/optimizers/problems/booth_function.hpp | 2 +- .../core/optimizers/problems/bukin_function.hpp | 2 +- .../core/optimizers/problems/colville_function.hpp | 2 +- .../core/optimizers/problems/drop_wave_function.hpp | 2 +- .../core/optimizers/problems/easom_function.hpp | 2 +- .../core/optimizers/problems/eggholder_function.hpp | 2 +- .../problems/generalized_rosenbrock_function.cpp | 13 +++++++++++++ .../problems/generalized_rosenbrock_function.hpp | 13 ++++++++++++- .../core/optimizers/problems/matyas_function.hpp | 2 +- .../optimizers/problems/mc_cormick_function.hpp | 2 +- .../core/optimizers/problems/rastrigin_function.hpp | 2 +- .../optimizers/problems/rosenbrock_function.hpp | 2 +- .../problems/rosenbrock_wood_function.hpp | 2 +- .../core/optimizers/problems/schwefel_function.hpp | 2 +- .../core/optimizers/problems/sgd_test_function.hpp | 2 +- .../core/optimizers/problems/sphere_function.hpp | 2 +- .../problems/styblinski_tang_function.hpp | 2 +- .../core/optimizers/problems/wood_function.cpp | 3 ++- .../core/optimizers/problems/wood_function.hpp | 2 +- 19 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/mlpack/core/optimizers/problems/booth_function.hpp b/src/mlpack/core/optimizers/problems/booth_function.hpp index 3977a0470a..495099baa8 100644 --- a/src/mlpack/core/optimizers/problems/booth_function.hpp +++ b/src/mlpack/core/optimizers/problems/booth_function.hpp @@ -77,7 +77,7 @@ class BoothFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/bukin_function.hpp b/src/mlpack/core/optimizers/problems/bukin_function.hpp index 55885af625..782a0583ac 100644 --- a/src/mlpack/core/optimizers/problems/bukin_function.hpp +++ b/src/mlpack/core/optimizers/problems/bukin_function.hpp @@ -78,7 +78,7 @@ class BukinFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/colville_function.hpp b/src/mlpack/core/optimizers/problems/colville_function.hpp index e1deb8c6a9..76d1f9b5c6 100644 --- a/src/mlpack/core/optimizers/problems/colville_function.hpp +++ b/src/mlpack/core/optimizers/problems/colville_function.hpp @@ -78,7 +78,7 @@ class ColvilleFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/drop_wave_function.hpp b/src/mlpack/core/optimizers/problems/drop_wave_function.hpp index e13ee71b56..dfa8f693a8 100644 --- a/src/mlpack/core/optimizers/problems/drop_wave_function.hpp +++ b/src/mlpack/core/optimizers/problems/drop_wave_function.hpp @@ -77,7 +77,7 @@ class DropWaveFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/easom_function.hpp b/src/mlpack/core/optimizers/problems/easom_function.hpp index 8043a92474..e3b97a8b67 100644 --- a/src/mlpack/core/optimizers/problems/easom_function.hpp +++ b/src/mlpack/core/optimizers/problems/easom_function.hpp @@ -77,7 +77,7 @@ class EasomFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/eggholder_function.hpp b/src/mlpack/core/optimizers/problems/eggholder_function.hpp index cc4153fad5..093984a34a 100644 --- a/src/mlpack/core/optimizers/problems/eggholder_function.hpp +++ b/src/mlpack/core/optimizers/problems/eggholder_function.hpp @@ -78,7 +78,7 @@ class EggholderFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.cpp b/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.cpp index c052d2f829..6a75881619 100644 --- a/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.cpp +++ b/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.cpp @@ -100,3 +100,16 @@ void GeneralizedRosenbrockFunction::Gradient(const arma::mat& coordinates, gradient[n - 1] = 200 * (coordinates[n - 1] - std::pow(coordinates[n - 2], 2)); } + +void GeneralizedRosenbrockFunction::Gradient(const arma::mat& coordinates, + const size_t begin, + arma::sp_mat& gradient) const +{ + gradient.set_size(n); + + const size_t p = visitationOrder[begin]; + + gradient[p] = 400 * (std::pow(coordinates[p], 3) - coordinates[p] * + coordinates[p + 1]) + 2 * (coordinates[p] - 1); + gradient[p + 1] = 200 * (coordinates[p + 1] - std::pow(coordinates[p], 2)); +} diff --git a/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.hpp b/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.hpp index 68d5f095c2..b541464ed2 100644 --- a/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.hpp +++ b/src/mlpack/core/optimizers/problems/generalized_rosenbrock_function.hpp @@ -86,7 +86,7 @@ class GeneralizedRosenbrockFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. @@ -98,6 +98,17 @@ class GeneralizedRosenbrockFunction arma::mat& gradient, const size_t batchSize = 1) const; + /* + * Evaluate the gradient of a function for a particular batch-size. + * + * @param coordinates The function coordinates. + * @param begin The first function. + * @param gradient The function gradient. + */ + void Gradient(const arma::mat& coordinates, + const size_t begin, + arma::sp_mat& gradient) const; + /* * Evaluate the gradient of a function with the given coordinates. * diff --git a/src/mlpack/core/optimizers/problems/matyas_function.hpp b/src/mlpack/core/optimizers/problems/matyas_function.hpp index 979e69119e..be5b5d35ad 100644 --- a/src/mlpack/core/optimizers/problems/matyas_function.hpp +++ b/src/mlpack/core/optimizers/problems/matyas_function.hpp @@ -77,7 +77,7 @@ class MatyasFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp b/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp index 56b31b2737..0b91d22b71 100644 --- a/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp +++ b/src/mlpack/core/optimizers/problems/mc_cormick_function.hpp @@ -77,7 +77,7 @@ class McCormickFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/rastrigin_function.hpp b/src/mlpack/core/optimizers/problems/rastrigin_function.hpp index a062724a9a..522a10dd50 100644 --- a/src/mlpack/core/optimizers/problems/rastrigin_function.hpp +++ b/src/mlpack/core/optimizers/problems/rastrigin_function.hpp @@ -80,7 +80,7 @@ class RastriginFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/rosenbrock_function.hpp b/src/mlpack/core/optimizers/problems/rosenbrock_function.hpp index d5243b1333..a686622a1a 100644 --- a/src/mlpack/core/optimizers/problems/rosenbrock_function.hpp +++ b/src/mlpack/core/optimizers/problems/rosenbrock_function.hpp @@ -80,7 +80,7 @@ class RosenbrockFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/rosenbrock_wood_function.hpp b/src/mlpack/core/optimizers/problems/rosenbrock_wood_function.hpp index 4f1c952a6c..34d7333f7e 100644 --- a/src/mlpack/core/optimizers/problems/rosenbrock_wood_function.hpp +++ b/src/mlpack/core/optimizers/problems/rosenbrock_wood_function.hpp @@ -64,7 +64,7 @@ class RosenbrockWoodFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/schwefel_function.hpp b/src/mlpack/core/optimizers/problems/schwefel_function.hpp index 69469ec4a4..e1e0dfdee1 100644 --- a/src/mlpack/core/optimizers/problems/schwefel_function.hpp +++ b/src/mlpack/core/optimizers/problems/schwefel_function.hpp @@ -80,7 +80,7 @@ class SchwefelFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/sgd_test_function.hpp b/src/mlpack/core/optimizers/problems/sgd_test_function.hpp index 2709b597c7..bdfe7afdd7 100644 --- a/src/mlpack/core/optimizers/problems/sgd_test_function.hpp +++ b/src/mlpack/core/optimizers/problems/sgd_test_function.hpp @@ -45,7 +45,7 @@ class SGDTestFunction //! Evaluate a function. double Evaluate(const arma::mat& coordinates, const size_t i) const; - //! Evaluate a function for a particular batch-size + //! Evaluate a function for a particular batch-size. double Evaluate(const arma::mat& coordinates, const size_t begin, const size_t batchSize) const; diff --git a/src/mlpack/core/optimizers/problems/sphere_function.hpp b/src/mlpack/core/optimizers/problems/sphere_function.hpp index cdd172dde9..80b88a77b3 100644 --- a/src/mlpack/core/optimizers/problems/sphere_function.hpp +++ b/src/mlpack/core/optimizers/problems/sphere_function.hpp @@ -81,7 +81,7 @@ class SphereFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/styblinski_tang_function.hpp b/src/mlpack/core/optimizers/problems/styblinski_tang_function.hpp index 1dab305604..4e52f266f5 100644 --- a/src/mlpack/core/optimizers/problems/styblinski_tang_function.hpp +++ b/src/mlpack/core/optimizers/problems/styblinski_tang_function.hpp @@ -82,7 +82,7 @@ class StyblinskiTangFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. diff --git a/src/mlpack/core/optimizers/problems/wood_function.cpp b/src/mlpack/core/optimizers/problems/wood_function.cpp index 07cb3a0aa5..62f9c823f2 100644 --- a/src/mlpack/core/optimizers/problems/wood_function.cpp +++ b/src/mlpack/core/optimizers/problems/wood_function.cpp @@ -65,7 +65,8 @@ void WoodFunction::Gradient(const arma::mat& coordinates, (1.0 / 5.0) * (x2 - x4); } -void WoodFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) const +void WoodFunction::Gradient(const arma::mat& coordinates, arma::mat& gradient) + const { Gradient(coordinates, 0, gradient, 1); } diff --git a/src/mlpack/core/optimizers/problems/wood_function.hpp b/src/mlpack/core/optimizers/problems/wood_function.hpp index f4f2b4d267..c8fb443b1b 100644 --- a/src/mlpack/core/optimizers/problems/wood_function.hpp +++ b/src/mlpack/core/optimizers/problems/wood_function.hpp @@ -84,7 +84,7 @@ class WoodFunction double Evaluate(const arma::mat& coordinates) const; /* - * Evaluate the gradient of a function for a particular batch-size + * Evaluate the gradient of a function for a particular batch-size. * * @param coordinates The function coordinates. * @param begin The first function. From 9a449d82510923eb78a6ce42d91286fe9bd97a94 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Sat, 23 Dec 2017 23:27:50 +0100 Subject: [PATCH 013/113] Fix Rastrigin expression and use it for the SA test. --- .../problems/rastrigin_function.cpp | 10 ++---- .../problems/rosenbrock_function.hpp | 2 +- src/mlpack/tests/sa_test.cpp | 36 ++++--------------- 3 files changed, 9 insertions(+), 39 deletions(-) diff --git a/src/mlpack/core/optimizers/problems/rastrigin_function.cpp b/src/mlpack/core/optimizers/problems/rastrigin_function.cpp index 745cb1638d..65fa3bb85f 100644 --- a/src/mlpack/core/optimizers/problems/rastrigin_function.cpp +++ b/src/mlpack/core/optimizers/problems/rastrigin_function.cpp @@ -21,13 +21,7 @@ RastriginFunction::RastriginFunction(const size_t n) : { initialPoint.set_size(n, 1); - for (size_t i = 0; i < n; ++i) // Set to [4.13 -4.15 4.13 -4.15...]. - { - if (i % 2 == 1) - initialPoint(i) = -4.15; - else - initialPoint(i) = 4.13; - } + initialPoint.fill(-3); } void RastriginFunction::Shuffle() @@ -47,7 +41,7 @@ double RastriginFunction::Evaluate(const arma::mat& coordinates, objective += std::pow(coordinates(p), 2) - 10.0 * std::cos(2.0 * M_PI * coordinates(p)); } - objective *= 10.0 * n; + objective += 10.0 * n; return objective; } diff --git a/src/mlpack/core/optimizers/problems/rosenbrock_function.hpp b/src/mlpack/core/optimizers/problems/rosenbrock_function.hpp index a686622a1a..9079b10762 100644 --- a/src/mlpack/core/optimizers/problems/rosenbrock_function.hpp +++ b/src/mlpack/core/optimizers/problems/rosenbrock_function.hpp @@ -59,7 +59,7 @@ class RosenbrockFunction size_t NumFunctions() const { return 1; } //! Get the starting point. - arma::mat GetInitialPoint() const { return arma::mat("-9; -9"); } + arma::mat GetInitialPoint() const { return arma::mat("-1.2; 1"); } /* * Evaluate a function for a particular batch-size. diff --git a/src/mlpack/tests/sa_test.cpp b/src/mlpack/tests/sa_test.cpp index 6a46f21b5a..9f964166c0 100644 --- a/src/mlpack/tests/sa_test.cpp +++ b/src/mlpack/tests/sa_test.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,7 @@ using namespace mlpack::metric; BOOST_AUTO_TEST_SUITE(SATest); +// The Generalized-Rosenbrock function is a simple function to optimize. BOOST_AUTO_TEST_CASE(GeneralizedRosenbrockTest) { size_t dim = 10; @@ -75,36 +77,9 @@ BOOST_AUTO_TEST_CASE(RosenbrockTest) } /** - * The Rastrigrin function, a (not very) simple nonconvex function. It is - * defined by - * - * f(x) = 10n + \sum_{i = 1}^{n} (x_i^2 - 10 cos(2 \pi x_i)). - * - * It has very many local minima, so finding the true global minimum is - * difficult. The function is two-dimensional, and has minimum 0 where - * x = [0 0]. We are only using it for simulated annealing, so there is no need - * to implement the gradient. + * The Rastrigrin function, a (not very) simple nonconvex function. It has very + * many local minima, so finding the true global minimum is difficult. */ -class RastrigrinFunction -{ - public: - double Evaluate(const arma::mat& coordinates) const - { - double objective = 20; // 10 * n, n = 2. - objective += std::pow(coordinates[0], 2.0) - - 10 * std::cos(2 * M_PI * coordinates[0]); - objective += std::pow(coordinates[1], 2.0) - - 10 * std::cos(2 * M_PI * coordinates[1]); - - return objective; - } - - arma::mat GetInitialPoint() const - { - return arma::mat("-3 -3"); - } -}; - BOOST_AUTO_TEST_CASE(RastrigrinFunctionTest) { // Simulated annealing isn't guaranteed to converge (except in very specific @@ -114,9 +89,10 @@ BOOST_AUTO_TEST_CASE(RastrigrinFunctionTest) for (size_t trial = 0; trial < 4; ++trial) { - RastrigrinFunction f; + RastriginFunction f(2); ExponentialSchedule schedule; // The convergence is very sensitive to the choices of maxMove and initMove. + // SA<> sa(schedule, 2000000, 100, 50, 1000, 1e-12, 2, 2.0, 0.5, 0.1); SA<> sa(schedule, 2000000, 100, 50, 1000, 1e-12, 2, 2.0, 0.5, 0.1); arma::mat coordinates = f.GetInitialPoint(); From 5741b58b29b8bc9c2bb5b784ce7d571aa1bf4f96 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 2 Jan 2018 12:16:14 -0500 Subject: [PATCH 014/113] Let's have AppVeyor run the tests too. --- .appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.appveyor.yml b/.appveyor.yml index 3d157b9ebf..1c4079eaa9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -34,6 +34,7 @@ build_script: - '"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" "C:\projects\mlpack\armadillo-7.800.2\build\armadillo.sln" /m /verbosity:quiet /p:Configuration=Release;Platform=x64' - cd C:\projects\mlpack && mkdir build && cd build - cmake -G "Visual Studio 14 2015 Win64" -DBLAS_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DARMADILLO_INCLUDE_DIR="C:/projects/mlpack/armadillo-7.800.2/include" -DARMADILLO_LIBRARY:FILEPATH="C:\projects\mlpack\armadillo-7.800.2\build\Debug\armadillo.lib" -DBOOST_INCLUDEDIR:PATH="C:\projects\mlpack\boost.1.60.0.0\lib\native\include" -DBOOST_LIBRARYDIR:PATH="C:\projects\mlpack\boost_libs" -DDEBUG=ON -DPROFILE=ON -DBUILD_PYTHON_BINDINGS=OFF .. + - ctest . - '"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" "C:\projects\mlpack\build\mlpack.sln" /m /verbosity:minimal /nologo /p:BuildInParallel=true /p:Configuration=Release;Platform=x64' - 7z a mlpack-windows-no-libs.zip "%APPVEYOR_BUILD_FOLDER%\build\Release\*.exe" - 7z a mlpack-windows.zip "%APPVEYOR_BUILD_FOLDER%\build\Release\*.*" "%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/*.*" From cac5dca85ad75830c51197f2ae901542489e6088 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 2 Jan 2018 13:01:22 -0500 Subject: [PATCH 015/113] Wait, there is already a testing block... --- .appveyor.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 1c4079eaa9..cb130d9f58 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -34,7 +34,6 @@ build_script: - '"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" "C:\projects\mlpack\armadillo-7.800.2\build\armadillo.sln" /m /verbosity:quiet /p:Configuration=Release;Platform=x64' - cd C:\projects\mlpack && mkdir build && cd build - cmake -G "Visual Studio 14 2015 Win64" -DBLAS_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DARMADILLO_INCLUDE_DIR="C:/projects/mlpack/armadillo-7.800.2/include" -DARMADILLO_LIBRARY:FILEPATH="C:\projects\mlpack\armadillo-7.800.2\build\Debug\armadillo.lib" -DBOOST_INCLUDEDIR:PATH="C:\projects\mlpack\boost.1.60.0.0\lib\native\include" -DBOOST_LIBRARYDIR:PATH="C:\projects\mlpack\boost_libs" -DDEBUG=ON -DPROFILE=ON -DBUILD_PYTHON_BINDINGS=OFF .. - - ctest . - '"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" "C:\projects\mlpack\build\mlpack.sln" /m /verbosity:minimal /nologo /p:BuildInParallel=true /p:Configuration=Release;Platform=x64' - 7z a mlpack-windows-no-libs.zip "%APPVEYOR_BUILD_FOLDER%\build\Release\*.exe" - 7z a mlpack-windows.zip "%APPVEYOR_BUILD_FOLDER%\build\Release\*.*" "%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/*.*" @@ -57,5 +56,5 @@ cache: # All plans have maximum build job execution time of 60 minutes. But right, now # the machine takes 30 minutes to build the code and at least 50 minutes to run # all tests. -# test_script: - -# '"C:\projects\mlpack\build\Release\mlpack_test.exe" -p' +test_script: + - '"C:\projects\mlpack\build\Release\mlpack_test.exe" -p' From 68bc759cf821b4b85fc443ae1b0abeaf1c51f1bf Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 2 Jan 2018 15:16:35 -0500 Subject: [PATCH 016/113] Try to use ctest to run the tests. --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index cb130d9f58..4e80c97a8a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -57,4 +57,4 @@ cache: # the machine takes 30 minutes to build the code and at least 50 minutes to run # all tests. test_script: - - '"C:\projects\mlpack\build\Release\mlpack_test.exe" -p' + - ctest From 7d5626053998ca9769fafca8b4d381ddecf3a677 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 2 Jan 2018 18:10:52 -0500 Subject: [PATCH 017/113] Specify config target for tests. Hopefully it's right... --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4e80c97a8a..5fdf71d141 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -57,4 +57,4 @@ cache: # the machine takes 30 minutes to build the code and at least 50 minutes to run # all tests. test_script: - - ctest + - ctest -C Release From 357d6d300b52aebf0b5dd0f32bfad0d6006c3083 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Wed, 3 Jan 2018 10:23:50 -0500 Subject: [PATCH 018/113] Try explicitly specifying build type. --- .appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 5fdf71d141..3398654e8b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -30,10 +30,10 @@ build_script: - if not exist armadillo.tar.xz appveyor DownloadFile "http://sourceforge.net/projects/arma/files/armadillo-7.800.2.tar.xz" -FileName armadillo.tar.xz - 7z x armadillo.tar.xz -so | 7z x -si -ttar > nul - cd armadillo-7.800.2 && mkdir build && cd build - - cmake -G "Visual Studio 14 2015 Win64" -DBLAS_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DCMAKE_PREFIX:FILEPATH="%APPVEYOR_BUILD_FOLDER%/armadillo" -DBUILD_SHARED_LIBS=OFF .. + - cmake -G "Visual Studio 14 2015 Win64" -DBLAS_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DCMAKE_PREFIX:FILEPATH="%APPVEYOR_BUILD_FOLDER%/armadillo" -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Debug .. - '"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" "C:\projects\mlpack\armadillo-7.800.2\build\armadillo.sln" /m /verbosity:quiet /p:Configuration=Release;Platform=x64' - cd C:\projects\mlpack && mkdir build && cd build - - cmake -G "Visual Studio 14 2015 Win64" -DBLAS_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DARMADILLO_INCLUDE_DIR="C:/projects/mlpack/armadillo-7.800.2/include" -DARMADILLO_LIBRARY:FILEPATH="C:\projects\mlpack\armadillo-7.800.2\build\Debug\armadillo.lib" -DBOOST_INCLUDEDIR:PATH="C:\projects\mlpack\boost.1.60.0.0\lib\native\include" -DBOOST_LIBRARYDIR:PATH="C:\projects\mlpack\boost_libs" -DDEBUG=ON -DPROFILE=ON -DBUILD_PYTHON_BINDINGS=OFF .. + - cmake -G "Visual Studio 14 2015 Win64" -DBLAS_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DARMADILLO_INCLUDE_DIR="C:/projects/mlpack/armadillo-7.800.2/include" -DARMADILLO_LIBRARY:FILEPATH="C:\projects\mlpack\armadillo-7.800.2\build\Debug\armadillo.lib" -DBOOST_INCLUDEDIR:PATH="C:\projects\mlpack\boost.1.60.0.0\lib\native\include" -DBOOST_LIBRARYDIR:PATH="C:\projects\mlpack\boost_libs" -DDEBUG=ON -DPROFILE=ON -DBUILD_PYTHON_BINDINGS=OFF -DCMAKE_BUILD_TYPE=Debug .. - '"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" "C:\projects\mlpack\build\mlpack.sln" /m /verbosity:minimal /nologo /p:BuildInParallel=true /p:Configuration=Release;Platform=x64' - 7z a mlpack-windows-no-libs.zip "%APPVEYOR_BUILD_FOLDER%\build\Release\*.exe" - 7z a mlpack-windows.zip "%APPVEYOR_BUILD_FOLDER%\build\Release\*.*" "%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/*.*" @@ -57,4 +57,4 @@ cache: # the machine takes 30 minutes to build the code and at least 50 minutes to run # all tests. test_script: - - ctest -C Release + - ctest -C Debug From 1f6da87a0c7d59faaf0d0775fc025115c2141072 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 5 Jan 2018 13:33:12 -0500 Subject: [PATCH 019/113] Build in release mode. --- .appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 3398654e8b..0df5e42fd3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -30,10 +30,10 @@ build_script: - if not exist armadillo.tar.xz appveyor DownloadFile "http://sourceforge.net/projects/arma/files/armadillo-7.800.2.tar.xz" -FileName armadillo.tar.xz - 7z x armadillo.tar.xz -so | 7z x -si -ttar > nul - cd armadillo-7.800.2 && mkdir build && cd build - - cmake -G "Visual Studio 14 2015 Win64" -DBLAS_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DCMAKE_PREFIX:FILEPATH="%APPVEYOR_BUILD_FOLDER%/armadillo" -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Debug .. + - cmake -G "Visual Studio 14 2015 Win64" -DBLAS_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DCMAKE_PREFIX:FILEPATH="%APPVEYOR_BUILD_FOLDER%/armadillo" -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release .. - '"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" "C:\projects\mlpack\armadillo-7.800.2\build\armadillo.sln" /m /verbosity:quiet /p:Configuration=Release;Platform=x64' - cd C:\projects\mlpack && mkdir build && cd build - - cmake -G "Visual Studio 14 2015 Win64" -DBLAS_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DARMADILLO_INCLUDE_DIR="C:/projects/mlpack/armadillo-7.800.2/include" -DARMADILLO_LIBRARY:FILEPATH="C:\projects\mlpack\armadillo-7.800.2\build\Debug\armadillo.lib" -DBOOST_INCLUDEDIR:PATH="C:\projects\mlpack\boost.1.60.0.0\lib\native\include" -DBOOST_LIBRARYDIR:PATH="C:\projects\mlpack\boost_libs" -DDEBUG=ON -DPROFILE=ON -DBUILD_PYTHON_BINDINGS=OFF -DCMAKE_BUILD_TYPE=Debug .. + - cmake -G "Visual Studio 14 2015 Win64" -DBLAS_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DLAPACK_LIBRARY:FILEPATH="%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a" -DARMADILLO_INCLUDE_DIR="C:/projects/mlpack/armadillo-7.800.2/include" -DARMADILLO_LIBRARY:FILEPATH="C:\projects\mlpack\armadillo-7.800.2\build\Debug\armadillo.lib" -DBOOST_INCLUDEDIR:PATH="C:\projects\mlpack\boost.1.60.0.0\lib\native\include" -DBOOST_LIBRARYDIR:PATH="C:\projects\mlpack\boost_libs" -DDEBUG=OFF -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF -DCMAKE_BUILD_TYPE=Release .. - '"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" "C:\projects\mlpack\build\mlpack.sln" /m /verbosity:minimal /nologo /p:BuildInParallel=true /p:Configuration=Release;Platform=x64' - 7z a mlpack-windows-no-libs.zip "%APPVEYOR_BUILD_FOLDER%\build\Release\*.exe" - 7z a mlpack-windows.zip "%APPVEYOR_BUILD_FOLDER%\build\Release\*.*" "%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/*.*" @@ -57,4 +57,4 @@ cache: # the machine takes 30 minutes to build the code and at least 50 minutes to run # all tests. test_script: - - ctest -C Debug + - ctest -C Release From 04b1e279f4c246520d3019f216325a6f02f26521 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Sat, 6 Jan 2018 23:31:42 +0100 Subject: [PATCH 020/113] Add some more tests for each problem. --- src/mlpack/tests/adam_test.cpp | 103 ++++++++++++++++++++++++++++++++ src/mlpack/tests/lbfgs_test.cpp | 18 ++++++ 2 files changed, 121 insertions(+) diff --git a/src/mlpack/tests/adam_test.cpp b/src/mlpack/tests/adam_test.cpp index 06144e9fb2..c5e1d71a45 100644 --- a/src/mlpack/tests/adam_test.cpp +++ b/src/mlpack/tests/adam_test.cpp @@ -14,7 +14,15 @@ #include #include + #include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -31,6 +39,101 @@ using namespace mlpack; BOOST_AUTO_TEST_SUITE(AdamTest); + +/** + * Test the Adam optimizer on the Sphere function. + */ +BOOST_AUTO_TEST_CASE(AdamSphereFunctionTest) +{ + SphereFunction f(2); + Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); + + arma::mat coordinates = f.GetInitialPoint(); + optimizer.Optimize(f, coordinates); + + BOOST_REQUIRE_SMALL(coordinates[0], 0.1); + BOOST_REQUIRE_SMALL(coordinates[1], 0.1); +} + +/** + * Test the Adam optimizer on the Wood function. + */ +BOOST_AUTO_TEST_CASE(AdamStyblinskiTangFunctionTest) +{ + StyblinskiTangFunction f(2); + Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false); + + arma::mat coordinates = f.GetInitialPoint(); + optimizer.Optimize(f, coordinates); + + BOOST_REQUIRE_CLOSE(coordinates[0], -2.9, 1.0); // 1% error tolerance. + BOOST_REQUIRE_CLOSE(coordinates[1], -2.9, 1.0); // 1% error tolerance. +} + +/** + * Test the Adam optimizer on the McCormick function. + */ +BOOST_AUTO_TEST_CASE(AdamMcCormickFunctionTest) +{ + McCormickFunction f; + Adam optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); + + arma::mat coordinates = f.GetInitialPoint(); + optimizer.Optimize(f, coordinates); + + BOOST_REQUIRE_CLOSE(coordinates[0], -0.547, 3.0); // 3% error tolerance. + BOOST_REQUIRE_CLOSE(coordinates[1], -1.547, 3.0); // 3% error tolerance. +} + +/** + * Test the Adam optimizer on the Matyas function. + */ +BOOST_AUTO_TEST_CASE(AdamMatyasFunctionTest) +{ + MatyasFunction f; + Adam optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); + + arma::mat coordinates = f.GetInitialPoint(); + optimizer.Optimize(f, coordinates); + + std::cout << coordinates << std::endl; + + // 3% error tolerance. + BOOST_REQUIRE_CLOSE(std::trunc(100.0 * coordinates[0]) / 100.0, 0.0, 3.0); + BOOST_REQUIRE_CLOSE(std::trunc(100.0 * coordinates[1]) / 100.0, 0.0, 3.0); +} + +/** + * Test the Adam optimizer on the Easom function. + */ +BOOST_AUTO_TEST_CASE(AdamEasomFunctionTest) +{ + EasomFunction f; + Adam optimizer(0.2, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false); + + arma::mat coordinates = arma::mat("2.9; 2.9"); + optimizer.Optimize(f, coordinates); + + // 5% error tolerance. + BOOST_REQUIRE_CLOSE(std::trunc(100.0 * coordinates[0]) / 100.0, 3.14, 3.0); + BOOST_REQUIRE_CLOSE(std::trunc(100.0 * coordinates[1]) / 100.0, 3.14, 3.0); +} + +/** + * Test the Adam optimizer on the Booth function. + */ +BOOST_AUTO_TEST_CASE(AdamBoothFunctionTest) +{ + BoothFunction f; + Adam optimizer(1e-1, 1, 0.7, 0.999, 1e-8, 500000, 1e-9, true); + + arma::mat coordinates = f.GetInitialPoint(); + optimizer.Optimize(f, coordinates); + + BOOST_REQUIRE_CLOSE(coordinates[0], 1.0, 0.2); + BOOST_REQUIRE_CLOSE(coordinates[1], 3.0, 0.2); +} + /** * Tests the Adam optimizer using a simple test function. */ diff --git a/src/mlpack/tests/lbfgs_test.cpp b/src/mlpack/tests/lbfgs_test.cpp index f1eb863e97..dc95ae0f24 100644 --- a/src/mlpack/tests/lbfgs_test.cpp +++ b/src/mlpack/tests/lbfgs_test.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include "test_tools.hpp" @@ -44,6 +45,23 @@ BOOST_AUTO_TEST_CASE(RosenbrockFunctionTest) BOOST_REQUIRE_CLOSE(coords[1], 1.0, 1e-5); } +/** + * Tests the L-BFGS optimizer using the Colville Function. + */ +BOOST_AUTO_TEST_CASE(ColvilleFunctionTest) +{ + ColvilleFunction f; + L_BFGS lbfgs; + lbfgs.MaxIterations() = 10000; + + arma::vec coords = f.GetInitialPoint(); + if (!lbfgs.Optimize(f, coords)) + BOOST_FAIL("L-BFGS optimization reported failure."); + + BOOST_REQUIRE_CLOSE(coords[0], 1.0, 1e-5); + BOOST_REQUIRE_CLOSE(coords[1], 1.0, 1e-5); +} + /** * Tests the L-BFGS optimizer using the Wood Function. */ From 616ba3f11e6d25ce960dc2cf8e7618b977a955a9 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 8 Jan 2018 13:52:24 -0500 Subject: [PATCH 021/113] Always use /bigobj on MSVC. --- CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d18bc4733..82742c8981 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,11 @@ endif() # specific. This list is a subset of MLPACK_LIBRARIES. set(COMPILER_SUPPORT_LIBRARIES "") +# If we are using MSVC, we need /bigobj. +if (MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") +endif () + # If using clang, we have to link against libc++ depending on the # OS (at least on some systems). Further, gcc sometimes optimizes calls to # math.h functions, making -lm unnecessary with gcc, but it may still be @@ -136,8 +141,6 @@ if(DEBUG) add_definitions(-DDEBUG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -ftemplate-backtrace-limit=0") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -g -O0") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") endif() # mlpack uses it's own mlpack::backtrace class based on Binary File Descriptor From 2244fcbb9cc9dce3792b173d808adc211c3a11db Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Mon, 8 Jan 2018 21:19:41 +0100 Subject: [PATCH 022/113] Fix Schwefel function expression. --- src/mlpack/core/optimizers/problems/schwefel_function.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/core/optimizers/problems/schwefel_function.cpp b/src/mlpack/core/optimizers/problems/schwefel_function.cpp index fc1efe9e47..8e0ca9336c 100644 --- a/src/mlpack/core/optimizers/problems/schwefel_function.cpp +++ b/src/mlpack/core/optimizers/problems/schwefel_function.cpp @@ -40,7 +40,7 @@ double SchwefelFunction::Evaluate(const arma::mat& coordinates, const size_t p = visitationOrder[j]; objective += coordinates(p) * std::sin(std::sqrt(std::abs(coordinates(p)))); } - objective *= 418.9829 * n; + objective -= 418.9829 * batchSize; return objective; } @@ -60,7 +60,7 @@ void SchwefelFunction::Gradient(const arma::mat& coordinates, for (size_t j = begin; j < begin + batchSize; ++j) { const size_t p = visitationOrder[j]; - gradient(p) += (418.9829 * n) * (std::pow(coordinates(p), 2) * + gradient(p) += (std::pow(coordinates(p), 2) * std::cos(std::sqrt(std::abs(coordinates(p)))) / (2 * std::pow(std::abs(coordinates(p)), 1.5)) + std::sin(std::sqrt(std::abs(coordinates(p))))); From 3f1bac6ea59ec367ccbfcea39b2480b406fbc89c Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 8 Jan 2018 15:33:40 -0500 Subject: [PATCH 023/113] Let's try running the test directly... --- .appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 0df5e42fd3..bde3a63115 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -57,4 +57,5 @@ cache: # the machine takes 30 minutes to build the code and at least 50 minutes to run # all tests. test_script: - - ctest -C Release +# - ctest -C Release + - "%APPVEYOR_BUILD_FOLDER%\build\Release\mlpack_test.exe" From b02689c9f5360ab1cd42634f4edd4d1856eba28b Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Tue, 9 Jan 2018 17:30:34 +0100 Subject: [PATCH 024/113] Remove debug output. --- src/mlpack/tests/adam_test.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mlpack/tests/adam_test.cpp b/src/mlpack/tests/adam_test.cpp index c5e1d71a45..f1751e00ba 100644 --- a/src/mlpack/tests/adam_test.cpp +++ b/src/mlpack/tests/adam_test.cpp @@ -96,8 +96,6 @@ BOOST_AUTO_TEST_CASE(AdamMatyasFunctionTest) arma::mat coordinates = f.GetInitialPoint(); optimizer.Optimize(f, coordinates); - std::cout << coordinates << std::endl; - // 3% error tolerance. BOOST_REQUIRE_CLOSE(std::trunc(100.0 * coordinates[0]) / 100.0, 0.0, 3.0); BOOST_REQUIRE_CLOSE(std::trunc(100.0 * coordinates[1]) / 100.0, 0.0, 3.0); From 4cf202ed0e0bacab997a91383b4908262c784dc0 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 9 Jan 2018 11:36:38 -0500 Subject: [PATCH 025/113] I guess even though it's Windows we still use forward slashes. --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index bde3a63115..d42537c332 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -58,4 +58,4 @@ cache: # all tests. test_script: # - ctest -C Release - - "%APPVEYOR_BUILD_FOLDER%\build\Release\mlpack_test.exe" + - "%APPVEYOR_BUILD_FOLDER%/build/Release/mlpack_test.exe" From 6d53af0fa1de9a9a22398ca8e329200d3a5ccd95 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 9 Jan 2018 16:23:14 -0500 Subject: [PATCH 026/113] Set working directory first. --- .appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index d42537c332..51e2a7f8a7 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -58,4 +58,5 @@ cache: # all tests. test_script: # - ctest -C Release - - "%APPVEYOR_BUILD_FOLDER%/build/Release/mlpack_test.exe" + - cd "%APPVEYOR_BUILD_FOLDER%/build/Release/" + - mlpack_test.exe From cfd2e2ecea044c9133a5c33cd4817024eb44c55e Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 23 Jan 2018 14:34:04 -0500 Subject: [PATCH 027/113] Add RDP support to debug the tests. --- .appveyor.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index 51e2a7f8a7..b8c5c83180 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -6,11 +6,15 @@ environment: VSVER: Visual Studio 14 2015 Win64 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 VSVER: Visual Studio 15 2017 Win64 + APPVEYOR_RDP_PASSWORD: 'testing12345' configuration: Release os: Visual Studio 2015 +init: + - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + install: - ps: nuget install boost -o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0 - ps: nuget install boost_unit_test_framework-vc140 -o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0 @@ -60,3 +64,6 @@ test_script: # - ctest -C Release - cd "%APPVEYOR_BUILD_FOLDER%/build/Release/" - mlpack_test.exe + +on_finish: + - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) From c78dcedb8de7211a4956c829b2014c89014458df Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 23 Jan 2018 15:52:10 -0500 Subject: [PATCH 028/113] More complex password. --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index b8c5c83180..a0fb824805 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -6,7 +6,7 @@ environment: VSVER: Visual Studio 14 2015 Win64 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 VSVER: Visual Studio 15 2017 Win64 - APPVEYOR_RDP_PASSWORD: 'testing12345' + APPVEYOR_RDP_PASSWORD: 'testing12345Aa!>>' configuration: Release From 18bc36580269b01b458fec2b410845eb75e6b9a2 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 23 Jan 2018 15:55:32 -0500 Subject: [PATCH 029/113] Allow non-CredSSP connections. --- .appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.appveyor.yml b/.appveyor.yml index a0fb824805..ec39ccd99e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -13,6 +13,7 @@ configuration: Release os: Visual Studio 2015 init: + - ps: reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 0 /f - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) install: From 08c3cdfd88f162b9362cab5b2050f86900e94b25 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 23 Jan 2018 16:42:42 -0500 Subject: [PATCH 030/113] Copy DLLs before running the tests; remove RDP support as a test. --- .appveyor.yml | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index ec39ccd99e..0b0cdf8d85 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -6,15 +6,15 @@ environment: VSVER: Visual Studio 14 2015 Win64 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 VSVER: Visual Studio 15 2017 Win64 - APPVEYOR_RDP_PASSWORD: 'testing12345Aa!>>' +# APPVEYOR_RDP_PASSWORD: 'testing12345Aa!>>' configuration: Release os: Visual Studio 2015 -init: - - ps: reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 0 /f - - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) +#init: +# - ps: reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 0 /f +# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) install: - ps: nuget install boost -o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0 @@ -58,13 +58,12 @@ cache: - packages -> **\packages.config - armadillo.tar.xz -> appveyor.yaml -# All plans have maximum build job execution time of 60 minutes. But right, now -# the machine takes 30 minutes to build the code and at least 50 minutes to run -# all tests. test_script: -# - ctest -C Release - - cd "%APPVEYOR_BUILD_FOLDER%/build/Release/" - - mlpack_test.exe + # Copy all DLLs into the right place before running the test. + - cd "%APPVEYOR_BUILD_FOLDER%/build/" + - cp C:\projects\mlpack\boost_libs\*.* . + - cp C:\projects\mlpack\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.* . + - ctest -C Release -on_finish: - - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) +#on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) From 8977e56c368569a2d595bc7b0265ea071a0318be Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 23 Jan 2018 17:16:34 -0500 Subject: [PATCH 031/113] Use powershell for the copy commands. --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 0b0cdf8d85..3b6d3befbf 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -60,9 +60,9 @@ cache: test_script: # Copy all DLLs into the right place before running the test. + - ps: cp C:\projects\mlpack\boost_libs\*.* "%APPVEYOR_BUILD_FOLDER%/build/" + - ps: cp C:\projects\mlpack\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.* "%APPVEYOR_BUILD_FOLDER%/build/" - cd "%APPVEYOR_BUILD_FOLDER%/build/" - - cp C:\projects\mlpack\boost_libs\*.* . - - cp C:\projects\mlpack\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.* . - ctest -C Release #on_finish: From 131c647348ee73355d6949fd258765d4e0f9a4aa Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Wed, 24 Jan 2018 09:06:44 -0500 Subject: [PATCH 032/113] Seems like powershell commands can't use environment variables. --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 3b6d3befbf..731acec941 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -60,8 +60,8 @@ cache: test_script: # Copy all DLLs into the right place before running the test. - - ps: cp C:\projects\mlpack\boost_libs\*.* "%APPVEYOR_BUILD_FOLDER%/build/" - - ps: cp C:\projects\mlpack\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.* "%APPVEYOR_BUILD_FOLDER%/build/" + - ps: cp C:\projects\mlpack\boost_libs\*.* C:\projects\mlpack\build\ + - ps: cp C:\projects\mlpack\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.* C:\projects\mlpack\build\ - cd "%APPVEYOR_BUILD_FOLDER%/build/" - ctest -C Release From 7f0c453be761b9008bf4e481448835432607d15b Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Wed, 24 Jan 2018 11:29:04 -0500 Subject: [PATCH 033/113] Take ownership of given parameters to fix memory leak. This fixes #1201 but does collateral damage: now every matrix that is passed in will be modified. This will be fixed next... --- src/mlpack/bindings/python/mlpack/cli.pxd | 4 +-- .../bindings/python/mlpack/cli_util.hpp | 15 ++++++----- .../python/print_input_processing.hpp | 4 +++ .../python/tests/test_python_binding.py | 27 ++++++++++--------- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/mlpack/bindings/python/mlpack/cli.pxd b/src/mlpack/bindings/python/mlpack/cli.pxd index d081a774b0..860bc4a756 100644 --- a/src/mlpack/bindings/python/mlpack/cli.pxd +++ b/src/mlpack/bindings/python/mlpack/cli.pxd @@ -37,8 +37,8 @@ cdef extern from "" namespace "mlpack" nogil: cdef extern from "" \ namespace "mlpack::util" nogil: - void SetParam[T](string, const T&) nogil except + - void SetParamWithInfo[T](string, const T&, const bool*) nogil except + + void SetParam[T](string, T&) nogil except + + void SetParamWithInfo[T](string, T&, const bool*) nogil except + (T&) GetParamWithInfo[T](string) nogil except + void EnableVerbose() nogil except + void DisableVerbose() nogil except + diff --git a/src/mlpack/bindings/python/mlpack/cli_util.hpp b/src/mlpack/bindings/python/mlpack/cli_util.hpp index 657eb7b14a..85a9be170e 100644 --- a/src/mlpack/bindings/python/mlpack/cli_util.hpp +++ b/src/mlpack/bindings/python/mlpack/cli_util.hpp @@ -29,9 +29,9 @@ namespace util { * @param value Value to set parameter to. */ template -inline void SetParam(const std::string& identifier, const T& value) +inline void SetParam(const std::string& identifier, T& value) { - CLI::GetParam(identifier) = value; + CLI::GetParam(identifier) = std::move(value); } /** @@ -39,19 +39,20 @@ inline void SetParam(const std::string& identifier, const T& value) */ template inline void SetParamWithInfo(const std::string& identifier, - const T& matrix, + T& matrix, const bool* dims) { typedef typename std::tuple TupleType; typedef typename T::elem_type eT; // The true type of the parameter is std::tuple. - std::get<1>(CLI::GetParam(identifier)) = matrix; + const size_t dimensions = matrix.n_rows; + std::get<1>(CLI::GetParam(identifier)) = std::move(matrix); data::DatasetInfo& di = std::get<0>(CLI::GetParam(identifier)); - di = data::DatasetInfo(matrix.n_rows); + di = data::DatasetInfo(dimensions); bool hasCategoricals = false; - for (size_t i = 0; i < matrix.n_rows; ++i) + for (size_t i = 0; i < dimensions; ++i) { if (dims[i]) { @@ -65,7 +66,7 @@ inline void SetParamWithInfo(const std::string& identifier, { arma::vec maxs = arma::max(matrix, 1); - for (size_t i = 0; i < matrix.n_rows; ++i) + for (size_t i = 0; i < dimensions; ++i) { if (dims[i]) { diff --git a/src/mlpack/bindings/python/print_input_processing.hpp b/src/mlpack/bindings/python/print_input_processing.hpp index 533b81eb40..9982449fa9 100644 --- a/src/mlpack/bindings/python/print_input_processing.hpp +++ b/src/mlpack/bindings/python/print_input_processing.hpp @@ -123,6 +123,7 @@ void PrintInputProcessing( << std::endl; std::cout << prefix << " CLI.SetPassed( '" << d.name << "')" << std::endl; + std::cout << prefix << " del " << d.name << "_mat"; } else { @@ -135,6 +136,7 @@ void PrintInputProcessing( << std::endl; std::cout << prefix << "CLI.SetPassed( '" << d.name << "')" << std::endl; + std::cout << prefix << "del " << d.name << "_mat"; } std::cout << std::endl; } @@ -250,6 +252,7 @@ void PrintInputProcessing( << "bool*> " << d.name << "_dims.data)" << std::endl; std::cout << prefix << " CLI.SetPassed( '" << d.name << "')" << std::endl; + std::cout << prefix << " del " << d.name << "_mat" << std::endl; } else { @@ -264,6 +267,7 @@ void PrintInputProcessing( << "bool*> " << d.name << "_dims.data)" << std::endl; std::cout << prefix << "CLI.SetPassed( '" << d.name << "')" << std::endl; + std::cout << prefix << "del " << d.name << "_mat" << std::endl; } std::cout << std::endl; } diff --git a/src/mlpack/bindings/python/tests/test_python_binding.py b/src/mlpack/bindings/python/tests/test_python_binding.py index b72ecd34f2..38ae922364 100644 --- a/src/mlpack/bindings/python/tests/test_python_binding.py +++ b/src/mlpack/bindings/python/tests/test_python_binding.py @@ -7,8 +7,10 @@ Test that passing types to Python bindings works successfully. import unittest import pandas as pd import numpy as np +import copy from mlpack.test_python_binding import test_python_binding +from mlpack.matrix_utils import to_matrix_with_info class TestPythonBinding(unittest.TestCase): """ @@ -98,7 +100,7 @@ class TestPythonBinding(unittest.TestCase): output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - matrix_in=x) + matrix_in=copy.copy(x)) self.assertEqual(output['matrix_out'].shape[0], 100) self.assertEqual(output['matrix_out'].shape[1], 4) @@ -121,7 +123,7 @@ class TestPythonBinding(unittest.TestCase): output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - matrix_in=x) + matrix_in=copy.copy(x)) self.assertEqual(output['matrix_out'].shape[0], 3) self.assertEqual(output['matrix_out'].shape[1], 4) @@ -148,7 +150,7 @@ class TestPythonBinding(unittest.TestCase): output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - umatrix_in=x) + umatrix_in=copy.copy(x)) self.assertEqual(output['umatrix_out'].shape[0], 100) self.assertEqual(output['umatrix_out'].shape[1], 4) @@ -171,7 +173,7 @@ class TestPythonBinding(unittest.TestCase): output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - umatrix_in=x) + umatrix_in=copy.copy(x)) self.assertEqual(output['umatrix_out'].shape[0], 3) self.assertEqual(output['umatrix_out'].shape[1], 4) @@ -198,7 +200,7 @@ class TestPythonBinding(unittest.TestCase): output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - col_in=x) + col_in=copy.copy(x)) self.assertEqual(output['col_out'].shape[0], 100) self.assertEqual(output['col_out'].dtype, np.double) @@ -215,7 +217,7 @@ class TestPythonBinding(unittest.TestCase): output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - ucol_in=x) + ucol_in=copy.copy(x)) self.assertEqual(output['ucol_out'].shape[0], 100) self.assertEqual(output['ucol_out'].dtype, np.long) @@ -231,7 +233,7 @@ class TestPythonBinding(unittest.TestCase): output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - row_in=x) + row_in=copy.copy(x)) self.assertEqual(output['row_out'].shape[0], 100) self.assertEqual(output['row_out'].dtype, np.double) @@ -248,7 +250,7 @@ class TestPythonBinding(unittest.TestCase): output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - urow_in=x) + urow_in=copy.copy(x)) self.assertEqual(output['urow_out'].shape[0], 100) self.assertEqual(output['urow_out'].dtype, np.long) @@ -265,7 +267,7 @@ class TestPythonBinding(unittest.TestCase): output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - matrix_and_info_in=x) + matrix_and_info_in=copy.copy(x)) self.assertEqual(output['matrix_and_info_out'].shape[0], 100) self.assertEqual(output['matrix_and_info_out'].shape[1], 10) @@ -281,11 +283,12 @@ class TestPythonBinding(unittest.TestCase): x = pd.DataFrame(np.random.rand(10, 4), columns=list('abcd')) x['e'] = pd.Series(['a', 'b', 'c', 'd', 'a', 'b', 'e', 'c', 'a', 'b'], dtype='category') + z, d = to_matrix_with_info(x, np.float64) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - matrix_and_info_in=x) + matrix_and_info_in=copy.copy(x)) self.assertEqual(output['matrix_and_info_out'].shape[0], 10) self.assertEqual(output['matrix_and_info_out'].shape[1], 5) @@ -294,10 +297,10 @@ class TestPythonBinding(unittest.TestCase): for i in range(4): for j in range(10): - self.assertEqual(output['matrix_and_info_out'][j, i], x[cols[i]][j] * 2) + self.assertEqual(output['matrix_and_info_out'][j, i], z[j, i] * 2) for j in range(10): - self.assertEqual(output['matrix_and_info_out'][j, 4], x[cols[4]][j]) + self.assertEqual(output['matrix_and_info_out'][j, 4], z[j, 4] * 2) def testIntVector(self): """ From 0e374295cadd06d0fdcc0c7a0ff18400bbeb603a Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Wed, 24 Jan 2018 18:27:47 -0500 Subject: [PATCH 034/113] Output more test information upon failure. --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 731acec941..4ca4183d62 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -63,7 +63,7 @@ test_script: - ps: cp C:\projects\mlpack\boost_libs\*.* C:\projects\mlpack\build\ - ps: cp C:\projects\mlpack\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.* C:\projects\mlpack\build\ - cd "%APPVEYOR_BUILD_FOLDER%/build/" - - ctest -C Release + - ctest -C Release --output-on-failure #on_finish: # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) From 7f3f4514dadbf4c2a3b6718812437c7babe22488 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Wed, 24 Jan 2018 18:34:20 -0500 Subject: [PATCH 035/113] Print default values in the help. --- src/mlpack/bindings/python/print_doc.hpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/mlpack/bindings/python/print_doc.hpp b/src/mlpack/bindings/python/print_doc.hpp index 08bd612da4..08cbebdf26 100644 --- a/src/mlpack/bindings/python/print_doc.hpp +++ b/src/mlpack/bindings/python/print_doc.hpp @@ -40,6 +40,25 @@ void PrintDoc(const util::ParamData& d, else oss << d.name << " ("; oss << GetPythonType(d) << "): " << d.desc; + + // Print a default, if possible. + if (!d.required) + { + if (d.cppType == "std::string") + { + oss << " Default value '" << boost::any_cast(d.value) + << "'."; + } + else if (d.cppType == "double") + { + oss << " Default value " << boost::any_cast(d.value) << "."; + } + else if (d.cppType == "int") + { + oss << " Default value " << boost::any_cast(d.value) << "."; + } + } + std::cout << util::HyphenateString(oss.str(), indent + 4); } From 92a5b6b0afd10249b1b78b05091290f8c92f1e97 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Wed, 24 Jan 2018 18:34:37 -0500 Subject: [PATCH 036/113] Fix more subtle memory bugs. First: don't transfer the memory state to Armadillo. Instead, make a non-strict alias; this means that Armadillo will only allocate new memory on a size change, and we won't end up making the Python user's numpy array be nothing when we're done because we std::move()d the memory. Second: Only transfer the ownership of the matrix to numpy if the Armadillo matrix actually allocated its own memory. This can help with situations where the user passes a numpy matrix that they have a reference to that will also be a part of the output. --- .../bindings/python/mlpack/arma_numpy.pyx | 94 ++++++++----------- .../bindings/python/mlpack/arma_util.hpp | 14 +++ .../bindings/python/mlpack/cli_util.hpp | 3 +- .../python/tests/test_python_binding.py | 35 ++++--- 4 files changed, 79 insertions(+), 67 deletions(-) diff --git a/src/mlpack/bindings/python/mlpack/arma_numpy.pyx b/src/mlpack/bindings/python/mlpack/arma_numpy.pyx index 8a550c40f2..40508d17a1 100644 --- a/src/mlpack/bindings/python/mlpack/arma_numpy.pyx +++ b/src/mlpack/bindings/python/mlpack/arma_numpy.pyx @@ -31,6 +31,7 @@ cdef extern from "numpy/arrayobject.h": cdef extern from "": void SetMemState[T](T& m, int state) + size_t GetMemState[T](T& m) double* GetMemory(arma.Mat[double]& m) double* GetMemory(arma.Col[double]& m) double* GetMemory(arma.Row[double]& m) @@ -41,35 +42,28 @@ cdef extern from "": cdef arma.Mat[double]* numpy_to_mat_d(numpy.ndarray[numpy.double_t, ndim=2] X) \ except +: """ - Convert a numpy ndarray to a matrix. + Convert a numpy ndarray to a matrix. The memory will still be owned by numpy. """ if not (X.flags.c_contiguous or X.flags.owndata): # If needed, make a copy where we own the memory. X = X.copy(order="C") - cdef arma.Mat[double]* m = new arma.Mat[double]( X.data, X.shape[1], X.shape[0], False, True) - - # Transfer ownership to the Armadillo matrix. - PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA) - SetMemState[arma.Mat[double]](m[0], 0) + cdef arma.Mat[double]* m = new arma.Mat[double]( X.data, X.shape[1],\ + X.shape[0], False, False) return m cdef arma.Mat[size_t]* numpy_to_mat_s(numpy.ndarray[numpy.npy_intp, ndim=2] X) \ except +: """ - Convert a numpy ndarray to a matrix. + Convert a numpy ndarray to a matrix. The memory will still be owned by numpy. """ if not (X.flags.c_contiguous or X.flags.owndata): # If needed, make a copy where we own the memory. X = X.copy(order="C") cdef arma.Mat[size_t]* m = new arma.Mat[size_t]( X.data, X.shape[1], - X.shape[0], False, True) - - # Transfer ownership to the Armadillo matrix. - PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA) - SetMemState[arma.Mat[size_t]](m[0], 0) + X.shape[0], False, False) return m @@ -85,9 +79,10 @@ cdef numpy.ndarray[numpy.double_t, ndim=2] mat_to_numpy_d(arma.Mat[double]& X) \ cdef numpy.ndarray[numpy.double_t, ndim=2] output = \ numpy.PyArray_SimpleNewFromData(2, &dims[0], numpy.NPY_DOUBLE, GetMemory(X)) - # Transfer memory ownership. - SetMemState[arma.Mat[double]](X, 1) - PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA) + # Transfer memory ownership, if needed. + if GetMemState[arma.Mat[double]](X) == 0: + SetMemState[arma.Mat[double]](X, 1) + PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA) return output @@ -103,45 +98,40 @@ cdef numpy.ndarray[numpy.npy_intp, ndim=2] mat_to_numpy_s(arma.Mat[size_t]& X) \ cdef numpy.ndarray[numpy.npy_intp, ndim=2] output = \ numpy.PyArray_SimpleNewFromData(2, &dims[0], numpy.NPY_INTP, GetMemory(X)) - # Transfer memory ownership. - SetMemState[arma.Mat[size_t]](X, 1) - PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA) + # Transfer memory ownership, if needed. + if GetMemState[arma.Mat[size_t]](X) == 0: + SetMemState[arma.Mat[size_t]](X, 1) + PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA) return output cdef arma.Row[double]* numpy_to_row_d(numpy.ndarray[numpy.double_t, ndim=1] X) \ except +: """ - Convert a numpy one-dimensional ndarray to a row. + Convert a numpy one-dimensional ndarray to a row. The memory will still be + owned by numpy. """ if not (X.flags.c_contiguous or X.flags.owndata): # If needed, make a copy where we own the memory. X = X.copy(order="C") cdef arma.Row[double]* m = new arma.Row[double]( X.data, X.shape[0], - False, True) - - # Transfer ownership to the Armadillo matrix. - PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA) - SetMemState[arma.Row[double]](m[0], 0) + False, False) return m cdef arma.Row[size_t]* numpy_to_row_s(numpy.ndarray[numpy.npy_intp, ndim=1] X) \ except +: """ - Convert a numpy one-dimensional ndarray to a row. + Convert a numpy one-dimensional ndarray to a row. The memory will still be + owned by numpy. """ if not (X.flags.c_contiguous or X.flags.owndata): # If needed, make a copy where we own the memory. X = X.copy(order="C") cdef arma.Row[size_t]* m = new arma.Row[size_t]( X.data, X.shape[0], - False, True) - - # Transfer ownership to the Armadillo matrix. - PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA) - SetMemState[arma.Row[size_t]](m[0], 0) + False, False) return m @@ -155,9 +145,10 @@ cdef numpy.ndarray[numpy.double_t, ndim=1] row_to_numpy_d(arma.Row[double]& X) \ cdef numpy.ndarray[numpy.double_t, ndim=1] output = \ numpy.PyArray_SimpleNewFromData(1, &dim, numpy.NPY_DOUBLE, GetMemory(X)) - # Transfer memory ownership. - SetMemState[arma.Row[double]](X, 1) - PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA) + # Transfer memory ownership, if needed. + if GetMemState[arma.Row[double]](X) == 0: + SetMemState[arma.Row[double]](X, 1) + PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA) return output @@ -171,16 +162,18 @@ cdef numpy.ndarray[numpy.npy_intp, ndim=1] row_to_numpy_s(arma.Row[size_t]& X) \ cdef numpy.ndarray[numpy.npy_intp, ndim=1] output = \ numpy.PyArray_SimpleNewFromData(1, &dim, numpy.NPY_INTP, GetMemory(X)) - # Transfer memory ownership. - SetMemState[arma.Row[size_t]](X, 1) - PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA) + # Transfer memory ownership, if needed. + if GetMemState[arma.Row[size_t]](X) == 0: + SetMemState[arma.Row[size_t]](X, 1) + PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA) return output cdef arma.Col[double]* numpy_to_col_d(numpy.ndarray[numpy.double_t, ndim=1] X) \ except +: """ - Convert a numpy one-dimensional ndarray to a column vector. + Convert a numpy one-dimensional ndarray to a column vector. The memory will + still be owned by numpy. """ if not (X.flags.c_contiguous or X.flags.owndata): # If needed, make a copy where we own the memory. @@ -189,27 +182,20 @@ cdef arma.Col[double]* numpy_to_col_d(numpy.ndarray[numpy.double_t, ndim=1] X) \ cdef arma.Col[double]* m = new arma.Col[double]( X.data, X.shape[0], False, True) - # Transfer ownership to the Armadillo matrix. - PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA) - SetMemState[arma.Col[double]](m[0], 0) - return m cdef arma.Col[size_t]* numpy_to_col_s(numpy.ndarray[numpy.npy_intp, ndim=1] X) \ except +: """ - Convert a numpy one-dimensional ndarray to a column vector. + Convert a numpy one-dimensional ndarray to a column vector. The memory will + still be owned by numpy. """ if not (X.flags.c_contiguous or X.flags.owndata): # If needed, make a copy where we own the memory. X = X.copy(order="C") cdef arma.Col[size_t]* m = new arma.Col[size_t]( X.data, X.shape[0], - False, True) - - # Transfer ownership to the Armadillo matrix. - PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA) - SetMemState[arma.Col[size_t]](m[0], 0) + False, False) return m @@ -223,9 +209,10 @@ cdef numpy.ndarray[numpy.double_t, ndim=1] col_to_numpy_d(arma.Col[double]& X) \ cdef numpy.ndarray[numpy.double_t, ndim=1] output = \ numpy.PyArray_SimpleNewFromData(1, &dim, numpy.NPY_DOUBLE, GetMemory(X)) - # Transfer memory ownership. - SetMemState[arma.Col[double]](X, 1) - PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA) + # Transfer memory ownership, if needed. + if GetMemState[arma.Col[double]](X) == 0: + SetMemState[arma.Col[double]](X, 1) + PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA) return output @@ -239,8 +226,9 @@ cdef numpy.ndarray[numpy.npy_intp, ndim=1] col_to_numpy_s(arma.Col[size_t]& X) \ cdef numpy.ndarray[numpy.npy_intp, ndim=1] output = \ numpy.PyArray_SimpleNewFromData(1, &dim, numpy.NPY_INTP, GetMemory(X)) - # Transfer memory ownership. - SetMemState[arma.Col[size_t]](X, 1) - PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA) + # Transfer memory ownership, if needed. + if GetMemState[arma.Col[size_t]](X) == 0: + SetMemState[arma.Col[size_t]](X, 1) + PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA) return output diff --git a/src/mlpack/bindings/python/mlpack/arma_util.hpp b/src/mlpack/bindings/python/mlpack/arma_util.hpp index 7770877c3c..c94a51e67f 100644 --- a/src/mlpack/bindings/python/mlpack/arma_util.hpp +++ b/src/mlpack/bindings/python/mlpack/arma_util.hpp @@ -24,6 +24,20 @@ void SetMemState(T& t, int state) const_cast(t.mem_state) = state; } +/** + * Get the memory state of the given Armadillo object. + */ +template +size_t GetMemState(T& t) +{ + // Fake the memory state if we are using preallocated memory---since we will + // end up copying that memory, NumPy can own it. + if (t.mem && t.n_elem <= arma::arma_config::mat_prealloc) + return 0; + + return (size_t) t.mem_state; +} + /** * Return the matrix's allocated memory pointer, unless the matrix is using its * internal preallocated memory, in which case we copy that and return a diff --git a/src/mlpack/bindings/python/mlpack/cli_util.hpp b/src/mlpack/bindings/python/mlpack/cli_util.hpp index 85a9be170e..e1fdcc0c55 100644 --- a/src/mlpack/bindings/python/mlpack/cli_util.hpp +++ b/src/mlpack/bindings/python/mlpack/cli_util.hpp @@ -64,7 +64,8 @@ inline void SetParamWithInfo(const std::string& identifier, // Do we need to find how many categories we have? if (hasCategoricals) { - arma::vec maxs = arma::max(matrix, 1); + arma::vec maxs = arma::max( + std::get<1>(CLI::GetParam(identifier)), 1); for (size_t i = 0; i < dimensions; ++i) { diff --git a/src/mlpack/bindings/python/tests/test_python_binding.py b/src/mlpack/bindings/python/tests/test_python_binding.py index 38ae922364..b95e1a2305 100644 --- a/src/mlpack/bindings/python/tests/test_python_binding.py +++ b/src/mlpack/bindings/python/tests/test_python_binding.py @@ -96,11 +96,12 @@ class TestPythonBinding(unittest.TestCase): and the fifth forgotten. """ x = np.random.rand(100, 5); + z = copy.copy(x) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - matrix_in=copy.copy(x)) + matrix_in=z) self.assertEqual(output['matrix_out'].shape[0], 100) self.assertEqual(output['matrix_out'].shape[1], 4) @@ -119,11 +120,12 @@ class TestPythonBinding(unittest.TestCase): x = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]] + z = copy.copy(x) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - matrix_in=copy.copy(x)) + matrix_in=z) self.assertEqual(output['matrix_out'].shape[0], 3) self.assertEqual(output['matrix_out'].shape[1], 4) @@ -146,11 +148,12 @@ class TestPythonBinding(unittest.TestCase): Same as testNumpyMatrix() but with an unsigned matrix. """ x = np.random.randint(0, high=500, size=[100, 5]) + z = copy.copy(x) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - umatrix_in=copy.copy(x)) + umatrix_in=z) self.assertEqual(output['umatrix_out'].shape[0], 100) self.assertEqual(output['umatrix_out'].shape[1], 4) @@ -169,11 +172,12 @@ class TestPythonBinding(unittest.TestCase): x = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]] + z = copy.copy(x) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - umatrix_in=copy.copy(x)) + umatrix_in=z) self.assertEqual(output['umatrix_out'].shape[0], 3) self.assertEqual(output['umatrix_out'].shape[1], 4) @@ -196,11 +200,12 @@ class TestPythonBinding(unittest.TestCase): Test a column vector input parameter. """ x = np.random.rand(100) + z = copy.copy(x) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - col_in=copy.copy(x)) + col_in=z) self.assertEqual(output['col_out'].shape[0], 100) self.assertEqual(output['col_out'].dtype, np.double) @@ -213,11 +218,12 @@ class TestPythonBinding(unittest.TestCase): Test an unsigned column vector input parameter. """ x = np.random.randint(0, high=500, size=100) + z = copy.copy(x) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - ucol_in=copy.copy(x)) + ucol_in=z) self.assertEqual(output['ucol_out'].shape[0], 100) self.assertEqual(output['ucol_out'].dtype, np.long) @@ -229,11 +235,12 @@ class TestPythonBinding(unittest.TestCase): Test a row vector input parameter. """ x = np.random.rand(100) + z = copy.copy(x) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - row_in=copy.copy(x)) + row_in=z) self.assertEqual(output['row_out'].shape[0], 100) self.assertEqual(output['row_out'].dtype, np.double) @@ -246,11 +253,12 @@ class TestPythonBinding(unittest.TestCase): Test an unsigned row vector input parameter. """ x = np.random.randint(0, high=500, size=100) + z = copy.copy(x) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - urow_in=copy.copy(x)) + urow_in=z) self.assertEqual(output['urow_out'].shape[0], 100) self.assertEqual(output['urow_out'].dtype, np.long) @@ -263,11 +271,12 @@ class TestPythonBinding(unittest.TestCase): Test that we can pass a matrix with all numeric features. """ x = np.random.rand(100, 10) + z = copy.copy(x) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - matrix_and_info_in=copy.copy(x)) + matrix_and_info_in=z) self.assertEqual(output['matrix_and_info_out'].shape[0], 100) self.assertEqual(output['matrix_and_info_out'].shape[1], 10) @@ -283,12 +292,12 @@ class TestPythonBinding(unittest.TestCase): x = pd.DataFrame(np.random.rand(10, 4), columns=list('abcd')) x['e'] = pd.Series(['a', 'b', 'c', 'd', 'a', 'b', 'e', 'c', 'a', 'b'], dtype='category') - z, d = to_matrix_with_info(x, np.float64) + z = copy.copy(x) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - matrix_and_info_in=copy.copy(x)) + matrix_and_info_in=z) self.assertEqual(output['matrix_and_info_out'].shape[0], 10) self.assertEqual(output['matrix_and_info_out'].shape[1], 5) @@ -297,10 +306,10 @@ class TestPythonBinding(unittest.TestCase): for i in range(4): for j in range(10): - self.assertEqual(output['matrix_and_info_out'][j, i], z[j, i] * 2) + self.assertEqual(output['matrix_and_info_out'][j, i], z[cols[i]][j] * 2) for j in range(10): - self.assertEqual(output['matrix_and_info_out'][j, 4], z[j, 4] * 2) + self.assertEqual(output['matrix_and_info_out'][j, 4], z[cols[4]][j]) def testIntVector(self): """ From 86ffadc4858f4490feade4dbeebf8603b1e9f7a1 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Wed, 24 Jan 2018 18:43:40 -0500 Subject: [PATCH 037/113] This import is no longer needed. --- src/mlpack/bindings/python/tests/test_python_binding.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/bindings/python/tests/test_python_binding.py b/src/mlpack/bindings/python/tests/test_python_binding.py index b95e1a2305..93ac2615c6 100644 --- a/src/mlpack/bindings/python/tests/test_python_binding.py +++ b/src/mlpack/bindings/python/tests/test_python_binding.py @@ -10,7 +10,6 @@ import numpy as np import copy from mlpack.test_python_binding import test_python_binding -from mlpack.matrix_utils import to_matrix_with_info class TestPythonBinding(unittest.TestCase): """ From a69bad392b8a0ba21a142660caad4fb17da58e1a Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 25 Jan 2018 08:25:51 -0500 Subject: [PATCH 038/113] Try running the tests by hand and getting the XML output. --- .appveyor.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4ca4183d62..24d5495bb8 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -63,7 +63,12 @@ test_script: - ps: cp C:\projects\mlpack\boost_libs\*.* C:\projects\mlpack\build\ - ps: cp C:\projects\mlpack\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.* C:\projects\mlpack\build\ - cd "%APPVEYOR_BUILD_FOLDER%/build/" - - ctest -C Release --output-on-failure + - Release\mlpack_test.exe --report_level=detailed --log_level=test_suite --log_format=XML > mlpack_test.xml +# - ctest -C Release --output-on-failure + # upload results to AppVeyor + - ps: | + $wc = New-Object 'System.Net.WebClient' + $wc.UploadFile("https://ci.appveyor.com/api/testresults/xunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\mlpack_test.xml)) #on_finish: # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) From a84c9237ef80cd213cd152e7ae6f8ffe5bd781c3 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 25 Jan 2018 10:28:41 -0500 Subject: [PATCH 039/113] Force clean exit of tests even if some failed. --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 24d5495bb8..085bde6e86 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -63,7 +63,7 @@ test_script: - ps: cp C:\projects\mlpack\boost_libs\*.* C:\projects\mlpack\build\ - ps: cp C:\projects\mlpack\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.* C:\projects\mlpack\build\ - cd "%APPVEYOR_BUILD_FOLDER%/build/" - - Release\mlpack_test.exe --report_level=detailed --log_level=test_suite --log_format=XML > mlpack_test.xml + - Release\mlpack_test.exe --report_level=detailed --log_level=test_suite --log_format=XML > mlpack_test.xml & exit 0 # - ctest -C Release --output-on-failure # upload results to AppVeyor - ps: | From 462737772df44887742ba43ea082960e9a36063c Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 26 Jan 2018 13:44:24 -0500 Subject: [PATCH 040/113] Refactor CLI bindings to hold pointers to models. Specifically, whereas before any serializable type would actually be held as a std::tuple, but now we will hold this as a std::tuple. This also requires some changes for memory handling. Our assumption is that the CLI object will *own* (and delete) any pointers it is holding, so we must also do some extra handling in the end_program.hpp code. --- src/mlpack/bindings/cli/CMakeLists.txt | 2 + src/mlpack/bindings/cli/add_to_po.hpp | 6 +- src/mlpack/bindings/cli/cli_option.hpp | 18 ++++-- src/mlpack/bindings/cli/default_param.hpp | 13 +++- .../bindings/cli/default_param_impl.hpp | 19 +++++- .../bindings/cli/delete_allocated_memory.hpp | 57 ++++++++++++++++++ src/mlpack/bindings/cli/end_program.hpp | 31 ++++++++++ .../bindings/cli/get_allocated_memory.hpp | 59 +++++++++++++++++++ src/mlpack/bindings/cli/get_param.hpp | 14 +++-- .../bindings/cli/get_printable_param.hpp | 15 ++++- .../bindings/cli/get_printable_param_impl.hpp | 19 +++++- .../bindings/cli/get_printable_param_name.hpp | 3 +- .../cli/get_printable_param_value.hpp | 3 +- src/mlpack/bindings/cli/get_raw_param.hpp | 23 ++++++-- .../bindings/cli/map_parameter_name.hpp | 3 +- src/mlpack/bindings/cli/output_param.hpp | 2 +- src/mlpack/bindings/cli/output_param_impl.hpp | 14 ++--- .../bindings/cli/parse_command_line.hpp | 2 +- src/mlpack/bindings/cli/set_param.hpp | 21 ++++++- 19 files changed, 285 insertions(+), 39 deletions(-) create mode 100644 src/mlpack/bindings/cli/delete_allocated_memory.hpp create mode 100644 src/mlpack/bindings/cli/get_allocated_memory.hpp diff --git a/src/mlpack/bindings/cli/CMakeLists.txt b/src/mlpack/bindings/cli/CMakeLists.txt index 095fee3c1a..83c50292ee 100644 --- a/src/mlpack/bindings/cli/CMakeLists.txt +++ b/src/mlpack/bindings/cli/CMakeLists.txt @@ -5,7 +5,9 @@ set(SOURCES cli_option.hpp default_param.hpp default_param_impl.hpp + delete_allocated_memory.hpp end_program.hpp + get_allocated_memory.hpp get_param.hpp get_raw_param.hpp get_printable_param.hpp diff --git a/src/mlpack/bindings/cli/add_to_po.hpp b/src/mlpack/bindings/cli/add_to_po.hpp index 2251649a83..0c3a1d789b 100644 --- a/src/mlpack/bindings/cli/add_to_po.hpp +++ b/src/mlpack/bindings/cli/add_to_po.hpp @@ -89,13 +89,15 @@ void AddToPO(const util::ParamData& d, (boost::program_options::options_description*) output; // Generate the name to be given to boost::program_options. - const std::string mappedName = MapParameterName(d.name); + const std::string mappedName = + MapParameterName::type>(d.name); std::string boostName = (d.alias != '\0') ? mappedName + "," + std::string(1, d.alias) : mappedName; // Note that we have to add the option as type equal to the mapped type, not // the true type of the option. - AddToPO::type>(boostName, d.desc, *desc); + AddToPO::type>::type>( + boostName, d.desc, *desc); } } // namespace cli diff --git a/src/mlpack/bindings/cli/cli_option.hpp b/src/mlpack/bindings/cli/cli_option.hpp index 47233b29ec..7944039628 100644 --- a/src/mlpack/bindings/cli/cli_option.hpp +++ b/src/mlpack/bindings/cli/cli_option.hpp @@ -28,6 +28,8 @@ #include "set_param.hpp" #include "get_printable_param_name.hpp" #include "get_printable_param_value.hpp" +#include "get_allocated_memory.hpp" +#include "delete_allocated_memory.hpp" namespace mlpack { namespace bindings { @@ -88,19 +90,21 @@ class CLIOption data.cppType = cppName; // Apply default value. - if (std::is_same::type>::value) + if (std::is_same::type, + typename ParameterType::type>::type>::value) { data.value = boost::any(defaultValue); } else { - typename ParameterType::type tmp; - data.value = boost::any(std::tuple::type>( - defaultValue, tmp)); + typename ParameterType::type>::type tmp; + data.value = boost::any(std::tuple(defaultValue, tmp)); } const std::string tname = data.tname; - const std::string boostName = MapParameterName(identifier); + const std::string boostName = MapParameterName< + typename std::remove_pointer::type>(identifier); std::string progOptId = (alias[0] != '\0') ? boostName + "," + std::string(1, alias[0]) : boostName; @@ -152,6 +156,10 @@ class CLIOption &GetPrintableParamName; CLI::GetSingleton().functionMap[tname]["GetPrintableParamValue"] = &GetPrintableParamValue; + CLI::GetSingleton().functionMap[tname]["GetAllocatedMemory"] = + &GetAllocatedMemory; + CLI::GetSingleton().functionMap[tname]["DeleteAllocatedMemory"] = + &DeleteAllocatedMemory; } }; diff --git a/src/mlpack/bindings/cli/default_param.hpp b/src/mlpack/bindings/cli/default_param.hpp index 815ee8c3de..74347c9601 100644 --- a/src/mlpack/bindings/cli/default_param.hpp +++ b/src/mlpack/bindings/cli/default_param.hpp @@ -54,10 +54,19 @@ std::string DefaultParamImpl( const util::ParamData& data, const typename boost::enable_if_c< arma::is_arma_type::value || - data::HasSerialize::value || std::is_same>::value>::type* /* junk */ = 0); +/** + * Return the default value of a model option (this returns the default + * filename, or '' if the default is no file). + */ +template +std::string DefaultParamImpl( + const util::ParamData& data, + const typename boost::disable_if>::type* = 0, + const typename boost::enable_if>::type* = 0); + /** * Return the default value of an option. This is the function that will be * placed into the CLI functionMap. @@ -68,7 +77,7 @@ void DefaultParam(const util::ParamData& data, void* output) { std::string* outstr = (std::string*) output; - *outstr = DefaultParamImpl(data); + *outstr = DefaultParamImpl::type>(data); } } // namespace cli diff --git a/src/mlpack/bindings/cli/default_param_impl.hpp b/src/mlpack/bindings/cli/default_param_impl.hpp index ec8f6d4095..377b25ff16 100644 --- a/src/mlpack/bindings/cli/default_param_impl.hpp +++ b/src/mlpack/bindings/cli/default_param_impl.hpp @@ -70,7 +70,6 @@ std::string DefaultParamImpl( const util::ParamData& data, const typename boost::enable_if_c< arma::is_arma_type::value || - data::HasSerialize::value || std::is_same>::value>::type* /* junk */) { @@ -81,6 +80,24 @@ std::string DefaultParamImpl( return "'" + filename + "'"; } +/** + * Return the default value of a model option (this returns the default + * filename, or '' if the default is no file). + */ +template +std::string DefaultParamImpl( + const util::ParamData& data, + const typename boost::disable_if>::type* /* junk */, + const typename boost::enable_if>::type* /* junk */) +{ + // Get the filename and return it, or return an empty string. + typedef std::tuple TupleType; + const TupleType& tuple = *boost::any_cast(&data.value); + const std::string& filename = std::get<1>(tuple); + return "'" + filename + "'"; +} + + } // namespace cli } // namespace bindings } // namespace mlpack diff --git a/src/mlpack/bindings/cli/delete_allocated_memory.hpp b/src/mlpack/bindings/cli/delete_allocated_memory.hpp new file mode 100644 index 0000000000..edc1fcf861 --- /dev/null +++ b/src/mlpack/bindings/cli/delete_allocated_memory.hpp @@ -0,0 +1,57 @@ +/** + * @file delete_allocated_memory.hpp + * @author Ryan Curtin + * + * If any memory has been allocated by the parameter, delete it. + */ +#ifndef MLPACK_BINDINGS_CLI_DELETE_ALLOCATED_MEMORY_HPP +#define MLPACK_BINDINGS_CLI_DELETE_ALLOCATED_MEMORY_HPP + +#include + +namespace mlpack { +namespace bindings { +namespace cli { + +template +void DeleteAllocatedMemoryImpl( + const util::ParamData& /* d */, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0) +{ + // Do nothing. +} + +template +void DeleteAllocatedMemoryImpl( + const util::ParamData& /* d */, + const typename boost::enable_if>::type* = 0) +{ + // Do nothing. +} + +template +void DeleteAllocatedMemoryImpl( + const util::ParamData& d, + const typename boost::disable_if>::type* = 0, + const typename boost::enable_if>::type* = 0) +{ + // Delete the allocated memory (hopefully we actually own it). + typedef std::tuple TupleType; + delete std::get<0>(*boost::any_cast(&d.value)); +} + +template +void DeleteAllocatedMemory( + const util::ParamData& d, + const void* /* input */, + void* /* output */) +{ + DeleteAllocatedMemoryImpl::type>(d); +} + +} // namespace cli +} // namespace bindings +} // namespace mlpack + +#endif diff --git a/src/mlpack/bindings/cli/end_program.hpp b/src/mlpack/bindings/cli/end_program.hpp index 4eed33438c..56a3809ebd 100644 --- a/src/mlpack/bindings/cli/end_program.hpp +++ b/src/mlpack/bindings/cli/end_program.hpp @@ -67,6 +67,37 @@ inline void EndProgram() CLI::GetSingleton().timer.PrintTimer(it2.first); } } + + // Lastly clean up any memory. If we are holding any pointers, then we "own" + // them. But we may hold the same pointer twice, so we have to be careful to + // not delete it multiple times. + std::unordered_map memoryAddresses; + it = parameters.begin(); + while (it != parameters.end()) + { + const util::ParamData& data = it->second; + + void* result; + CLI::GetSingleton().functionMap[data.tname]["GetAllocatedMemory"](data, + NULL, (void*) &result); + if (result != NULL && memoryAddresses.count(result) == 0) + memoryAddresses[result] = &data; + + ++it; + } + + // Now we have all the unique addresses that need to be deleted. + std::unordered_map::const_iterator it2; + it2 = memoryAddresses.begin(); + while (it2 != memoryAddresses.end()) + { + const util::ParamData& data = *(it2->second); + + CLI::GetSingleton().functionMap[data.tname]["DeleteAllocatedMemory"](data, + NULL, NULL); + + ++it2; + } } } // namespace cli diff --git a/src/mlpack/bindings/cli/get_allocated_memory.hpp b/src/mlpack/bindings/cli/get_allocated_memory.hpp new file mode 100644 index 0000000000..2dda83e212 --- /dev/null +++ b/src/mlpack/bindings/cli/get_allocated_memory.hpp @@ -0,0 +1,59 @@ +/** + * @file get_allocated_memory.hpp + * @author Ryan Curtin + * + * If the parameter has a type that may need to be deleted, return the address + * of that object. Otherwise return NULL. + */ +#ifndef MLPACK_BINDINGS_CLI_GET_ALLOCATED_MEMORY_HPP +#define MLPACK_BINDINGS_CLI_GET_ALLOCATED_MEMORY_HPP + +#include + +namespace mlpack { +namespace bindings { +namespace cli { + +template +void* GetAllocatedMemory( + const util::ParamData& /* d */, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0) +{ + return NULL; +} + +template +void* GetAllocatedMemory( + const util::ParamData& /* d */, + const typename boost::enable_if>::type* = 0) +{ + return NULL; +} + +template +void* GetAllocatedMemory( + const util::ParamData& d, + const typename boost::disable_if>::type* = 0, + const typename boost::enable_if>::type* = 0) +{ + // Here we have a model, which is a tuple, and we need the address of the + // memory. + typedef std::tuple TupleType; + return std::get<0>(*boost::any_cast(&d.value)); +} + +template +void GetAllocatedMemory(const util::ParamData& d, + const void* /* input */, + void* output) +{ + *((void**) output) = + GetAllocatedMemory::type>(d); +} + +} // namespace cli +} // namespace bindings +} // namespace mlpack + +#endif diff --git a/src/mlpack/bindings/cli/get_param.hpp b/src/mlpack/bindings/cli/get_param.hpp index fca9c823fe..9c16b10f26 100644 --- a/src/mlpack/bindings/cli/get_param.hpp +++ b/src/mlpack/bindings/cli/get_param.hpp @@ -95,24 +95,25 @@ T& GetParam( * @param d ParamData object to get parameter value from. */ template -T& GetParam( +T*& GetParam( util::ParamData& d, const typename boost::disable_if>::type* = 0, const typename boost::enable_if>::type* = 0) { // If the model is an input model, we have to load it from file. 'value' // contains the filename. - typedef std::tuple TupleType; + typedef std::tuple TupleType; TupleType* tuple = boost::any_cast(&d.value); const std::string& value = std::get<1>(*tuple); - T& model = std::get<0>(*tuple); if (d.input && !d.loaded) { - data::Load(value, "model", model, true); + T* model = new T(); + data::Load(value, "model", *model, true); d.loaded = true; + std::get<0>(*tuple) = model; } - return model; + return std::get<0>(*tuple); } /** @@ -127,7 +128,8 @@ template void GetParam(const util::ParamData& d, const void* /* input */, void* output) { // Cast to the correct type. - *((T**) output) = &GetParam(const_cast(d)); + *((T**) output) = &GetParam::type>( + const_cast(d)); } } // namespace cli diff --git a/src/mlpack/bindings/cli/get_printable_param.hpp b/src/mlpack/bindings/cli/get_printable_param.hpp index 2b082b338d..5688dc2209 100644 --- a/src/mlpack/bindings/cli/get_printable_param.hpp +++ b/src/mlpack/bindings/cli/get_printable_param.hpp @@ -37,16 +37,24 @@ std::string GetPrintableParam( const typename std::enable_if::value>::type* = 0); /** - * Print a matrix option (this just prints the filename). + * Print a matrix/tuple option (this just prints the filename). */ template std::string GetPrintableParam( const util::ParamData& data, const typename std::enable_if::value || - data::HasSerialize::value || std::is_same>::value>::type* = 0); +/** + * Print a model option (this just prints the filename). + */ +template +std::string GetPrintableParam( + const util::ParamData& data, + const typename boost::disable_if>::type* = 0, + const typename boost::enable_if>::type* = 0); + /** * Print an option into a std::string. This should print a short, one-line * representation of the object. The string will be stored in the output @@ -57,7 +65,8 @@ void GetPrintableParam(const util::ParamData& data, const void* /* input */, void* output) { - *((std::string*) output) = GetPrintableParam(data); + *((std::string*) output) = + GetPrintableParam::type>(data); } } // namespace cli diff --git a/src/mlpack/bindings/cli/get_printable_param_impl.hpp b/src/mlpack/bindings/cli/get_printable_param_impl.hpp index 0e55cb649a..6fb65bc48d 100644 --- a/src/mlpack/bindings/cli/get_printable_param_impl.hpp +++ b/src/mlpack/bindings/cli/get_printable_param_impl.hpp @@ -43,12 +43,11 @@ std::string GetPrintableParam( return oss.str(); } -//! Print a matrix/model/tuple option (this just prints the filename). +//! Print a matrix/tuple option (this just prints the filename). template std::string GetPrintableParam( const util::ParamData& data, const typename std::enable_if::value || - data::HasSerialize::value || std::is_same>::value>::type* /* junk */) { @@ -61,6 +60,22 @@ std::string GetPrintableParam( return oss.str(); } +//! Print a model option (this just prints the filename). +template +std::string GetPrintableParam( + const util::ParamData& data, + const typename boost::disable_if>::type* /* junk */, + const typename boost::enable_if>::type* /* junk */) +{ + // Extract the string from the tuple that's being held. + typedef std::tuple::type> TupleType; + const TupleType* tuple = boost::any_cast(&data.value); + + std::ostringstream oss; + oss << std::get<1>(*tuple); + return oss.str(); +} + } // namespace cli } // namespace bindings } // namespace mlpack diff --git a/src/mlpack/bindings/cli/get_printable_param_name.hpp b/src/mlpack/bindings/cli/get_printable_param_name.hpp index 12c7f92cfd..e323d2378a 100644 --- a/src/mlpack/bindings/cli/get_printable_param_name.hpp +++ b/src/mlpack/bindings/cli/get_printable_param_name.hpp @@ -64,7 +64,8 @@ void GetPrintableParamName( const void* /* input */, void* output) { - *((std::string*) output) = GetPrintableParamName(d); + *((std::string*) output) = + GetPrintableParamName::type>(d); } } // namespace cli diff --git a/src/mlpack/bindings/cli/get_printable_param_value.hpp b/src/mlpack/bindings/cli/get_printable_param_value.hpp index be29934d51..0110c0dfdc 100644 --- a/src/mlpack/bindings/cli/get_printable_param_value.hpp +++ b/src/mlpack/bindings/cli/get_printable_param_value.hpp @@ -68,7 +68,8 @@ void GetPrintableParamValue( const void* input, void* output) { - *((std::string*) output) = GetPrintableParamValue(d, + *((std::string*) output) = + GetPrintableParamValue::type>(d, *((std::string*) input)); } diff --git a/src/mlpack/bindings/cli/get_raw_param.hpp b/src/mlpack/bindings/cli/get_raw_param.hpp index ae73ca0d36..a397ffff54 100644 --- a/src/mlpack/bindings/cli/get_raw_param.hpp +++ b/src/mlpack/bindings/cli/get_raw_param.hpp @@ -40,15 +40,29 @@ T& GetRawParam( const typename boost::enable_if_c< arma::is_arma_type::value || std::is_same>::value || - data::HasSerialize::value>::type* = 0) + arma::mat>>::value>::type* = 0) { - // Don't load the matrix/model. + // Don't load the matrix. typedef std::tuple TupleType; T& value = std::get<0>(*boost::any_cast(&d.value)); return value; } +/** + * Return the name of a model parameter. + */ +template +T*& GetRawParam( + util::ParamData& d, + const typename boost::disable_if>::type* = 0, + const typename boost::enable_if>::type* = 0) +{ + // Don't load the model. + typedef std::tuple TupleType; + T*& value = std::get<0>(*boost::any_cast(&d.value)); + return value; +} + /** * Return a parameter casted to the given type. Type checking does not happen * here! @@ -63,7 +77,8 @@ void GetRawParam(const util::ParamData& d, void* output) { // Cast to the correct type. - *((T**) output) = &GetRawParam(const_cast(d)); + *((T**) output) = &GetRawParam::type>( + const_cast(d)); } } // namespace cli diff --git a/src/mlpack/bindings/cli/map_parameter_name.hpp b/src/mlpack/bindings/cli/map_parameter_name.hpp index f75f3ad4af..2d37d6c384 100644 --- a/src/mlpack/bindings/cli/map_parameter_name.hpp +++ b/src/mlpack/bindings/cli/map_parameter_name.hpp @@ -61,7 +61,8 @@ void MapParameterName(const util::ParamData& d, { // Store the mapped name in the output pointer, which is actually a string // pointer. - *((std::string*) output) = MapParameterName(d.name); + *((std::string*) output) = + MapParameterName::type>(d.name); } } // namespace cli diff --git a/src/mlpack/bindings/cli/output_param.hpp b/src/mlpack/bindings/cli/output_param.hpp index c4ce9c3b5d..4ed052d55f 100644 --- a/src/mlpack/bindings/cli/output_param.hpp +++ b/src/mlpack/bindings/cli/output_param.hpp @@ -70,7 +70,7 @@ void OutputParam(const util::ParamData& data, const void* /* input */, void* /* output */) { - OutputParamImpl(data); + OutputParamImpl::type>(data); } } // namespace cli diff --git a/src/mlpack/bindings/cli/output_param_impl.hpp b/src/mlpack/bindings/cli/output_param_impl.hpp index 3e30a66ff8..a85e55a941 100644 --- a/src/mlpack/bindings/cli/output_param_impl.hpp +++ b/src/mlpack/bindings/cli/output_param_impl.hpp @@ -55,10 +55,10 @@ void OutputParamImpl( if (output.n_elem > 0 && filename != "") { - if (arma::is_Row::value || arma::is_Col::value) - data::Save(filename, output, false); - else - data::Save(filename, output, false, !data.noTranspose); + if (arma::is_Row::value || arma::is_Col::value) + data::Save(filename, output, false); + else + data::Save(filename, output, false, !data.noTranspose); } } @@ -72,14 +72,14 @@ void OutputParamImpl( // The const cast is necessary here because Serialize() can't ever be marked // const. In this case we can assume it though, since we will be saving and // not loading. - typedef std::tuple TupleType; - T& output = const_cast(std::get<0>(*boost::any_cast( + typedef std::tuple TupleType; + T*& output = const_cast(std::get<0>(*boost::any_cast( &data.value))); const std::string& filename = std::get<1>(*boost::any_cast(&data.value)); if (filename != "") - data::Save(filename, "model", output); + data::Save(filename, "model", *output); } //! Output a mapped dataset. diff --git a/src/mlpack/bindings/cli/parse_command_line.hpp b/src/mlpack/bindings/cli/parse_command_line.hpp index 3e0b959eaf..b7f7cac0de 100644 --- a/src/mlpack/bindings/cli/parse_command_line.hpp +++ b/src/mlpack/bindings/cli/parse_command_line.hpp @@ -52,7 +52,7 @@ void ParseCommandLine(int argc, char** argv) boostNameMap[boostName] = d.name; } - // TODO: we have to mark somehow that we parsed. + // Mark that we did parsing. CLI::GetSingleton().didParse = true; // Parse the command line, then place the values in the right place. diff --git a/src/mlpack/bindings/cli/set_param.hpp b/src/mlpack/bindings/cli/set_param.hpp index fb1fc0efce..64103135c5 100644 --- a/src/mlpack/bindings/cli/set_param.hpp +++ b/src/mlpack/bindings/cli/set_param.hpp @@ -54,7 +54,6 @@ void SetParam( util::ParamData& d, const boost::any& value, const typename std::enable_if::value || - data::HasSerialize::value || std::is_same>::value>::type* = 0) { @@ -64,6 +63,23 @@ void SetParam( std::get<1>(tuple) = boost::any_cast(value); } +/** + * Set a serializable object. This sets the filename referring to the + * parameter. + */ +template +void SetParam( + util::ParamData& d, + const boost::any& value, + const typename boost::disable_if>::type* = 0, + const typename boost::enable_if>::type* = 0) +{ + // We're setting the string filename. + typedef std::tuple::type> TupleType; + TupleType& tuple = *boost::any_cast(&d.value); + std::get<1>(tuple) = boost::any_cast(value); +} + /** * Return a parameter casted to the given type. Type checking does not happen * here! @@ -75,7 +91,8 @@ void SetParam( template void SetParam(const util::ParamData& d, const void* input, void* /* output */) { - SetParam(const_cast(d), *((boost::any*) input)); + SetParam::type>( + const_cast(d), *((boost::any*) input)); } } // namespace cli From 84427e1fe2bd2389aeae73c954c78e8d4617b300 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 26 Jan 2018 13:55:14 -0500 Subject: [PATCH 041/113] Fix memory handling of numpy arrays. If we make a copy during the conversion, then Armadillo should own the memory (otherwise Python will delete the temporary). --- .../bindings/python/mlpack/arma_numpy.pxd | 25 ++++---- .../bindings/python/mlpack/arma_numpy.pyx | 60 +++++++++++++++---- .../bindings/python/mlpack/matrix_utils.py | 27 +++++++-- 3 files changed, 82 insertions(+), 30 deletions(-) diff --git a/src/mlpack/bindings/python/mlpack/arma_numpy.pxd b/src/mlpack/bindings/python/mlpack/arma_numpy.pxd index 167810cb68..a0e9b8547e 100644 --- a/src/mlpack/bindings/python/mlpack/arma_numpy.pxd +++ b/src/mlpack/bindings/python/mlpack/arma_numpy.pxd @@ -19,14 +19,15 @@ import numpy numpy.import_array() cimport arma +from libcpp cimport bool """ Convert a numpy ndarray to a matrix. """ -cdef arma.Mat[double]* numpy_to_mat_d(numpy.ndarray[numpy.double_t, ndim=2] X) \ - except + -cdef arma.Mat[size_t]* numpy_to_mat_s(numpy.ndarray[numpy.npy_intp, ndim=2] X) \ - except + +cdef arma.Mat[double]* numpy_to_mat_d(numpy.ndarray[numpy.double_t, ndim=2] X, \ + bool takeOwnership) except + +cdef arma.Mat[size_t]* numpy_to_mat_s(numpy.ndarray[numpy.npy_intp, ndim=2] X, \ + bool takeOwnership) except + """ Convert an Armadillo object to a numpy ndarray of the given type. @@ -39,10 +40,10 @@ cdef numpy.ndarray[numpy.npy_intp, ndim=2] mat_to_numpy_s(arma.Mat[size_t]& X) \ """ Convert a numpy one-dimensional ndarray to a row of the given type. """ -cdef arma.Row[double]* numpy_to_row_d(numpy.ndarray[numpy.double_t, ndim=1] X) \ - except + -cdef arma.Row[size_t]* numpy_to_row_s(numpy.ndarray[numpy.npy_intp, ndim=1] X) \ - except + +cdef arma.Row[double]* numpy_to_row_d(numpy.ndarray[numpy.double_t, ndim=1] X, \ + bool takeOwnership) except + +cdef arma.Row[size_t]* numpy_to_row_s(numpy.ndarray[numpy.npy_intp, ndim=1] X, \ + bool takeOwnership) except + """ Convert an Armadillo row vector to a one-dimensional numpy ndarray of the @@ -56,10 +57,10 @@ cdef numpy.ndarray[numpy.npy_intp, ndim=1] row_to_numpy_s(arma.Row[size_t]& X) \ """ Convert a numpy one-dimensional ndarray to a column vector of the given type. """ -cdef arma.Col[double]* numpy_to_col_d(numpy.ndarray[numpy.double_t, ndim=1] X) \ - except + -cdef arma.Col[size_t]* numpy_to_col_s(numpy.ndarray[numpy.npy_intp, ndim=1] X) \ - except + +cdef arma.Col[double]* numpy_to_col_d(numpy.ndarray[numpy.double_t, ndim=1] X, \ + bool takeOwnership) except + +cdef arma.Col[size_t]* numpy_to_col_s(numpy.ndarray[numpy.npy_intp, ndim=1] X, \ + bool takeOwnership) except + """ Convert an Armadillo column vector to a one-dimensional numpy ndarray of the diff --git a/src/mlpack/bindings/python/mlpack/arma_numpy.pyx b/src/mlpack/bindings/python/mlpack/arma_numpy.pyx index 40508d17a1..dcf6908d94 100644 --- a/src/mlpack/bindings/python/mlpack/arma_numpy.pyx +++ b/src/mlpack/bindings/python/mlpack/arma_numpy.pyx @@ -24,6 +24,7 @@ import numpy numpy.import_array() cimport arma +from libcpp cimport bool cdef extern from "numpy/arrayobject.h": void PyArray_ENABLEFLAGS(numpy.ndarray arr, int flags) @@ -39,32 +40,44 @@ cdef extern from "": size_t* GetMemory(arma.Col[size_t]& m) size_t* GetMemory(arma.Row[size_t]& m) -cdef arma.Mat[double]* numpy_to_mat_d(numpy.ndarray[numpy.double_t, ndim=2] X) \ - except +: +cdef arma.Mat[double]* numpy_to_mat_d(numpy.ndarray[numpy.double_t, ndim=2] X, \ + bool takeOwnership) except +: """ Convert a numpy ndarray to a matrix. The memory will still be owned by numpy. """ if not (X.flags.c_contiguous or X.flags.owndata): # If needed, make a copy where we own the memory. X = X.copy(order="C") + takeOwnership = True cdef arma.Mat[double]* m = new arma.Mat[double]( X.data, X.shape[1],\ X.shape[0], False, False) + # Take ownership of the memory, if we need to. + if takeOwnership: + PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA) + SetMemState[arma.Mat[double]](m[0], 0) + return m -cdef arma.Mat[size_t]* numpy_to_mat_s(numpy.ndarray[numpy.npy_intp, ndim=2] X) \ - except +: +cdef arma.Mat[size_t]* numpy_to_mat_s(numpy.ndarray[numpy.npy_intp, ndim=2] X, \ + bool takeOwnership) except +: """ Convert a numpy ndarray to a matrix. The memory will still be owned by numpy. """ if not (X.flags.c_contiguous or X.flags.owndata): # If needed, make a copy where we own the memory. X = X.copy(order="C") + takeOwnership = True cdef arma.Mat[size_t]* m = new arma.Mat[size_t]( X.data, X.shape[1], X.shape[0], False, False) + # Take ownership of the memory, if we need to. + if takeOwnership: + PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA) + SetMemState[arma.Mat[size_t]](m[0], 0) + return m cdef numpy.ndarray[numpy.double_t, ndim=2] mat_to_numpy_d(arma.Mat[double]& X) \ @@ -105,8 +118,8 @@ cdef numpy.ndarray[numpy.npy_intp, ndim=2] mat_to_numpy_s(arma.Mat[size_t]& X) \ return output -cdef arma.Row[double]* numpy_to_row_d(numpy.ndarray[numpy.double_t, ndim=1] X) \ - except +: +cdef arma.Row[double]* numpy_to_row_d(numpy.ndarray[numpy.double_t, ndim=1] X, \ + bool takeOwnership) except +: """ Convert a numpy one-dimensional ndarray to a row. The memory will still be owned by numpy. @@ -114,14 +127,20 @@ cdef arma.Row[double]* numpy_to_row_d(numpy.ndarray[numpy.double_t, ndim=1] X) \ if not (X.flags.c_contiguous or X.flags.owndata): # If needed, make a copy where we own the memory. X = X.copy(order="C") + takeOwnership = True cdef arma.Row[double]* m = new arma.Row[double]( X.data, X.shape[0], False, False) + # Transfer memory ownership, if needed. + if takeOwnership: + PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA) + SetMemState[arma.Row[double]](m[0], 0) + return m -cdef arma.Row[size_t]* numpy_to_row_s(numpy.ndarray[numpy.npy_intp, ndim=1] X) \ - except +: +cdef arma.Row[size_t]* numpy_to_row_s(numpy.ndarray[numpy.npy_intp, ndim=1] X, \ + bool takeOwnership) except +: """ Convert a numpy one-dimensional ndarray to a row. The memory will still be owned by numpy. @@ -129,10 +148,16 @@ cdef arma.Row[size_t]* numpy_to_row_s(numpy.ndarray[numpy.npy_intp, ndim=1] X) \ if not (X.flags.c_contiguous or X.flags.owndata): # If needed, make a copy where we own the memory. X = X.copy(order="C") + takeOwnership = True cdef arma.Row[size_t]* m = new arma.Row[size_t]( X.data, X.shape[0], False, False) + # Transfer memory ownership, if needed. + if takeOwnership: + PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA) + SetMemState[arma.Row[size_t]](m[0], 0) + return m cdef numpy.ndarray[numpy.double_t, ndim=1] row_to_numpy_d(arma.Row[double]& X) \ @@ -169,8 +194,8 @@ cdef numpy.ndarray[numpy.npy_intp, ndim=1] row_to_numpy_s(arma.Row[size_t]& X) \ return output -cdef arma.Col[double]* numpy_to_col_d(numpy.ndarray[numpy.double_t, ndim=1] X) \ - except +: +cdef arma.Col[double]* numpy_to_col_d(numpy.ndarray[numpy.double_t, ndim=1] X, \ + bool takeOwnership) except +: """ Convert a numpy one-dimensional ndarray to a column vector. The memory will still be owned by numpy. @@ -178,14 +203,20 @@ cdef arma.Col[double]* numpy_to_col_d(numpy.ndarray[numpy.double_t, ndim=1] X) \ if not (X.flags.c_contiguous or X.flags.owndata): # If needed, make a copy where we own the memory. X = X.copy(order="C") + takeOwnership = True cdef arma.Col[double]* m = new arma.Col[double]( X.data, X.shape[0], False, True) + # Transfer memory ownership, if needed. + if takeOwnership: + PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA) + SetMemState[arma.Col[double]](m[0], 0) + return m -cdef arma.Col[size_t]* numpy_to_col_s(numpy.ndarray[numpy.npy_intp, ndim=1] X) \ - except +: +cdef arma.Col[size_t]* numpy_to_col_s(numpy.ndarray[numpy.npy_intp, ndim=1] X, \ + bool takeOwnership) except +: """ Convert a numpy one-dimensional ndarray to a column vector. The memory will still be owned by numpy. @@ -197,6 +228,11 @@ cdef arma.Col[size_t]* numpy_to_col_s(numpy.ndarray[numpy.npy_intp, ndim=1] X) \ cdef arma.Col[size_t]* m = new arma.Col[size_t]( X.data, X.shape[0], False, False) + # Transfer memory ownership, if needed. + if takeOwnership: + PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA) + SetMemState[arma.Col[size_t]](m[0], 0) + return m cdef numpy.ndarray[numpy.double_t, ndim=1] col_to_numpy_d(arma.Col[double]& X) \ diff --git a/src/mlpack/bindings/python/mlpack/matrix_utils.py b/src/mlpack/bindings/python/mlpack/matrix_utils.py index 04c9d4778d..9cf0cbadda 100644 --- a/src/mlpack/bindings/python/mlpack/matrix_utils.py +++ b/src/mlpack/bindings/python/mlpack/matrix_utils.py @@ -48,9 +48,9 @@ def to_matrix(x, dtype=np.double): raise TypeError("given argument is not array-like") if (isinstance(x, np.ndarray) and x.dtype == dtype and x.flags.c_contiguous): - return x + return x, False else: - return np.array(x, copy=True, dtype=dtype, order='C') + return np.array(x, copy=True, dtype=dtype, order='C'), True def to_matrix_with_info(x, dtype): """ @@ -66,7 +66,7 @@ def to_matrix_with_info(x, dtype): if isinstance(x, np.ndarray): # It is already an ndarray, so the vector of info is all 0s (all numeric). d = np.zeros([x.shape[1]], dtype=np.bool) - return (x, d) + return (x, False, d) if isinstance(x, pd.DataFrame) or isinstance(x, pd.Series): # It's a pandas dataframe. So we need to see if any of the dtypes are @@ -79,8 +79,9 @@ def to_matrix_with_info(x, dtype): not np.dtype(str) in dtype_array and \ not np.dtype(unicode) in dtype_array: # We can just return the matrix as-is; it's all numeric. + t = to_matrix(x) d = np.zeros([x.shape[1]], dtype=np.bool) - return (to_matrix(x), d) + return (t[0], t[1], d) if np.dtype(str) in dtype_array or np.dtype(unicode) in dtype_array: raise TypeError('cannot convert matrices with string types') @@ -115,7 +116,10 @@ def to_matrix_with_info(x, dtype): catColumnIndices = [y.columns.get_loc(i) for i in catColumns] d[catColumnIndices] = 1 - return (to_matrix(y.apply(pd.to_numeric)), d) + # We'll have to force the second part of the tuple (whether or not to take + # ownership) to true. + t = to_matrix(y.apply(pd.to_numeric)) + return (t[0], True, d) if isinstance(x, list): # Get the number of dimensions. @@ -126,7 +130,18 @@ def to_matrix_with_info(x, dtype): dims = len(x) d = np.zeros([dims]) - return (np.array(x, dtype=dtype), d) + out = np.array(x, dtype=dtype, copy=False) # Try to avoid copy... + + # Since we don't have a great way to check if these are using the same + # memory location, we will probe manually (ugh). + oldval = x[0] + x[0] *= 2 + alias = False + if out[0] == x[0]: + alias = True + x[0] = oldval + + return (np.array(x, dtype=dtype), not alias, d) # If we got here, the type is not known. raise TypeError("given matrix is not a numpy ndarray or pandas DataFrame or "\ From 7903a0ed398dd08cc789ce3ffacde3aa606373ac Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 26 Jan 2018 13:56:48 -0500 Subject: [PATCH 042/113] Make Python bindings hold pointers. This refactors the Python bindings to deal with holding pointers to serializable types. Some minor extra work is necessary to prevent Python from accidentally deleting models multiple times. --- .../bindings/python/get_cython_type.hpp | 2 +- src/mlpack/bindings/python/get_param.hpp | 12 ++- .../bindings/python/get_printable_param.hpp | 5 +- src/mlpack/bindings/python/import_decl.hpp | 2 +- src/mlpack/bindings/python/mlpack/cli.pxd | 7 +- .../bindings/python/mlpack/cli_util.hpp | 25 +++++ src/mlpack/bindings/python/mlpack/move.hpp | 30 ------ .../bindings/python/print_class_defn.hpp | 2 +- src/mlpack/bindings/python/print_doc.hpp | 3 +- .../python/print_input_processing.hpp | 61 ++++++------ .../python/print_output_processing.hpp | 94 ++++++++++++++++--- src/mlpack/bindings/python/print_pyx.cpp | 4 +- 12 files changed, 163 insertions(+), 84 deletions(-) delete mode 100644 src/mlpack/bindings/python/mlpack/move.hpp diff --git a/src/mlpack/bindings/python/get_cython_type.hpp b/src/mlpack/bindings/python/get_cython_type.hpp index f5ae807abe..8e95dc2d9d 100644 --- a/src/mlpack/bindings/python/get_cython_type.hpp +++ b/src/mlpack/bindings/python/get_cython_type.hpp @@ -113,7 +113,7 @@ inline std::string GetCythonType( const typename boost::disable_if>::type* = 0, const typename boost::enable_if>::type* = 0) { - return d.cppType; + return d.cppType + "*"; } } // namespace python diff --git a/src/mlpack/bindings/python/get_param.hpp b/src/mlpack/bindings/python/get_param.hpp index 62c898a15e..e2c1c33108 100644 --- a/src/mlpack/bindings/python/get_param.hpp +++ b/src/mlpack/bindings/python/get_param.hpp @@ -22,7 +22,17 @@ void GetParam(const util::ParamData& d, const void* /* input */, void* output) { - *((T**) output) = const_cast(boost::any_cast(&d.value)); +// typedef typename std::remove_pointer::type TRaw; +// if (std::is_pointer::value) // If true, this is a model. +// { +// std::cout << "get a raw pointer for " << d.name << ": " << boost::any_cast(d.value) << +//"\n"; +// *((TRaw***) output) = const_cast(boost::any_cast(&d.value)); +// } +// else + { + *((T**) output) = const_cast(boost::any_cast(&d.value)); + } } } // namespace python diff --git a/src/mlpack/bindings/python/get_printable_param.hpp b/src/mlpack/bindings/python/get_printable_param.hpp index b7258bc7c8..0c21dd5a61 100644 --- a/src/mlpack/bindings/python/get_printable_param.hpp +++ b/src/mlpack/bindings/python/get_printable_param.hpp @@ -73,7 +73,7 @@ std::string GetPrintableParam( const typename boost::enable_if>::type* = 0) { std::ostringstream oss; - oss << data.cppType << " model"; + oss << data.cppType << " model at " << boost::any_cast(data.value); return oss.str(); } @@ -110,7 +110,8 @@ void GetPrintableParam(const util::ParamData& data, const void* /* input */, void* output) { - *((std::string*) output) = GetPrintableParam(data); + *((std::string*) output) = + GetPrintableParam::type>(data); } } // namespace python diff --git a/src/mlpack/bindings/python/import_decl.hpp b/src/mlpack/bindings/python/import_decl.hpp index b638ecde42..52d1026340 100644 --- a/src/mlpack/bindings/python/import_decl.hpp +++ b/src/mlpack/bindings/python/import_decl.hpp @@ -79,7 +79,7 @@ void ImportDecl(const util::ParamData& d, const void* indent, void* /* output */) { - ImportDecl(d, *((size_t*) indent)); + ImportDecl::type>(d, *((size_t*) indent)); } } // namespace python diff --git a/src/mlpack/bindings/python/mlpack/cli.pxd b/src/mlpack/bindings/python/mlpack/cli.pxd index 860bc4a756..f6c6435c18 100644 --- a/src/mlpack/bindings/python/mlpack/cli.pxd +++ b/src/mlpack/bindings/python/mlpack/cli.pxd @@ -38,15 +38,12 @@ cdef extern from "" namespace "mlpack" nogil: cdef extern from "" \ namespace "mlpack::util" nogil: void SetParam[T](string, T&) nogil except + + void SetParamPtr[T](string, T*) nogil except + void SetParamWithInfo[T](string, T&, const bool*) nogil except + + (T*) GetParamPtr[T](string) nogil except + (T&) GetParamWithInfo[T](string) nogil except + void EnableVerbose() nogil except + void DisableVerbose() nogil except + void DisableBacktrace() nogil except + void ResetTimers() nogil except + void EnableTimers() nogil except + - -cdef extern from "" \ - namespace "mlpack::util" nogil: - void MoveFromPtr[T](T&, T*) nogil except + - void MoveToPtr[T](T*, T&) nogil except + diff --git a/src/mlpack/bindings/python/mlpack/cli_util.hpp b/src/mlpack/bindings/python/mlpack/cli_util.hpp index e1fdcc0c55..6c4ef5ff7b 100644 --- a/src/mlpack/bindings/python/mlpack/cli_util.hpp +++ b/src/mlpack/bindings/python/mlpack/cli_util.hpp @@ -34,6 +34,21 @@ inline void SetParam(const std::string& identifier, T& value) CLI::GetParam(identifier) = std::move(value); } +/** + * Set the parameter to the given value, given that the type is a pointer. + * + * This function exists to work around both Cython's lack of support for lvalue + * references and also its seeming lack of support for template pointer types. + * + * @param identifier Name of parameter. + * @param value Value to set parameter to. + */ +template +inline void SetParamPtr(const std::string& identifier, T* value) +{ + CLI::GetParam(identifier) = value; +} + /** * Set the parameter (which is a matrix/DatasetInfo tuple) to the given value. */ @@ -83,6 +98,16 @@ inline void SetParamWithInfo(const std::string& identifier, } } +/** + * Return a pointer. This function exists to work around Cython's seeming lack + * of support for template pointer types. + */ +template +T* GetParamPtr(const std::string& paramName) +{ + return CLI::GetParam(paramName); +} + /** * Return the matrix part of a matrix + dataset info parameter. */ diff --git a/src/mlpack/bindings/python/mlpack/move.hpp b/src/mlpack/bindings/python/mlpack/move.hpp deleted file mode 100644 index b4a145b2d7..0000000000 --- a/src/mlpack/bindings/python/mlpack/move.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file move.hpp - * @author Ryan Curtin - * - * Utility function for Cython to use std::move. - */ -#ifndef MLPACK_BINDINGS_PYTHON_CYTHON_MOVE_HPP -#define MLPACK_BINDINGS_PYTHON_CYTHON_MOVE_HPP - -#include - -namespace mlpack { -namespace util { - -template -void MoveToPtr(T* dest, T& src) -{ - *(dest) = std::move(src); -} - -template -void MoveFromPtr(T& dest, T* src) -{ - dest = std::move(*src); -} - -} // namespace util -} // namespace mlpack - -#endif diff --git a/src/mlpack/bindings/python/print_class_defn.hpp b/src/mlpack/bindings/python/print_class_defn.hpp index 77148531b9..8bb4e0fdc2 100644 --- a/src/mlpack/bindings/python/print_class_defn.hpp +++ b/src/mlpack/bindings/python/print_class_defn.hpp @@ -108,7 +108,7 @@ void PrintClassDefn(const util::ParamData& d, const void* /* input */, void* /* output */) { - PrintClassDefn(d); + PrintClassDefn::type>(d); } } // namespace python diff --git a/src/mlpack/bindings/python/print_doc.hpp b/src/mlpack/bindings/python/print_doc.hpp index 08cbebdf26..353e558a9a 100644 --- a/src/mlpack/bindings/python/print_doc.hpp +++ b/src/mlpack/bindings/python/print_doc.hpp @@ -39,7 +39,8 @@ void PrintDoc(const util::ParamData& d, oss << d.name << "_ ("; else oss << d.name << " ("; - oss << GetPythonType(d) << "): " << d.desc; + oss << GetPythonType::type>(d) << "): " + << d.desc; // Print a default, if possible. if (!d.required) diff --git a/src/mlpack/bindings/python/print_input_processing.hpp b/src/mlpack/bindings/python/print_input_processing.hpp index 9982449fa9..14d487b3fb 100644 --- a/src/mlpack/bindings/python/print_input_processing.hpp +++ b/src/mlpack/bindings/python/print_input_processing.hpp @@ -104,7 +104,9 @@ void PrintInputProcessing( * * # Detect if the parameter was passed; set if so. * if param_name is not None: - * param_name_mat = arma_numpy.numpy_to_mat_d(param_name) + * param_name_tuple = to_matrix(param_name) + * param_name_mat = arma_numpy.numpy_to_mat_d(param_name_tuple[0], + * param_name_tuple[1]) * SetParam[mat]( 'param_name', dereference(param_name_mat)) * CLI.SetPassed( 'param_name') */ @@ -114,10 +116,12 @@ void PrintInputProcessing( { std::cout << prefix << "if " << d.name << " is not None:" << std::endl; + std::cout << prefix << " " << d.name << "_tuple = to_matrix(" << d.name + << ", dtype=" << GetNumpyType() << ")" + << std::endl; std::cout << prefix << " " << d.name << "_mat = arma_numpy.numpy_to_" - << GetArmaType() << "_" << GetNumpyTypeChar() << "(to_matrix(" - << d.name << ", " << "dtype=" << GetNumpyType() - << "))" << std::endl; + << GetArmaType() << "_" << GetNumpyTypeChar() << "(" << d.name + << "_tuple[0], " << d.name << "_tuple[1])" << std::endl; std::cout << prefix << " SetParam[" << GetCythonType(d) << "]( '" << d.name << "', dereference(" << d.name << "_mat))" << std::endl; @@ -127,10 +131,12 @@ void PrintInputProcessing( } else { + std::cout << prefix << d.name << "_tuple = to_matrix(" << d.name + << ", dtype=" << GetNumpyType() << ")" + << std::endl; std::cout << prefix << d.name << "_mat = arma_numpy.numpy_to_" - << GetArmaType() << "_" << GetNumpyTypeChar() << "(to_matrix(" - << d.name << ", " << "dtype=" << GetNumpyType() - << "))" << std::endl; + << GetArmaType() << "_" << GetNumpyTypeChar() << "(" << d.name + << "_tuple[0], " << d.name << "_tuple[1])" << std::endl; std::cout << prefix << "SetParam[" << GetCythonType(d) << "]( '" << d.name << "', dereference(" << d.name << "_mat))" << std::endl; @@ -163,12 +169,10 @@ void PrintInputProcessing( * # Detect if the parameter was passed; set if so. * if param_name is not None: * try: - * MoveFromPtr[Model](CLI.GetParam[Model]('param_name'), - * ( param_name).modelptr) + * SetParamPtr[Model]('param_name', ( param_name).modelptr) * except TypeError as e: * if type(param_name).__name__ == "ModelType": - * MoveFromPtr[Model](CLI.GetParam[Model]('param_name'), - * ( param_name).modelptr) + * SetParamPtr[Model]('param_name', ( param_name).modelptr) * else: * raise e * CLI.SetPassed( 'param_name') @@ -179,15 +183,15 @@ void PrintInputProcessing( { std::cout << prefix << "if " << d.name << " is not None:" << std::endl; std::cout << prefix << " try:" << std::endl; - std::cout << prefix << " MoveFromPtr[" << strippedType - << "](CLI.GetParam[" << strippedType << "]('" << d.name << "'), (<" - << strippedType << "Type?> " << d.name << ").modelptr)" << std::endl; + std::cout << prefix << " SetParamPtr[" << strippedType << "]('" << d.name + << "', (<" << strippedType << "Type?> " << d.name << ").modelptr)" + << std::endl; std::cout << prefix << " except TypeError as e:" << std::endl; std::cout << prefix << " if type(" << d.name << ").__name__ == '" << strippedType << "Type':" << std::endl; - std::cout << prefix << " MoveFromPtr[" << strippedType - << "](CLI.GetParam[" << strippedType << "]('" << d.name << "'), (<" - << strippedType << "Type> " << d.name << ").modelptr)" << std::endl; + std::cout << prefix << " SetParamPtr[" << strippedType << "]('" << d.name + << "', (<" << strippedType << "Type> " << d.name << ").modelptr)" + << std::endl; std::cout << prefix << " else:" << std::endl; std::cout << prefix << " raise e" << std::endl; std::cout << prefix << " CLI.SetPassed( '" << d.name << "')" @@ -196,15 +200,15 @@ void PrintInputProcessing( else { std::cout << prefix << "try:" << std::endl; - std::cout << prefix << " MoveFromPtr[" << strippedType << "](CLI.GetParam[" - << strippedType << "]('" << d.name << "'), (<" << strippedType - << "Type?> " << d.name << ").modelptr)" << std::endl; + std::cout << prefix << " SetParamPtr[" << strippedType << "]('" << d.name + << "', (<" << strippedType << "Type?> " << d.name << ").modelptr)" + << std::endl; std::cout << prefix << "except TypeError as e:" << std::endl; std::cout << prefix << " if type(" << d.name << ").__name__ == '" << strippedType << "Type':" << std::endl; - std::cout << prefix << " MoveFromPtr[" << strippedType - << "](CLI.GetParam[" << strippedType << "]('" << d.name << "'), (<" - << strippedType << "Type> " << d.name << ").modelptr)" << std::endl; + std::cout << prefix << " SetParamPtr[" << strippedType << "]('" << d.name + << "', (<" << strippedType << "Type> " << d.name << ").modelptr)" + << std::endl; std::cout << prefix << " else:" << std::endl; std::cout << prefix << " raise e" << std::endl; std::cout << prefix << "CLI.SetPassed( '" << d.name << "')" @@ -244,8 +248,8 @@ void PrintInputProcessing( std::cout << prefix << " " << d.name << "_tuple = to_matrix_with_info(" << d.name << ", dtype=np.double)" << std::endl; std::cout << prefix << " " << d.name << "_mat = arma_numpy.numpy_to_mat_d(" - << d.name << "_tuple[0])" << std::endl; - std::cout << prefix << " " << d.name << "_dims = " << d.name << "_tuple[1]" + << d.name << "_tuple[0], " << d.name << "_tuple[1])" << std::endl; + std::cout << prefix << " " << d.name << "_dims = " << d.name << "_tuple[2]" << std::endl; std::cout << prefix << " SetParamWithInfo[arma.Mat[double]](" << " '" << d.name << "', dereference(" << d.name << "_mat), " << " '" << d.name << "', dereference(" << d.name << "_mat), (d, *((size_t*) input)); + PrintInputProcessing::type>(d, + *((size_t*) input)); } } // namespace python diff --git a/src/mlpack/bindings/python/print_output_processing.hpp b/src/mlpack/bindings/python/print_output_processing.hpp index d20da67f4e..00833ceceb 100644 --- a/src/mlpack/bindings/python/print_output_processing.hpp +++ b/src/mlpack/bindings/python/print_output_processing.hpp @@ -180,13 +180,47 @@ void PrintOutputProcessing( * This gives us code like: * * result = ModelType() - * MoveToPtr[Model](( model).modelptr), - * CLI.GetParam[Model]('name')) + * ( result).modelptr = GetParamPtr[Model]('name') */ std::cout << prefix << "result = " << strippedType << "Type()" << std::endl; - std::cout << prefix << "MoveToPtr[" << strippedType << "]((<" - << strippedType << "Type?> result).modelptr, CLI.GetParam[" - << strippedType << "]('" << d.name << "'))" << std::endl; + std::cout << prefix << "(<" << strippedType << "Type?> result).modelptr = " + << "GetParamPtr[" << strippedType << "]('" << d.name << "')" + << std::endl; + + /** + * But we also have to check to ensure there aren't any input model + * parameters of the same type that could have the same model pointer. + * So we need to loop through all input parameters that have the same type, + * and double-check. + */ + std::map& parameters = CLI::Parameters(); + for (auto it = parameters.begin(); it != parameters.end(); ++it) + { + // Is it an input parameter of the same type? + const util::ParamData& data = it->second; + if (data.input && data.cppType == d.cppType && data.required) + { + std::cout << prefix << "if (<" << strippedType + << "Type> result).modelptr" << d.name << " == (<" << strippedType + << "Type> " << data.name << ").modelptr:" << std::endl; + std::cout << prefix << " (<" << strippedType + << "Type> result).modelptr = <" << strippedType << "*> 0" + << std::endl; + std::cout << prefix << " result = " << data.name << std::endl; + } + else if (data.input && data.cppType == d.cppType) + { + std::cout << prefix << "if " << data.name << " is not None:" + << std::endl; + std::cout << prefix << " if (<" << strippedType + << "Type> result).modelptr" << d.name << " == (<" << strippedType + << "Type> " << data.name << ").modelptr:" << std::endl; + std::cout << prefix << " (<" << strippedType + << "Type> result).modelptr = <" << strippedType << "*> 0" + << std::endl; + std::cout << prefix << " result = " << data.name << std::endl; + } + } } else { @@ -194,15 +228,50 @@ void PrintOutputProcessing( * This gives us code like: * * result['name'] = ModelType() - * MoveToPtr[Model*](( result['name']).modelptr), - * CLI.GetParam[Model]('name')) + * ( result['name']).modelptr = GetParamPtr[Model]('name')) */ std::cout << prefix << "result['" << d.name << "'] = " << strippedType << "Type()" << std::endl; - std::cout << prefix << "MoveToPtr[" << strippedType << "]((<" - << strippedType << "Type?>" << " result['" << d.name - << "']).modelptr, CLI.GetParam[" << strippedType << "]('" - << d.name << "'))" << std::endl; + std::cout << prefix << "(<" << strippedType << "Type?> result['" << d.name + << "']).modelptr = GetParamPtr[" << strippedType << "]('" << d.name + << "')" << std::endl; + + /** + * But we also have to check to ensure there aren't any input model + * parameters of the same type that could have the same model pointer. + * So we need to loop through all input parameters that have the same type, + * and double-check. + */ + std::map& parameters = CLI::Parameters(); + for (auto it = parameters.begin(); it != parameters.end(); ++it) + { + // Is it an input parameter of the same type? + const util::ParamData& data = it->second; + if (data.input && data.cppType == d.cppType && data.required) + { + std::cout << prefix << "if (<" << strippedType << "Type> result['" + << d.name << "']).modelptr == (<" << strippedType << "Type> " + << data.name << ").modelptr:" << std::endl; + std::cout << prefix << " (<" << strippedType << "Type> result['" + << d.name << "']).modelptr = <" << strippedType << "*> 0" + << std::endl; + std::cout << prefix << " result['" << d.name << "'] = " << data.name + << std::endl; + } + else if (data.input && data.cppType == d.cppType) + { + std::cout << prefix << "if " << data.name << " is not None:" + << std::endl; + std::cout << prefix << " if (<" << strippedType << "Type> result['" + << d.name << "']).modelptr == (<" << strippedType << "Type> " + << data.name << ").modelptr:" << std::endl; + std::cout << prefix << " (<" << strippedType << "Type> result['" + << d.name << "']).modelptr = <" << strippedType << "*> 0" + << std::endl; + std::cout << prefix << " result['" << d.name << "'] = " << data.name + << std::endl; + } + } } } @@ -227,7 +296,8 @@ void PrintOutputProcessing(const util::ParamData& d, { std::tuple* tuple = (std::tuple*) input; - PrintOutputProcessing(d, std::get<0>(*tuple), std::get<1>(*tuple)); + PrintOutputProcessing::type>(d, + std::get<0>(*tuple), std::get<1>(*tuple)); } } // namespace python diff --git a/src/mlpack/bindings/python/print_pyx.cpp b/src/mlpack/bindings/python/print_pyx.cpp index cb92389366..423de61a41 100644 --- a/src/mlpack/bindings/python/print_pyx.cpp +++ b/src/mlpack/bindings/python/print_pyx.cpp @@ -71,10 +71,10 @@ void PrintPYX(const ProgramDoc& programInfo, cout << "cimport arma" << endl; cout << "cimport arma_numpy" << endl; cout << "from cli cimport CLI" << endl; - cout << "from cli cimport SetParam, SetParamWithInfo" << endl; + cout << "from cli cimport SetParam, SetParamPtr, SetParamWithInfo, " + << "GetParamPtr" << endl; cout << "from cli cimport EnableVerbose, DisableVerbose, DisableBacktrace, " << "ResetTimers, EnableTimers" << endl; - cout << "from cli cimport MoveFromPtr, MoveToPtr" << endl; cout << "from matrix_utils import to_matrix, to_matrix_with_info" << endl; cout << "from serialization cimport SerializeIn, SerializeOut" << endl; cout << endl; From 7e2dcf9563d02cc7eff208bf4b36d0474f74658c Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 26 Jan 2018 13:59:20 -0500 Subject: [PATCH 043/113] Update test bindings to hold model pointers. --- src/mlpack/bindings/tests/get_printable_param.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mlpack/bindings/tests/get_printable_param.hpp b/src/mlpack/bindings/tests/get_printable_param.hpp index e95234549b..5720a0433c 100644 --- a/src/mlpack/bindings/tests/get_printable_param.hpp +++ b/src/mlpack/bindings/tests/get_printable_param.hpp @@ -72,7 +72,8 @@ void GetPrintableParam(const util::ParamData& data, const void* /* input */, void* output) { - *((std::string*) output) = GetPrintableParam(data); + *((std::string*) output) = + GetPrintableParam::type>(data); } } // namespace tests From 7c53e3e79a50032c79c0748e0f884a5062e6fb8a Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 26 Jan 2018 13:59:38 -0500 Subject: [PATCH 044/113] Update PARAM_MODEL_IN() and PARAM_MODEL_OUT() macros to hold pointers. --- src/mlpack/core/util/param.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mlpack/core/util/param.hpp b/src/mlpack/core/util/param.hpp index 2683d59b77..b812887fbd 100644 --- a/src/mlpack/core/util/param.hpp +++ b/src/mlpack/core/util/param.hpp @@ -1058,9 +1058,9 @@ using DatasetInfo = DatasetMapper; // 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 \ + static mlpack::util::Option \ JOIN(cli_option_dummy_model_, __COUNTER__) \ - (TYPE(), ID, DESC, ALIAS, #TYPE, REQ, IN, false, testName); + (nullptr, 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 @@ -1113,9 +1113,9 @@ using DatasetInfo = DatasetMapper; !TRANS, testName); #define PARAM_MODEL(TYPE, ID, DESC, ALIAS, REQ, IN) \ - static mlpack::util::Option \ + static mlpack::util::Option \ JOIN(JOIN(cli_option_dummy_object_model_, __LINE__), opt) \ - (TYPE(), ID, DESC, ALIAS, #TYPE, REQ, IN, false, \ + (nullptr, ID, DESC, ALIAS, #TYPE, REQ, IN, false, \ testName); #endif From ede36869753ba38e35f84f7fa8096303bb427b80 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 26 Jan 2018 14:01:41 -0500 Subject: [PATCH 045/113] Refactor all programs to work with model pointers. --- src/mlpack/methods/adaboost/adaboost_main.cpp | 30 +++++----- .../methods/approx_kfn/approx_kfn_main.cpp | 29 ++++----- src/mlpack/methods/cf/cf_main.cpp | 22 ++++--- .../decision_stump/decision_stump_main.cpp | 20 +++---- .../decision_tree/decision_tree_main.cpp | 26 ++++---- src/mlpack/methods/det/det_main.cpp | 14 ++--- src/mlpack/methods/fastmks/fastmks_main.cpp | 55 ++++++++--------- src/mlpack/methods/gmm/gmm_generate_main.cpp | 9 ++- .../methods/gmm/gmm_probability_main.cpp | 7 +-- src/mlpack/methods/gmm/gmm_train_main.cpp | 27 +++++---- src/mlpack/methods/hmm/hmm_loglik_main.cpp | 2 +- src/mlpack/methods/hmm/hmm_train_main.cpp | 12 ++-- src/mlpack/methods/hmm/hmm_viterbi_main.cpp | 5 +- .../hoeffding_trees/hoeffding_tree_main.cpp | 34 +++++------ src/mlpack/methods/lars/lars_main.cpp | 23 ++++---- .../linear_regression_main.cpp | 18 +++--- .../local_coordinate_coding_main.cpp | 51 ++++++++-------- .../logistic_regression_main.cpp | 23 ++++---- src/mlpack/methods/lsh/lsh_main.cpp | 24 ++++---- src/mlpack/methods/naive_bayes/nbc_main.cpp | 27 ++++----- .../methods/neighbor_search/kfn_main.cpp | 47 ++++++++------- .../methods/neighbor_search/knn_main.cpp | 53 ++++++++--------- .../methods/perceptron/perceptron_main.cpp | 47 ++++++++------- .../random_forest/random_forest_main.cpp | 25 ++++---- .../range_search/range_search_main.cpp | 29 ++++----- src/mlpack/methods/rann/krann_main.cpp | 52 ++++++++-------- .../softmax_regression_main.cpp | 21 +++---- .../sparse_coding/sparse_coding_main.cpp | 59 +++++++++---------- 28 files changed, 377 insertions(+), 414 deletions(-) diff --git a/src/mlpack/methods/adaboost/adaboost_main.cpp b/src/mlpack/methods/adaboost/adaboost_main.cpp index e5209efb46..2634ff08a1 100644 --- a/src/mlpack/methods/adaboost/adaboost_main.cpp +++ b/src/mlpack/methods/adaboost/adaboost_main.cpp @@ -145,10 +145,11 @@ static void mlpackMain() ReportIgnoredParam({{ "test", false }}, "output"); - AdaBoostModel m; + AdaBoostModel* m; if (CLI::HasParam("training")) { mat trainingData = std::move(CLI::GetParam("training")); + m = new AdaBoostModel(); // Load labels. arma::Row labelsIn; @@ -172,28 +173,28 @@ static void mlpackMain() Row labels; // Normalize the labels. - data::NormalizeLabels(labelsIn, labels, m.Mappings()); + data::NormalizeLabels(labelsIn, labels, m->Mappings()); // Get other training parameters. const double tolerance = CLI::GetParam("tolerance"); const size_t iterations = (size_t) CLI::GetParam("iterations"); const string weakLearner = CLI::GetParam("weak_learner"); if (weakLearner == "decision_stump") - m.WeakLearnerType() = AdaBoostModel::WeakLearnerTypes::DECISION_STUMP; + m->WeakLearnerType() = AdaBoostModel::WeakLearnerTypes::DECISION_STUMP; else if (weakLearner == "perceptron") - m.WeakLearnerType() = AdaBoostModel::WeakLearnerTypes::PERCEPTRON; + m->WeakLearnerType() = AdaBoostModel::WeakLearnerTypes::PERCEPTRON; - const size_t numClasses = m.Mappings().n_elem; + const size_t numClasses = m->Mappings().n_elem; Log::Info << numClasses << " classes in dataset." << endl; Timer::Start("adaboost_training"); - m.Train(trainingData, labels, numClasses, iterations, tolerance); + m->Train(trainingData, labels, numClasses, iterations, tolerance); Timer::Stop("adaboost_training"); } else { // We have a specified input model. - m = std::move(CLI::GetParam("input_model")); + m = CLI::GetParam("input_model"); } // Perform classification, if desired. @@ -201,24 +202,21 @@ static void mlpackMain() { mat testingData = std::move(CLI::GetParam("test")); - if (testingData.n_rows != m.Dimensionality()) + if (testingData.n_rows != m->Dimensionality()) Log::Fatal << "Test data dimensionality (" << testingData.n_rows << ") " << "must be the same as the model dimensionality (" - << m.Dimensionality() << ")!" << endl; + << m->Dimensionality() << ")!" << endl; Row predictedLabels(testingData.n_cols); Timer::Start("adaboost_classification"); - m.Classify(testingData, predictedLabels); + m->Classify(testingData, predictedLabels); Timer::Stop("adaboost_classification"); Row results; - data::RevertLabels(predictedLabels, m.Mappings(), results); + data::RevertLabels(predictedLabels, m->Mappings(), results); - if (CLI::HasParam("output")) - CLI::GetParam>("output") = std::move(results); + CLI::GetParam>("output") = std::move(results); } - // Should we save the model, too? - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(m); + CLI::GetParam("output_model") = m; } diff --git a/src/mlpack/methods/approx_kfn/approx_kfn_main.cpp b/src/mlpack/methods/approx_kfn/approx_kfn_main.cpp index f73008583d..030fb90132 100644 --- a/src/mlpack/methods/approx_kfn/approx_kfn_main.cpp +++ b/src/mlpack/methods/approx_kfn/approx_kfn_main.cpp @@ -190,11 +190,12 @@ static void mlpackMain() } // Do the building of a model, if necessary. - ApproxKFNModel m; + ApproxKFNModel* m; arma::mat referenceSet; // This may be used at query time. if (CLI::HasParam("reference")) { referenceSet = std::move(CLI::GetParam("reference")); + m = new ApproxKFNModel(); const size_t numTables = (size_t) CLI::GetParam("num_tables"); const size_t numProjections = @@ -205,16 +206,16 @@ static void mlpackMain() { Timer::Start("drusilla_select_construct"); Log::Info << "Building DrusillaSelect model..." << endl; - m.type = 0; - m.ds = DrusillaSelect<>(referenceSet, numTables, numProjections); + m->type = 0; + m->ds = DrusillaSelect<>(referenceSet, numTables, numProjections); Timer::Stop("drusilla_select_construct"); } else { Timer::Start("qdafn_construct"); Log::Info << "Building QDAFN model..." << endl; - m.type = 1; - m.qdafn = QDAFN<>(referenceSet, numTables, numProjections); + m->type = 1; + m->qdafn = QDAFN<>(referenceSet, numTables, numProjections); Timer::Stop("qdafn_construct"); } Log::Info << "Model built." << endl; @@ -222,7 +223,7 @@ static void mlpackMain() else { // We must load the model from what was passed. - m = std::move(CLI::GetParam("input_model")); + m = CLI::GetParam("input_model"); } // Now, do we need to do any queries? @@ -238,12 +239,12 @@ static void mlpackMain() if (CLI::HasParam("query")) querySet = std::move(CLI::GetParam("query")); - if (m.type == 0) + if (m->type == 0) { Timer::Start("drusilla_select_search"); Log::Info << "Searching for " << k << " furthest neighbors with " << "DrusillaSelect..." << endl; - m.ds.Search(set, k, neighbors, distances); + m->ds.Search(set, k, neighbors, distances); Timer::Stop("drusilla_select_search"); } else @@ -251,7 +252,7 @@ static void mlpackMain() Timer::Start("qdafn_search"); Log::Info << "Searching for " << k << " furthest neighbors with " << "QDAFN..." << endl; - m.qdafn.Search(set, k, neighbors, distances); + m->qdafn.Search(set, k, neighbors, distances); Timer::Stop("qdafn_search"); } Log::Info << "Search complete." << endl; @@ -288,13 +289,9 @@ static void mlpackMain() } // Save results, if desired. - if (CLI::HasParam("neighbors")) - CLI::GetParam>("neighbors") = std::move(neighbors); - if (CLI::HasParam("distances")) - CLI::GetParam("distances") = std::move(distances); + CLI::GetParam>("neighbors") = std::move(neighbors); + CLI::GetParam("distances") = std::move(distances); } - // Should we save the model? - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(m); + CLI::GetParam("output_model") = m; } diff --git a/src/mlpack/methods/cf/cf_main.cpp b/src/mlpack/methods/cf/cf_main.cpp index 2fedefb4ed..f09280dacd 100644 --- a/src/mlpack/methods/cf/cf_main.cpp +++ b/src/mlpack/methods/cf/cf_main.cpp @@ -115,7 +115,7 @@ PARAM_INT_IN("recommendations", "Number of recommendations to generate for each" PARAM_INT_IN("seed", "Set the random seed (0 uses std::time(NULL)).", "s", 0); -void ComputeRecommendations(CF& cf, +void ComputeRecommendations(CF* cf, const size_t numRecs, arma::Mat& recommendations) { @@ -132,16 +132,16 @@ void ComputeRecommendations(CF& cf, Log::Info << "Generating recommendations for " << users.n_elem << " users." << endl; - cf.GetRecommendations(numRecs, recommendations, users.row(0).t()); + cf->GetRecommendations(numRecs, recommendations, users.row(0).t()); } else { Log::Info << "Generating recommendations for all users." << endl; - cf.GetRecommendations(numRecs, recommendations); + cf->GetRecommendations(numRecs, recommendations); } } -void ComputeRMSE(CF& cf) +void ComputeRMSE(CF* cf) { // Now, compute each test point. arma::mat testData = std::move(CLI::GetParam("test")); @@ -156,7 +156,7 @@ void ComputeRMSE(CF& cf) // Now compute the RMSE. arma::vec predictions; - cf.Predict(combinations, predictions); + cf->Predict(combinations, predictions); // Compute the root of the sum of the squared errors, divide by the number of // points to get the RMSE. It turns out this is just the L2-norm divided by @@ -168,7 +168,7 @@ void ComputeRMSE(CF& cf) Log::Info << "RMSE is " << rmse << "." << endl; } -void PerformAction(CF& c) +void PerformAction(CF* c) { if (CLI::HasParam("query") || CLI::HasParam("all_user_recommendations")) { @@ -180,15 +180,13 @@ void PerformAction(CF& c) ComputeRecommendations(c, numRecs, recommendations); // Save the output. - if (CLI::HasParam("output")) - CLI::GetParam>("output") = recommendations; + CLI::GetParam>("output") = recommendations; } if (CLI::HasParam("test")) ComputeRMSE(c); - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(c); + CLI::GetParam("output_model") = c; } template @@ -198,7 +196,7 @@ void PerformAction(Factorizer&& factorizer, { // Parameters for generating the CF object. const size_t neighborhood = (size_t) CLI::GetParam("neighborhood"); - CF c(dataset, factorizer, neighborhood, rank); + CF* c = new CF(dataset, factorizer, neighborhood, rank); PerformAction(c); } @@ -323,7 +321,7 @@ static void mlpackMain() else { // Load an input model. - CF c = std::move(CLI::GetParam("input_model")); + CF* c = std::move(CLI::GetParam("input_model")); PerformAction(c); } diff --git a/src/mlpack/methods/decision_stump/decision_stump_main.cpp b/src/mlpack/methods/decision_stump/decision_stump_main.cpp index 2bfe230043..aa4d9a67d8 100644 --- a/src/mlpack/methods/decision_stump/decision_stump_main.cpp +++ b/src/mlpack/methods/decision_stump/decision_stump_main.cpp @@ -116,9 +116,10 @@ static void mlpackMain() ReportIgnoredParam({{ "test", false }}, "predictions"); // We must either load a model, or train a new stump. - DSModel model; + DSModel* model; if (CLI::HasParam("training")) { + model = new DSModel(); mat trainingData = std::move(CLI::GetParam("training")); // Load labels, if necessary. @@ -140,18 +141,18 @@ static void mlpackMain() // Normalize the labels. Row labels; - data::NormalizeLabels(labelsIn, labels, model.mappings); + data::NormalizeLabels(labelsIn, labels, model->mappings); const size_t bucketSize = CLI::GetParam("bucket_size"); const size_t classes = labels.max() + 1; Timer::Start("training"); - model.stump.Train(trainingData, labels, classes, bucketSize); + model->stump.Train(trainingData, labels, classes, bucketSize); Timer::Stop("training"); } else { - model = std::move(CLI::GetParam("input_model")); + model = CLI::GetParam("input_model"); } // Now, do we need to do any testing? @@ -160,21 +161,21 @@ static void mlpackMain() // Load the test file. mat testingData = std::move(CLI::GetParam("test")); - if (testingData.n_rows <= model.stump.SplitDimension()) + if (testingData.n_rows <= model->stump.SplitDimension()) Log::Fatal << "Test data dimensionality (" << testingData.n_rows << ") " << "is too low; the trained stump requires at least " - << model.stump.SplitDimension() << " dimensions!" << endl; + << model->stump.SplitDimension() << " dimensions!" << endl; Row predictedLabels(testingData.n_cols); Timer::Start("testing"); - model.stump.Classify(testingData, predictedLabels); + model->stump.Classify(testingData, predictedLabels); Timer::Stop("testing"); // Denormalize predicted labels, if we want to save them. if (CLI::HasParam("predictions")) { Row actualLabels; - data::RevertLabels(predictedLabels, model.mappings, actualLabels); + data::RevertLabels(predictedLabels, model->mappings, actualLabels); // Save the predicted labels as output. CLI::GetParam>("predictions") = std::move(actualLabels); @@ -182,6 +183,5 @@ static void mlpackMain() } // Save the model, if desired. - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(model); + CLI::GetParam("output_model") = model; } diff --git a/src/mlpack/methods/decision_tree/decision_tree_main.cpp b/src/mlpack/methods/decision_tree/decision_tree_main.cpp index e86f34042e..e4ee8fcedc 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_main.cpp +++ b/src/mlpack/methods/decision_tree/decision_tree_main.cpp @@ -137,13 +137,14 @@ static void mlpackMain() "leaf size must be positive"); // Load the model or build the tree. - DecisionTreeModel model; + DecisionTreeModel* model; arma::mat trainingSet; arma::Row labels; if (CLI::HasParam("training")) { - model.info = std::move(std::get<0>(CLI::GetParam("training"))); + model = new DecisionTreeModel(); + model->info = std::move(std::get<0>(CLI::GetParam("training"))); trainingSet = std::move(std::get<1>(CLI::GetParam("training"))); if (CLI::HasParam("labels")) { @@ -169,12 +170,12 @@ static void mlpackMain() { arma::Row weights = std::move(CLI::GetParam>("weights")); - model.tree = DecisionTree<>(trainingSet, model.info, labels, + model->tree = DecisionTree<>(trainingSet, model->info, labels, numClasses, weights, minLeafSize); } else { - model.tree = DecisionTree<>(trainingSet, model.info, labels, + model->tree = DecisionTree<>(trainingSet, model->info, labels, numClasses, minLeafSize); } @@ -184,7 +185,7 @@ static void mlpackMain() arma::Row predictions; arma::mat probabilities; - model.tree.Classify(trainingSet, predictions, probabilities); + model->tree.Classify(trainingSet, predictions, probabilities); size_t correct = 0; for (size_t i = 0; i < trainingSet.n_cols; ++i) @@ -199,19 +200,19 @@ static void mlpackMain() } else { - model = std::move(CLI::GetParam("input_model")); + model = CLI::GetParam("input_model"); } // Do we need to get predictions? if (CLI::HasParam("test")) { - std::get<0>(CLI::GetRawParam("test")) = model.info; + std::get<0>(CLI::GetRawParam("test")) = model->info; arma::mat testPoints = std::get<1>(CLI::GetParam("test")); arma::Row predictions; arma::mat probabilities; - model.tree.Classify(testPoints, predictions, probabilities); + model->tree.Classify(testPoints, predictions, probabilities); // Do we need to calculate accuracy? if (CLI::HasParam("test_labels")) @@ -231,13 +232,10 @@ static void mlpackMain() } // Do we need to save outputs? - if (CLI::HasParam("predictions")) - CLI::GetParam>("predictions") = std::move(predictions); - if (CLI::HasParam("probabilities")) - CLI::GetParam("probabilities") = std::move(probabilities); + CLI::GetParam>("predictions") = predictions; + CLI::GetParam("probabilities") = probabilities; } // Do we need to save the model? - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(model); + CLI::GetParam("output_model") = model; } diff --git a/src/mlpack/methods/det/det_main.cpp b/src/mlpack/methods/det/det_main.cpp index 29ecd56c99..a9cb4ec47c 100644 --- a/src/mlpack/methods/det/det_main.cpp +++ b/src/mlpack/methods/det/det_main.cpp @@ -168,7 +168,7 @@ static void mlpackMain() } else { - tree = &CLI::GetParam>("input_model"); + tree = CLI::GetParam*>("input_model"); } // Compute the density at the provided test points and output the density in @@ -213,8 +213,7 @@ static void mlpackMain() if (!ofs.is_open()) { Log::Warn << "Unable to open file '" << tagFile - << "' to save tag membership info." - << std::endl; + << "' to save tag membership info." << std::endl; } else if (CLI::HasParam("path_format")) { @@ -231,7 +230,7 @@ static void mlpackMain() else { Log::Warn << "Unknown path format specified: '" << pathFormat - << "'. Valid are: lr | lr-id | id-lr. Defaults to 'lr'." << endl; + << "'. Valid are: lr | lr-id | id-lr. Defaults to 'lr'." << endl; theFormat = PathCacher::FormatLR; } @@ -284,10 +283,5 @@ static void mlpackMain() } // Save the model, if desired. - if (CLI::HasParam("output_model")) - CLI::GetParam>("output_model") = std::move(*tree); - - // Clean up memory, if we need to. - if (!CLI::HasParam("input_model") && !CLI::HasParam("output_model")) - delete tree; + CLI::GetParam*>("output_model") = tree; } diff --git a/src/mlpack/methods/fastmks/fastmks_main.cpp b/src/mlpack/methods/fastmks/fastmks_main.cpp index f3b7333ebe..1d8e7e7fb6 100644 --- a/src/mlpack/methods/fastmks/fastmks_main.cpp +++ b/src/mlpack/methods/fastmks/fastmks_main.cpp @@ -111,10 +111,11 @@ static void mlpackMain() // Naive mode overrides single mode. ReportIgnoredParam({{ "naive", true }}, "single"); - FastMKSModel model; + FastMKSModel* model; arma::mat referenceData; if (CLI::HasParam("reference")) { + model = new FastMKSModel(); referenceData = std::move(CLI::GetParam("reference")); Log::Info << "Loaded reference data (" << referenceData.n_rows << " x " @@ -137,55 +138,55 @@ static void mlpackMain() if (kernelType == "linear") { LinearKernel lk; - model.KernelType() = FastMKSModel::LINEAR_KERNEL; - model.BuildModel(referenceData, lk, single, naive, base); + model->KernelType() = FastMKSModel::LINEAR_KERNEL; + model->BuildModel(referenceData, lk, single, naive, base); } else if (kernelType == "polynomial") { PolynomialKernel pk(degree, offset); - model.KernelType() = FastMKSModel::POLYNOMIAL_KERNEL; - model.BuildModel(referenceData, pk, single, naive, base); + model->KernelType() = FastMKSModel::POLYNOMIAL_KERNEL; + model->BuildModel(referenceData, pk, single, naive, base); } else if (kernelType == "cosine") { CosineDistance cd; - model.KernelType() = FastMKSModel::COSINE_DISTANCE; - model.BuildModel(referenceData, cd, single, naive, base); + model->KernelType() = FastMKSModel::COSINE_DISTANCE; + model->BuildModel(referenceData, cd, single, naive, base); } else if (kernelType == "gaussian") { GaussianKernel gk(bandwidth); - model.KernelType() = FastMKSModel::GAUSSIAN_KERNEL; - model.BuildModel(referenceData, gk, single, naive, base); + model->KernelType() = FastMKSModel::GAUSSIAN_KERNEL; + model->BuildModel(referenceData, gk, single, naive, base); } else if (kernelType == "epanechnikov") { EpanechnikovKernel ek(bandwidth); - model.KernelType() = FastMKSModel::EPANECHNIKOV_KERNEL; - model.BuildModel(referenceData, ek, single, naive, base); + model->KernelType() = FastMKSModel::EPANECHNIKOV_KERNEL; + model->BuildModel(referenceData, ek, single, naive, base); } else if (kernelType == "triangular") { TriangularKernel tk(bandwidth); - model.KernelType() = FastMKSModel::TRIANGULAR_KERNEL; - model.BuildModel(referenceData, tk, single, naive, base); + model->KernelType() = FastMKSModel::TRIANGULAR_KERNEL; + model->BuildModel(referenceData, tk, single, naive, base); } else if (kernelType == "hyptan") { HyperbolicTangentKernel htk(scale, offset); - model.KernelType() = FastMKSModel::HYPTAN_KERNEL; - model.BuildModel(referenceData, htk, single, naive, base); + model->KernelType() = FastMKSModel::HYPTAN_KERNEL; + model->BuildModel(referenceData, htk, single, naive, base); } } else { // Load model from file, then do whatever is necessary. - model = std::move(CLI::GetParam("input_model")); + model = CLI::GetParam("input_model"); } // Set search preferences. - model.Naive() = CLI::HasParam("naive"); - model.SingleMode() = CLI::HasParam("single"); + model->Naive() = CLI::HasParam("naive"); + model->SingleMode() = CLI::HasParam("single"); // Should we do search? if (CLI::HasParam("k")) @@ -202,23 +203,19 @@ static void mlpackMain() Log::Info << "Loaded query data (" << queryData.n_rows << " x " << queryData.n_cols << ")." << endl; - model.Search(queryData, (size_t) CLI::GetParam("k"), indices, + model->Search(queryData, (size_t) CLI::GetParam("k"), indices, kernels, base); } else { - model.Search((size_t) CLI::GetParam("k"), indices, kernels); + model->Search((size_t) CLI::GetParam("k"), indices, kernels); } - // Save output, if we were asked to. - if (CLI::HasParam("kernels")) - CLI::GetParam("kernels") = std::move(kernels); - - if (CLI::HasParam("indices")) - CLI::GetParam>("indices") = std::move(indices); + // Save output. + CLI::GetParam("kernels") = std::move(kernels); + CLI::GetParam>("indices") = std::move(indices); } - // Save the model, if requested. - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(model); + // Save the model. + CLI::GetParam("output_model") = model; } diff --git a/src/mlpack/methods/gmm/gmm_generate_main.cpp b/src/mlpack/methods/gmm/gmm_generate_main.cpp index a6ed7d6ba4..7842349414 100644 --- a/src/mlpack/methods/gmm/gmm_generate_main.cpp +++ b/src/mlpack/methods/gmm/gmm_generate_main.cpp @@ -55,15 +55,14 @@ static void mlpackMain() RequireParamValue("samples", [](int x) { return x > 0; }, true, "number of samples must be greater than 0"); - GMM gmm = std::move(CLI::GetParam("input_model")); + GMM* gmm = CLI::GetParam("input_model"); size_t length = (size_t) CLI::GetParam("samples"); Log::Info << "Generating " << length << " samples..." << endl; - arma::mat samples(gmm.Dimensionality(), length); + arma::mat samples(gmm->Dimensionality(), length); for (size_t i = 0; i < length; ++i) - samples.col(i) = gmm.Random(); + samples.col(i) = gmm->Random(); // Save, if the user asked for it. - if (CLI::HasParam("output")) - CLI::GetParam("output") = std::move(samples); + CLI::GetParam("output") = std::move(samples); } diff --git a/src/mlpack/methods/gmm/gmm_probability_main.cpp b/src/mlpack/methods/gmm/gmm_probability_main.cpp index ac1669aaac..f40c866284 100644 --- a/src/mlpack/methods/gmm/gmm_probability_main.cpp +++ b/src/mlpack/methods/gmm/gmm_probability_main.cpp @@ -46,16 +46,15 @@ static void mlpackMain() RequireAtLeastOnePassed({ "output" }, false, "no results will be saved"); // Get the GMM and the points. - GMM gmm = std::move(CLI::GetParam("input_model")); + GMM* gmm = CLI::GetParam("input_model"); arma::mat dataset = std::move(CLI::GetParam("input")); // Now calculate the probabilities. arma::rowvec probabilities(dataset.n_cols); for (size_t i = 0; i < dataset.n_cols; ++i) - probabilities[i] = gmm.Probability(dataset.unsafe_col(i)); + probabilities[i] = gmm->Probability(dataset.unsafe_col(i)); // And save the result. - if (CLI::HasParam("output")) - CLI::GetParam("output") = std::move(probabilities); + CLI::GetParam("output") = std::move(probabilities); } diff --git a/src/mlpack/methods/gmm/gmm_train_main.cpp b/src/mlpack/methods/gmm/gmm_train_main.cpp index 82694fb17c..c331d04dc0 100644 --- a/src/mlpack/methods/gmm/gmm_train_main.cpp +++ b/src/mlpack/methods/gmm/gmm_train_main.cpp @@ -153,17 +153,21 @@ static void mlpackMain() } // Initialize GMM. - GMM gmm(size_t(gaussians), dataPoints.n_rows); + GMM* gmm; if (CLI::HasParam("input_model")) { - gmm = std::move(CLI::GetParam("input_model")); + gmm = CLI::GetParam("input_model"); - if (gmm.Dimensionality() != dataPoints.n_rows) + if (gmm->Dimensionality() != dataPoints.n_rows) Log::Fatal << "Given input data (with " << PRINT_PARAM_STRING("input") << ") has dimensionality " << dataPoints.n_rows << ", but the initial" << " model (given with " << PRINT_PARAM_STRING("input_model") - << " has dimensionality " << gmm.Dimensionality() << "!" << endl; + << " has dimensionality " << gmm->Dimensionality() << "!" << endl; + } + else + { + gmm = new GMM(size_t(gaussians), dataPoints.n_rows); } // Gather parameters for EMFit object. @@ -199,7 +203,7 @@ static void mlpackMain() // Compute the parameters of the model using the EM algorithm. Timer::Start("em"); EMFit em(maxIterations, tolerance, k); - likelihood = gmm.Train(dataPoints, CLI::GetParam("trials"), false, + likelihood = gmm->Train(dataPoints, CLI::GetParam("trials"), false, em); Timer::Stop("em"); } @@ -208,7 +212,7 @@ static void mlpackMain() // Compute the parameters of the model using the EM algorithm. Timer::Start("em"); EMFit em(maxIterations, tolerance, k); - likelihood = gmm.Train(dataPoints, CLI::GetParam("trials"), false, + likelihood = gmm->Train(dataPoints, CLI::GetParam("trials"), false, em); Timer::Stop("em"); } @@ -217,7 +221,7 @@ static void mlpackMain() // Compute the parameters of the model using the EM algorithm. Timer::Start("em"); EMFit em(maxIterations, tolerance, k); - likelihood = gmm.Train(dataPoints, CLI::GetParam("trials"), false, + likelihood = gmm->Train(dataPoints, CLI::GetParam("trials"), false, em); Timer::Stop("em"); } @@ -231,7 +235,7 @@ static void mlpackMain() // Compute the parameters of the model using the EM algorithm. Timer::Start("em"); EMFit, DiagonalConstraint> em(maxIterations, tolerance); - likelihood = gmm.Train(dataPoints, CLI::GetParam("trials"), false, + likelihood = gmm->Train(dataPoints, CLI::GetParam("trials"), false, em); Timer::Stop("em"); } @@ -240,7 +244,7 @@ static void mlpackMain() // Compute the parameters of the model using the EM algorithm. Timer::Start("em"); EMFit<> em(maxIterations, tolerance); - likelihood = gmm.Train(dataPoints, CLI::GetParam("trials"), false, + likelihood = gmm->Train(dataPoints, CLI::GetParam("trials"), false, em); Timer::Stop("em"); } @@ -249,7 +253,7 @@ static void mlpackMain() // Compute the parameters of the model using the EM algorithm. Timer::Start("em"); EMFit, NoConstraint> em(maxIterations, tolerance); - likelihood = gmm.Train(dataPoints, CLI::GetParam("trials"), false, + likelihood = gmm->Train(dataPoints, CLI::GetParam("trials"), false, em); Timer::Stop("em"); } @@ -257,6 +261,5 @@ static void mlpackMain() Log::Info << "Log-likelihood of estimate: " << likelihood << "." << endl; - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(gmm); + CLI::GetParam("output_model") = gmm; } diff --git a/src/mlpack/methods/hmm/hmm_loglik_main.cpp b/src/mlpack/methods/hmm/hmm_loglik_main.cpp index 1a3d51a8cf..6ebb3cbef1 100644 --- a/src/mlpack/methods/hmm/hmm_loglik_main.cpp +++ b/src/mlpack/methods/hmm/hmm_loglik_main.cpp @@ -79,5 +79,5 @@ struct Loglik static void mlpackMain() { // Load model, and calculate the log-likelihood of the sequence. - CLI::GetParam("input_model").PerformAction((void*) NULL); + CLI::GetParam("input_model")->PerformAction((void*) NULL); } diff --git a/src/mlpack/methods/hmm/hmm_train_main.cpp b/src/mlpack/methods/hmm/hmm_train_main.cpp index 2983c2528b..06cf01db0e 100644 --- a/src/mlpack/methods/hmm/hmm_train_main.cpp +++ b/src/mlpack/methods/hmm/hmm_train_main.cpp @@ -436,21 +436,21 @@ static void mlpackMain() typeId = HMMType::GaussianMixtureModelHMM; // If we have a model file, we can autodetect the type. - HMMModel hmm(typeId); + HMMModel* hmm; if (CLI::HasParam("input_model")) { - hmm = std::move(CLI::GetParam("input_model")); + hmm = CLI::GetParam("input_model"); } else { // We need to initialize the model. - hmm.PerformAction>(&trainSeq); + hmm = new HMMModel(typeId); + hmm->PerformAction>(&trainSeq); } // Train the model. - hmm.PerformAction>(&trainSeq); + hmm->PerformAction>(&trainSeq); // If necessary, save the output. - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(hmm); + CLI::GetParam("output_model") = hmm; } diff --git a/src/mlpack/methods/hmm/hmm_viterbi_main.cpp b/src/mlpack/methods/hmm/hmm_viterbi_main.cpp index 323bc066cc..d0e1168b3d 100644 --- a/src/mlpack/methods/hmm/hmm_viterbi_main.cpp +++ b/src/mlpack/methods/hmm/hmm_viterbi_main.cpp @@ -77,8 +77,7 @@ struct Viterbi hmm.Predict(dataSeq, sequence); // Save output. - if (CLI::HasParam("output")) - CLI::GetParam>("output") = std::move(sequence); + CLI::GetParam>("output") = std::move(sequence); } }; @@ -86,5 +85,5 @@ static void mlpackMain() { RequireAtLeastOnePassed({ "output" }, false, "no results will be saved"); - CLI::GetParam("input_model").PerformAction((void*) NULL); + CLI::GetParam("input_model")->PerformAction((void*) NULL); } diff --git a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_main.cpp b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_main.cpp index 73012a6265..2c4576337b 100644 --- a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_main.cpp +++ b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_main.cpp @@ -140,25 +140,25 @@ static void mlpackMain() true, "unrecognized numeric split strategy"); // Do we need to load a model or do we already have one? - HoeffdingTreeModel model; + HoeffdingTreeModel* model; DatasetInfo datasetInfo; arma::mat trainingSet; arma::Row labels; if (CLI::HasParam("input_model")) { - model = std::move(CLI::GetParam("input_model")); + model = CLI::GetParam("input_model"); } else { // Initialize a model. if (!CLI::HasParam("info_gain") && (numericSplitStrategy == "domingos")) - model = HoeffdingTreeModel(HoeffdingTreeModel::GINI_HOEFFDING); + model = new HoeffdingTreeModel(HoeffdingTreeModel::GINI_HOEFFDING); else if (!CLI::HasParam("info_gain") && (numericSplitStrategy == "binary")) - model = HoeffdingTreeModel(HoeffdingTreeModel::GINI_BINARY); + model = new HoeffdingTreeModel(HoeffdingTreeModel::GINI_BINARY); else if (CLI::HasParam("info_gain") && (numericSplitStrategy == "domingos")) - model = HoeffdingTreeModel(HoeffdingTreeModel::INFO_HOEFFDING); + model = new HoeffdingTreeModel(HoeffdingTreeModel::INFO_HOEFFDING); else if (CLI::HasParam("info_gain") && (numericSplitStrategy == "binary")) - model = HoeffdingTreeModel(HoeffdingTreeModel::INFO_BINARY); + model = new HoeffdingTreeModel(HoeffdingTreeModel::INFO_BINARY); } // Now, do we need to train? @@ -207,7 +207,7 @@ static void mlpackMain() if (!CLI::HasParam("input_model")) { // Build the model. - model.BuildModel(trainingSet, datasetInfo, labels, + model->BuildModel(trainingSet, datasetInfo, labels, arma::max(labels) + 1, batchTraining, confidence, maxSamples, 100, minSamples, bins, observationsBeforeBinning); --passes; // This model-building takes one pass. @@ -219,12 +219,12 @@ static void mlpackMain() // We only need to do batch training if we've not already called // BuildModel. if (CLI::HasParam("input_model")) - model.Train(trainingSet, labels, true); + model->Train(trainingSet, labels, true); } else { for (size_t p = 0; p < passes; ++p) - model.Train(trainingSet, labels, false); + model->Train(trainingSet, labels, false); } Timer::Stop("tree_training"); @@ -235,7 +235,7 @@ static void mlpackMain() { // Get training error. arma::Row predictions; - model.Classify(trainingSet, predictions); + model->Classify(trainingSet, predictions); size_t correct = 0; for (size_t i = 0; i < labels.n_elem; ++i) @@ -248,7 +248,7 @@ static void mlpackMain() } // Get the number of nodes in the tree. - Log::Info << model.NumNodes() << " nodes in the tree." << endl; + Log::Info << model->NumNodes() << " nodes in the tree." << endl; // The tree is trained or loaded. Now do any testing if we need. if (CLI::HasParam("test")) @@ -262,7 +262,7 @@ static void mlpackMain() arma::rowvec probabilities; Timer::Start("tree_testing"); - model.Classify(testSet, predictions, probabilities); + model->Classify(testSet, predictions, probabilities); Timer::Stop("tree_testing"); if (CLI::HasParam("test_labels")) @@ -281,14 +281,10 @@ static void mlpackMain() 100.0 << ")." << endl; } - if (CLI::HasParam("predictions")) - CLI::GetParam>("predictions") = std::move(predictions); - - if (CLI::HasParam("probabilities")) - CLI::GetParam("probabilities") = std::move(probabilities); + CLI::GetParam>("predictions") = std::move(predictions); + CLI::GetParam("probabilities") = std::move(probabilities); } // Check the accuracy on the training set. - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(model); + CLI::GetParam("output_model") = model; } diff --git a/src/mlpack/methods/lars/lars_main.cpp b/src/mlpack/methods/lars/lars_main.cpp index 0c6d1a28e5..040c5f0c3e 100644 --- a/src/mlpack/methods/lars/lars_main.cpp +++ b/src/mlpack/methods/lars/lars_main.cpp @@ -120,11 +120,12 @@ static void mlpackMain() "no results will be saved"); ReportIgnoredParam({{ "test", true }}, "output_predictions"); - // Initialize the object. - LARS lars(useCholesky, lambda1, lambda2); - + LARS* lars; if (CLI::HasParam("input")) { + // Initialize the object. + lars = new LARS(useCholesky, lambda1, lambda2); + // Load covariates. We can avoid LARS transposing our data by choosing to // not transpose this data (that's why we used PARAM_TMATRIX_IN). mat matX = std::move(CLI::GetParam("input")); @@ -146,11 +147,11 @@ static void mlpackMain() vec beta; arma::rowvec y = std::move(matY); - lars.Train(matX, y, beta, false /* do not transpose */); + lars->Train(matX, y, beta, false /* do not transpose */); } else // We must have --input_model_file. { - lars = std::move(CLI::GetParam("input_model")); + lars = CLI::GetParam("input_model"); } if (CLI::HasParam("test")) @@ -162,19 +163,17 @@ static void mlpackMain() // Make sure the dimensionality is right. We haven't transposed, so, we // check n_cols not n_rows. - if (testPoints.n_cols != lars.BetaPath().back().n_elem) + if (testPoints.n_cols != lars->BetaPath().back().n_elem) Log::Fatal << "Dimensionality of test set (" << testPoints.n_cols << ") " << "is not equal to the dimensionality of the model (" - << lars.BetaPath().back().n_elem << ")!" << endl; + << lars->BetaPath().back().n_elem << ")!" << endl; arma::rowvec predictions; - lars.Predict(testPoints.t(), predictions, false); + lars->Predict(testPoints.t(), predictions, false); // Save test predictions (one per line). - if (CLI::HasParam("output_predictions")) - CLI::GetParam("output_predictions") = predictions.t(); + CLI::GetParam("output_predictions") = predictions.t(); } - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(lars); + CLI::GetParam("output_model") = lars; } diff --git a/src/mlpack/methods/linear_regression/linear_regression_main.cpp b/src/mlpack/methods/linear_regression/linear_regression_main.cpp index 19c418151c..d98a385f9c 100644 --- a/src/mlpack/methods/linear_regression/linear_regression_main.cpp +++ b/src/mlpack/methods/linear_regression/linear_regression_main.cpp @@ -96,7 +96,7 @@ static void mlpackMain() mat regressors; rowvec responses; - LinearRegression lr; + LinearRegression* lr; const bool computeModel = !CLI::HasParam("input_model"); const bool computePrediction = CLI::HasParam("test"); @@ -148,14 +148,14 @@ static void mlpackMain() } Timer::Start("regression"); - lr = LinearRegression(regressors, responses, lambda); + lr = new LinearRegression(regressors, responses, lambda); Timer::Stop("regression"); } else { // A model file was passed in, so load it. Timer::Start("load_model"); - lr = std::move(CLI::GetParam("input_model")); + lr = CLI::GetParam("input_model"); Timer::Stop("load_model"); } @@ -168,9 +168,9 @@ static void mlpackMain() Timer::Stop("load_test_points"); // Ensure that test file data has the right number of features. - if ((lr.Parameters().n_elem - 1) != points.n_rows) + if ((lr->Parameters().n_elem - 1) != points.n_rows) { - Log::Fatal << "The model was trained on " << lr.Parameters().n_elem - 1 + Log::Fatal << "The model was trained on " << lr->Parameters().n_elem - 1 << "-dimensional data, but the test points in '" << CLI::GetPrintableParam("test") << "' are " << points.n_rows << "-dimensional!" << endl; @@ -179,15 +179,13 @@ static void mlpackMain() // Perform the predictions using our model. rowvec predictions; Timer::Start("prediction"); - lr.Predict(points, predictions); + lr->Predict(points, predictions); Timer::Stop("prediction"); // Save predictions. - if (CLI::HasParam("output_predictions")) - CLI::GetParam("output_predictions") = std::move(predictions); + CLI::GetParam("output_predictions") = std::move(predictions); } // Save the model if needed. - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(lr); + CLI::GetParam("output_model") = lr; } diff --git a/src/mlpack/methods/local_coordinate_coding/local_coordinate_coding_main.cpp b/src/mlpack/methods/local_coordinate_coding/local_coordinate_coding_main.cpp index cdfc34c258..f0ee7e6dc5 100644 --- a/src/mlpack/methods/local_coordinate_coding/local_coordinate_coding_main.cpp +++ b/src/mlpack/methods/local_coordinate_coding/local_coordinate_coding_main.cpp @@ -120,9 +120,11 @@ static void mlpackMain() ReportIgnoredParam({{ "training", false }}, "tolerance"); // Do we have an existing model? - LocalCoordinateCoding lcc(0, 0.0); + LocalCoordinateCoding* lcc; if (CLI::HasParam("input_model")) - lcc = std::move(CLI::GetParam("input_model")); + lcc = CLI::GetParam("input_model"); + else + lcc = new LocalCoordinateCoding(0, 0.0); if (CLI::HasParam("training")) { @@ -136,10 +138,10 @@ static void mlpackMain() matX.col(i) /= norm(matX.col(i), 2); } - lcc.Lambda() = CLI::GetParam("lambda"); - lcc.Atoms() = (size_t) CLI::GetParam("atoms"); - lcc.MaxIterations() = (size_t) CLI::GetParam("max_iterations"); - lcc.Tolerance() = CLI::GetParam("tolerance"); + lcc->Lambda() = CLI::GetParam("lambda"); + lcc->Atoms() = (size_t) CLI::GetParam("atoms"); + lcc->MaxIterations() = (size_t) CLI::GetParam("max_iterations"); + lcc->Tolerance() = CLI::GetParam("tolerance"); // Inform the user if we are overwriting their model. if (CLI::HasParam("input_model")) @@ -147,35 +149,35 @@ static void mlpackMain() Log::Info << "Using dictionary from existing model in '" << CLI::GetPrintableParam("input_model") << "' as initial " << "dictionary for training." << endl; - lcc.Train(matX); + lcc->Train(matX); } else if (CLI::HasParam("initial_dictionary")) { // Load initial dictionary directly into LCC object. - lcc.Dictionary() = std::move(CLI::GetParam("initial_dictionary")); + lcc->Dictionary() = std::move(CLI::GetParam("initial_dictionary")); // Validate the size of the initial dictionary. - if (lcc.Dictionary().n_cols != lcc.Atoms()) + if (lcc->Dictionary().n_cols != lcc->Atoms()) { - Log::Fatal << "The initial dictionary has " << lcc.Dictionary().n_cols + Log::Fatal << "The initial dictionary has " << lcc->Dictionary().n_cols << " atoms, but the number of atoms was specified to be " - << lcc.Atoms() << "!" << endl; + << lcc->Atoms() << "!" << endl; } - if (lcc.Dictionary().n_rows != matX.n_rows) + if (lcc->Dictionary().n_rows != matX.n_rows) { - Log::Fatal << "The initial dictionary has " << lcc.Dictionary().n_rows + Log::Fatal << "The initial dictionary has " << lcc->Dictionary().n_rows << " dimensions, but the data has " << matX.n_rows << " dimensions!" << endl; } // Train the model. - lcc.Train(matX); + lcc->Train(matX); } else { // Run with the default initialization. - lcc.Train(matX); + lcc->Train(matX); } } @@ -184,9 +186,9 @@ static void mlpackMain() { mat matY = std::move(CLI::GetParam("test")); - if (matY.n_rows != lcc.Dictionary().n_rows) + if (matY.n_rows != lcc->Dictionary().n_rows) Log::Fatal << "Model was trained with a dimensionality of " - << lcc.Dictionary().n_rows << ", but data in test file " + << lcc->Dictionary().n_rows << ", but data in test file " << CLI::GetPrintableParam("test") << " has a dimensionality of " << matY.n_rows << "!" << endl; @@ -199,17 +201,12 @@ static void mlpackMain() } mat codes; - lcc.Encode(matY, codes); + lcc->Encode(matY, codes); - if (CLI::HasParam("codes")) - CLI::GetParam("codes") = std::move(codes); + CLI::GetParam("codes") = std::move(codes); } - // Did the user want to save the dictionary? - if (CLI::HasParam("dictionary")) - CLI::GetParam("dictionary") = std::move(lcc.Dictionary()); - - // Did the user want to save the model? - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(lcc); + // Save the dictionary and the model. + CLI::GetParam("dictionary") = lcc->Dictionary(); + CLI::GetParam("output_model") = lcc; } diff --git a/src/mlpack/methods/logistic_regression/logistic_regression_main.cpp b/src/mlpack/methods/logistic_regression/logistic_regression_main.cpp index 02a12022e3..0720dd028e 100644 --- a/src/mlpack/methods/logistic_regression/logistic_regression_main.cpp +++ b/src/mlpack/methods/logistic_regression/logistic_regression_main.cpp @@ -206,16 +206,18 @@ static void mlpackMain() regressors = std::move(CLI::GetParam("training")); // Load the model, if necessary. - LogisticRegression<> model(0, 0); // Empty model. + LogisticRegression<>* model; if (CLI::HasParam("input_model")) - model = std::move(CLI::GetParam>("input_model")); + model = CLI::GetParam*>("input_model"); else { + model = new LogisticRegression<>(0, 0); + // Set the size of the parameters vector, if necessary. if (!CLI::HasParam("labels")) - model.Parameters() = arma::zeros(regressors.n_rows); + model->Parameters() = arma::zeros(regressors.n_rows); else - model.Parameters() = arma::zeros(regressors.n_rows + 1); + model->Parameters() = arma::zeros(regressors.n_rows + 1); } // Check if the responses are in a separate file. @@ -242,7 +244,7 @@ static void mlpackMain() // Now, do the training. if (CLI::HasParam("training")) { - model.Lambda() = lambda; + model->Lambda() = lambda; if (optimizerType == "sgd") { @@ -254,7 +256,7 @@ static void mlpackMain() Log::Info << "Training model with SGD optimizer." << endl; // This will train the model. - model.Train(regressors, responses, sgdOpt); + model->Train(regressors, responses, sgdOpt); } else if (optimizerType == "lbfgs") { @@ -264,7 +266,7 @@ static void mlpackMain() Log::Info << "Training model with L-BFGS optimizer." << endl; // This will train the model. - model.Train(regressors, responses, lbfgsOpt); + model->Train(regressors, responses, lbfgsOpt); } } @@ -278,7 +280,7 @@ static void mlpackMain() { Log::Info << "Predicting classes of points in '" << CLI::GetPrintableParam("test") << "'." << endl; - model.Classify(testSet, predictions, decisionBoundary); + model->Classify(testSet, predictions, decisionBoundary); CLI::GetParam>("output") = std::move(predictions); } @@ -288,13 +290,12 @@ static void mlpackMain() Log::Info << "Calculating class probabilities of points in '" << CLI::GetPrintableParam("test") << "'." << endl; arma::mat probabilities; - model.Classify(testSet, probabilities); + model->Classify(testSet, probabilities); CLI::GetParam("output_probabilities") = std::move(probabilities); } } - if (CLI::HasParam("output_model")) - CLI::GetParam>("output_model") = std::move(model); + CLI::GetParam*>("output_model") = model; } diff --git a/src/mlpack/methods/lsh/lsh_main.cpp b/src/mlpack/methods/lsh/lsh_main.cpp index f9ce2de8b5..eec2049daa 100644 --- a/src/mlpack/methods/lsh/lsh_main.cpp +++ b/src/mlpack/methods/lsh/lsh_main.cpp @@ -154,9 +154,10 @@ static void mlpackMain() Log::Info << "Using LSH with " << numProj << " projections (K) and " << numTables << " tables (L) with hash width(r): " << hashWidth << endl; - LSHSearch<> allkann; + LSHSearch<>* allkann; if (CLI::HasParam("reference")) { + allkann = new LSHSearch<>(); referenceData = std::move(CLI::GetParam("reference")); Log::Info << "Using reference data from '" << CLI::GetPrintableParam("reference") << "' (" @@ -164,13 +165,13 @@ static void mlpackMain() << endl; Timer::Start("hash_building"); - allkann.Train(std::move(referenceData), numProj, numTables, hashWidth, + allkann->Train(std::move(referenceData), numProj, numTables, hashWidth, secondHashSize, bucketSize); Timer::Stop("hash_building"); } else if (CLI::HasParam("input_model")) { - allkann = std::move(CLI::GetParam>("input_model")); + allkann = CLI::GetParam*>("input_model"); } if (CLI::HasParam("k")) @@ -184,11 +185,11 @@ static void mlpackMain() << CLI::GetPrintableParam("query") << "' (" << queryData.n_rows << " x " << queryData.n_cols << ")." << endl; - allkann.Search(queryData, k, neighbors, distances, 0, numProbes); + allkann->Search(queryData, k, neighbors, distances, 0, numProbes); } else { - allkann.Search(k, neighbors, distances, 0, numProbes); + allkann->Search(k, neighbors, distances, 0, numProbes); } Log::Info << "Neighbors computed." << endl; @@ -205,20 +206,17 @@ static void mlpackMain() << endl; // Compute recall and print it. - double recallPercentage = 100 * allkann.ComputeRecall(neighbors, + double recallPercentage = 100 * allkann->ComputeRecall(neighbors, trueNeighbors); Log::Info << "Recall: " << recallPercentage << endl; } - // Save output, if desired. + // Save output, if we did a search.. if (CLI::HasParam("k")) { - if (CLI::HasParam("distances")) - CLI::GetParam("distances") = std::move(distances); - if (CLI::HasParam("neighbors")) - CLI::GetParam>("neighbors") = std::move(neighbors); + CLI::GetParam("distances") = std::move(distances); + CLI::GetParam>("neighbors") = std::move(neighbors); } - if (CLI::HasParam("output_model")) - CLI::GetParam>("output_model") = std::move(allkann); + CLI::GetParam*>("output_model") = allkann; } diff --git a/src/mlpack/methods/naive_bayes/nbc_main.cpp b/src/mlpack/methods/naive_bayes/nbc_main.cpp index 99b76cb7e7..68a4a70e04 100644 --- a/src/mlpack/methods/naive_bayes/nbc_main.cpp +++ b/src/mlpack/methods/naive_bayes/nbc_main.cpp @@ -118,9 +118,10 @@ static void mlpackMain() Log::Warn << "No test set given; no task will be performed!" << std::endl; // Either we have to train a model, or load a model. - NBCModel model; + NBCModel* model; if (CLI::HasParam("training")) { + model = new NBCModel(); mat trainingData = std::move(CLI::GetParam("training")); Row labels; @@ -130,7 +131,7 @@ static void mlpackMain() { // Load labels. Row rawLabels = std::move(CLI::GetParam>("labels")); - data::NormalizeLabels(rawLabels, labels, model.mappings); + data::NormalizeLabels(rawLabels, labels, model->mappings); } else { @@ -138,7 +139,7 @@ static void mlpackMain() Log::Info << "Using last dimension of training data as training labels." << endl; data::NormalizeLabels(trainingData.row(trainingData.n_rows - 1), labels, - model.mappings); + model->mappings); // Remove the label row. trainingData.shed_row(trainingData.n_rows - 1); } @@ -146,14 +147,14 @@ static void mlpackMain() const bool incrementalVariance = CLI::HasParam("incremental_variance"); Timer::Start("nbc_training"); - model.nbc = NaiveBayesClassifier<>(trainingData, labels, - model.mappings.n_elem, incrementalVariance); + model->nbc = NaiveBayesClassifier<>(trainingData, labels, + model->mappings.n_elem, incrementalVariance); Timer::Stop("nbc_training"); } else { // Load the model from file. - model = std::move(CLI::GetParam("input_model")); + model = CLI::GetParam("input_model"); } // Do we need to do testing? @@ -161,10 +162,10 @@ static void mlpackMain() { mat testingData = std::move(CLI::GetParam("test")); - if (testingData.n_rows != model.nbc.Means().n_rows) + if (testingData.n_rows != model->nbc.Means().n_rows) { Log::Fatal << "Test data dimensionality (" << testingData.n_rows << ") " - << "must be the same as training data (" << model.nbc.Means().n_rows + << "must be the same as training data (" << model->nbc.Means().n_rows << ")!" << std::endl; } @@ -172,23 +173,21 @@ static void mlpackMain() Row predictions; mat probabilities; Timer::Start("nbc_testing"); - model.nbc.Classify(testingData, predictions, probabilities); + model->nbc.Classify(testingData, predictions, probabilities); Timer::Stop("nbc_testing"); if (CLI::HasParam("output")) { // Un-normalize labels to prepare output. Row rawResults; - data::RevertLabels(predictions, model.mappings, rawResults); + data::RevertLabels(predictions, model->mappings, rawResults); // Output results. CLI::GetParam>("output") = std::move(rawResults); } - if (CLI::HasParam("output_probs")) - CLI::GetParam("output_probs") = probabilities; + CLI::GetParam("output_probs") = probabilities; } - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(model); + CLI::GetParam("output_model") = model; } diff --git a/src/mlpack/methods/neighbor_search/kfn_main.cpp b/src/mlpack/methods/neighbor_search/kfn_main.cpp index d6a5d3d0d7..7488be23bd 100644 --- a/src/mlpack/methods/neighbor_search/kfn_main.cpp +++ b/src/mlpack/methods/neighbor_search/kfn_main.cpp @@ -157,7 +157,7 @@ static void mlpackMain() epsilon = 1 - percentage; // We either have to load the reference data, or we have to load the model. - NSModel kfn; + NSModel* kfn; const string algorithm = CLI::GetParam("algorithm"); RequireParamInSet("algorithm", { "naive", "single_tree", "dual_tree", @@ -175,6 +175,8 @@ static void mlpackMain() if (CLI::HasParam("reference")) { + kfn = new KFNModel(); + // Get all the parameters. RequireParamInSet("tree_type", { "kd", "cover", "r", "r-star", "ball", "x", "hilbert-r", "r-plus", "r-plus-plus", "vp", "rp", "max-rp", @@ -212,8 +214,8 @@ static void mlpackMain() else if (treeType == "oct") tree = KFNModel::OCTREE; - kfn.TreeType() = tree; - kfn.RandomBasis() = randomBasis; + kfn->TreeType() = tree; + kfn->RandomBasis() = randomBasis; arma::mat referenceSet = std::move(CLI::GetParam("reference")); @@ -221,27 +223,27 @@ static void mlpackMain() << CLI::GetPrintableParam("reference") << "' (" << referenceSet.n_rows << "x" << referenceSet.n_cols << ")." << endl; - kfn.BuildModel(std::move(referenceSet), size_t(lsInt), searchMode, epsilon); + kfn->BuildModel(std::move(referenceSet), size_t(lsInt), searchMode, epsilon); } else { // Load the model from file. - kfn = std::move(CLI::GetParam("input_model")); + kfn = CLI::GetParam("input_model"); // Adjust search mode. - kfn.SearchMode() = searchMode; - kfn.Epsilon() = epsilon; + kfn->SearchMode() = searchMode; + kfn->Epsilon() = epsilon; // If leaf_size wasn't provided, let's consider the current value in the // loaded model. Else, update it (only considered when building the query // tree). if (CLI::HasParam("leaf_size")) - kfn.LeafSize() = size_t(lsInt); + kfn->LeafSize() = size_t(lsInt); Log::Info << "Using kFN model from '" - << CLI::GetPrintableParam("input_model") << "' (trained on " - << kfn.Dataset().n_rows << "x" << kfn.Dataset().n_cols << " dataset)." - << endl; + << CLI::GetPrintableParam("input_model") << "' (trained on " + << kfn->Dataset().n_rows << "x" << kfn->Dataset().n_cols + << " dataset)." << endl; } // Perform search, if desired. @@ -261,11 +263,11 @@ static void mlpackMain() // Sanity check on k value: must be greater than 0, must be less than the // number of reference points. Since it is unsigned, we only test the upper // bound. - if (k > kfn.Dataset().n_cols) + if (k > kfn->Dataset().n_cols) { Log::Fatal << "Invalid k: " << k << "; must be greater than 0 and less " << "than or equal to the number of reference points (" - << kfn.Dataset().n_cols << ")." << endl; + << kfn->Dataset().n_cols << ")." << endl; } // Now run the search. @@ -273,21 +275,19 @@ static void mlpackMain() arma::mat distances; if (CLI::HasParam("query")) - kfn.Search(std::move(queryData), k, neighbors, distances); + kfn->Search(std::move(queryData), k, neighbors, distances); else - kfn.Search(k, neighbors, distances); + kfn->Search(k, neighbors, distances); Log::Info << "Search complete." << endl; - // Save output, if desired. - if (CLI::HasParam("neighbors")) - CLI::GetParam>("neighbors") = std::move(neighbors); - if (CLI::HasParam("distances")) - CLI::GetParam("distances") = std::move(distances); + // Save output. + CLI::GetParam>("neighbors") = std::move(neighbors); + CLI::GetParam("distances") = std::move(distances); // Calculate the effective error, if desired. if (CLI::HasParam("true_distances")) { - if (kfn.Epsilon() == 0) + if (kfn->Epsilon() == 0) Log::Warn << PRINT_PARAM_STRING("true_distances") << " specified, but " << "the search is exact, so there is no need to calculate the " << "error!" << endl; @@ -307,7 +307,7 @@ static void mlpackMain() // Calculate the recall, if desired. if (CLI::HasParam("true_neighbors")) { - if (kfn.Epsilon() == 0) + if (kfn->Epsilon() == 0) Log::Warn << PRINT_PARAM_STRING("true_neighbors") << " specified, but " << "the search is exact, so there is no need to calculate the " << "recall!" << endl; @@ -324,6 +324,5 @@ static void mlpackMain() } } - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(kfn); + CLI::GetParam("output_model") = kfn; } diff --git a/src/mlpack/methods/neighbor_search/knn_main.cpp b/src/mlpack/methods/neighbor_search/knn_main.cpp index 9c43abceaf..aae9ff699a 100644 --- a/src/mlpack/methods/neighbor_search/knn_main.cpp +++ b/src/mlpack/methods/neighbor_search/knn_main.cpp @@ -166,7 +166,7 @@ static void mlpackMain() "epsilon must be positive"); // We either have to load the reference data, or we have to load the model. - KNNModel knn; + KNNModel* knn; const string algorithm = CLI::GetParam("algorithm"); RequireParamInSet("algorithm", { "naive", "single_tree", "dual_tree", @@ -184,6 +184,8 @@ static void mlpackMain() if (CLI::HasParam("reference")) { + knn = new KNNModel(); + // Get all the parameters. const string treeType = CLI::GetParam("tree_type"); const bool randomBasis = CLI::HasParam("random_basis"); @@ -223,11 +225,11 @@ static void mlpackMain() else if (treeType == "oct") tree = KNNModel::OCTREE; - knn.TreeType() = tree; - knn.RandomBasis() = randomBasis; - knn.LeafSize() = size_t(lsInt); - knn.Tau() = tau; - knn.Rho() = rho; + knn->TreeType() = tree; + knn->RandomBasis() = randomBasis; + knn->LeafSize() = size_t(lsInt); + knn->Tau() = tau; + knn->Rho() = rho; arma::mat referenceSet = std::move(CLI::GetParam("reference")); @@ -236,27 +238,27 @@ static void mlpackMain() << referenceSet.n_rows << " x " << referenceSet.n_cols << ")." << endl; - knn.BuildModel(std::move(referenceSet), size_t(lsInt), searchMode, epsilon); + knn->BuildModel(std::move(referenceSet), size_t(lsInt), searchMode, epsilon); } else { // Load the model from file. - knn = std::move(CLI::GetParam("input_model")); + knn = CLI::GetParam("input_model"); // Adjust search mode. - knn.SearchMode() = searchMode; - knn.Epsilon() = epsilon; + knn->SearchMode() = searchMode; + knn->Epsilon() = epsilon; // If leaf_size wasn't provided, let's consider the current value in the // loaded model. Else, update it (only considered when building the query // tree). if (CLI::HasParam("leaf_size")) - knn.LeafSize() = size_t(lsInt); + knn->LeafSize() = size_t(lsInt); Log::Info << "Loaded kNN model from '" - << CLI::GetPrintableParam("input_model") << "' (trained on " - << knn.Dataset().n_rows << "x" << knn.Dataset().n_cols << " dataset)." - << endl; + << CLI::GetPrintableParam("input_model") << "' (trained on " + << knn->Dataset().n_rows << "x" << knn->Dataset().n_cols + << " dataset)." << endl; } // Perform search, if desired. @@ -276,11 +278,11 @@ static void mlpackMain() // Sanity check on k value: must be greater than 0, must be less than the // number of reference points. Since it is unsigned, we only test the upper // bound. - if (k > knn.Dataset().n_cols) + if (k > knn->Dataset().n_cols) { Log::Fatal << "Invalid k: " << k << "; must be greater than 0 and less "; Log::Fatal << "than or equal to the number of reference points ("; - Log::Fatal << knn.Dataset().n_cols << ")." << endl; + Log::Fatal << knn->Dataset().n_cols << ")." << endl; } // Now run the search. @@ -288,21 +290,19 @@ static void mlpackMain() arma::mat distances; if (CLI::HasParam("query")) - knn.Search(std::move(queryData), k, neighbors, distances); + knn->Search(std::move(queryData), k, neighbors, distances); else - knn.Search(k, neighbors, distances); + knn->Search(k, neighbors, distances); Log::Info << "Search complete." << endl; - // Save output, if desired. - if (CLI::HasParam("neighbors")) - CLI::GetParam>("neighbors") = std::move(neighbors); - if (CLI::HasParam("distances")) - CLI::GetParam("distances") = std::move(distances); + // Save output. + CLI::GetParam>("neighbors") = std::move(neighbors); + CLI::GetParam("distances") = std::move(distances); // Calculate the effective error, if desired. if (CLI::HasParam("true_distances")) { - if (knn.TreeType() != KNNModel::SPILL_TREE && knn.Epsilon() == 0) + if (knn->TreeType() != KNNModel::SPILL_TREE && knn->Epsilon() == 0) Log::Warn << PRINT_PARAM_STRING("true_distances") << "specified, but " << "the search is exact, so there is no need to calculate the " << "error!" << endl; @@ -322,7 +322,7 @@ static void mlpackMain() // Calculate the recall, if desired. if (CLI::HasParam("true_neighbors")) { - if (knn.TreeType() != KNNModel::SPILL_TREE && knn.Epsilon() == 0) + if (knn->TreeType() != KNNModel::SPILL_TREE && knn->Epsilon() == 0) Log::Warn << PRINT_PARAM_STRING("true_neighbors") << " specified, but " << " the search is exact, so there is no need to calculate the " << "recall!" << endl; @@ -339,6 +339,5 @@ static void mlpackMain() } } - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(knn); + CLI::GetParam("output_model") = knn; } diff --git a/src/mlpack/methods/perceptron/perceptron_main.cpp b/src/mlpack/methods/perceptron/perceptron_main.cpp index c7a5b17796..0f2e18e0f8 100644 --- a/src/mlpack/methods/perceptron/perceptron_main.cpp +++ b/src/mlpack/methods/perceptron/perceptron_main.cpp @@ -137,14 +137,18 @@ static void mlpackMain() true, "maximum number of iterations must be nonnegative"); // Now, load our model, if there is one. - PerceptronModel p; + PerceptronModel* p; if (CLI::HasParam("input_model")) { Log::Info << "Using saved perceptron from " - << CLI::GetPrintableParam("input_model") << "." + << CLI::GetPrintableParam("input_model") << "." << endl; - p = std::move(CLI::GetParam("input_model")); + p = CLI::GetParam("input_model"); + } + else + { + p = new PerceptronModel(); } // Next, load the training data and labels (if they have been given). @@ -186,8 +190,8 @@ static void mlpackMain() // Normalize the labels. Row labels; - data::NormalizeLabels(labelsIn, labels, p.Map()); - const size_t numClasses = p.Map().n_elem; + data::NormalizeLabels(labelsIn, labels, p->Map()); + const size_t numClasses = p->Map().n_elem; // Now, if we haven't already created a perceptron, do it. Otherwise, make // sure the dimensions are right, then continue training. @@ -195,35 +199,35 @@ static void mlpackMain() { // Create and train the classifier. Timer::Start("training"); - p.P() = Perceptron<>(trainingData, labels, numClasses, maxIterations); + p->P() = Perceptron<>(trainingData, labels, numClasses, maxIterations); Timer::Stop("training"); } else { // Check dimensionality. - if (p.P().Weights().n_rows != trainingData.n_rows) + if (p->P().Weights().n_rows != trainingData.n_rows) { Log::Fatal << "Perceptron from '" - << CLI::GetPrintableParam("input_model") - << "' is built on data with " << p.P().Weights().n_rows + << CLI::GetPrintableParam("input_model") + << "' is built on data with " << p->P().Weights().n_rows << " dimensions, but data in '" << CLI::GetPrintableParam("training") << "' has " << trainingData.n_rows << "dimensions!" << endl; } // Check the number of labels. - if (numClasses > p.P().Weights().n_cols) + if (numClasses > p->P().Weights().n_cols) { Log::Fatal << "Perceptron from '" - << CLI::GetPrintableParam("input_model") << "' " - << "has " << p.P().Weights().n_cols << " classes, but the training " - << "data has " << numClasses + 1 << " classes!" << endl; + << CLI::GetPrintableParam("input_model") << "' " + << "has " << p->P().Weights().n_cols << " classes, but the training" + << " data has " << numClasses + 1 << " classes!" << endl; } // Now train. Timer::Start("training"); - p.P().MaxIterations() = maxIterations; - p.P().Train(trainingData, labels.t(), numClasses); + p->P().MaxIterations() = maxIterations; + p->P().Train(trainingData, labels.t(), numClasses); Timer::Stop("training"); } } @@ -235,29 +239,28 @@ static void mlpackMain() << CLI::GetPrintableParam("test") << "'." << endl; mat testData = std::move(CLI::GetParam("test")); - if (testData.n_rows != p.P().Weights().n_rows) + if (testData.n_rows != p->P().Weights().n_rows) { Log::Fatal << "Test data dimensionality (" << testData.n_rows << ") must " << "be the same as the dimensionality of the perceptron (" - << p.P().Weights().n_rows << ")!" << endl; + << p->P().Weights().n_rows << ")!" << endl; } // Time the running of the perceptron classifier. Row predictedLabels(testData.n_cols); Timer::Start("testing"); - p.P().Classify(testData, predictedLabels); + p->P().Classify(testData, predictedLabels); Timer::Stop("testing"); // Un-normalize labels to prepare output. Row results; - data::RevertLabels(predictedLabels, p.Map(), results); + data::RevertLabels(predictedLabels, p->Map(), results); // Save the predicted labels. if (CLI::HasParam("output")) CLI::GetParam>("output") = std::move(results); } - // Lastly, do we need to save the output model? - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(p); + // Lastly, save the output model. + CLI::GetParam("output_model") = p; } diff --git a/src/mlpack/methods/random_forest/random_forest_main.cpp b/src/mlpack/methods/random_forest/random_forest_main.cpp index e6cdfd5aa3..df38516fb9 100644 --- a/src/mlpack/methods/random_forest/random_forest_main.cpp +++ b/src/mlpack/methods/random_forest/random_forest_main.cpp @@ -104,9 +104,11 @@ static void mlpackMain() ReportIgnoredParam({{ "training", false }}, "num_trees"); ReportIgnoredParam({{ "training", false }}, "minimum_leaf_size"); - RandomForestModel rfModel; + RandomForestModel* rfModel; if (CLI::HasParam("training")) { + rfModel = new RandomForestModel(); + // Train the model on the given input data. arma::mat data = std::move(CLI::GetParam("training")); arma::Row labels = @@ -121,13 +123,13 @@ static void mlpackMain() const size_t numClasses = arma::max(labels) + 1; // Train the model. - rfModel.rf.Train(data, labels, numClasses, numTrees, minimumLeafSize); + rfModel->rf.Train(data, labels, numClasses, numTrees, minimumLeafSize); // Did we want training accuracy? if (CLI::HasParam("print_training_accuracy")) { arma::Row predictions; - rfModel.rf.Classify(data, predictions); + rfModel->rf.Classify(data, predictions); const size_t correct = arma::accu(predictions == labels); @@ -139,7 +141,7 @@ static void mlpackMain() else { // Then we must be loading a model. - rfModel = std::move(CLI::GetParam("input_model")); + rfModel = CLI::GetParam("input_model"); } if (CLI::HasParam("test")) @@ -149,7 +151,7 @@ static void mlpackMain() // Get predictions and probabilities. arma::Row predictions; arma::mat probabilities; - rfModel.rf.Classify(testData, predictions, probabilities); + rfModel->rf.Classify(testData, predictions, probabilities); // Did we want to calculate test accuracy? if (CLI::HasParam("test_labels")) @@ -164,14 +166,11 @@ static void mlpackMain() << ")." << endl; } - // Should we save the outputs? - if (CLI::HasParam("probabilities")) - CLI::GetParam("probabilities") = std::move(probabilities); - if (CLI::HasParam("predictions")) - CLI::GetParam>("predictions") = std::move(predictions); + // Save the outputs. + CLI::GetParam("probabilities") = std::move(probabilities); + CLI::GetParam>("predictions") = std::move(predictions); } - // Did the user want to save the output model? - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(rfModel); + // Save the output model. + CLI::GetParam("output_model") = rfModel; } diff --git a/src/mlpack/methods/range_search/range_search_main.cpp b/src/mlpack/methods/range_search/range_search_main.cpp index 66a070e6d6..27e49caf19 100644 --- a/src/mlpack/methods/range_search/range_search_main.cpp +++ b/src/mlpack/methods/range_search/range_search_main.cpp @@ -136,11 +136,13 @@ static void mlpackMain() "leaf size must be greater than 0"); // We either have to load the reference data, or we have to load the model. - RSModel rs; + RSModel* rs; const bool naive = CLI::HasParam("naive"); const bool singleMode = CLI::HasParam("single_mode"); if (CLI::HasParam("reference")) { + rs = new RSModel(); + // Get all the parameters. const string treeType = CLI::GetParam("tree_type"); RequireParamInSet("tree_type", { "kd", "cover", "r", "r-star", @@ -178,8 +180,8 @@ static void mlpackMain() else if (treeType == "oct") tree = RSModel::OCTREE; - rs.TreeType() = tree; - rs.RandomBasis() = randomBasis; + rs->TreeType() = tree; + rs->RandomBasis() = randomBasis; arma::mat referenceSet = std::move(CLI::GetParam("reference")); @@ -189,22 +191,22 @@ static void mlpackMain() const size_t leafSize = size_t(lsInt); - rs.BuildModel(std::move(referenceSet), leafSize, naive, singleMode); + rs->BuildModel(std::move(referenceSet), leafSize, naive, singleMode); } else { // Load the model from file. - rs = std::move(CLI::GetParam("input_model")); + rs = CLI::GetParam("input_model"); Log::Info << "Using range search model from '" << CLI::GetPrintableParam("input_model") << "' (" - << "trained on " << rs.Dataset().n_rows << "x" << rs.Dataset().n_cols + << "trained on " << rs->Dataset().n_rows << "x" << rs->Dataset().n_cols << " dataset)." << endl; // Adjust singleMode and naive if necessary. - rs.SingleMode() = CLI::HasParam("single_mode"); - rs.Naive() = CLI::HasParam("naive"); - rs.LeafSize() = size_t(lsInt); + rs->SingleMode() = CLI::HasParam("single_mode"); + rs->Naive() = CLI::HasParam("naive"); + rs->LeafSize() = size_t(lsInt); } // Perform search, if desired. @@ -235,9 +237,9 @@ static void mlpackMain() vector> distances; if (CLI::HasParam("query")) - rs.Search(std::move(queryData), r, neighbors, distances); + rs->Search(std::move(queryData), r, neighbors, distances); else - rs.Search(r, neighbors, distances); + rs->Search(r, neighbors, distances); Log::Info << "Search complete." << endl; @@ -301,7 +303,6 @@ static void mlpackMain() } } - // Save the output model, if desired. - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(rs); + // Save the output model. + CLI::GetParam("output_model") = rs; } diff --git a/src/mlpack/methods/rann/krann_main.cpp b/src/mlpack/methods/rann/krann_main.cpp index dd7fdef538..703fdd0850 100644 --- a/src/mlpack/methods/rann/krann_main.cpp +++ b/src/mlpack/methods/rann/krann_main.cpp @@ -135,11 +135,13 @@ static void mlpackMain() "leaf size must be greater than 0"); // We either have to load the reference data, or we have to load the model. - RANNModel rann; + RANNModel* rann; const bool naive = CLI::HasParam("naive"); const bool singleMode = CLI::HasParam("single_mode"); if (CLI::HasParam("reference")) { + rann = new RANNModel(); + // Get all the parameters. const string treeType = CLI::GetParam("tree_type"); RequireParamInSet("tree_type", { "kd", "cover", "r", "r-star", "x", @@ -169,8 +171,8 @@ static void mlpackMain() else if (treeType == "oct") tree = RANNModel::OCTREE; - rann.TreeType() = tree; - rann.RandomBasis() = randomBasis; + rann->TreeType() = tree; + rann->RandomBasis() = randomBasis; arma::mat referenceSet = std::move(CLI::GetParam("reference")); @@ -179,33 +181,33 @@ static void mlpackMain() << referenceSet.n_rows << " x " << referenceSet.n_cols << ")." << endl; - rann.BuildModel(std::move(referenceSet), size_t(lsInt), naive, singleMode); + rann->BuildModel(std::move(referenceSet), size_t(lsInt), naive, singleMode); } else { // Load the model from file. - rann = std::move(CLI::GetParam("input_model")); + rann = CLI::GetParam("input_model"); Log::Info << "Using rank-approximate kNN model from '" << CLI::GetPrintableParam("input_model") << "' (trained on " - << rann.Dataset().n_rows << "x" << rann.Dataset().n_cols << " dataset)." - << endl; + << rann->Dataset().n_rows << "x" << rann->Dataset().n_cols + << " dataset)." << endl; // Adjust singleMode and naive if necessary. - rann.SingleMode() = CLI::HasParam("single_mode"); - rann.Naive() = CLI::HasParam("naive"); - rann.LeafSize() = size_t(lsInt); + rann->SingleMode() = CLI::HasParam("single_mode"); + rann->Naive() = CLI::HasParam("naive"); + rann->LeafSize() = size_t(lsInt); } // Apply the parameters for search. if (CLI::HasParam("tau")) - rann.Tau() = CLI::GetParam("tau"); + rann->Tau() = CLI::GetParam("tau"); if (CLI::HasParam("alpha")) - rann.Alpha() = CLI::GetParam("alpha"); + rann->Alpha() = CLI::GetParam("alpha"); if (CLI::HasParam("single_sample_limit")) - rann.SingleSampleLimit() = CLI::GetParam("single_sample_limit"); - rann.SampleAtLeaves() = CLI::HasParam("sample_at_leaves"); - rann.FirstLeafExact() = CLI::HasParam("sample_at_leaves"); + rann->SingleSampleLimit() = CLI::GetParam("single_sample_limit"); + rann->SampleAtLeaves() = CLI::HasParam("sample_at_leaves"); + rann->FirstLeafExact() = CLI::HasParam("sample_at_leaves"); // Perform search, if desired. if (CLI::HasParam("k")) @@ -224,28 +226,26 @@ static void mlpackMain() // Sanity check on k value: must be greater than 0, must be less than the // number of reference points. Since it is unsigned, we only test the upper // bound. - if (k > rann.Dataset().n_cols) + if (k > rann->Dataset().n_cols) { Log::Fatal << "Invalid k: " << k << "; must be greater than 0 and less "; Log::Fatal << "than or equal to the number of reference points ("; - Log::Fatal << rann.Dataset().n_cols << ")." << endl; + Log::Fatal << rann->Dataset().n_cols << ")." << endl; } arma::Mat neighbors; arma::mat distances; if (CLI::HasParam("query")) - rann.Search(std::move(queryData), k, neighbors, distances); + rann->Search(std::move(queryData), k, neighbors, distances); else - rann.Search(k, neighbors, distances); + rann->Search(k, neighbors, distances); Log::Info << "Search complete." << endl; - // Save output, if desired. - if (CLI::HasParam("neighbors")) - CLI::GetParam>("neighbors") = std::move(neighbors); - if (CLI::HasParam("distances")) - CLI::GetParam("distances") = std::move(distances); + // Save output. + CLI::GetParam>("neighbors") = std::move(neighbors); + CLI::GetParam("distances") = std::move(distances); } - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(rann); + // Save the output model. + CLI::GetParam("output_model") = rann; } diff --git a/src/mlpack/methods/softmax_regression/softmax_regression_main.cpp b/src/mlpack/methods/softmax_regression/softmax_regression_main.cpp index 78e8c96245..d61723143e 100644 --- a/src/mlpack/methods/softmax_regression/softmax_regression_main.cpp +++ b/src/mlpack/methods/softmax_regression/softmax_regression_main.cpp @@ -113,7 +113,7 @@ void TestClassifyAcc(const size_t numClasses, const Model& model); // Build the softmax model given the parameters. template -unique_ptr TrainSoftmax(const size_t maxIterations); +Model* TrainSoftmax(const size_t maxIterations); static void mlpackMain() { @@ -141,13 +141,11 @@ static void mlpackMain() RequireAtLeastOnePassed({ "output_model", "predictions" }, false, "no results" " will be saved"); - using SM = SoftmaxRegression; - unique_ptr sm = TrainSoftmax(maxIterations); + SoftmaxRegression* sm = TrainSoftmax(maxIterations); TestClassifyAcc(sm->NumClasses(), *sm); - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(*sm); + CLI::GetParam("output_model") = sm; } size_t CalculateNumberOfClasses(const size_t numClasses, @@ -230,17 +228,14 @@ void TestClassifyAcc(size_t numClasses, const Model& model) } template -unique_ptr TrainSoftmax(const size_t maxIterations) +Model* TrainSoftmax(const size_t maxIterations) { using namespace mlpack; - using SRF = regression::SoftmaxRegressionFunction; - - unique_ptr sm; + Model* sm; if (CLI::HasParam("input_model")) { - sm.reset(new Model(0, 0, false)); - *sm = std::move(CLI::GetParam("input_model")); + sm = CLI::GetParam("input_model"); } else { @@ -259,8 +254,8 @@ unique_ptr TrainSoftmax(const size_t maxIterations) const size_t numBasis = 5; optimization::L_BFGS optimizer(numBasis, maxIterations); - sm.reset(new Model(trainData, trainLabels, numClasses, - CLI::GetParam("lambda"), intercept, std::move(optimizer))); + sm = new Model(trainData, trainLabels, numClasses, + CLI::GetParam("lambda"), intercept, std::move(optimizer)); } return sm; diff --git a/src/mlpack/methods/sparse_coding/sparse_coding_main.cpp b/src/mlpack/methods/sparse_coding/sparse_coding_main.cpp index 0ce5bf8336..87a2cd278f 100644 --- a/src/mlpack/methods/sparse_coding/sparse_coding_main.cpp +++ b/src/mlpack/methods/sparse_coding/sparse_coding_main.cpp @@ -146,9 +146,11 @@ static void mlpackMain() "Newton method tolerance must be nonnegative"); // Do we have an existing model? - SparseCoding sc(0, 0.0); + SparseCoding* sc; if (CLI::HasParam("input_model")) - sc = std::move(CLI::GetParam("input_model")); + sc = CLI::GetParam("input_model"); + else + sc = new SparseCoding(0, 0.0); if (CLI::HasParam("training")) { @@ -162,12 +164,12 @@ static void mlpackMain() matX.col(i) /= norm(matX.col(i), 2); } - sc.Lambda1() = CLI::GetParam("lambda1"); - sc.Lambda2() = CLI::GetParam("lambda2"); - sc.MaxIterations() = (size_t) CLI::GetParam("max_iterations"); - sc.Atoms() = (size_t) CLI::GetParam("atoms"); - sc.ObjTolerance() = CLI::GetParam("objective_tolerance"); - sc.NewtonTolerance() = CLI::GetParam("newton_tolerance"); + sc->Lambda1() = CLI::GetParam("lambda1"); + sc->Lambda2() = CLI::GetParam("lambda2"); + sc->MaxIterations() = (size_t) CLI::GetParam("max_iterations"); + sc->Atoms() = (size_t) CLI::GetParam("atoms"); + sc->ObjTolerance() = CLI::GetParam("objective_tolerance"); + sc->NewtonTolerance() = CLI::GetParam("newton_tolerance"); // Inform the user if we are overwriting their model. if (CLI::HasParam("input_model")) @@ -175,36 +177,36 @@ static void mlpackMain() Log::Info << "Using dictionary from existing model in '" << CLI::GetPrintableParam("input_model") << "' as initial dictionary for training." << endl; - sc.Train(matX); + sc->Train(matX); } else if (CLI::HasParam("initial_dictionary")) { // Load initial dictionary directly into sparse coding object. - sc.Dictionary() = + sc->Dictionary() = std::move(CLI::GetParam("initial_dictionary")); // Validate size of initial dictionary. - if (sc.Dictionary().n_cols != sc.Atoms()) + if (sc->Dictionary().n_cols != sc->Atoms()) { - Log::Fatal << "The initial dictionary has " << sc.Dictionary().n_cols + Log::Fatal << "The initial dictionary has " << sc->Dictionary().n_cols << " atoms, but the number of atoms was specified to be " - << sc.Atoms() << "!" << endl; + << sc->Atoms() << "!" << endl; } - if (sc.Dictionary().n_rows != matX.n_rows) + if (sc->Dictionary().n_rows != matX.n_rows) { - Log::Fatal << "The initial dictionary has " << sc.Dictionary().n_rows + Log::Fatal << "The initial dictionary has " << sc->Dictionary().n_rows << " dimensions, but the data has " << matX.n_rows << " dimensions!" << endl; } // Run sparse coding. - sc.Train(matX); + sc->Train(matX); } else { // Run sparse coding with the default initialization. - sc.Train(matX); + sc->Train(matX); } } @@ -213,9 +215,9 @@ static void mlpackMain() { mat matY = std::move(CLI::GetParam("test")); - if (matY.n_rows != sc.Dictionary().n_rows) + if (matY.n_rows != sc->Dictionary().n_rows) Log::Fatal << "Model was trained with a dimensionality of " - << sc.Dictionary().n_rows << ", but test data '" + << sc->Dictionary().n_rows << ", but test data '" << CLI::GetPrintableParam("test") << "' have a " << "dimensionality of " << matY.n_rows << "!" << endl; @@ -228,20 +230,15 @@ static void mlpackMain() } mat codes; - sc.Encode(matY, codes); + sc->Encode(matY, codes); - if (CLI::HasParam("codes")) - CLI::GetParam("codes") = std::move(codes); + CLI::GetParam("codes") = std::move(codes); } - // Did the user want to save the dictionary? If so we can move that, but only - // if we are not also saving an output model. - if (CLI::HasParam("dictionary") && !CLI::HasParam("output_model")) - CLI::GetParam("dictionary") = std::move(sc.Dictionary()); - else if (CLI::HasParam("dictionary")) - CLI::GetParam("dictionary") = sc.Dictionary(); + // Did the user want to save the dictionary? Use an alias for the dictionary. + CLI::GetParam("dictionary") = arma::mat(sc->Dictionary().memptr(), + sc->Dictionary().n_rows, sc->Dictionary().n_cols, false, false); - // Did the user want to save the model? - if (CLI::HasParam("output_model")) - CLI::GetParam("output_model") = std::move(sc); + // Save the model. + CLI::GetParam("output_model") = sc; } From 6b954ebf4c76d97b1a8ce41ca58a1ec9da319131 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 26 Jan 2018 14:02:39 -0500 Subject: [PATCH 046/113] Oops, this snuck in somehow. --- src/mlpack/tests/gmm_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/tests/gmm_test.cpp b/src/mlpack/tests/gmm_test.cpp index 9a694cd12a..f1945c9836 100644 --- a/src/mlpack/tests/gmm_test.cpp +++ b/src/mlpack/tests/gmm_test.cpp @@ -761,7 +761,6 @@ BOOST_AUTO_TEST_CASE(UseExistingModelTest) */ BOOST_AUTO_TEST_CASE(DiagonalGMMTrainTest) { - Log::Warn.ignoreInput = false; // We'll have three diagonal-covariance Gaussian distributions from this // mixture. distribution::GaussianDistribution d1("0.0 1.0 0.0", "1.0 0.0 0.0;" From 6e3f0cb4376715fd866ea05f80649e709d48ae81 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 26 Jan 2018 17:25:05 -0500 Subject: [PATCH 047/113] Remove move.hpp from build configuration. --- src/mlpack/bindings/python/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mlpack/bindings/python/CMakeLists.txt b/src/mlpack/bindings/python/CMakeLists.txt index be49a1f238..88ec98a949 100644 --- a/src/mlpack/bindings/python/CMakeLists.txt +++ b/src/mlpack/bindings/python/CMakeLists.txt @@ -79,7 +79,6 @@ set(CYTHON_SOURCES mlpack/arma_util.hpp mlpack/cli.pxd mlpack/cli_util.hpp - mlpack/move.hpp mlpack/matrix_utils.py mlpack/serialization.hpp mlpack/serialization.pxd @@ -148,7 +147,6 @@ add_custom_command(TARGET python POST_BUILD mlpack/arma_util.hpp mlpack/cli.pxd mlpack/cli_util.hpp - mlpack/move.hpp mlpack/matrix_utils.py mlpack WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/) From b773276c1799a72fec9e9744be6c87d0380f3548 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 26 Jan 2018 17:26:08 -0500 Subject: [PATCH 048/113] Adapt tests to use pointers to models. --- src/mlpack/bindings/cli/get_param.hpp | 1 - src/mlpack/tests/cli_binding_test.cpp | 27 ++++++++++--------- src/mlpack/tests/cli_test.cpp | 15 ++++++----- .../tests/main_tests/decision_tree_test.cpp | 4 +-- .../main_tests/linear_regression_test.cpp | 6 ++--- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/mlpack/bindings/cli/get_param.hpp b/src/mlpack/bindings/cli/get_param.hpp index 9c16b10f26..4ddfe7f72b 100644 --- a/src/mlpack/bindings/cli/get_param.hpp +++ b/src/mlpack/bindings/cli/get_param.hpp @@ -112,7 +112,6 @@ T*& GetParam( d.loaded = true; std::get<0>(*tuple) = model; } - return std::get<0>(*tuple); } diff --git a/src/mlpack/tests/cli_binding_test.cpp b/src/mlpack/tests/cli_binding_test.cpp index 526bb00545..0aba4f49e4 100644 --- a/src/mlpack/tests/cli_binding_test.cpp +++ b/src/mlpack/tests/cli_binding_test.cpp @@ -238,20 +238,21 @@ BOOST_AUTO_TEST_CASE(GetParamModelTest) data::Save("kernel.bin", "model", gk); // Create tuple. - gk.Bandwidth(2.0); - tuple t = make_tuple(gk, filename); + tuple t = make_tuple((GaussianKernel*) NULL, + filename); d.value = boost::any(t); // Make sure it is not loaded yet. d.input = true; d.loaded = false; - GaussianKernel* output = NULL; - GetParam((const util::ParamData&) d, (void*) NULL, + GaussianKernel** output = NULL; + GetParam((const util::ParamData&) d, (void*) NULL, (void*) &output); - BOOST_REQUIRE_EQUAL(output->Bandwidth(), 5.0); + BOOST_REQUIRE_EQUAL((*output)->Bandwidth(), 5.0); remove("kernel.bin"); + delete *output; } BOOST_AUTO_TEST_CASE(RawParamDoubleTest) @@ -300,17 +301,17 @@ BOOST_AUTO_TEST_CASE(GetRawParamModelTest) kernel::GaussianKernel gk(5.0); // Create tuple. - tuple t = make_tuple(gk, filename); + tuple t = make_tuple(&gk, filename); d.value = boost::any(t); // Make sure it is not loaded yet. d.input = true; d.loaded = false; - tuple* output = NULL; - GetRawParam>((const util::ParamData&) d, + tuple* output = NULL; + GetRawParam>((const util::ParamData&) d, (void*) NULL, (void*) &output); - BOOST_REQUIRE_EQUAL(get<0>(*output).Bandwidth(), 5.0); + BOOST_REQUIRE_EQUAL(get<0>(*output)->Bandwidth(), 5.0); } BOOST_AUTO_TEST_CASE(GetRawParamDatasetInfoTest) @@ -403,7 +404,7 @@ BOOST_AUTO_TEST_CASE(OutputParamModelTest) // Create value. string filename = "kernel.bin"; GaussianKernel gk(5.0); - tuple t = make_tuple(gk, filename); + tuple t = make_tuple(&gk, filename); d.value = boost::any(t); d.input = false; @@ -491,7 +492,7 @@ BOOST_AUTO_TEST_CASE(SetParamModelTest) // Create initial value. string filename = "kernel.bin"; GaussianKernel gk(2.0); - d.value = boost::any(make_tuple(gk, filename)); + d.value = boost::any(make_tuple(&gk, filename)); // Get a new string. string newFilename = "new_kernel.bin"; @@ -501,8 +502,8 @@ BOOST_AUTO_TEST_CASE(SetParamModelTest) (void*) NULL); // Make sure the change went through. - tuple& t = - *boost::any_cast>(&d.value); + tuple& t = + *boost::any_cast>(&d.value); BOOST_REQUIRE_EQUAL(get<1>(t), "new_kernel.bin"); } diff --git a/src/mlpack/tests/cli_test.cpp b/src/mlpack/tests/cli_test.cpp index 144e8c9967..5b44385a6f 100644 --- a/src/mlpack/tests/cli_test.cpp +++ b/src/mlpack/tests/cli_test.cpp @@ -866,9 +866,9 @@ BOOST_AUTO_TEST_CASE(UnmappedParamTest) BOOST_REQUIRE_EQUAL(CLI::GetPrintableParam("matrix"), "file1.csv"); BOOST_REQUIRE_EQUAL(CLI::GetPrintableParam("matrix2"), "file2.csv"); - BOOST_REQUIRE_EQUAL(CLI::GetPrintableParam("kernel"), + BOOST_REQUIRE_EQUAL(CLI::GetPrintableParam("kernel"), "kernel.txt"); - BOOST_REQUIRE_EQUAL(CLI::GetPrintableParam("kernel2"), + BOOST_REQUIRE_EQUAL(CLI::GetPrintableParam("kernel2"), "kernel2.txt"); remove("kernel.txt"); @@ -894,9 +894,9 @@ BOOST_AUTO_TEST_CASE(SerializationTest) ParseCommandLine(argc, const_cast(argv)); // Create the kernel we'll save. - GaussianKernel gk(0.5); + GaussianKernel* gk = new GaussianKernel(0.5); - CLI::GetParam("kernel") = move(gk); + CLI::GetParam("kernel") = gk; // Save it. EndProgram(); @@ -910,9 +910,12 @@ BOOST_AUTO_TEST_CASE(SerializationTest) ParseCommandLine(argc, const_cast(argv)); // Load the kernel from file. - GaussianKernel gk2 = move(CLI::GetParam("kernel")); + GaussianKernel* gk2 = CLI::GetParam("kernel"); - BOOST_REQUIRE_CLOSE(gk2.Bandwidth(), 0.5, 1e-5); + BOOST_REQUIRE_CLOSE(gk2->Bandwidth(), 0.5, 1e-5); + + // Clean up the memory... + delete gk2; // Now remove the file we made. remove("kernel.txt"); diff --git a/src/mlpack/tests/main_tests/decision_tree_test.cpp b/src/mlpack/tests/main_tests/decision_tree_test.cpp index 6ed311689a..3cf1f0761e 100644 --- a/src/mlpack/tests/main_tests/decision_tree_test.cpp +++ b/src/mlpack/tests/main_tests/decision_tree_test.cpp @@ -210,7 +210,7 @@ BOOST_AUTO_TEST_CASE(DecisionModelReuseTest) // Input trained model. SetInputParam("test", std::move(std::make_tuple(info, testData))); SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + std::move(CLI::GetParam("output_model"))); mlpackMain(); @@ -281,7 +281,7 @@ BOOST_AUTO_TEST_CASE(DecisionModelCategoricalReuseTest) // Input trained model. SetInputParam("test", std::move(std::make_tuple(info, testData))); SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + std::move(CLI::GetParam("output_model"))); mlpackMain(); diff --git a/src/mlpack/tests/main_tests/linear_regression_test.cpp b/src/mlpack/tests/main_tests/linear_regression_test.cpp index e3d0d7993d..28a205aacd 100644 --- a/src/mlpack/tests/main_tests/linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/linear_regression_test.cpp @@ -135,12 +135,12 @@ BOOST_AUTO_TEST_CASE(LRModelReload) mlpackMain(); - LinearRegression model = CLI::GetParam("output_model"); + LinearRegression* model = CLI::GetParam("output_model"); const arma::rowvec testY1 = CLI::GetParam("output_predictions"); ResetSettings(); - SetInputParam("input_model", std::move(model)); + SetInputParam("input_model", model); SetInputParam("test", std::move(testX)); mlpackMain(); @@ -209,7 +209,7 @@ BOOST_AUTO_TEST_CASE(LRWrongDimOfDataTest2) mlpackMain(); - LinearRegression model = CLI::GetParam("output_model"); + LinearRegression* model = CLI::GetParam("output_model"); ResetSettings(); From 934682ecc54c09c574ddf2ffe96bd41ff2b7a95d Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 26 Jan 2018 18:23:24 -0500 Subject: [PATCH 049/113] Remove code that wasn't needed in the end. --- src/mlpack/bindings/python/get_param.hpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/mlpack/bindings/python/get_param.hpp b/src/mlpack/bindings/python/get_param.hpp index e2c1c33108..62c898a15e 100644 --- a/src/mlpack/bindings/python/get_param.hpp +++ b/src/mlpack/bindings/python/get_param.hpp @@ -22,17 +22,7 @@ void GetParam(const util::ParamData& d, const void* /* input */, void* output) { -// typedef typename std::remove_pointer::type TRaw; -// if (std::is_pointer::value) // If true, this is a model. -// { -// std::cout << "get a raw pointer for " << d.name << ": " << boost::any_cast(d.value) << -//"\n"; -// *((TRaw***) output) = const_cast(boost::any_cast(&d.value)); -// } -// else - { - *((T**) output) = const_cast(boost::any_cast(&d.value)); - } + *((T**) output) = const_cast(boost::any_cast(&d.value)); } } // namespace python From cb829ac3046a217b475091993fae0b550988d271 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 26 Jan 2018 18:24:40 -0500 Subject: [PATCH 050/113] Fix too-long lines. --- src/mlpack/bindings/python/print_input_processing.hpp | 6 +++--- src/mlpack/methods/neighbor_search/kfn_main.cpp | 3 ++- src/mlpack/methods/neighbor_search/knn_main.cpp | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mlpack/bindings/python/print_input_processing.hpp b/src/mlpack/bindings/python/print_input_processing.hpp index 14d487b3fb..290366f185 100644 --- a/src/mlpack/bindings/python/print_input_processing.hpp +++ b/src/mlpack/bindings/python/print_input_processing.hpp @@ -189,9 +189,9 @@ void PrintInputProcessing( std::cout << prefix << " except TypeError as e:" << std::endl; std::cout << prefix << " if type(" << d.name << ").__name__ == '" << strippedType << "Type':" << std::endl; - std::cout << prefix << " SetParamPtr[" << strippedType << "]('" << d.name - << "', (<" << strippedType << "Type> " << d.name << ").modelptr)" - << std::endl; + std::cout << prefix << " SetParamPtr[" << strippedType << "]('" + << d.name << "', (<" << strippedType << "Type> " << d.name + << ").modelptr)" << std::endl; std::cout << prefix << " else:" << std::endl; std::cout << prefix << " raise e" << std::endl; std::cout << prefix << " CLI.SetPassed( '" << d.name << "')" diff --git a/src/mlpack/methods/neighbor_search/kfn_main.cpp b/src/mlpack/methods/neighbor_search/kfn_main.cpp index 7488be23bd..9d1ebb35bb 100644 --- a/src/mlpack/methods/neighbor_search/kfn_main.cpp +++ b/src/mlpack/methods/neighbor_search/kfn_main.cpp @@ -223,7 +223,8 @@ static void mlpackMain() << CLI::GetPrintableParam("reference") << "' (" << referenceSet.n_rows << "x" << referenceSet.n_cols << ")." << endl; - kfn->BuildModel(std::move(referenceSet), size_t(lsInt), searchMode, epsilon); + kfn->BuildModel(std::move(referenceSet), size_t(lsInt), searchMode, + epsilon); } else { diff --git a/src/mlpack/methods/neighbor_search/knn_main.cpp b/src/mlpack/methods/neighbor_search/knn_main.cpp index aae9ff699a..2fe257700b 100644 --- a/src/mlpack/methods/neighbor_search/knn_main.cpp +++ b/src/mlpack/methods/neighbor_search/knn_main.cpp @@ -238,7 +238,8 @@ static void mlpackMain() << referenceSet.n_rows << " x " << referenceSet.n_cols << ")." << endl; - knn->BuildModel(std::move(referenceSet), size_t(lsInt), searchMode, epsilon); + knn->BuildModel(std::move(referenceSet), size_t(lsInt), searchMode, + epsilon); } else { From 787e0904edcceef887767448002b0404c84ba74b Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sat, 27 Jan 2018 13:13:52 -0500 Subject: [PATCH 051/113] Add a 'copy_all_inputs' option to Python bindings. This is hand-tested as working, but I need to write actual tests still. --- src/mlpack/bindings/python/mlpack/cli.pxd | 5 ++- .../bindings/python/mlpack/cli_util.hpp | 7 +++- .../bindings/python/mlpack/matrix_utils.py | 20 +++++++--- .../python/print_input_processing.hpp | 39 ++++++++++++------- src/mlpack/bindings/python/print_pyx.cpp | 9 ++++- src/mlpack/bindings/python/py_option.hpp | 4 +- src/mlpack/core/util/mlpack_main.hpp | 4 ++ 7 files changed, 61 insertions(+), 27 deletions(-) diff --git a/src/mlpack/bindings/python/mlpack/cli.pxd b/src/mlpack/bindings/python/mlpack/cli.pxd index f6c6435c18..20380817f5 100644 --- a/src/mlpack/bindings/python/mlpack/cli.pxd +++ b/src/mlpack/bindings/python/mlpack/cli.pxd @@ -20,6 +20,9 @@ cdef extern from "" namespace "mlpack" nogil: @staticmethod (T&) GetParam[T](string) nogil except + + @staticmethod + bool HasParam(string) nogil except + + @staticmethod void SetPassed(string) nogil except + @@ -38,7 +41,7 @@ cdef extern from "" namespace "mlpack" nogil: cdef extern from "" \ namespace "mlpack::util" nogil: void SetParam[T](string, T&) nogil except + - void SetParamPtr[T](string, T*) nogil except + + void SetParamPtr[T](string, T*, bool) nogil except + void SetParamWithInfo[T](string, T&, const bool*) nogil except + (T*) GetParamPtr[T](string) nogil except + (T&) GetParamWithInfo[T](string) nogil except + diff --git a/src/mlpack/bindings/python/mlpack/cli_util.hpp b/src/mlpack/bindings/python/mlpack/cli_util.hpp index 6c4ef5ff7b..c2873fcf36 100644 --- a/src/mlpack/bindings/python/mlpack/cli_util.hpp +++ b/src/mlpack/bindings/python/mlpack/cli_util.hpp @@ -42,11 +42,14 @@ inline void SetParam(const std::string& identifier, T& value) * * @param identifier Name of parameter. * @param value Value to set parameter to. + * @param copy Whether or not the object should be copied. */ template -inline void SetParamPtr(const std::string& identifier, T* value) +inline void SetParamPtr(const std::string& identifier, + T* value, + const bool copy) { - CLI::GetParam(identifier) = value; + CLI::GetParam(identifier) = copy ? new T(*value) : value; } /** diff --git a/src/mlpack/bindings/python/mlpack/matrix_utils.py b/src/mlpack/bindings/python/mlpack/matrix_utils.py index 9cf0cbadda..5529315ac6 100644 --- a/src/mlpack/bindings/python/mlpack/matrix_utils.py +++ b/src/mlpack/bindings/python/mlpack/matrix_utils.py @@ -37,7 +37,7 @@ try: except: buffer = memoryview -def to_matrix(x, dtype=np.double): +def to_matrix(x, dtype=np.double, copy=False): """ Given some array-like X, return a numpy ndarray of the same type. """ @@ -48,11 +48,14 @@ def to_matrix(x, dtype=np.double): raise TypeError("given argument is not array-like") if (isinstance(x, np.ndarray) and x.dtype == dtype and x.flags.c_contiguous): - return x, False + if copy: # Copy the matrix if required. + return x.copy("C"), True + else: + return x, False else: return np.array(x, copy=True, dtype=dtype, order='C'), True -def to_matrix_with_info(x, dtype): +def to_matrix_with_info(x, dtype, copy=False): """ Given some array-like X (which should be either a numpy ndarray or a pandas DataFrame, convert into a numpy matrix of the given dtype. @@ -66,7 +69,12 @@ def to_matrix_with_info(x, dtype): if isinstance(x, np.ndarray): # It is already an ndarray, so the vector of info is all 0s (all numeric). d = np.zeros([x.shape[1]], dtype=np.bool) - return (x, False, d) + + # Copy the matrix if needed. + if copy: + return (x.copy(order="C"), True, d) + else: + return (x, False, d) if isinstance(x, pd.DataFrame) or isinstance(x, pd.Series): # It's a pandas dataframe. So we need to see if any of the dtypes are @@ -79,7 +87,7 @@ def to_matrix_with_info(x, dtype): not np.dtype(str) in dtype_array and \ not np.dtype(unicode) in dtype_array: # We can just return the matrix as-is; it's all numeric. - t = to_matrix(x) + t = to_matrix(x, copy) d = np.zeros([x.shape[1]], dtype=np.bool) return (t[0], t[1], d) @@ -130,7 +138,7 @@ def to_matrix_with_info(x, dtype): dims = len(x) d = np.zeros([dims]) - out = np.array(x, dtype=dtype, copy=False) # Try to avoid copy... + out = np.array(x, dtype=dtype, copy=copy) # Try to avoid copy... # Since we don't have a great way to check if these are using the same # memory location, we will probe manually (ugh). diff --git a/src/mlpack/bindings/python/print_input_processing.hpp b/src/mlpack/bindings/python/print_input_processing.hpp index 290366f185..bb688ad463 100644 --- a/src/mlpack/bindings/python/print_input_processing.hpp +++ b/src/mlpack/bindings/python/print_input_processing.hpp @@ -31,6 +31,11 @@ void PrintInputProcessing( const typename boost::disable_if>>::type* = 0) { + // The copy_all_inputs parameter must be handled first, and so is outside the + // scope of this code. + if (d.name == "copy_all_inputs") + return; + const std::string prefix(indent, ' '); std::string def = "None"; @@ -117,8 +122,8 @@ void PrintInputProcessing( std::cout << prefix << "if " << d.name << " is not None:" << std::endl; std::cout << prefix << " " << d.name << "_tuple = to_matrix(" << d.name - << ", dtype=" << GetNumpyType() << ")" - << std::endl; + << ", dtype=" << GetNumpyType() << ", " + << "copy=CLI.HasParam('copy_all_inputs'))" << std::endl; std::cout << prefix << " " << d.name << "_mat = arma_numpy.numpy_to_" << GetArmaType() << "_" << GetNumpyTypeChar() << "(" << d.name << "_tuple[0], " << d.name << "_tuple[1])" << std::endl; @@ -132,8 +137,8 @@ void PrintInputProcessing( else { std::cout << prefix << d.name << "_tuple = to_matrix(" << d.name - << ", dtype=" << GetNumpyType() << ")" - << std::endl; + << ", dtype=" << GetNumpyType() << ", " + << "copy=CLI.HasParam('copy_all_inputs'))" << std::endl; std::cout << prefix << d.name << "_mat = arma_numpy.numpy_to_" << GetArmaType() << "_" << GetNumpyTypeChar() << "(" << d.name << "_tuple[0], " << d.name << "_tuple[1])" << std::endl; @@ -169,10 +174,12 @@ void PrintInputProcessing( * # Detect if the parameter was passed; set if so. * if param_name is not None: * try: - * SetParamPtr[Model]('param_name', ( param_name).modelptr) + * SetParamPtr[Model]('param_name', ( param_name).modelptr, + * CLI.HasParam('copy_all_inputs')) * except TypeError as e: * if type(param_name).__name__ == "ModelType": - * SetParamPtr[Model]('param_name', ( param_name).modelptr) + * SetParamPtr[Model]('param_name', ( param_name).modelptr, + * CLI.HasParam('copy_all_inputs')) TODO * else: * raise e * CLI.SetPassed( 'param_name') @@ -184,14 +191,14 @@ void PrintInputProcessing( std::cout << prefix << "if " << d.name << " is not None:" << std::endl; std::cout << prefix << " try:" << std::endl; std::cout << prefix << " SetParamPtr[" << strippedType << "]('" << d.name - << "', (<" << strippedType << "Type?> " << d.name << ").modelptr)" - << std::endl; + << "', (<" << strippedType << "Type?> " << d.name << ").modelptr, " + << "CLI.HasParam('copy_all_inputs'))" << std::endl; std::cout << prefix << " except TypeError as e:" << std::endl; std::cout << prefix << " if type(" << d.name << ").__name__ == '" << strippedType << "Type':" << std::endl; std::cout << prefix << " SetParamPtr[" << strippedType << "]('" << d.name << "', (<" << strippedType << "Type> " << d.name - << ").modelptr)" << std::endl; + << ").modelptr, CLI.HasParam('copy_all_inputs'))" << std::endl; std::cout << prefix << " else:" << std::endl; std::cout << prefix << " raise e" << std::endl; std::cout << prefix << " CLI.SetPassed( '" << d.name << "')" @@ -201,14 +208,14 @@ void PrintInputProcessing( { std::cout << prefix << "try:" << std::endl; std::cout << prefix << " SetParamPtr[" << strippedType << "]('" << d.name - << "', (<" << strippedType << "Type?> " << d.name << ").modelptr)" - << std::endl; + << "', (<" << strippedType << "Type?> " << d.name << ").modelptr, " + << "CLI.HasParam('copy_all_inputs'))" << std::endl; std::cout << prefix << "except TypeError as e:" << std::endl; std::cout << prefix << " if type(" << d.name << ").__name__ == '" << strippedType << "Type':" << std::endl; std::cout << prefix << " SetParamPtr[" << strippedType << "]('" << d.name - << "', (<" << strippedType << "Type> " << d.name << ").modelptr)" - << std::endl; + << "', (<" << strippedType << "Type> " << d.name << ").modelptr, " + << "CLI.HasParam('copy_all_inputs'))" << std::endl; std::cout << prefix << " else:" << std::endl; std::cout << prefix << " raise e" << std::endl; std::cout << prefix << "CLI.SetPassed( '" << d.name << "')" @@ -246,7 +253,8 @@ void PrintInputProcessing( { std::cout << prefix << "if " << d.name << " is not None:" << std::endl; std::cout << prefix << " " << d.name << "_tuple = to_matrix_with_info(" - << d.name << ", dtype=np.double)" << std::endl; + << d.name << ", dtype=np.double, copy=CLI.HasParam('copy_all_inputs'))" + << std::endl; std::cout << prefix << " " << d.name << "_mat = arma_numpy.numpy_to_mat_d(" << d.name << "_tuple[0], " << d.name << "_tuple[1])" << std::endl; std::cout << prefix << " " << d.name << "_dims = " << d.name << "_tuple[2]" @@ -261,7 +269,8 @@ void PrintInputProcessing( else { std::cout << prefix << d.name << "_tuple = to_matrix_with_info(" << d.name - << ", dtype=np.double)" << std::endl; + << ", dtype=np.double, copy=CLI.HasParam('copy_all_inputs'))" + << std::endl; std::cout << prefix << d.name << "_mat = arma_numpy.numpy_to_mat_d(" << d.name << "_tuple[0], " << d.name << "_tuple[1])" << std::endl; std::cout << prefix << d.name << "_dims = " << d.name << "_tuple[2]" diff --git a/src/mlpack/bindings/python/print_pyx.cpp b/src/mlpack/bindings/python/print_pyx.cpp index 423de61a41..498bd07940 100644 --- a/src/mlpack/bindings/python/print_pyx.cpp +++ b/src/mlpack/bindings/python/print_pyx.cpp @@ -177,7 +177,14 @@ void PrintPYX(const ProgramDoc& programInfo, cout << " DisableVerbose()" << endl; // Restore the parameters. - cout << " CLI.RestoreSettings(\"" << programInfo.programName << "\")"; + cout << " CLI.RestoreSettings(\"" << programInfo.programName << "\")" + << endl; + + // Determine whether or not we need to copy parameters. + cout << " if copy_all_inputs:" << endl; + cout << " SetParam[bool]( 'copy_all_inputs', " + << "copy_all_inputs)" << endl; + cout << " CLI.SetPassed( 'copy_all_inputs')" << endl; // Do any input processing. for (size_t i = 0; i < inputOptions.size(); ++i) diff --git a/src/mlpack/bindings/python/py_option.hpp b/src/mlpack/bindings/python/py_option.hpp index 60eaf3a1c4..b25be68a4b 100644 --- a/src/mlpack/bindings/python/py_option.hpp +++ b/src/mlpack/bindings/python/py_option.hpp @@ -58,8 +58,8 @@ class PyOption data.required = required; data.input = input; data.loaded = false; - // Only "verbose" will be persistent. - if (identifier == "verbose") + // Only "verbose" and "copy_all_inputs" will be persistent. + if (identifier == "verbose" || identifier == "copy_all_inputs") data.persistent = true; else data.persistent = false; diff --git a/src/mlpack/core/util/mlpack_main.hpp b/src/mlpack/core/util/mlpack_main.hpp index a26a5c6ff7..e675d3d1b0 100644 --- a/src/mlpack/core/util/mlpack_main.hpp +++ b/src/mlpack/core/util/mlpack_main.hpp @@ -138,6 +138,10 @@ static const std::string testName = ""; PARAM_FLAG("verbose", "Display informational messages and the full list of " "parameters and timers at the end of execution.", "v"); +PARAM_FLAG("copy_all_inputs", "If specified, all input parameters will be deep" + " copied before the method is run. This is useful for debugging problems " + "where the input parameters are being modified by the algorithm, but can " + "slow down the code.", ""); // Nothing else needs to be defined---the binding will use mlpackMain() as-is. From 6f8828859241a0b363b3ddceedb086ca18ae3853 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sat, 27 Jan 2018 23:16:33 -0500 Subject: [PATCH 052/113] Add tests for Python bindings and update for new to_matrix() API. --- .../bindings/python/mlpack/matrix_utils.py | 6 +- .../python/tests/dataset_info_test.py | 26 +- .../python/tests/test_python_binding.py | 255 +++++++++++++++++- .../python/tests/test_python_binding_main.cpp | 4 +- 4 files changed, 269 insertions(+), 22 deletions(-) diff --git a/src/mlpack/bindings/python/mlpack/matrix_utils.py b/src/mlpack/bindings/python/mlpack/matrix_utils.py index 5529315ac6..58f39b61ed 100644 --- a/src/mlpack/bindings/python/mlpack/matrix_utils.py +++ b/src/mlpack/bindings/python/mlpack/matrix_utils.py @@ -87,7 +87,7 @@ def to_matrix_with_info(x, dtype, copy=False): not np.dtype(str) in dtype_array and \ not np.dtype(unicode) in dtype_array: # We can just return the matrix as-is; it's all numeric. - t = to_matrix(x, copy) + t = to_matrix(x, dtype=dtype, copy=copy) d = np.zeros([x.shape[1]], dtype=np.bool) return (t[0], t[1], d) @@ -126,7 +126,7 @@ def to_matrix_with_info(x, dtype, copy=False): # We'll have to force the second part of the tuple (whether or not to take # ownership) to true. - t = to_matrix(y.apply(pd.to_numeric)) + t = to_matrix(y.apply(pd.to_numeric), dtype=dtype) return (t[0], True, d) if isinstance(x, list): @@ -149,7 +149,7 @@ def to_matrix_with_info(x, dtype, copy=False): alias = True x[0] = oldval - return (np.array(x, dtype=dtype), not alias, d) + return (out, not alias, d) # If we got here, the type is not known. raise TypeError("given matrix is not a numpy ndarray or pandas DataFrame or "\ diff --git a/src/mlpack/bindings/python/tests/dataset_info_test.py b/src/mlpack/bindings/python/tests/dataset_info_test.py index dd14d73071..e72c529d00 100644 --- a/src/mlpack/bindings/python/tests/dataset_info_test.py +++ b/src/mlpack/bindings/python/tests/dataset_info_test.py @@ -23,7 +23,7 @@ class TestToMatrix(unittest.TestCase): """ d = pd.DataFrame(np.random.randn(100, 4), columns=list('abcd')) - m = to_matrix(d) + m, _ = to_matrix(d) self.assertTrue(isinstance(m, np.ndarray)) self.assertEqual(m.shape[0], 100) @@ -40,7 +40,7 @@ class TestToMatrix(unittest.TestCase): """ d = pd.DataFrame({'a': range(5)}) - m = to_matrix(d) + m, _ = to_matrix(d) self.assertTrue(isinstance(m, np.ndarray)) self.assertEqual(m.shape[0], 5) @@ -58,7 +58,7 @@ class TestToMatrix(unittest.TestCase): self.assertEqual(d['a'].dtype, int) self.assertEqual(d['b'].dtype, np.dtype(np.double)) - m = to_matrix(d) + m, _ = to_matrix(d) self.assertTrue(isinstance(m, np.ndarray)) self.assertEqual(m.dtype, np.dtype(np.double)) @@ -79,7 +79,7 @@ class TestToMatrix(unittest.TestCase): [0.07, 0.08, 0.09], [0.10, 0.11, 0.12]] - m = to_matrix(a) + m, _ = to_matrix(a) self.assertTrue(isinstance(m, np.ndarray)) self.assertEqual(m.dtype, np.dtype(np.double)) @@ -100,7 +100,7 @@ class TestToMatrix(unittest.TestCase): [0.07, 0.08, 9], [0.10, 0.11, 12]] - m = to_matrix(a) + m, _ = to_matrix(a) self.assertTrue(isinstance(m, np.ndarray)) self.assertEqual(m.dtype, np.dtype(np.double)) @@ -116,7 +116,7 @@ class TestToMatrix(unittest.TestCase): Make sure we can convert a numpy matrix without copying anything. """ m1 = np.random.randn(100, 5) - m2 = to_matrix(m1) + m2, _ = to_matrix(m1) self.assertTrue(isinstance(m2, np.ndarray)) self.assertEqual(m2.dtype, np.dtype(np.double)) @@ -144,7 +144,7 @@ class TestToMatrixWithInfo(unittest.TestCase): """ d = pd.DataFrame(np.random.randn(100, 4), columns=list('abcd')) - m, dims = to_matrix_with_info(d, np.double) + m, _, dims = to_matrix_with_info(d, np.double) self.assertTrue(isinstance(m, np.ndarray)) self.assertEqual(m.shape[0], 100) @@ -167,7 +167,7 @@ class TestToMatrixWithInfo(unittest.TestCase): """ d = pd.DataFrame({'a': range(5)}) - m, dims = to_matrix_with_info(d, np.double) + m, _, dims = to_matrix_with_info(d, np.double) self.assertTrue(isinstance(m, np.ndarray)) self.assertEqual(m.shape[0], 5) @@ -188,7 +188,7 @@ class TestToMatrixWithInfo(unittest.TestCase): self.assertEqual(d['a'].dtype, int) self.assertEqual(d['b'].dtype, np.dtype(np.double)) - m, dims = to_matrix_with_info(d, np.double) + m, _, dims = to_matrix_with_info(d, np.double) self.assertTrue(isinstance(m, np.ndarray)) self.assertEqual(m.dtype, np.dtype(np.double)) @@ -213,7 +213,7 @@ class TestToMatrixWithInfo(unittest.TestCase): [0.07, 0.08, 0.09], [0.10, 0.11, 0.12]] - m, dims = to_matrix_with_info(a, np.double) + m, _, dims = to_matrix_with_info(a, np.double) self.assertTrue(isinstance(m, np.ndarray)) self.assertEqual(m.dtype, np.dtype(np.double)) @@ -239,7 +239,7 @@ class TestToMatrixWithInfo(unittest.TestCase): [0.07, 0.08, 9], [0.10, 0.11, 12]] - m, dims = to_matrix_with_info(a, np.double) + m, _, dims = to_matrix_with_info(a, np.double) self.assertTrue(isinstance(m, np.ndarray)) self.assertEqual(m.dtype, np.dtype(np.double)) @@ -260,7 +260,7 @@ class TestToMatrixWithInfo(unittest.TestCase): Make sure we can convert a numpy matrix without copying anything. """ m1 = np.random.randn(100, 5) - m2, dims = to_matrix_with_info(m1, np.double) + m2, _, dims = to_matrix_with_info(m1, np.double) self.assertTrue(isinstance(m2, np.ndarray)) self.assertEqual(m2.dtype, np.dtype(np.double)) @@ -284,7 +284,7 @@ class TestToMatrixWithInfo(unittest.TestCase): d = pd.DataFrame({"A": ["a", "b", "c", "a"] }) d["A"] = d["A"].astype('category') # Convert to categorical. - m, dims = to_matrix_with_info(d, np.double) + m, _, dims = to_matrix_with_info(d, np.double) self.assertTrue(isinstance(m, np.ndarray)) self.assertEqual(m.dtype, np.dtype(np.double)) diff --git a/src/mlpack/bindings/python/tests/test_python_binding.py b/src/mlpack/bindings/python/tests/test_python_binding.py index 93ac2615c6..bd10b83a2e 100644 --- a/src/mlpack/bindings/python/tests/test_python_binding.py +++ b/src/mlpack/bindings/python/tests/test_python_binding.py @@ -112,6 +112,29 @@ class TestPythonBinding(unittest.TestCase): for j in range(100): self.assertEqual(2 * x[j, 2], output['matrix_out'][j, 2]) + def testNumpyMatrixForceCopy(self): + """ + The matrix we pass in, we should get back with the third dimension doubled + and the fifth forgotten. + """ + x = np.random.rand(100, 5); + + output = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + matrix_in=x, + copy_all_inputs=True) + + self.assertEqual(output['matrix_out'].shape[0], 100) + self.assertEqual(output['matrix_out'].shape[1], 4) + self.assertEqual(output['matrix_out'].dtype, np.double) + for i in [0, 1, 3]: + for j in range(100): + self.assertEqual(x[j, i], output['matrix_out'][j, i]) + + for j in range(100): + self.assertEqual(2 * x[j, 2], output['matrix_out'][j, 2]) + def testArraylikeMatrix(self): """ Test that we can pass an arraylike matrix. @@ -119,12 +142,11 @@ class TestPythonBinding(unittest.TestCase): x = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]] - z = copy.copy(x) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - matrix_in=z) + matrix_in=x) self.assertEqual(output['matrix_out'].shape[0], 3) self.assertEqual(output['matrix_out'].shape[1], 4) @@ -142,6 +164,38 @@ class TestPythonBinding(unittest.TestCase): self.assertEqual(output['matrix_out'][2, 2], 26) self.assertEqual(output['matrix_out'][2, 3], 14) + def testArraylikeMatrixForceCopy(self): + """ + Test that we can pass an arraylike matrix. + """ + x = [[1, 2, 3, 4, 5], + [6, 7, 8, 9, 10], + [11, 12, 13, 14, 15]] + + output = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + matrix_in=x, + copy_all_inputs=True) + + self.assertEqual(output['matrix_out'].shape[0], 3) + self.assertEqual(output['matrix_out'].shape[1], 4) + self.assertEqual(len(x), 3) + self.assertEqual(len(x[0]), 5) + self.assertEqual(output['matrix_out'].dtype, np.double) + self.assertEqual(output['matrix_out'][0, 0], 1) + self.assertEqual(output['matrix_out'][0, 1], 2) + self.assertEqual(output['matrix_out'][0, 2], 6) + self.assertEqual(output['matrix_out'][0, 3], 4) + self.assertEqual(output['matrix_out'][1, 0], 6) + self.assertEqual(output['matrix_out'][1, 1], 7) + self.assertEqual(output['matrix_out'][1, 2], 16) + self.assertEqual(output['matrix_out'][1, 3], 9) + self.assertEqual(output['matrix_out'][2, 0], 11) + self.assertEqual(output['matrix_out'][2, 1], 12) + self.assertEqual(output['matrix_out'][2, 2], 26) + self.assertEqual(output['matrix_out'][2, 3], 14) + def testNumpyUmatrix(self): """ Same as testNumpyMatrix() but with an unsigned matrix. @@ -164,6 +218,28 @@ class TestPythonBinding(unittest.TestCase): for j in range(100): self.assertEqual(2 * x[j, 2], output['umatrix_out'][j, 2]) + def testNumpyUmatrixForceCopy(self): + """ + Same as testNumpyMatrix() but with an unsigned matrix. + """ + x = np.random.randint(0, high=500, size=[100, 5]) + + output = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + umatrix_in=x, + copy_all_inputs=True) + + self.assertEqual(output['umatrix_out'].shape[0], 100) + self.assertEqual(output['umatrix_out'].shape[1], 4) + self.assertEqual(output['umatrix_out'].dtype, np.long) + for i in [0, 1, 3]: + for j in range(100): + self.assertEqual(x[j, i], output['umatrix_out'][j, i]) + + for j in range(100): + self.assertEqual(2 * x[j, 2], output['umatrix_out'][j, 2]) + def testArraylikeUmatrix(self): """ Test that we can pass an arraylike unsigned matrix. @@ -171,12 +247,11 @@ class TestPythonBinding(unittest.TestCase): x = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]] - z = copy.copy(x) output = test_python_binding(string_in='hello', int_in=12, double_in=4.0, - umatrix_in=z) + umatrix_in=x) self.assertEqual(output['umatrix_out'].shape[0], 3) self.assertEqual(output['umatrix_out'].shape[1], 4) @@ -194,6 +269,38 @@ class TestPythonBinding(unittest.TestCase): self.assertEqual(output['umatrix_out'][2, 2], 26) self.assertEqual(output['umatrix_out'][2, 3], 14) + def testArraylikeUmatrixForceCopy(self): + """ + Test that we can pass an arraylike unsigned matrix. + """ + x = [[1, 2, 3, 4, 5], + [6, 7, 8, 9, 10], + [11, 12, 13, 14, 15]] + + output = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + umatrix_in=x, + copy_all_inputs=True) + + self.assertEqual(output['umatrix_out'].shape[0], 3) + self.assertEqual(output['umatrix_out'].shape[1], 4) + self.assertEqual(len(x), 3) + self.assertEqual(len(x[0]), 5) + self.assertEqual(output['umatrix_out'].dtype, np.long) + self.assertEqual(output['umatrix_out'][0, 0], 1) + self.assertEqual(output['umatrix_out'][0, 1], 2) + self.assertEqual(output['umatrix_out'][0, 2], 6) + self.assertEqual(output['umatrix_out'][0, 3], 4) + self.assertEqual(output['umatrix_out'][1, 0], 6) + self.assertEqual(output['umatrix_out'][1, 1], 7) + self.assertEqual(output['umatrix_out'][1, 2], 16) + self.assertEqual(output['umatrix_out'][1, 3], 9) + self.assertEqual(output['umatrix_out'][2, 0], 11) + self.assertEqual(output['umatrix_out'][2, 1], 12) + self.assertEqual(output['umatrix_out'][2, 2], 26) + self.assertEqual(output['umatrix_out'][2, 3], 14) + def testCol(self): """ Test a column vector input parameter. @@ -212,6 +319,24 @@ class TestPythonBinding(unittest.TestCase): for i in range(100): self.assertEqual(output['col_out'][i], x[i] * 2) + def testColForceCopy(self): + """ + Test a column vector input parameter. + """ + x = np.random.rand(100) + + output = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + col_in=x, + copy_all_inputs=True) + + self.assertEqual(output['col_out'].shape[0], 100) + self.assertEqual(output['col_out'].dtype, np.double) + + for i in range(100): + self.assertEqual(output['col_out'][i], x[i] * 2) + def testUcol(self): """ Test an unsigned column vector input parameter. @@ -229,6 +354,23 @@ class TestPythonBinding(unittest.TestCase): for i in range(100): self.assertEqual(output['ucol_out'][i], x[i] * 2) + def testUcolForceCopy(self): + """ + Test an unsigned column vector input parameter. + """ + x = np.random.randint(0, high=500, size=100) + + output = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + ucol_in=x, + copy_all_inputs=True) + + self.assertEqual(output['ucol_out'].shape[0], 100) + self.assertEqual(output['ucol_out'].dtype, np.long) + for i in range(100): + self.assertEqual(output['ucol_out'][i], x[i] * 2) + def testRow(self): """ Test a row vector input parameter. @@ -247,6 +389,24 @@ class TestPythonBinding(unittest.TestCase): for i in range(100): self.assertEqual(output['row_out'][i], x[i] * 2) + def testRowForceCopy(self): + """ + Test a row vector input parameter. + """ + x = np.random.rand(100) + + output = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + row_in=x, + copy_all_inputs=True) + + self.assertEqual(output['row_out'].shape[0], 100) + self.assertEqual(output['row_out'].dtype, np.double) + + for i in range(100): + self.assertEqual(output['row_out'][i], x[i] * 2) + def testUrow(self): """ Test an unsigned row vector input parameter. @@ -265,6 +425,24 @@ class TestPythonBinding(unittest.TestCase): for i in range(100): self.assertEqual(output['urow_out'][i], x[i] * 2) + def testUrowForceCopy(self): + """ + Test an unsigned row vector input parameter. + """ + x = np.random.randint(0, high=500, size=100) + + output = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + urow_in=x, + copy_all_inputs=True) + + self.assertEqual(output['urow_out'].shape[0], 100) + self.assertEqual(output['urow_out'].dtype, np.long) + + for i in range(100): + self.assertEqual(output['urow_out'][i], x[i] * 2) + def testMatrixAndInfoNumpy(self): """ Test that we can pass a matrix with all numeric features. @@ -284,6 +462,25 @@ class TestPythonBinding(unittest.TestCase): for j in range(100): self.assertEqual(output['matrix_and_info_out'][j, i], x[j, i] * 2.0) + def testMatrixAndInfoNumpyForceCopy(self): + """ + Test that we can pass a matrix with all numeric features. + """ + x = np.random.rand(100, 10) + + output = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + matrix_and_info_in=x, + copy_all_inputs=True) + + self.assertEqual(output['matrix_and_info_out'].shape[0], 100) + self.assertEqual(output['matrix_and_info_out'].shape[1], 10) + + for i in range(10): + for j in range(100): + self.assertEqual(output['matrix_and_info_out'][j, i], x[j, i] * 2.0) + def testMatrixAndInfoPandas(self): """ Test that we can pass a matrix with some categorical features. @@ -310,6 +507,32 @@ class TestPythonBinding(unittest.TestCase): for j in range(10): self.assertEqual(output['matrix_and_info_out'][j, 4], z[cols[4]][j]) + def testMatrixAndInfoPandasForceCopy(self): + """ + Test that we can pass a matrix with some categorical features. + """ + x = pd.DataFrame(np.random.rand(10, 4), columns=list('abcd')) + x['e'] = pd.Series(['a', 'b', 'c', 'd', 'a', 'b', 'e', 'c', 'a', 'b'], + dtype='category') + + output = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + matrix_and_info_in=x, + copy_all_inputs=True) + + self.assertEqual(output['matrix_and_info_out'].shape[0], 10) + self.assertEqual(output['matrix_and_info_out'].shape[1], 5) + + cols = list('abcde') + + for i in range(4): + for j in range(10): + self.assertEqual(output['matrix_and_info_out'][j, i], x[cols[i]][j] * 2) + + for j in range(10): + self.assertEqual(output['matrix_and_info_out'][j, 4], x[cols[4]][j]) + def testIntVector(self): """ Test that we can pass a vector of ints and get back that same vector but @@ -356,5 +579,29 @@ class TestPythonBinding(unittest.TestCase): self.assertEqual(output2['model_bw_out'], 20.0) + def testModelForceCopy(self): + """ + First create a GaussianKernel object, then send it back and make sure we get + the right double value. + """ + output = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + build_model=True) + + output2 = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + model_in=output['model_out'], + copy_all_inputs=True) + + output3 = test_python_binding(string_in='hello', + int_in=12, + double_in=4.0, + model_in=output['model_out']) + + self.assertEqual(output2['model_bw_out'], 20.0) + self.assertEqual(output3['model_bw_out'], 20.0) + if __name__ == '__main__': unittest.main() diff --git a/src/mlpack/bindings/python/tests/test_python_binding_main.cpp b/src/mlpack/bindings/python/tests/test_python_binding_main.cpp index 8be2f4947a..9af5a26693 100644 --- a/src/mlpack/bindings/python/tests/test_python_binding_main.cpp +++ b/src/mlpack/bindings/python/tests/test_python_binding_main.cpp @@ -172,13 +172,13 @@ static void mlpackMain() // If we got a request to build a model, then build it. if (CLI::HasParam("build_model")) { - CLI::GetParam("model_out") = GaussianKernel(10.0); + CLI::GetParam("model_out") = new GaussianKernel(10.0); } // If we got an input model, double the bandwidth and output that. if (CLI::HasParam("model_in")) { CLI::GetParam("model_bw_out") = - CLI::GetParam("model_in").Bandwidth() * 2.0; + CLI::GetParam("model_in")->Bandwidth() * 2.0; } } From ef91472178d482b2501bc9ba13d544521a24c549 Mon Sep 17 00:00:00 2001 From: manish7294 Date: Sun, 28 Jan 2018 16:26:58 +0530 Subject: [PATCH 053/113] Added Binding Test for Sparse Coding --- src/mlpack/tests/CMakeLists.txt | 1 + .../tests/main_tests/sparse_coding_test.cpp | 465 ++++++++++++++++++ 2 files changed, 466 insertions(+) create mode 100644 src/mlpack/tests/main_tests/sparse_coding_test.cpp diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index 89a02af421..34a5f3c099 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -136,6 +136,7 @@ add_executable(mlpack_test main_tests/preprocess_split_test.cpp main_tests/random_forest_test.cpp main_tests/softmax_regression_test.cpp + main_tests/sparse_coding_test.cpp ) # Link dependencies of test executable. diff --git a/src/mlpack/tests/main_tests/sparse_coding_test.cpp b/src/mlpack/tests/main_tests/sparse_coding_test.cpp new file mode 100644 index 0000000000..79746e9d74 --- /dev/null +++ b/src/mlpack/tests/main_tests/sparse_coding_test.cpp @@ -0,0 +1,465 @@ +/** + * @file sparse_coding_test.cpp + * @author Manish Kumar + * + * Test mlpackMain() of sparse_coding_main.cpp. + * + * 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. + */ +#include + +#define BINDING_TYPE BINDING_TYPE_TEST +static const std::string testName = "SparseCoding"; + +#include +#include +#include +#include "test_helper.hpp" + +#include +#include "../test_tools.hpp" + +using namespace mlpack; + +struct SparseCodingTestFixture +{ + public: + SparseCodingTestFixture() + { + // Cache in the options for this program. + CLI::RestoreSettings(testName); + } + + ~SparseCodingTestFixture() + { + // Clear the settings. + CLI::ClearSettings(); + } +}; + +BOOST_FIXTURE_TEST_SUITE(SparseCodingMainTest, SparseCodingTestFixture); + +/** + * Make sure that output points in dictionary equals number of + * atoms passed and codes have desired dimension. + */ +BOOST_AUTO_TEST_CASE(SparseCodingOutputDimensionTest) +{ + mat inputData; + inputData.load("mnist_first250_training_4s_and_9s.arm"); + + // Shuffle input dataset. + inputData = shuffle(inputData); + + // Generate test dataset. + mat testData; + testData = inputData.cols(450, 499); + + // Generate train dataset. + inputData.shed_cols(450, 499); + + // Input data. + SetInputParam("training", std::move(inputData)); + SetInputParam("atoms", (int) 30); + SetInputParam("max_iterations", (int) 500); + SetInputParam("normalize", (bool) true); + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + // Check that number of output dictionary points are equals number of atoms. + BOOST_REQUIRE_EQUAL(CLI::GetParam("dictionary").n_cols, 30); + + // Check that number of output dictionary rows equal number of input rows + // which equal 784 for each data point. + BOOST_REQUIRE_EQUAL(CLI::GetParam("dictionary").n_rows, 784); + + // Check that number of output points are equal to number of test points. + BOOST_REQUIRE_EQUAL(CLI::GetParam("codes").n_cols, 50); + + // Check that number of output codes rows equal number of atoms. + BOOST_REQUIRE_EQUAL(CLI::GetParam("codes").n_rows, 30); +} + +/** + * Ensure that training data is normalized if normalize + * parameter is set to true. + */ +BOOST_AUTO_TEST_CASE(SparseCodingNormalizationTest) +{ + mat inputData; + inputData.load("mnist_first250_training_4s_and_9s.arm"); + + // Shuffle input dataset. + inputData = shuffle(inputData); + + // Generate test dataset. + mat testData; + testData = inputData.cols(450, 499); + + // Generate train dataset. + inputData.shed_cols(450, 499); + + // Generate initial dictionary. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 30); + SetInputParam("max_iterations", (int) 10); + SetInputParam("normalize", (bool) true); + + mlpackMain(); + + mat initialDictionary; + initialDictionary = std::move(CLI::GetParam + ("dictionary")); + + // Train for normalization set to true. + + // Input data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 30); + SetInputParam("initial_dictionary", initialDictionary); + SetInputParam("max_iterations", (int) 100); + SetInputParam("normalize", (bool) true); + SetInputParam("test", testData); + + mlpackMain(); + + // Store outputs. + arma::mat dictionary; + arma::mat codes; + dictionary = std::move(CLI::GetParam("dictionary")); + codes = std::move(CLI::GetParam("codes")); + + // Train for normalization set to false. + + // Reset passed parameters. + CLI::GetSingleton().Parameters()["normalize"].wasPassed = false; + + // Normalize train dataset. + for (size_t i = 0; i < inputData.n_cols; ++i) + inputData.col(i) /= norm(inputData.col(i), 2); + + // Normalize test dataset. + for (size_t i = 0; i < testData.n_cols; ++i) + testData.col(i) /= norm(testData.col(i), 2); + + // Input data. + SetInputParam("training", std::move(inputData)); + SetInputParam("atoms", (int) 30); + SetInputParam("initial_dictionary", std::move(initialDictionary)); + SetInputParam("max_iterations", (int) 100); + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + // Check that initial outputs and final outputs + // using two models model are same. + CheckMatrices(dictionary, CLI::GetParam("dictionary")); + CheckMatrices(codes, CLI::GetParam("codes")); +} + +/** + * Ensure that l1, l2, max_iterations, objective_tolerance, + * newton_tolerance value is always non-negative and number + * of atoms is always positive. + */ +BOOST_AUTO_TEST_CASE(SparseCodingBoundsTest) +{ + mat inputData; + inputData.load("mnist_first250_training_4s_and_9s.arm"); + + // Test for L1 value. + + // Input training data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 10); + SetInputParam("lambda1", (double) -1.0); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; + + // Test for L2 value. + + // Input training data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 10); + SetInputParam("lambda2", (double) -1.0); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; + + // Test for max_iterations. + + // Input training data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 10); + SetInputParam("max_iterations", (int) -1.0); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; + + // Test for objective_tolerance. + + // Input training data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 10); + SetInputParam("objective_tolerance", (double) -1.0); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; + + // Test for newton_tolerance. + + // Input training data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 10); + SetInputParam("newton_tolerance", (double) -1.0); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; + + // Test for atoms. + + // Input training data. + SetInputParam("training", std::move(inputData)); + SetInputParam("atoms", (int) 0); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Make sure atoms are specified if training data is passed. + */ +BOOST_AUTO_TEST_CASE(SparseCodingReqAtomsTest) +{ + mat inputData; + inputData.load("mnist_first250_training_4s_and_9s.arm"); + + // Input training data. + SetInputParam("training", std::move(inputData)); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Ensure only one of input_model or initial_dictionary + * is specified. + */ +BOOST_AUTO_TEST_CASE(SparseCodingModelVerTest) +{ + mat inputData; + inputData.load("mnist_first250_training_4s_and_9s.arm"); + + // Shuffle input dataset. + inputData = shuffle(inputData); + + // Input data. + SetInputParam("training", std::move(inputData)); + SetInputParam("atoms", (int) 30); + SetInputParam("max_iterations", (int) 10); + SetInputParam("normalize", (bool) true); + + mlpackMain(); + + mat initialDictionary; + initialDictionary = std::move(CLI::GetParam + ("dictionary")); + + // Input trained model and initial_dictionary. + SetInputParam("input_model", + std::move(CLI::GetParam("output_model"))); + SetInputParam("initial_dictionary", std::move(initialDictionary)); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Ensure that specified number of atoms and initial_dictionary + * atoms are equal. + */ +BOOST_AUTO_TEST_CASE(SparseCodingAtomsVerTest) +{ + mat inputData; + inputData.load("mnist_first250_training_4s_and_9s.arm"); + + // Shuffle input dataset. + inputData = shuffle(inputData); + + // Input data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 30); + SetInputParam("max_iterations", (int) 10); + SetInputParam("normalize", (bool) true); + + mlpackMain(); + + mat initialDictionary; + initialDictionary = std::move(CLI::GetParam + ("dictionary")); + + // Input data and initial_dictionary. + SetInputParam("training", std::move(inputData)); + SetInputParam("atoms", (int) 40); // Invalid. + SetInputParam("initial_dictionary", std::move(initialDictionary)); + SetInputParam("max_iterations", (int) 100); + SetInputParam("normalize", (bool) true); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Ensure that input data and initial_dictionary + * have same number of rows. + */ +BOOST_AUTO_TEST_CASE(SparseCodingRowsVerTest) +{ + mat inputData; + inputData.load("mnist_first250_training_4s_and_9s.arm"); + + // Shuffle input dataset. + inputData = shuffle(inputData); + + // Input data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 30); + SetInputParam("max_iterations", (int) 100); + SetInputParam("normalize", (bool) true); + + mlpackMain(); + + mat initialDictionary; + initialDictionary = std::move(CLI::GetParam + ("dictionary")); + + // Trim inputData. + inputData.shed_rows(100, 400); + + // Input data and initial_dictionary. + SetInputParam("training", std::move(inputData)); // Invalid Data. + SetInputParam("atoms", (int) 30); + SetInputParam("initial_dictionary", std::move(initialDictionary)); + SetInputParam("max_iterations", (int) 100); + SetInputParam("normalize", (bool) true); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Ensure that training data and test data + * have same dimensionality w.r.t rows. + */ +BOOST_AUTO_TEST_CASE(SparseCodingDataDimensionalityTest) +{ + mat inputData; + inputData.load("mnist_first250_training_4s_and_9s.arm"); + + // Shuffle input dataset. + inputData = shuffle(inputData); + + // Generate test dataset. + mat testData; + testData = inputData.cols(450, 499); + + // Trim testData. + testData.shed_rows(100, 400); + + // Generate train dataset. + inputData.shed_cols(450, 499); + + // Input data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 30); + SetInputParam("max_iterations", (int) 100); + SetInputParam("normalize", (bool) true); + SetInputParam("test", std::move(testData)); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Check that saved model can be reused again. + */ +BOOST_AUTO_TEST_CASE(SparseCodingModelReuseTest) +{ + mat inputData; + inputData.load("mnist_first250_training_4s_and_9s.arm"); + + // Shuffle input dataset. + inputData = shuffle(inputData); + + // Generate test dataset. + mat testData; + testData = inputData.cols(450, 499); + + // Generate train dataset. + inputData.shed_cols(450, 499); + + // Input data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 30); + SetInputParam("max_iterations", (int) 100); + SetInputParam("normalize", (bool) true); + SetInputParam("test", testData); + + mlpackMain(); + + // Store outputs. + arma::mat dictionary; + arma::mat codes; + dictionary = std::move(CLI::GetParam("dictionary")); + codes = std::move(CLI::GetParam("codes")); + + // Reset passed parameters. + CLI::GetSingleton().Parameters()["training"].wasPassed = false; + + // Test the correctness of trained model. + + // Input data. + SetInputParam("max_iterations", (int) 100); + SetInputParam("input_model", + std::move(CLI::GetParam("output_model"))); + SetInputParam("normalize", (bool) true); + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + // Check that number of output dictionary points are equals number of atoms. + BOOST_REQUIRE_EQUAL(CLI::GetParam("dictionary").n_cols, 30); + + // Check that number of output dictionary rows equal number of input rows + // which equal 784 for each data point. + BOOST_REQUIRE_EQUAL(CLI::GetParam("dictionary").n_rows, 784); + + // Check that number of output points are equal to number of test points. + BOOST_REQUIRE_EQUAL(CLI::GetParam("codes").n_cols, 50); + + // Check that number of output codes rows equal number of atoms. + BOOST_REQUIRE_EQUAL(CLI::GetParam("codes").n_rows, 30); + + // Check that initial outputs and final outputs + // using two models model are same. + CheckMatrices(dictionary, CLI::GetParam("dictionary")); + CheckMatrices(codes, CLI::GetParam("codes")); +} + +BOOST_AUTO_TEST_SUITE_END(); From 3b756a0cf88241e4916d98625eea30ebd5109f42 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sun, 28 Jan 2018 14:36:16 -0500 Subject: [PATCH 054/113] Update tests to use pointers. (This is probably not completely correct but I am moving systems right now.) --- .../tests/main_tests/decision_stump_test.cpp | 8 +++++-- .../tests/main_tests/decision_tree_test.cpp | 2 +- src/mlpack/tests/main_tests/nbc_test.cpp | 8 +++++-- .../tests/main_tests/random_forest_test.cpp | 23 +++++++++++++------ .../main_tests/softmax_regression_test.cpp | 4 +++- 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/mlpack/tests/main_tests/decision_stump_test.cpp b/src/mlpack/tests/main_tests/decision_stump_test.cpp index f2e07a9198..02a6212471 100644 --- a/src/mlpack/tests/main_tests/decision_stump_test.cpp +++ b/src/mlpack/tests/main_tests/decision_stump_test.cpp @@ -198,7 +198,7 @@ BOOST_AUTO_TEST_CASE(DecisionStumpModelReuseTest) // Input trained model. SetInputParam("test", std::move(testData)); SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + std::move(CLI::GetParam("output_model"))); mlpackMain(); @@ -213,6 +213,8 @@ BOOST_AUTO_TEST_CASE(DecisionStumpModelReuseTest) // Check that initial predictions and final predicitons matrix // using saved model are same. CheckMatrices(predictions, CLI::GetParam>("predictions")); + + delete CLI::GetParam("output_model"); } /** @@ -249,11 +251,13 @@ BOOST_AUTO_TEST_CASE(DecisionStumpTrainingVerTest) // Input pre-trained model. SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + std::move(CLI::GetParam("output_model"))); Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; + + delete CLI::GetParam("output_model"); } BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/main_tests/decision_tree_test.cpp b/src/mlpack/tests/main_tests/decision_tree_test.cpp index 09312c0452..3511239f40 100644 --- a/src/mlpack/tests/main_tests/decision_tree_test.cpp +++ b/src/mlpack/tests/main_tests/decision_tree_test.cpp @@ -254,7 +254,7 @@ BOOST_AUTO_TEST_CASE(DecisionTreeTrainingVerTest) // Input pre-trained model. SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + std::move(CLI::GetParam("output_model"))); Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); diff --git a/src/mlpack/tests/main_tests/nbc_test.cpp b/src/mlpack/tests/main_tests/nbc_test.cpp index ebb58cab27..1e12cf9aa5 100644 --- a/src/mlpack/tests/main_tests/nbc_test.cpp +++ b/src/mlpack/tests/main_tests/nbc_test.cpp @@ -208,7 +208,7 @@ BOOST_AUTO_TEST_CASE(NBCModelReuseTest) // Input trained model. SetInputParam("test", std::move(testData)); SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + std::move(CLI::GetParam("output_model"))); mlpackMain(); @@ -226,6 +226,8 @@ BOOST_AUTO_TEST_CASE(NBCModelReuseTest) // matrix using saved model are same. CheckMatrices(output, CLI::GetParam>("output")); CheckMatrices(output_probs, CLI::GetParam("output_probs")); + + delete CLI::GetParam("output_model"); } /** @@ -244,11 +246,13 @@ BOOST_AUTO_TEST_CASE(NBCTrainingVerTest) // Input pre-trained model. SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + std::move(CLI::GetParam("output_model"))); Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; + + delete CLI::GetParam("output_model"); } /** diff --git a/src/mlpack/tests/main_tests/random_forest_test.cpp b/src/mlpack/tests/main_tests/random_forest_test.cpp index f4460ed752..340d34f1da 100644 --- a/src/mlpack/tests/main_tests/random_forest_test.cpp +++ b/src/mlpack/tests/main_tests/random_forest_test.cpp @@ -124,7 +124,7 @@ BOOST_AUTO_TEST_CASE(RandomForestModelReuseTest) // Input trained model. SetInputParam("test", std::move(testData)); SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + CLI::GetParam("output_model")); mlpackMain(); @@ -143,6 +143,8 @@ BOOST_AUTO_TEST_CASE(RandomForestModelReuseTest) // Check that initial predictions and predictions using saved model are same. CheckMatrices(predictions, CLI::GetParam>("predictions")); CheckMatrices(probabilities, CLI::GetParam("probabilities")); + + delete CLI::GetParam("output_model"); } /** @@ -206,11 +208,13 @@ BOOST_AUTO_TEST_CASE(RandomForestTrainingVerTest) // Input pre-trained model. SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + CLI::GetParam("output_model")); Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; + + delete CLI::GetParam("output_model"); } /** @@ -236,7 +240,7 @@ BOOST_AUTO_TEST_CASE(RandomForestDiffMinLeafSizeTest) // Calculate training accuracy. arma::Row predictions; - CLI::GetParam("output_model").rf.Classify(inputData, + CLI::GetParam("output_model")->rf.Classify(inputData, predictions); size_t correct = arma::accu(predictions == labels); @@ -252,7 +256,7 @@ BOOST_AUTO_TEST_CASE(RandomForestDiffMinLeafSizeTest) mlpackMain(); // Calculate training accuracy. - CLI::GetParam("output_model").rf.Classify(inputData, + CLI::GetParam("output_model")->rf.Classify(inputData, predictions); correct = arma::accu(predictions == labels); @@ -275,6 +279,8 @@ BOOST_AUTO_TEST_CASE(RandomForestDiffMinLeafSizeTest) double accuracy1 = (double(correct) / double(labels.n_elem) * 100); BOOST_REQUIRE(accuracy1 > accuracy10 && accuracy10 > accuracy20); + + delete CLI::GetParam("output_model"); } /** @@ -308,8 +314,9 @@ BOOST_AUTO_TEST_CASE(RandomForestDiffNumTreeTest) // Calculate training accuracy. arma::Row predictions; - CLI::GetParam("output_model").rf.Classify(testData, + CLI::GetParam("output_model")->rf.Classify(testData, predictions); + delete CLI::GetParam("output_model"); size_t correct = arma::accu(predictions == testLabels); double accuracy1 = (double(correct) / double(testLabels.n_elem) * 100); @@ -324,8 +331,9 @@ BOOST_AUTO_TEST_CASE(RandomForestDiffNumTreeTest) mlpackMain(); // Calculate training accuracy. - CLI::GetParam("output_model").rf.Classify(testData, + CLI::GetParam("output_model")->rf.Classify(testData, predictions); + delete CLI::GetParam("output_model"); correct = arma::accu(predictions == testLabels); double accuracy5 = (double(correct) / double(testLabels.n_elem) * 100); @@ -340,8 +348,9 @@ BOOST_AUTO_TEST_CASE(RandomForestDiffNumTreeTest) mlpackMain(); // Calculate training accuracy. - CLI::GetParam("output_model").rf.Classify(testData, + CLI::GetParam("output_model")->rf.Classify(testData, predictions); + delete CLI::GetParam("output_model"); correct = arma::accu(predictions == testLabels); double accuracy10 = (double(correct) / double(testLabels.n_elem) * 100); diff --git a/src/mlpack/tests/main_tests/softmax_regression_test.cpp b/src/mlpack/tests/main_tests/softmax_regression_test.cpp index 04dc10169a..358ad1b8bd 100644 --- a/src/mlpack/tests/main_tests/softmax_regression_test.cpp +++ b/src/mlpack/tests/main_tests/softmax_regression_test.cpp @@ -150,7 +150,7 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionModelReuseTest) // Input trained model. SetInputParam("test", std::move(testData)); SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + CLI::GetParam("output_model")); mlpackMain(); @@ -165,6 +165,8 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionModelReuseTest) // Check that initial predictions and final predicitons matrix // using saved model are same. CheckMatrices(predictions, CLI::GetParam>("predictions")); + + delete CLI::GetParam("output_model"); } /** From 30c2671bca28166f0edb13530532c5bf4e58da83 Mon Sep 17 00:00:00 2001 From: kris-singh Date: Sun, 27 Aug 2017 08:09:18 +0530 Subject: [PATCH 055/113] Rebase from Gan Layer --- src/mlpack/methods/ann/layer/CMakeLists.txt | 2 + .../layer/cross_entropy_error_with_logits.hpp | 104 ++++++++++++++++++ .../cross_entropy_error_with_logits_impl.hpp | 79 +++++++++++++ src/mlpack/methods/ann/layer/layer_types.hpp | 2 + src/mlpack/tests/ann_layer_test.cpp | 36 ++++++ 5 files changed, 223 insertions(+) create mode 100644 src/mlpack/methods/ann/layer/cross_entropy_error_with_logits.hpp create mode 100644 src/mlpack/methods/ann/layer/cross_entropy_error_with_logits_impl.hpp diff --git a/src/mlpack/methods/ann/layer/CMakeLists.txt b/src/mlpack/methods/ann/layer/CMakeLists.txt index 4729b2265c..3b027ad5e2 100644 --- a/src/mlpack/methods/ann/layer/CMakeLists.txt +++ b/src/mlpack/methods/ann/layer/CMakeLists.txt @@ -16,6 +16,8 @@ set(SOURCES convolution_impl.hpp cross_entropy_error.hpp cross_entropy_error_impl.hpp + cross_entropy_error_with_logits.hpp + cross_entropy_error_with_logits_impl.hpp dropconnect.hpp dropconnect_impl.hpp dropout.hpp diff --git a/src/mlpack/methods/ann/layer/cross_entropy_error_with_logits.hpp b/src/mlpack/methods/ann/layer/cross_entropy_error_with_logits.hpp new file mode 100644 index 0000000000..895468ca84 --- /dev/null +++ b/src/mlpack/methods/ann/layer/cross_entropy_error_with_logits.hpp @@ -0,0 +1,104 @@ +/** + * @file cross_entropy_error_with_logits.hpp + * @author Kris Singh + * + * Definition of the cross-entropy with logit performance function. + * + * 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_CROSS_ENTROPY_LOGIT_ERROR_HPP +#define MLPACK_METHODS_ANN_LAYER_CROSS_ENTROPY_LOGIT_ERROR_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * The cross-entropy with logits performance function measures the network's + * performance according to the cross-entropy function. + * between the input and target distributions. + * For more detail look here goo.gl/tRjS6j + * + * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, + * 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 CrossEntropyErrorLogits +{ + public: + /** + * Create the CrossEntropyErrorLogits object. + * + * @param eps The minimum value used for computing logarithms + * and denominators in a numerically stable way. + */ + CrossEntropyErrorLogits(); + + /* + * Computes the cross-entropy with logits function. + * + * @param input Input data used for evaluating the specified function. + * @param output Resulting output activation. + */ + template + double Forward(const arma::Mat&& input, const arma::Mat&& target); + /** + * Ordinary feed backward pass of a neural network. + * + * @param input The propagated input activation. + * @param target The target vector. + * @param output The calculated error. + */ + template + void Backward(const arma::Mat&& input, + const arma::Mat&& target, + arma::Mat&& output); + + //! Get the input parameter. + InputDataType& InputParameter() const { return inputParameter; } + //! Modify the input parameter. + InputDataType& InputParameter() { return inputParameter; } + + //! Get the output parameter. + OutputDataType& OutputParameter() const { return outputParameter; } + //! Modify the output parameter. + OutputDataType& OutputParameter() { return outputParameter; } + + //! Get the delta. + OutputDataType& Delta() const { return delta; } + //! Modify the delta. + OutputDataType& Delta() { return delta; } + + /** + * Serialize the layer. + */ + template + 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; +}; // class CrossEntropyErrorLogits + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "cross_entropy_error_with_logits_impl.hpp" + +#endif diff --git a/src/mlpack/methods/ann/layer/cross_entropy_error_with_logits_impl.hpp b/src/mlpack/methods/ann/layer/cross_entropy_error_with_logits_impl.hpp new file mode 100644 index 0000000000..2973b17228 --- /dev/null +++ b/src/mlpack/methods/ann/layer/cross_entropy_error_with_logits_impl.hpp @@ -0,0 +1,79 @@ +/** + * @file cross_entropy_error_with_logits_impl.hpp + * @author Kris Singh + * + * Implementation of the cross-entropy with logits performance function. + * + * 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_CROSS_ENTROPY_LOGIT_ERROR_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_CROSS_ENTROPY_LOGIT_ERROR_IMPL_HPP + +// In case it hasn't yet been included. +#include "cross_entropy_error_with_logits.hpp" +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +CrossEntropyErrorLogits +::CrossEntropyErrorLogits() +{ + // Nothing to do here. +} + +template +template +double CrossEntropyErrorLogits::Forward( + const arma::Mat&& input, const arma::Mat&& target) +{ + eT loss = 0; + for (size_t i = 0; i < input.n_elem; i++) + if (input(i) > 0) + { + loss += input(i) - input(i) * target(i) + + SoftplusFunction::Fn(-std::abs(input(i))); + } + else + { + loss += input(i) * target(i) + + SoftplusFunction::Fn(-std::abs(input(i)));; + } + + return loss / input.n_elem; +} + +template +template +void CrossEntropyErrorLogits::Backward( + const arma::Mat&& input, + const arma::Mat&& target, + arma::Mat&& output) +{ + output = input; + for (size_t i = 0; i < input.n_elem; i++) + { + if (input(i) > 0) + output(i) = 1 - target(i) - SoftplusFunction::Deriv(-std::abs(input(i))); + else + output(i) = -(target(i)) + SoftplusFunction::Deriv(-std::abs(input(i))); + } +} + +template +template +void CrossEntropyErrorLogits::Serialize( + Archive& /* ar */, + const unsigned int /* version */) +{ + // Nothing to do here +} + +} // namespace ann +} // namespace mlpack + +#endif diff --git a/src/mlpack/methods/ann/layer/layer_types.hpp b/src/mlpack/methods/ann/layer/layer_types.hpp index ddf377a84d..be207e583c 100644 --- a/src/mlpack/methods/ann/layer/layer_types.hpp +++ b/src/mlpack/methods/ann/layer/layer_types.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -93,6 +94,7 @@ using LayerTypes = boost::variant< NaiveConvolution, NaiveConvolution, arma::mat, arma::mat>*, CrossEntropyError*, + CrossEntropyErrorLogits*, DropConnect*, Dropout*, ELU*, diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 25edc36c94..bf51b78125 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1144,6 +1144,42 @@ BOOST_AUTO_TEST_CASE(SimpleLogSoftmaxLayerTest) arma::mat("1.6487; 0.6487") - delta)), 1e-3); } +BOOST_AUTO_TEST_CASE(SimpleCrossEntropyErrorLogitLayerTest) +{ + arma::mat input1, input2, output, target1, target2, expectedOutput; + CrossEntropyErrorLogits<> module; + + // Test the Forward function on a user generator input and compare it against + // the manually calculated result. + input1 = arma::mat("0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5"); + target1 = arma::zeros(1, 8); + double error1 = module.Forward(std::move(input1), std::move(target1)); + // value computed using tf + BOOST_REQUIRE_SMALL(error1 - 0.97407699, 1e-7); + + input2 = arma::mat("1 2 3 4 5"); + target2 = arma::mat("0 0 1 0 1"); + double error2 = module.Forward(std::move(input2), std::move(target2)); + BOOST_REQUIRE_SMALL(error2 - 1.5027283, 1e-6); + + // Test the Backward function. + module.Backward(std::move(input1), std::move(target1), std::move(output)); + for (size_t i = 0; i < output.n_elem; i++) + BOOST_REQUIRE_SMALL(output(i) - 0.62245929, 1e-5); + BOOST_REQUIRE_EQUAL(output.n_rows, input1.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input1.n_cols); + + expectedOutput = arma::mat( + "0.7310586 0.88079709 -0.04742587 0.98201376 -0.00669285"); + module.Backward(std::move(input2), std::move(target2), std::move(output)); + for (size_t i = 0; i < output.n_elem; i++) + BOOST_REQUIRE_SMALL(output(i) - expectedOutput(i), 1e-5); + + BOOST_REQUIRE_EQUAL(output.n_rows, input2.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input2.n_cols); +} + + /* * Simple test for the cross-entropy error performance function. */ From c7db6e798d96465583227eb9908a2c2a6f7333bd Mon Sep 17 00:00:00 2001 From: kris-singh Date: Tue, 29 Aug 2017 08:05:21 +0530 Subject: [PATCH 056/113] Fix comment vectorise loop --- src/mlpack/methods/ann/layer/CMakeLists.txt | 4 +- .../cross_entropy_error_with_logits_impl.hpp | 79 ------------------- src/mlpack/methods/ann/layer/layer_types.hpp | 4 +- ...ts.hpp => sigmoid_cross_entropy_error.hpp} | 26 +++--- .../sigmoid_cross_entropy_error_impl.hpp | 75 ++++++++++++++++++ src/mlpack/tests/ann_layer_test.cpp | 10 +-- 6 files changed, 96 insertions(+), 102 deletions(-) delete mode 100644 src/mlpack/methods/ann/layer/cross_entropy_error_with_logits_impl.hpp rename src/mlpack/methods/ann/layer/{cross_entropy_error_with_logits.hpp => sigmoid_cross_entropy_error.hpp} (78%) create mode 100644 src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp diff --git a/src/mlpack/methods/ann/layer/CMakeLists.txt b/src/mlpack/methods/ann/layer/CMakeLists.txt index 3b027ad5e2..50aea14eaf 100644 --- a/src/mlpack/methods/ann/layer/CMakeLists.txt +++ b/src/mlpack/methods/ann/layer/CMakeLists.txt @@ -16,8 +16,6 @@ set(SOURCES convolution_impl.hpp cross_entropy_error.hpp cross_entropy_error_impl.hpp - cross_entropy_error_with_logits.hpp - cross_entropy_error_with_logits_impl.hpp dropconnect.hpp dropconnect_impl.hpp dropout.hpp @@ -67,6 +65,8 @@ set(SOURCES recurrent_attention_impl.hpp reinforce_normal.hpp reinforce_normal_impl.hpp + sigmoid_cross_entropy_error.hpp + sigmoid_cross_entropy_error_impl.hpp select.hpp select_impl.hpp sequential.hpp diff --git a/src/mlpack/methods/ann/layer/cross_entropy_error_with_logits_impl.hpp b/src/mlpack/methods/ann/layer/cross_entropy_error_with_logits_impl.hpp deleted file mode 100644 index 2973b17228..0000000000 --- a/src/mlpack/methods/ann/layer/cross_entropy_error_with_logits_impl.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file cross_entropy_error_with_logits_impl.hpp - * @author Kris Singh - * - * Implementation of the cross-entropy with logits performance function. - * - * 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_CROSS_ENTROPY_LOGIT_ERROR_IMPL_HPP -#define MLPACK_METHODS_ANN_LAYER_CROSS_ENTROPY_LOGIT_ERROR_IMPL_HPP - -// In case it hasn't yet been included. -#include "cross_entropy_error_with_logits.hpp" -#include - -namespace mlpack { -namespace ann /** Artificial Neural Network. */ { - -template -CrossEntropyErrorLogits -::CrossEntropyErrorLogits() -{ - // Nothing to do here. -} - -template -template -double CrossEntropyErrorLogits::Forward( - const arma::Mat&& input, const arma::Mat&& target) -{ - eT loss = 0; - for (size_t i = 0; i < input.n_elem; i++) - if (input(i) > 0) - { - loss += input(i) - input(i) * target(i) + - SoftplusFunction::Fn(-std::abs(input(i))); - } - else - { - loss += input(i) * target(i) + - SoftplusFunction::Fn(-std::abs(input(i)));; - } - - return loss / input.n_elem; -} - -template -template -void CrossEntropyErrorLogits::Backward( - const arma::Mat&& input, - const arma::Mat&& target, - arma::Mat&& output) -{ - output = input; - for (size_t i = 0; i < input.n_elem; i++) - { - if (input(i) > 0) - output(i) = 1 - target(i) - SoftplusFunction::Deriv(-std::abs(input(i))); - else - output(i) = -(target(i)) + SoftplusFunction::Deriv(-std::abs(input(i))); - } -} - -template -template -void CrossEntropyErrorLogits::Serialize( - Archive& /* ar */, - const unsigned int /* version */) -{ - // Nothing to do here -} - -} // namespace ann -} // namespace mlpack - -#endif diff --git a/src/mlpack/methods/ann/layer/layer_types.hpp b/src/mlpack/methods/ann/layer/layer_types.hpp index be207e583c..327c1f94b0 100644 --- a/src/mlpack/methods/ann/layer/layer_types.hpp +++ b/src/mlpack/methods/ann/layer/layer_types.hpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -34,6 +33,7 @@ #include #include #include +#include #include // Convolution modules. @@ -94,7 +94,6 @@ using LayerTypes = boost::variant< NaiveConvolution, NaiveConvolution, arma::mat, arma::mat>*, CrossEntropyError*, - CrossEntropyErrorLogits*, DropConnect*, Dropout*, ELU*, @@ -118,6 +117,7 @@ using LayerTypes = boost::variant< Recurrent*, RecurrentAttention*, ReinforceNormal*, + SigmoidCrossEntropyError*, Select*, Sequential*, VRClassReward* diff --git a/src/mlpack/methods/ann/layer/cross_entropy_error_with_logits.hpp b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp similarity index 78% rename from src/mlpack/methods/ann/layer/cross_entropy_error_with_logits.hpp rename to src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp index 895468ca84..c812a591c7 100644 --- a/src/mlpack/methods/ann/layer/cross_entropy_error_with_logits.hpp +++ b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp @@ -1,5 +1,5 @@ /** - * @file cross_entropy_error_with_logits.hpp + * @file sigmoid_cross_entropy_error.hpp * @author Kris Singh * * Definition of the cross-entropy with logit performance function. @@ -9,8 +9,8 @@ * 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_CROSS_ENTROPY_LOGIT_ERROR_HPP -#define MLPACK_METHODS_ANN_LAYER_CROSS_ENTROPY_LOGIT_ERROR_HPP +#ifndef MLPACK_METHODS_ANN_LAYER_SIGMOID_CROSS_ENTROPY_ERROR_HPP +#define MLPACK_METHODS_ANN_LAYER_SIGMOID_CROSS_ENTROPY_ERROR_HPP #include @@ -18,7 +18,7 @@ namespace mlpack { namespace ann /** Artificial Neural Network. */ { /** - * The cross-entropy with logits performance function measures the network's + * The SigmoidCrossEntropyError performance function measures the network's * performance according to the cross-entropy function. * between the input and target distributions. * For more detail look here goo.gl/tRjS6j @@ -32,19 +32,16 @@ template < typename InputDataType = arma::mat, typename OutputDataType = arma::mat > -class CrossEntropyErrorLogits +class SigmoidCrossEntropyError { public: /** - * Create the CrossEntropyErrorLogits object. - * - * @param eps The minimum value used for computing logarithms - * and denominators in a numerically stable way. + * Create the SigmoidCrossEntropyError object. */ - CrossEntropyErrorLogits(); + SigmoidCrossEntropyError(); /* - * Computes the cross-entropy with logits function. + * Computes the Sigmoid CrossEntropy Error functions. * * @param input Input data used for evaluating the specified function. * @param output Resulting output activation. @@ -82,7 +79,7 @@ class CrossEntropyErrorLogits * Serialize the layer. */ template - void Serialize(Archive& /* ar */, const unsigned int /* version */); + void Serialize(Archive& ar, const unsigned int /* version */); private: //! Locally-stored delta object. @@ -93,12 +90,13 @@ class CrossEntropyErrorLogits //! Locally-stored output parameter object. OutputDataType outputParameter; -}; // class CrossEntropyErrorLogits + +}; // class SigmoidCrossEntropy } // namespace ann } // namespace mlpack // Include implementation. -#include "cross_entropy_error_with_logits_impl.hpp" +#include "sigmoid_cross_entropy_error_impl.hpp" #endif diff --git a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp new file mode 100644 index 0000000000..ad7cc1c874 --- /dev/null +++ b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp @@ -0,0 +1,75 @@ +/** + * @file sigmoid_cross_entropy_error_impl.hpp + * @author Kris Singh + * + * Implementation of the sigmoid cross entropy error performance function. + * + * 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_SIGMOID_CROSS_ENTROPY_ERROR +#define MLPACK_METHODS_ANN_LAYER_SIGMOID_CROSS_ENTROPY_ERROR + +// In case it hasn't yet been included. +#include "sigmoid_cross_entropy_error.hpp" +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +SigmoidCrossEntropyError +::SigmoidCrossEntropyError() +{ + // Nothing to do here. +} + +template +template +double SigmoidCrossEntropyError::Forward( + const arma::Mat&& input, const arma::Mat&& target) +{ + arma::uvec positive = arma::find(input > 0); + arma::mat output; + SoftplusFunction::Fn(static_cast(-arma::abs(input)), output); + double loss = arma::accu(input(positive)) - arma::accu(input % target) + + arma::accu(output); + + return loss; +} + +template +template +void SigmoidCrossEntropyError::Backward( + const arma::Mat&& input, + const arma::Mat&& target, + arma::Mat&& output) +{ + arma::mat temp; + + arma::uvec positive = arma::find(input > 0); + arma::uvec negative = arma::find(input < 0 || input == 0); + + SoftplusFunction::Deriv(static_cast(-arma::abs(input(positive))), + temp); + output(positive) = 1 - target(positive) - temp; + SoftplusFunction::Deriv(static_cast(-arma::abs(input(negative))), + temp); + output(negative) = -(target(negative)) - negative; +} + +template +template +void SigmoidCrossEntropyError::Serialize( + Archive& /* ar */, + const unsigned int /* version */) +{ + // Nothing to do here +} + +} // namespace ann +} // namespace mlpack + +#endif diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index bf51b78125..4f24ed5bfc 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -1144,10 +1143,10 @@ BOOST_AUTO_TEST_CASE(SimpleLogSoftmaxLayerTest) arma::mat("1.6487; 0.6487") - delta)), 1e-3); } -BOOST_AUTO_TEST_CASE(SimpleCrossEntropyErrorLogitLayerTest) +BOOST_AUTO_TEST_CASE(SimpleSigmoidCrossEntropyLayerTest) { arma::mat input1, input2, output, target1, target2, expectedOutput; - CrossEntropyErrorLogits<> module; + SigmoidCrossEntropyError<> module; // Test the Forward function on a user generator input and compare it against // the manually calculated result. @@ -1155,12 +1154,12 @@ BOOST_AUTO_TEST_CASE(SimpleCrossEntropyErrorLogitLayerTest) target1 = arma::zeros(1, 8); double error1 = module.Forward(std::move(input1), std::move(target1)); // value computed using tf - BOOST_REQUIRE_SMALL(error1 - 0.97407699, 1e-7); + BOOST_REQUIRE_SMALL(error1 / input1.n_elem - 0.97407699, 1e-7); input2 = arma::mat("1 2 3 4 5"); target2 = arma::mat("0 0 1 0 1"); double error2 = module.Forward(std::move(input2), std::move(target2)); - BOOST_REQUIRE_SMALL(error2 - 1.5027283, 1e-6); + BOOST_REQUIRE_SMALL(error2 / input2.n_elem - 1.5027283, 1e-6); // Test the Backward function. module.Backward(std::move(input1), std::move(target1), std::move(output)); @@ -1177,6 +1176,7 @@ BOOST_AUTO_TEST_CASE(SimpleCrossEntropyErrorLogitLayerTest) BOOST_REQUIRE_EQUAL(output.n_rows, input2.n_rows); BOOST_REQUIRE_EQUAL(output.n_cols, input2.n_cols); + } From c305e4cce94b8b4b49da30d7f484b6cc0b0ebd77 Mon Sep 17 00:00:00 2001 From: kris-singh Date: Tue, 29 Aug 2017 08:11:14 +0530 Subject: [PATCH 057/113] StyleFIx --- src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp | 1 - .../methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp | 2 +- src/mlpack/tests/ann_layer_test.cpp | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp index c812a591c7..575eb2d810 100644 --- a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp +++ b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp @@ -90,7 +90,6 @@ class SigmoidCrossEntropyError //! Locally-stored output parameter object. OutputDataType outputParameter; - }; // class SigmoidCrossEntropy } // namespace ann diff --git a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp index ad7cc1c874..d4c423e159 100644 --- a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp +++ b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp @@ -48,7 +48,7 @@ void SigmoidCrossEntropyError::Backward( arma::Mat&& output) { arma::mat temp; - + arma::uvec positive = arma::find(input > 0); arma::uvec negative = arma::find(input < 0 || input == 0); diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 4f24ed5bfc..219c85af2e 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1176,7 +1176,6 @@ BOOST_AUTO_TEST_CASE(SimpleSigmoidCrossEntropyLayerTest) BOOST_REQUIRE_EQUAL(output.n_rows, input2.n_rows); BOOST_REQUIRE_EQUAL(output.n_cols, input2.n_cols); - } From 965fb606bb763e1704a1087714319e3d0f5501aa Mon Sep 17 00:00:00 2001 From: kris-singh Date: Tue, 29 Aug 2017 17:41:55 +0530 Subject: [PATCH 058/113] Fix test --- .../methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp index d4c423e159..cc361b79d8 100644 --- a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp +++ b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp @@ -48,6 +48,7 @@ void SigmoidCrossEntropyError::Backward( arma::Mat&& output) { arma::mat temp; + output = input; arma::uvec positive = arma::find(input > 0); arma::uvec negative = arma::find(input < 0 || input == 0); From 20e6988097189b0a82ae8b37559758c0308fe56a Mon Sep 17 00:00:00 2001 From: kris-singh Date: Fri, 1 Sep 2017 15:37:19 +0530 Subject: [PATCH 059/113] Fix @zoq comments --- .../methods/ann/layer/sigmoid_cross_entropy_error.hpp | 9 +++++++-- .../ann/layer/sigmoid_cross_entropy_error_impl.hpp | 6 +++--- src/mlpack/tests/ann_layer_test.cpp | 6 +++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp index 575eb2d810..2171fb0d8d 100644 --- a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp +++ b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp @@ -21,6 +21,11 @@ namespace ann /** Artificial Neural Network. */ { * The SigmoidCrossEntropyError performance function measures the network's * performance according to the cross-entropy function. * between the input and target distributions. + * This function calculates the cross entropy + * given the real values instead of providing the sigmoid activations. + * The functions is much more numerically stable as can be found from the + * formula below. + * max(x, 0) - x * z + log(1 + exp(-abs(x))) * For more detail look here goo.gl/tRjS6j * * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, @@ -47,7 +52,7 @@ class SigmoidCrossEntropyError * @param output Resulting output activation. */ template - double Forward(const arma::Mat&& input, const arma::Mat&& target); + inline double Forward(const arma::Mat&& input, const arma::Mat&& target); /** * Ordinary feed backward pass of a neural network. * @@ -56,7 +61,7 @@ class SigmoidCrossEntropyError * @param output The calculated error. */ template - void Backward(const arma::Mat&& input, + inline void Backward(const arma::Mat&& input, const arma::Mat&& target, arma::Mat&& output); diff --git a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp index cc361b79d8..f48b7a78db 100644 --- a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp +++ b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp @@ -28,7 +28,7 @@ SigmoidCrossEntropyError template template -double SigmoidCrossEntropyError::Forward( +inline double SigmoidCrossEntropyError::Forward( const arma::Mat&& input, const arma::Mat&& target) { arma::uvec positive = arma::find(input > 0); @@ -42,13 +42,13 @@ double SigmoidCrossEntropyError::Forward( template template -void SigmoidCrossEntropyError::Backward( +inline void SigmoidCrossEntropyError::Backward( const arma::Mat&& input, const arma::Mat&& target, arma::Mat&& output) { arma::mat temp; - output = input; + output.set_size(input.n_rows, input.n_cols); arma::uvec positive = arma::find(input > 0); arma::uvec negative = arma::find(input < 0 || input == 0); diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 219c85af2e..822bc02fc5 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1143,6 +1143,10 @@ BOOST_AUTO_TEST_CASE(SimpleLogSoftmaxLayerTest) arma::mat("1.6487; 0.6487") - delta)), 1e-3); } +/* + * Simple test for the Sigmoid Cross Entropy Layer. + */ + BOOST_AUTO_TEST_CASE(SimpleSigmoidCrossEntropyLayerTest) { arma::mat input1, input2, output, target1, target2, expectedOutput; @@ -1153,7 +1157,7 @@ BOOST_AUTO_TEST_CASE(SimpleSigmoidCrossEntropyLayerTest) input1 = arma::mat("0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5"); target1 = arma::zeros(1, 8); double error1 = module.Forward(std::move(input1), std::move(target1)); - // value computed using tf + // Value computed using tensorflow. BOOST_REQUIRE_SMALL(error1 / input1.n_elem - 0.97407699, 1e-7); input2 = arma::mat("1 2 3 4 5"); From 5da6085710b6d50adfa8c63a1feb20e93b148195 Mon Sep 17 00:00:00 2001 From: kris-singh Date: Fri, 1 Sep 2017 16:20:36 +0530 Subject: [PATCH 060/113] Fix style issues --- src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp index 2171fb0d8d..19d86deff4 100644 --- a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp +++ b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp @@ -52,7 +52,8 @@ class SigmoidCrossEntropyError * @param output Resulting output activation. */ template - inline double Forward(const arma::Mat&& input, const arma::Mat&& target); + inline double Forward(const arma::Mat&& input, + const arma::Mat&& target); /** * Ordinary feed backward pass of a neural network. * From e1293aa3ac99805d8027baf4754349883dcdcca5 Mon Sep 17 00:00:00 2001 From: kris-singh Date: Sun, 3 Sep 2017 19:36:47 +0530 Subject: [PATCH 061/113] Fix style --- .../methods/ann/layer/sigmoid_cross_entropy_error.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp index 19d86deff4..5dfdb6ef71 100644 --- a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp +++ b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp @@ -25,7 +25,7 @@ namespace ann /** Artificial Neural Network. */ { * given the real values instead of providing the sigmoid activations. * The functions is much more numerically stable as can be found from the * formula below. - * max(x, 0) - x * z + log(1 + exp(-abs(x))) + * \f$max(x, 0) - x * z + \log(1 + e^{-|x|})\f$ * For more detail look here goo.gl/tRjS6j * * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, @@ -63,8 +63,8 @@ class SigmoidCrossEntropyError */ template inline void Backward(const arma::Mat&& input, - const arma::Mat&& target, - arma::Mat&& output); + const arma::Mat&& target, + arma::Mat&& output); //! Get the input parameter. InputDataType& InputParameter() const { return inputParameter; } From c2e170fab97de9c55f6054e0d0629ea0215fa962 Mon Sep 17 00:00:00 2001 From: kris-singh Date: Sun, 3 Sep 2017 21:17:23 +0530 Subject: [PATCH 062/113] Fix space --- src/mlpack/tests/ann_layer_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 822bc02fc5..0ae94ce549 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -1182,7 +1182,6 @@ BOOST_AUTO_TEST_CASE(SimpleSigmoidCrossEntropyLayerTest) BOOST_REQUIRE_EQUAL(output.n_cols, input2.n_cols); } - /* * Simple test for the cross-entropy error performance function. */ From ef783996e32c33283c92165024906daf0c8e4c5f Mon Sep 17 00:00:00 2001 From: Shikhar Jaiswal Date: Wed, 17 Jan 2018 07:11:26 +0530 Subject: [PATCH 063/113] Minor Fixes --- .../ann/layer/sigmoid_cross_entropy_error.hpp | 27 ++++++++++---- .../sigmoid_cross_entropy_error_impl.hpp | 37 +++++++------------ src/mlpack/tests/ann_layer_test.cpp | 36 ++++++++++++++---- 3 files changed, 61 insertions(+), 39 deletions(-) diff --git a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp index 5dfdb6ef71..f0dd42dfa1 100644 --- a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp +++ b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error.hpp @@ -1,6 +1,6 @@ /** * @file sigmoid_cross_entropy_error.hpp - * @author Kris Singh + * @author Kris Singh and Shikhar Jaiswal * * Definition of the cross-entropy with logit performance function. * @@ -19,14 +19,25 @@ namespace ann /** Artificial Neural Network. */ { /** * The SigmoidCrossEntropyError performance function measures the network's - * performance according to the cross-entropy function. - * between the input and target distributions. - * This function calculates the cross entropy + * performance according to the cross-entropy function between the input and + * target distributions. This function calculates the cross entropy * given the real values instead of providing the sigmoid activations. - * The functions is much more numerically stable as can be found from the - * formula below. + * The function uses this equivalent formulation: * \f$max(x, 0) - x * z + \log(1 + e^{-|x|})\f$ - * For more detail look here goo.gl/tRjS6j + * where x = input and z = target. + * + * For more information, see the following paper. + * + * @code + * @article{1702.05659, + * title={On Loss Functions for Deep Neural Networks in Classification}, + * author={Katarzyna Janocha, Wojciech Marian Czarnecki}, + * url = {http://arxiv.org/abs/1702.05659}, + * journal = {CoRR}, + * eprint={arXiv:1702.05659}, + * year={2017} + * } + * @endcode * * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, * arma::sp_mat or arma::cube). @@ -85,7 +96,7 @@ class SigmoidCrossEntropyError * Serialize the layer. */ template - void Serialize(Archive& ar, const unsigned int /* version */); + void serialize(Archive& ar, const unsigned int /* version */); private: //! Locally-stored delta object. diff --git a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp index f48b7a78db..67af3710f6 100644 --- a/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp +++ b/src/mlpack/methods/ann/layer/sigmoid_cross_entropy_error_impl.hpp @@ -1,6 +1,6 @@ /** * @file sigmoid_cross_entropy_error_impl.hpp - * @author Kris Singh + * @author Kris Singh and Shikhar Jaiswal * * Implementation of the sigmoid cross entropy error performance function. * @@ -9,8 +9,8 @@ * 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_SIGMOID_CROSS_ENTROPY_ERROR -#define MLPACK_METHODS_ANN_LAYER_SIGMOID_CROSS_ENTROPY_ERROR +#ifndef MLPACK_METHODS_ANN_LAYER_SIGMOID_CROSS_ENTROPY_ERROR_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_SIGMOID_CROSS_ENTROPY_ERROR_IMPL_HPP // In case it hasn't yet been included. #include "sigmoid_cross_entropy_error.hpp" @@ -31,39 +31,28 @@ template inline double SigmoidCrossEntropyError::Forward( const arma::Mat&& input, const arma::Mat&& target) { - arma::uvec positive = arma::find(input > 0); - arma::mat output; - SoftplusFunction::Fn(static_cast(-arma::abs(input)), output); - double loss = arma::accu(input(positive)) - arma::accu(input % target) + - arma::accu(output); - - return loss; + double maximum = 0; + for (size_t i = 0; i < input.n_elem; ++i) + { + maximum += std::max(input[i], 0.0) + + std::log(1 + std::exp(-std::abs(input[i]))); + } + return maximum - arma::accu(input % target); } template template -inline void SigmoidCrossEntropyError::Backward( +inline void SigmoidCrossEntropyError::Backward( const arma::Mat&& input, const arma::Mat&& target, arma::Mat&& output) { - arma::mat temp; - output.set_size(input.n_rows, input.n_cols); - - arma::uvec positive = arma::find(input > 0); - arma::uvec negative = arma::find(input < 0 || input == 0); - - SoftplusFunction::Deriv(static_cast(-arma::abs(input(positive))), - temp); - output(positive) = 1 - target(positive) - temp; - SoftplusFunction::Deriv(static_cast(-arma::abs(input(negative))), - temp); - output(negative) = -(target(negative)) - negative; + output = 1.0 / (1.0 + arma::exp(-input)) - target; } template template -void SigmoidCrossEntropyError::Serialize( +void SigmoidCrossEntropyError::serialize( Archive& /* ar */, const unsigned int /* version */) { diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 0ae94ce549..c768e744d5 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1143,13 +1144,13 @@ BOOST_AUTO_TEST_CASE(SimpleLogSoftmaxLayerTest) arma::mat("1.6487; 0.6487") - delta)), 1e-3); } -/* +/** * Simple test for the Sigmoid Cross Entropy Layer. */ - BOOST_AUTO_TEST_CASE(SimpleSigmoidCrossEntropyLayerTest) { - arma::mat input1, input2, output, target1, target2, expectedOutput; + arma::mat input1, input2, input3, output, target1, + target2, target3, expectedOutput; SigmoidCrossEntropyError<> module; // Test the Forward function on a user generator input and compare it against @@ -1157,18 +1158,27 @@ BOOST_AUTO_TEST_CASE(SimpleSigmoidCrossEntropyLayerTest) input1 = arma::mat("0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5"); target1 = arma::zeros(1, 8); double error1 = module.Forward(std::move(input1), std::move(target1)); + double expected = 0.97407699; // Value computed using tensorflow. - BOOST_REQUIRE_SMALL(error1 / input1.n_elem - 0.97407699, 1e-7); + BOOST_REQUIRE_SMALL(error1 / input1.n_elem - expected, 1e-7); input2 = arma::mat("1 2 3 4 5"); target2 = arma::mat("0 0 1 0 1"); double error2 = module.Forward(std::move(input2), std::move(target2)); - BOOST_REQUIRE_SMALL(error2 / input2.n_elem - 1.5027283, 1e-6); + expected = 1.5027283; + BOOST_REQUIRE_SMALL(error2 / input2.n_elem - expected, 1e-6); + + input3 = arma::mat("0 -1 -1 0 -1 0 0 -1"); + target3 = arma::mat("0 -1 -1 0 -1 0 0 -1"); + double error3 = module.Forward(std::move(input3), std::move(target3)); + expected = 0.00320443; + BOOST_REQUIRE_SMALL(error3 / input3.n_elem - expected, 1e-6); // Test the Backward function. module.Backward(std::move(input1), std::move(target1), std::move(output)); + expected = 0.62245929; for (size_t i = 0; i < output.n_elem; i++) - BOOST_REQUIRE_SMALL(output(i) - 0.62245929, 1e-5); + BOOST_REQUIRE_SMALL(output(i) - expected, 1e-5); BOOST_REQUIRE_EQUAL(output.n_rows, input1.n_rows); BOOST_REQUIRE_EQUAL(output.n_cols, input1.n_cols); @@ -1177,9 +1187,21 @@ BOOST_AUTO_TEST_CASE(SimpleSigmoidCrossEntropyLayerTest) module.Backward(std::move(input2), std::move(target2), std::move(output)); for (size_t i = 0; i < output.n_elem; i++) BOOST_REQUIRE_SMALL(output(i) - expectedOutput(i), 1e-5); - BOOST_REQUIRE_EQUAL(output.n_rows, input2.n_rows); BOOST_REQUIRE_EQUAL(output.n_cols, input2.n_cols); + + module.Backward(std::move(input3), std::move(target3), std::move(output)); + expectedOutput = arma::mat("0.5 1.2689414"); + for (size_t i = 0; i < 8; ++i) + { + double el = output.at(0, i); + if (std::abs(input3.at(i) - 0.0) < 1e-5) + BOOST_REQUIRE_SMALL(el - expectedOutput[0], 2e-6); + else + BOOST_REQUIRE_SMALL(el - expectedOutput[1], 2e-6); + } + BOOST_REQUIRE_EQUAL(output.n_rows, input3.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input3.n_cols); } /* From c7dc28b8c213c2422077ff60d69f9621ef07ebdc Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 29 Jan 2018 12:59:37 -0500 Subject: [PATCH 064/113] Add functions to clean up after tests. --- src/mlpack/bindings/tests/CMakeLists.txt | 4 ++ src/mlpack/bindings/tests/clean_memory.cpp | 54 ++++++++++++++++++ src/mlpack/bindings/tests/clean_memory.hpp | 24 ++++++++ .../tests/delete_allocated_memory.hpp | 56 ++++++++++++++++++ .../bindings/tests/get_allocated_memory.hpp | 57 +++++++++++++++++++ src/mlpack/bindings/tests/test_option.hpp | 6 ++ 6 files changed, 201 insertions(+) create mode 100644 src/mlpack/bindings/tests/clean_memory.cpp create mode 100644 src/mlpack/bindings/tests/clean_memory.hpp create mode 100644 src/mlpack/bindings/tests/delete_allocated_memory.hpp create mode 100644 src/mlpack/bindings/tests/get_allocated_memory.hpp diff --git a/src/mlpack/bindings/tests/CMakeLists.txt b/src/mlpack/bindings/tests/CMakeLists.txt index 5955a0a514..70b9928f91 100644 --- a/src/mlpack/bindings/tests/CMakeLists.txt +++ b/src/mlpack/bindings/tests/CMakeLists.txt @@ -1,8 +1,12 @@ # Define the files we need to compile. # Anything not in this list will not be compiled into mlpack. set(SOURCES + clean_memory.hpp + clean_memory.cpp test_option.hpp ignore_check.hpp + delete_allocated_memory.hpp + get_allocated_memory.hpp get_param.hpp get_printable_param.hpp get_printable_param_impl.hpp diff --git a/src/mlpack/bindings/tests/clean_memory.cpp b/src/mlpack/bindings/tests/clean_memory.cpp new file mode 100644 index 0000000000..dd40020177 --- /dev/null +++ b/src/mlpack/bindings/tests/clean_memory.cpp @@ -0,0 +1,54 @@ +/** + * @file clean_memory.cpp + * @author Ryan Curtin + * + * Delete any pointers held by the CLI object. + */ +#include "clean_memory.hpp" + +#include + +namespace mlpack { +namespace bindings { +namespace tests { + +/** + * Delete any pointers held by the CLI object. + */ +void CleanMemory() +{ + // If we are holding any pointers, then we "own" them. But we may hold the + // same pointer twice, so we have to be careful to not delete it multiple + // times. + std::unordered_map memoryAddresses; + auto it = CLI::Parameters().begin(); + while (it != CLI::Parameters().end()) + { + const util::ParamData& data = it->second; + + void* result; + CLI::GetSingleton().functionMap[data.tname]["GetAllocatedMemory"](data, + NULL, (void*) &result); + if (result != NULL && memoryAddresses.count(result) == 0) + memoryAddresses[result] = &data; + + ++it; + } + + // Now we have all the unique addresses that need to be deleted. + std::unordered_map::const_iterator it2; + it2 = memoryAddresses.begin(); + while (it2 != memoryAddresses.end()) + { + const util::ParamData& data = *(it2->second); + + CLI::GetSingleton().functionMap[data.tname]["DeleteAllocatedMemory"](data, + NULL, NULL); + + ++it2; + } +} + +} // namespace tests +} // namespace bindings +} // namespace mlpack diff --git a/src/mlpack/bindings/tests/clean_memory.hpp b/src/mlpack/bindings/tests/clean_memory.hpp new file mode 100644 index 0000000000..1035b7f5cb --- /dev/null +++ b/src/mlpack/bindings/tests/clean_memory.hpp @@ -0,0 +1,24 @@ +/** + * @file clean_memory.hpp + * @author Ryan Curtin + * + * Delete any unique pointers that are held by the CLI object. This is similar + * to the code in end_program.hpp. + */ +#ifndef MLPACK_BINDINGS_TESTS_CLEAN_MEMORY_HPP +#define MLPACK_BINDINGS_TESTS_CLEAN_MEMORY_HPP + +namespace mlpack { +namespace bindings { +namespace tests { + +/** + * Delete any unique pointers that are held by the CLI object. + */ +void CleanMemory(); + +} // namespace tests +} // namespace bindings +} // namespace mlpack + +#endif diff --git a/src/mlpack/bindings/tests/delete_allocated_memory.hpp b/src/mlpack/bindings/tests/delete_allocated_memory.hpp new file mode 100644 index 0000000000..f39deb113b --- /dev/null +++ b/src/mlpack/bindings/tests/delete_allocated_memory.hpp @@ -0,0 +1,56 @@ +/** + * @file delete_allocated_memory.hpp + * @author Ryan Curtin + * + * If any memory has been allocated by the parameter, delete it. + */ +#ifndef MLPACK_BINDINGS_CLI_DELETE_ALLOCATED_MEMORY_HPP +#define MLPACK_BINDINGS_CLI_DELETE_ALLOCATED_MEMORY_HPP + +#include + +namespace mlpack { +namespace bindings { +namespace tests { + +template +void DeleteAllocatedMemoryImpl( + const util::ParamData& /* d */, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0) +{ + // Do nothing. +} + +template +void DeleteAllocatedMemoryImpl( + const util::ParamData& /* d */, + const typename boost::enable_if>::type* = 0) +{ + // Do nothing. +} + +template +void DeleteAllocatedMemoryImpl( + const util::ParamData& d, + const typename boost::disable_if>::type* = 0, + const typename boost::enable_if>::type* = 0) +{ + // Delete the allocated memory (hopefully we actually own it). + delete *boost::any_cast(&d.value); +} + +template +void DeleteAllocatedMemory( + const util::ParamData& d, + const void* /* input */, + void* /* output */) +{ + DeleteAllocatedMemoryImpl::type>(d); +} + +} // namespace cli +} // namespace bindings +} // namespace mlpack + +#endif diff --git a/src/mlpack/bindings/tests/get_allocated_memory.hpp b/src/mlpack/bindings/tests/get_allocated_memory.hpp new file mode 100644 index 0000000000..ec53740a40 --- /dev/null +++ b/src/mlpack/bindings/tests/get_allocated_memory.hpp @@ -0,0 +1,57 @@ +/** + * @file get_allocated_memory.hpp + * @author Ryan Curtin + * + * If the parameter has a type that may need to be deleted, return the address + * of that object. Otherwise return NULL. + */ +#ifndef MLPACK_BINDINGS_CLI_GET_ALLOCATED_MEMORY_HPP +#define MLPACK_BINDINGS_CLI_GET_ALLOCATED_MEMORY_HPP + +#include + +namespace mlpack { +namespace bindings { +namespace tests { + +template +void* GetAllocatedMemory( + const util::ParamData& /* d */, + const typename boost::disable_if>::type* = 0, + const typename boost::disable_if>::type* = 0) +{ + return NULL; +} + +template +void* GetAllocatedMemory( + const util::ParamData& /* d */, + const typename boost::enable_if>::type* = 0) +{ + return NULL; +} + +template +void* GetAllocatedMemory( + const util::ParamData& d, + const typename boost::disable_if>::type* = 0, + const typename boost::enable_if>::type* = 0) +{ + // Here we have a model; return its memory location. + return *boost::any_cast(&d.value); +} + +template +void GetAllocatedMemory(const util::ParamData& d, + const void* /* input */, + void* output) +{ + *((void**) output) = + GetAllocatedMemory::type>(d); +} + +} // namespace cli +} // namespace bindings +} // namespace mlpack + +#endif diff --git a/src/mlpack/bindings/tests/test_option.hpp b/src/mlpack/bindings/tests/test_option.hpp index 336d9b93db..32f2fd4222 100644 --- a/src/mlpack/bindings/tests/test_option.hpp +++ b/src/mlpack/bindings/tests/test_option.hpp @@ -18,6 +18,8 @@ #include #include "get_printable_param.hpp" #include "get_param.hpp" +#include "get_allocated_memory.hpp" +#include "delete_allocated_memory.hpp" namespace mlpack { namespace bindings { @@ -90,6 +92,10 @@ class TestOption CLI::GetSingleton().functionMap[tname]["GetPrintableParam"] = &GetPrintableParam; CLI::GetSingleton().functionMap[tname]["GetParam"] = &GetParam; + CLI::GetSingleton().functionMap[tname]["GetAllocatedMemory"] = + &GetAllocatedMemory; + CLI::GetSingleton().functionMap[tname]["DeleteAllocatedMemory"] = + &DeleteAllocatedMemory; CLI::Add(std::move(data)); From fdb379979755e7b22e4c8160883e5cd8ff2dfda3 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 29 Jan 2018 13:00:11 -0500 Subject: [PATCH 065/113] Fix subtle memory leak. --- .../methods/linear_regression/linear_regression_main.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/linear_regression/linear_regression_main.cpp b/src/mlpack/methods/linear_regression/linear_regression_main.cpp index d98a385f9c..c1e33cd069 100644 --- a/src/mlpack/methods/linear_regression/linear_regression_main.cpp +++ b/src/mlpack/methods/linear_regression/linear_regression_main.cpp @@ -170,8 +170,13 @@ static void mlpackMain() // Ensure that test file data has the right number of features. if ((lr->Parameters().n_elem - 1) != points.n_rows) { - Log::Fatal << "The model was trained on " << lr->Parameters().n_elem - 1 - << "-dimensional data, but the test points in '" + // If we built the model, nothing will free it so we have to... + const size_t dimensions = lr->Parameters().n_elem - 1; + if (computeModel) + delete lr; + + Log::Fatal << "The model was trained on " << dimensions << "-dimensional " + << "data, but the test points in '" << CLI::GetPrintableParam("test") << "' are " << points.n_rows << "-dimensional!" << endl; } From 2a5304b7b735f10f19dc4033f0ac594dd42febbd Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 29 Jan 2018 13:00:32 -0500 Subject: [PATCH 066/113] Add tests for GetAllocatedMemory() and DeleteAllocatedMemory(). --- src/mlpack/tests/cli_binding_test.cpp | 93 +++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/src/mlpack/tests/cli_binding_test.cpp b/src/mlpack/tests/cli_binding_test.cpp index 0aba4f49e4..adab141c9f 100644 --- a/src/mlpack/tests/cli_binding_test.cpp +++ b/src/mlpack/tests/cli_binding_test.cpp @@ -538,4 +538,97 @@ BOOST_AUTO_TEST_CASE(SetParamDatasetInfoMatTest) BOOST_REQUIRE_EQUAL(get<1>(t3), "new_filename.csv"); } +// Test that GetAllocatedMemory() will properly return NULL for a non-model +// type. +BOOST_AUTO_TEST_CASE(GetAllocatedMemoryNonModelTest) +{ + util::ParamData d; + + bool b = true; + d.value = boost::any(b); + d.input = true; + + void* result = (void*) 1; // Invalid pointer, should be overwritten. + + GetAllocatedMemory((const util::ParamData&) d, + (const void*) NULL, (void*) &result); + + BOOST_REQUIRE_EQUAL(result, (void*) NULL); + + // Also test with a matrix type. + arma::mat test(10, 10, arma::fill::ones); + string filename = "test.csv"; + tuple t = make_tuple(test, filename); + d.value = boost::any(t); + + result = (void*) 1; + + GetAllocatedMemory((const util::ParamData&) d, + (const void*) NULL, (void*) &result); + + BOOST_REQUIRE_EQUAL(result, (void*) NULL); +} + +// Test that GetAllocatedMemory() will properly return pointers for a +// serializable model type. +BOOST_AUTO_TEST_CASE(GetAllocatedMemoryModelTest) +{ + util::ParamData d; + + GaussianKernel g(2.0); + string filename = "hello.bin"; + tuple t = make_tuple(&g, filename); + d.value = boost::any(t); + d.input = true; + + void* result = NULL; + + GetAllocatedMemory((const util::ParamData&) d, + (const void*) NULL, (void*) &result); + + BOOST_REQUIRE_EQUAL(&g, (GaussianKernel*) result); +} + +// Test that calling DeleteAllocatedMemory() on non-model types does not delete +// pointers. +BOOST_AUTO_TEST_CASE(DeleteAllocatedMemoryNonModelTest) +{ + util::ParamData d; + + bool b = true; + d.value = boost::any(b); + d.input = true; + + DeleteAllocatedMemory((const util::ParamData&) d, + (const void*) NULL, (void*) NULL); + + arma::mat test(10, 10, arma::fill::ones); + string filename = "test.csv"; + tuple t = make_tuple(test, filename); + d.value = boost::any(t); + + DeleteAllocatedMemory((const util::ParamData&) d, + (const void*) NULL, (void*) NULL); +} + +// Test that DeleteAllocatedMemory() will properly delete pointers for a +// serializable model type. +BOOST_AUTO_TEST_CASE(DeleteAllocatedMemoryModelTest) +{ + // This test will just delete it, and we'll hope that it worked and that + // valgrind won't throw any issues (so really we can't *quite* test this in + // the context of the boost unit test framework). + util::ParamData d; + + GaussianKernel* g = new GaussianKernel(2.0); + string filename = "hello.bin"; + tuple t = make_tuple(g, filename); + + d.value = boost::any(t); + d.input = false; + + DeleteAllocatedMemory((const util::ParamData&) d, + (const void*) NULL, (void*) NULL); +} + BOOST_AUTO_TEST_SUITE_END(); From 1096b2606190dbd4deea551e7d0d12b791450047 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 29 Jan 2018 13:01:30 -0500 Subject: [PATCH 067/113] Add header guards. --- src/mlpack/tests/main_tests/test_helper.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mlpack/tests/main_tests/test_helper.hpp b/src/mlpack/tests/main_tests/test_helper.hpp index 0043b6d242..12cb72c715 100644 --- a/src/mlpack/tests/main_tests/test_helper.hpp +++ b/src/mlpack/tests/main_tests/test_helper.hpp @@ -9,6 +9,10 @@ * 3-clause BSD license along with mlpack. If not, see * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ +#ifndef MLPACK_TESTS_MAIN_TESTS_TEST_HELPER_HPP +#define MLPACK_TESTS_MAIN_TESTS_TEST_HELPER_HPP + +#include namespace mlpack { namespace util { @@ -31,3 +35,5 @@ void SetInputParam(const std::string& name, T&& value) } // namespace util } // namespace mlpack + +#endif From 9d59cc82e033347e7bbb56c76008c7bbc972b5ef Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 29 Jan 2018 13:01:38 -0500 Subject: [PATCH 068/113] Correctly handle memory in all main tests. --- src/mlpack/core/util/mlpack_main.hpp | 1 + .../tests/main_tests/decision_stump_test.cpp | 8 ++--- .../tests/main_tests/decision_tree_test.cpp | 1 + src/mlpack/tests/main_tests/emst_test.cpp | 1 + .../main_tests/linear_regression_test.cpp | 3 ++ src/mlpack/tests/main_tests/nbc_test.cpp | 9 ++--- src/mlpack/tests/main_tests/pca_test.cpp | 1 + .../tests/main_tests/perceptron_test.cpp | 7 ++-- .../main_tests/preprocess_binarize_test.cpp | 1 + .../main_tests/preprocess_imputer_test.cpp | 1 + .../main_tests/preprocess_split_test.cpp | 1 + .../tests/main_tests/random_forest_test.cpp | 24 +++++++------- .../main_tests/softmax_regression_test.cpp | 33 +++++++++---------- 13 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/mlpack/core/util/mlpack_main.hpp b/src/mlpack/core/util/mlpack_main.hpp index e675d3d1b0..36df283031 100644 --- a/src/mlpack/core/util/mlpack_main.hpp +++ b/src/mlpack/core/util/mlpack_main.hpp @@ -74,6 +74,7 @@ int main(int argc, char** argv) #include #include +#include // These functions will do nothing. #define PRINT_PARAM_STRING(A) std::string(" ") diff --git a/src/mlpack/tests/main_tests/decision_stump_test.cpp b/src/mlpack/tests/main_tests/decision_stump_test.cpp index 02a6212471..f5de6b89d8 100644 --- a/src/mlpack/tests/main_tests/decision_stump_test.cpp +++ b/src/mlpack/tests/main_tests/decision_stump_test.cpp @@ -35,6 +35,7 @@ struct DecisionStumpTestFixture ~DecisionStumpTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; @@ -136,6 +137,9 @@ BOOST_AUTO_TEST_CASE(DecisionStumpLabelsLessDimensionTest) arma::Row predictions; predictions = std::move(CLI::GetParam>("predictions")); + // Delete the previous model. + bindings::tests::CleanMemory(); + // Now train DS with labels provided. // Delete last row of inputData. @@ -213,8 +217,6 @@ BOOST_AUTO_TEST_CASE(DecisionStumpModelReuseTest) // Check that initial predictions and final predicitons matrix // using saved model are same. CheckMatrices(predictions, CLI::GetParam>("predictions")); - - delete CLI::GetParam("output_model"); } /** @@ -256,8 +258,6 @@ BOOST_AUTO_TEST_CASE(DecisionStumpTrainingVerTest) Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; - - delete CLI::GetParam("output_model"); } BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/main_tests/decision_tree_test.cpp b/src/mlpack/tests/main_tests/decision_tree_test.cpp index 3511239f40..7e48d3ecbe 100644 --- a/src/mlpack/tests/main_tests/decision_tree_test.cpp +++ b/src/mlpack/tests/main_tests/decision_tree_test.cpp @@ -36,6 +36,7 @@ struct DecisionTreeTestFixture ~DecisionTreeTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; diff --git a/src/mlpack/tests/main_tests/emst_test.cpp b/src/mlpack/tests/main_tests/emst_test.cpp index f49d934a88..87ca2cd3a9 100644 --- a/src/mlpack/tests/main_tests/emst_test.cpp +++ b/src/mlpack/tests/main_tests/emst_test.cpp @@ -38,6 +38,7 @@ struct EMSTTestFixture ~EMSTTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; diff --git a/src/mlpack/tests/main_tests/linear_regression_test.cpp b/src/mlpack/tests/main_tests/linear_regression_test.cpp index 28a205aacd..d24e928844 100644 --- a/src/mlpack/tests/main_tests/linear_regression_test.cpp +++ b/src/mlpack/tests/main_tests/linear_regression_test.cpp @@ -32,6 +32,7 @@ struct LRTestFixture ~LRTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; @@ -66,6 +67,7 @@ BOOST_AUTO_TEST_CASE(LRDifferentLambdas) mlpackMain(); const double testY1 = CLI::GetParam("output_predictions")(0); + bindings::tests::CleanMemory(); ResetSettings(); SetInputParam("training", std::move(trainX)); @@ -100,6 +102,7 @@ BOOST_AUTO_TEST_CASE(LRResponsesRepresentation) mlpackMain(); const double testY1 = CLI::GetParam("output_predictions")(0); + bindings::tests::CleanMemory(); ResetSettings(); arma::mat trainX2({1.0, 2.0, 3.0}); diff --git a/src/mlpack/tests/main_tests/nbc_test.cpp b/src/mlpack/tests/main_tests/nbc_test.cpp index 1e12cf9aa5..212e0d1d98 100644 --- a/src/mlpack/tests/main_tests/nbc_test.cpp +++ b/src/mlpack/tests/main_tests/nbc_test.cpp @@ -35,6 +35,7 @@ struct NBCTestFixture ~NBCTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; @@ -142,6 +143,8 @@ BOOST_AUTO_TEST_CASE(NBCLabelsLessDimensionTest) output = std::move(CLI::GetParam>("output")); output_probs = std::move(CLI::GetParam("output_probs")); + bindings::tests::CleanMemory(); + // Now train NBC with labels provided. inputData.shed_row(inputData.n_rows - 1); @@ -226,8 +229,6 @@ BOOST_AUTO_TEST_CASE(NBCModelReuseTest) // matrix using saved model are same. CheckMatrices(output, CLI::GetParam>("output")); CheckMatrices(output_probs, CLI::GetParam("output_probs")); - - delete CLI::GetParam("output_model"); } /** @@ -251,8 +252,6 @@ BOOST_AUTO_TEST_CASE(NBCTrainingVerTest) Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; - - delete CLI::GetParam("output_model"); } /** @@ -294,6 +293,8 @@ BOOST_AUTO_TEST_CASE(NBCIncrementalVarianceTest) BOOST_REQUIRE_EQUAL(CLI::GetParam>("output").n_rows, 1); BOOST_REQUIRE_EQUAL(CLI::GetParam("output_probs").n_rows, 2); + bindings::tests::CleanMemory(); + // Reset data passed. CLI::GetSingleton().Parameters()["training"].wasPassed = false; CLI::GetSingleton().Parameters()["incremental_variance"].wasPassed = false; diff --git a/src/mlpack/tests/main_tests/pca_test.cpp b/src/mlpack/tests/main_tests/pca_test.cpp index a191aef906..b2b51984ed 100644 --- a/src/mlpack/tests/main_tests/pca_test.cpp +++ b/src/mlpack/tests/main_tests/pca_test.cpp @@ -31,6 +31,7 @@ struct PCATestFixture ~PCATestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; diff --git a/src/mlpack/tests/main_tests/perceptron_test.cpp b/src/mlpack/tests/main_tests/perceptron_test.cpp index 653a3ccbe4..d54dd80aba 100644 --- a/src/mlpack/tests/main_tests/perceptron_test.cpp +++ b/src/mlpack/tests/main_tests/perceptron_test.cpp @@ -35,6 +35,7 @@ struct PerceptronTestFixture ~PerceptronTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; @@ -137,7 +138,9 @@ BOOST_AUTO_TEST_CASE(PerceptronLabelsLessDimensionTest) arma::Row output; output = std::move(CLI::GetParam>("output")); - // Now train pereptron with labels provided. + bindings::tests::CleanMemory(); + + // Now train perceptron with labels provided. // Input training data. SetInputParam("training", std::move(inputData)); @@ -195,7 +198,7 @@ BOOST_AUTO_TEST_CASE(PerceptronModelReuseTest) // Input trained model. SetInputParam("test", std::move(testData)); SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + CLI::GetParam("output_model")); mlpackMain(); diff --git a/src/mlpack/tests/main_tests/preprocess_binarize_test.cpp b/src/mlpack/tests/main_tests/preprocess_binarize_test.cpp index 5f47d0dad9..bf93f75464 100644 --- a/src/mlpack/tests/main_tests/preprocess_binarize_test.cpp +++ b/src/mlpack/tests/main_tests/preprocess_binarize_test.cpp @@ -35,6 +35,7 @@ struct PreprocessBinarizeTestFixture ~PreprocessBinarizeTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; diff --git a/src/mlpack/tests/main_tests/preprocess_imputer_test.cpp b/src/mlpack/tests/main_tests/preprocess_imputer_test.cpp index bf30f102eb..ce1ed4f104 100644 --- a/src/mlpack/tests/main_tests/preprocess_imputer_test.cpp +++ b/src/mlpack/tests/main_tests/preprocess_imputer_test.cpp @@ -37,6 +37,7 @@ struct PreprocessImputerTestFixture ~PreprocessImputerTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; diff --git a/src/mlpack/tests/main_tests/preprocess_split_test.cpp b/src/mlpack/tests/main_tests/preprocess_split_test.cpp index 5911e92b8c..509a74a3d3 100644 --- a/src/mlpack/tests/main_tests/preprocess_split_test.cpp +++ b/src/mlpack/tests/main_tests/preprocess_split_test.cpp @@ -37,6 +37,7 @@ struct PreprocessSplitTestFixture ~PreprocessSplitTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; diff --git a/src/mlpack/tests/main_tests/random_forest_test.cpp b/src/mlpack/tests/main_tests/random_forest_test.cpp index 340d34f1da..ab4a8460da 100644 --- a/src/mlpack/tests/main_tests/random_forest_test.cpp +++ b/src/mlpack/tests/main_tests/random_forest_test.cpp @@ -35,6 +35,7 @@ struct RandomForestTestFixture ~RandomForestTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; @@ -143,8 +144,6 @@ BOOST_AUTO_TEST_CASE(RandomForestModelReuseTest) // Check that initial predictions and predictions using saved model are same. CheckMatrices(predictions, CLI::GetParam>("predictions")); CheckMatrices(probabilities, CLI::GetParam("probabilities")); - - delete CLI::GetParam("output_model"); } /** @@ -213,8 +212,6 @@ BOOST_AUTO_TEST_CASE(RandomForestTrainingVerTest) Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); Log::Fatal.ignoreInput = false; - - delete CLI::GetParam("output_model"); } /** @@ -222,7 +219,7 @@ BOOST_AUTO_TEST_CASE(RandomForestTrainingVerTest) */ BOOST_AUTO_TEST_CASE(RandomForestDiffMinLeafSizeTest) { - // Train for minimium leaf size 20. + // Train for minimum leaf size 20. arma::mat inputData; if (!data::Load("vc2.csv", inputData)) BOOST_FAIL("Cannot load train dataset vc2.csv!"); @@ -246,7 +243,9 @@ BOOST_AUTO_TEST_CASE(RandomForestDiffMinLeafSizeTest) size_t correct = arma::accu(predictions == labels); double accuracy20 = (double(correct) / double(labels.n_elem) * 100); - // Train for minimium leaf size 10. + bindings::tests::CleanMemory(); + + // Train for minimum leaf size 10. // Input training data. SetInputParam("training", inputData); @@ -262,7 +261,9 @@ BOOST_AUTO_TEST_CASE(RandomForestDiffMinLeafSizeTest) correct = arma::accu(predictions == labels); double accuracy10 = (double(correct) / double(labels.n_elem) * 100); - // Train for minimium leaf size 1. + bindings::tests::CleanMemory(); + + // Train for minimum leaf size 1. // Input training data. SetInputParam("training", inputData); @@ -272,15 +273,13 @@ BOOST_AUTO_TEST_CASE(RandomForestDiffMinLeafSizeTest) mlpackMain(); // Calculate training accuracy. - CLI::GetParam("output_model").rf.Classify(inputData, + CLI::GetParam("output_model")->rf.Classify(inputData, predictions); correct = arma::accu(predictions == labels); double accuracy1 = (double(correct) / double(labels.n_elem) * 100); BOOST_REQUIRE(accuracy1 > accuracy10 && accuracy10 > accuracy20); - - delete CLI::GetParam("output_model"); } /** @@ -316,7 +315,7 @@ BOOST_AUTO_TEST_CASE(RandomForestDiffNumTreeTest) arma::Row predictions; CLI::GetParam("output_model")->rf.Classify(testData, predictions); - delete CLI::GetParam("output_model"); + bindings::tests::CleanMemory(); size_t correct = arma::accu(predictions == testLabels); double accuracy1 = (double(correct) / double(testLabels.n_elem) * 100); @@ -333,7 +332,7 @@ BOOST_AUTO_TEST_CASE(RandomForestDiffNumTreeTest) // Calculate training accuracy. CLI::GetParam("output_model")->rf.Classify(testData, predictions); - delete CLI::GetParam("output_model"); + bindings::tests::CleanMemory(); correct = arma::accu(predictions == testLabels); double accuracy5 = (double(correct) / double(testLabels.n_elem) * 100); @@ -350,7 +349,6 @@ BOOST_AUTO_TEST_CASE(RandomForestDiffNumTreeTest) // Calculate training accuracy. CLI::GetParam("output_model")->rf.Classify(testData, predictions); - delete CLI::GetParam("output_model"); correct = arma::accu(predictions == testLabels); double accuracy10 = (double(correct) / double(testLabels.n_elem) * 100); diff --git a/src/mlpack/tests/main_tests/softmax_regression_test.cpp b/src/mlpack/tests/main_tests/softmax_regression_test.cpp index 358ad1b8bd..f646b69b9c 100644 --- a/src/mlpack/tests/main_tests/softmax_regression_test.cpp +++ b/src/mlpack/tests/main_tests/softmax_regression_test.cpp @@ -35,6 +35,7 @@ struct SoftmaxRegressionTestFixture ~SoftmaxRegressionTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; @@ -165,8 +166,6 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionModelReuseTest) // Check that initial predictions and final predicitons matrix // using saved model are same. CheckMatrices(predictions, CLI::GetParam>("predictions")); - - delete CLI::GetParam("output_model"); } /** @@ -275,7 +274,7 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionTrainingVerTest) // Input pre-trained model. SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + CLI::GetParam("output_model")); Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); @@ -308,8 +307,6 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffLambdaTest) // Delete the last row containing labels from test dataset. testData.shed_row(testData.n_rows - 1); - size_t testSize = testData.n_cols; - // Input training data. SetInputParam("training", inputData); SetInputParam("labels", labels); @@ -322,7 +319,9 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffLambdaTest) // Store output parameters. arma::mat modelParam; - modelParam = CLI::GetParam("output_model").Parameters(); + modelParam = CLI::GetParam("output_model")->Parameters(); + + bindings::tests::CleanMemory(); // Reset passed parameters. CLI::GetSingleton().Parameters()["training"].wasPassed = false; @@ -344,13 +343,13 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffLambdaTest) for (size_t i = 0; i < modelParam.n_elem; ++i) { BOOST_REQUIRE_NE(modelParam[i], - CLI::GetParam("output_model").Parameters()[i]); + CLI::GetParam("output_model")->Parameters()[i]); } } /** - * Check that output object parameters are different - * for different numbers of max_iterations. + * Check that output object parameters are different for different numbers of + * max_iterations. */ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffMaxItrTest) { @@ -374,8 +373,6 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffMaxItrTest) // Delete the last row containing labels from test dataset. testData.shed_row(testData.n_rows - 1); - size_t testSize = testData.n_cols; - // Input training data. SetInputParam("training", inputData); SetInputParam("labels", labels); @@ -388,7 +385,9 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffMaxItrTest) // Store output parameters. arma::mat modelParam; - modelParam = CLI::GetParam("output_model").Parameters(); + modelParam = CLI::GetParam("output_model")->Parameters(); + + bindings::tests::CleanMemory(); // Reset passed parameters. CLI::GetSingleton().Parameters()["training"].wasPassed = false; @@ -410,7 +409,7 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffMaxItrTest) for (size_t i = 0; i < modelParam.n_elem; ++i) { BOOST_REQUIRE_NE(modelParam[i], - CLI::GetParam("output_model").Parameters()[i]); + CLI::GetParam("output_model")->Parameters()[i]); } } @@ -440,8 +439,6 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffInterceptTest) // Delete the last row containing labels from test dataset. testData.shed_row(testData.n_rows - 1); - size_t testSize = testData.n_cols; - // Input training data. SetInputParam("training", inputData); SetInputParam("labels", labels); @@ -454,7 +451,9 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffInterceptTest) // Store output parameters. arma::mat modelParam; - modelParam = CLI::GetParam("output_model").Parameters(); + modelParam = CLI::GetParam("output_model")->Parameters(); + + bindings::tests::CleanMemory(); // Reset passed parameters. CLI::GetSingleton().Parameters()["training"].wasPassed = false; @@ -474,7 +473,7 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffInterceptTest) // Check that initial parameters has 1 more parameter than // final parameters matrix. BOOST_REQUIRE_EQUAL( - CLI::GetParam("output_model").Parameters().n_cols, + CLI::GetParam("output_model")->Parameters().n_cols, modelParam.n_cols + 1); } From a402f61455ff1a0f2fd2eab10b06d997e051e395 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 29 Jan 2018 13:05:21 -0500 Subject: [PATCH 069/113] Fix comments. --- src/mlpack/bindings/tests/delete_allocated_memory.hpp | 2 +- src/mlpack/bindings/tests/get_allocated_memory.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/bindings/tests/delete_allocated_memory.hpp b/src/mlpack/bindings/tests/delete_allocated_memory.hpp index f39deb113b..a0541a19e6 100644 --- a/src/mlpack/bindings/tests/delete_allocated_memory.hpp +++ b/src/mlpack/bindings/tests/delete_allocated_memory.hpp @@ -49,7 +49,7 @@ void DeleteAllocatedMemory( DeleteAllocatedMemoryImpl::type>(d); } -} // namespace cli +} // namespace tests } // namespace bindings } // namespace mlpack diff --git a/src/mlpack/bindings/tests/get_allocated_memory.hpp b/src/mlpack/bindings/tests/get_allocated_memory.hpp index ec53740a40..82f47e1130 100644 --- a/src/mlpack/bindings/tests/get_allocated_memory.hpp +++ b/src/mlpack/bindings/tests/get_allocated_memory.hpp @@ -50,7 +50,7 @@ void GetAllocatedMemory(const util::ParamData& d, GetAllocatedMemory::type>(d); } -} // namespace cli +} // namespace tests } // namespace bindings } // namespace mlpack From 847a916f7a33129993afd32c6ca2f599fd14b745 Mon Sep 17 00:00:00 2001 From: manish7294 Date: Tue, 30 Jan 2018 15:15:43 +0530 Subject: [PATCH 070/113] Added max_iteration test --- .../tests/main_tests/sparse_coding_test.cpp | 117 +++++++++++++++--- 1 file changed, 97 insertions(+), 20 deletions(-) diff --git a/src/mlpack/tests/main_tests/sparse_coding_test.cpp b/src/mlpack/tests/main_tests/sparse_coding_test.cpp index 79746e9d74..94645b48f7 100644 --- a/src/mlpack/tests/main_tests/sparse_coding_test.cpp +++ b/src/mlpack/tests/main_tests/sparse_coding_test.cpp @@ -111,9 +111,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingNormalizationTest) mlpackMain(); - mat initialDictionary; - initialDictionary = std::move(CLI::GetParam - ("dictionary")); + mat initialDictionary = + std::move(CLI::GetParam("dictionary")); // Train for normalization set to true. @@ -128,10 +127,10 @@ BOOST_AUTO_TEST_CASE(SparseCodingNormalizationTest) mlpackMain(); // Store outputs. - arma::mat dictionary; - arma::mat codes; - dictionary = std::move(CLI::GetParam("dictionary")); - codes = std::move(CLI::GetParam("codes")); + arma::mat dictionary = + std::move(CLI::GetParam("dictionary")); + arma::mat codes = + std::move(CLI::GetParam("codes")); // Train for normalization set to false. @@ -273,9 +272,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingModelVerTest) mlpackMain(); - mat initialDictionary; - initialDictionary = std::move(CLI::GetParam - ("dictionary")); + mat initialDictionary = + std::move(CLI::GetParam("dictionary")); // Input trained model and initial_dictionary. SetInputParam("input_model", @@ -307,9 +305,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingAtomsVerTest) mlpackMain(); - mat initialDictionary; - initialDictionary = std::move(CLI::GetParam - ("dictionary")); + mat initialDictionary = + std::move(CLI::GetParam("dictionary")); // Input data and initial_dictionary. SetInputParam("training", std::move(inputData)); @@ -343,9 +340,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingRowsVerTest) mlpackMain(); - mat initialDictionary; - initialDictionary = std::move(CLI::GetParam - ("dictionary")); + mat initialDictionary = + std::move(CLI::GetParam("dictionary")); // Trim inputData. inputData.shed_rows(100, 400); @@ -424,10 +420,10 @@ BOOST_AUTO_TEST_CASE(SparseCodingModelReuseTest) mlpackMain(); // Store outputs. - arma::mat dictionary; - arma::mat codes; - dictionary = std::move(CLI::GetParam("dictionary")); - codes = std::move(CLI::GetParam("codes")); + arma::mat dictionary = + std::move(CLI::GetParam("dictionary")); + arma::mat codes = + std::move(CLI::GetParam("codes")); // Reset passed parameters. CLI::GetSingleton().Parameters()["training"].wasPassed = false; @@ -462,4 +458,85 @@ BOOST_AUTO_TEST_CASE(SparseCodingModelReuseTest) CheckMatrices(codes, CLI::GetParam("codes")); } +/** + * Ensure that for different value of max iterations + * outputs are different. + */ +BOOST_AUTO_TEST_CASE(SparseCodingDiffMaxItrTest) +{ + mat inputData; + inputData.load("mnist_first250_training_4s_and_9s.arm"); + + // Shuffle input dataset. + inputData = shuffle(inputData); + + // Generate test dataset. + mat testData; + testData = inputData.cols(450, 499); + + // Generate train dataset. + inputData.shed_cols(450, 499); + + // Generate initial dictionary. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 30); + SetInputParam("max_iterations", (int) 1); + SetInputParam("normalize", (bool) true); + + mlpackMain(); + + mat initialDictionary = + std::move(CLI::GetParam("dictionary")); + + // Train for max_iterations equals to 2. + + // Input data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 30); + SetInputParam("initial_dictionary", initialDictionary); + SetInputParam("max_iterations", (int) 2); + SetInputParam("normalize", (bool) true); + SetInputParam("test", testData); + + mlpackMain(); + + // Store outputs. + arma::mat dictionary = + std::move(CLI::GetParam("dictionary")); + arma::mat codes = + std::move(CLI::GetParam("codes")); + + // Train for max_iterations equals to 100. + + // Input data. + SetInputParam("training", std::move(inputData)); + SetInputParam("atoms", (int) 30); + SetInputParam("initial_dictionary", std::move(initialDictionary)); + SetInputParam("max_iterations", (int) 100); + SetInputParam("normalize", (bool) true); + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + // Check that initial outputs and final outputs + // using two models model are different. + for (size_t i = 0; i < dictionary.n_elem; ++i) + { + if(dictionary[i]!=0 && CLI::GetParam("dictionary")[i]!=0) + { + BOOST_REQUIRE_NE(dictionary[i], + CLI::GetParam("dictionary")[i]); + } + } + + for (size_t i = 0; i < codes.n_elem; ++i) + { + if(codes[i]!=0 && CLI::GetParam("codes")[i]!=0) + { + BOOST_REQUIRE_NE(codes[i], + CLI::GetParam("codes")[i]); + } + } +} + BOOST_AUTO_TEST_SUITE_END(); From a7af1c49db42cece183b5cc1aa98ba121c4f3c07 Mon Sep 17 00:00:00 2001 From: manish7294 Date: Tue, 30 Jan 2018 21:10:00 +0530 Subject: [PATCH 071/113] Optimized Boost Check by rcurtin --- .../tests/main_tests/sparse_coding_test.cpp | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/mlpack/tests/main_tests/sparse_coding_test.cpp b/src/mlpack/tests/main_tests/sparse_coding_test.cpp index 94645b48f7..f61d066205 100644 --- a/src/mlpack/tests/main_tests/sparse_coding_test.cpp +++ b/src/mlpack/tests/main_tests/sparse_coding_test.cpp @@ -520,23 +520,11 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffMaxItrTest) // Check that initial outputs and final outputs // using two models model are different. - for (size_t i = 0; i < dictionary.n_elem; ++i) - { - if(dictionary[i]!=0 && CLI::GetParam("dictionary")[i]!=0) - { - BOOST_REQUIRE_NE(dictionary[i], - CLI::GetParam("dictionary")[i]); - } - } + BOOST_REQUIRE_LT(arma::accu(dictionary == + CLI::GetParam("dictionary")), dictionary.n_elem); - for (size_t i = 0; i < codes.n_elem; ++i) - { - if(codes[i]!=0 && CLI::GetParam("codes")[i]!=0) - { - BOOST_REQUIRE_NE(codes[i], - CLI::GetParam("codes")[i]); - } - } + BOOST_REQUIRE_LT(arma::accu(codes == + CLI::GetParam("codes")), codes.n_elem); } BOOST_AUTO_TEST_SUITE_END(); From 31d255a4d6ad4a3e94a73b064929f0ff107ae6e6 Mon Sep 17 00:00:00 2001 From: deepakks1995 Date: Wed, 31 Jan 2018 00:14:41 +0530 Subject: [PATCH 072/113] removed some warning messages --- src/mlpack/core/optimizers/fw/constr_lpball.hpp | 2 +- src/mlpack/methods/approx_kfn/drusilla_select_impl.hpp | 2 +- .../methods/naive_bayes/naive_bayes_classifier_impl.hpp | 2 +- src/mlpack/methods/perceptron/perceptron_impl.hpp | 2 +- src/mlpack/tests/binarize_test.cpp | 2 +- src/mlpack/tests/main_tests/softmax_regression_test.cpp | 6 ------ 6 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/mlpack/core/optimizers/fw/constr_lpball.hpp b/src/mlpack/core/optimizers/fw/constr_lpball.hpp index a95063020d..5f5b3766f9 100644 --- a/src/mlpack/core/optimizers/fw/constr_lpball.hpp +++ b/src/mlpack/core/optimizers/fw/constr_lpball.hpp @@ -115,7 +115,7 @@ class ConstrLpBallSolver else s = arma::abs(v); - arma::uword k; + arma::uword k = 0; s.max(k); // k is the linear index of the largest element. s.zeros(); s(k) = - mlpack::math::Sign(v(k)); diff --git a/src/mlpack/methods/approx_kfn/drusilla_select_impl.hpp b/src/mlpack/methods/approx_kfn/drusilla_select_impl.hpp index cfe646d749..4b02aaa713 100644 --- a/src/mlpack/methods/approx_kfn/drusilla_select_impl.hpp +++ b/src/mlpack/methods/approx_kfn/drusilla_select_impl.hpp @@ -95,7 +95,7 @@ void DrusillaSelect::Train( for (size_t i = 0; i < l; ++i) { // Pick best index. - arma::uword maxIndex; + arma::uword maxIndex = 0; norms.max(maxIndex); arma::vec line(refCopy.col(maxIndex) / arma::norm(refCopy.col(maxIndex))); diff --git a/src/mlpack/methods/naive_bayes/naive_bayes_classifier_impl.hpp b/src/mlpack/methods/naive_bayes/naive_bayes_classifier_impl.hpp index 69b5397dce..20fa070ddb 100644 --- a/src/mlpack/methods/naive_bayes/naive_bayes_classifier_impl.hpp +++ b/src/mlpack/methods/naive_bayes/naive_bayes_classifier_impl.hpp @@ -331,7 +331,7 @@ void NaiveBayesClassifier::Classify( // Now calculate maximum probabilities for each point. for (size_t i = 0; i < data.n_cols; ++i) { - arma::uword maxIndex; + arma::uword maxIndex = 0; logLikelihoods.unsafe_col(i).max(maxIndex); predictions[i] = maxIndex; } diff --git a/src/mlpack/methods/perceptron/perceptron_impl.hpp b/src/mlpack/methods/perceptron/perceptron_impl.hpp index 38226bdb9a..6e15b53e83 100644 --- a/src/mlpack/methods/perceptron/perceptron_impl.hpp +++ b/src/mlpack/methods/perceptron/perceptron_impl.hpp @@ -148,7 +148,7 @@ void Perceptron::Train( size_t j, i = 0; bool converged = false; size_t tempLabel; - arma::uword maxIndexRow, maxIndexCol; + arma::uword maxIndexRow = 0, maxIndexCol = 0; arma::mat tempLabelMat; LearnPolicy LP; diff --git a/src/mlpack/tests/binarize_test.cpp b/src/mlpack/tests/binarize_test.cpp index 2083383d59..712e79b769 100644 --- a/src/mlpack/tests/binarize_test.cpp +++ b/src/mlpack/tests/binarize_test.cpp @@ -2,7 +2,7 @@ * @file binarize_test.cpp * @author Keon Kim * - * Test the Binarzie method. + * Test the Binarize method. * * 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 diff --git a/src/mlpack/tests/main_tests/softmax_regression_test.cpp b/src/mlpack/tests/main_tests/softmax_regression_test.cpp index 04dc10169a..1cf5f70622 100644 --- a/src/mlpack/tests/main_tests/softmax_regression_test.cpp +++ b/src/mlpack/tests/main_tests/softmax_regression_test.cpp @@ -306,8 +306,6 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffLambdaTest) // Delete the last row containing labels from test dataset. testData.shed_row(testData.n_rows - 1); - size_t testSize = testData.n_cols; - // Input training data. SetInputParam("training", inputData); SetInputParam("labels", labels); @@ -372,8 +370,6 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffMaxItrTest) // Delete the last row containing labels from test dataset. testData.shed_row(testData.n_rows - 1); - size_t testSize = testData.n_cols; - // Input training data. SetInputParam("training", inputData); SetInputParam("labels", labels); @@ -438,8 +434,6 @@ BOOST_AUTO_TEST_CASE(SoftmaxRegressionDiffInterceptTest) // Delete the last row containing labels from test dataset. testData.shed_row(testData.n_rows - 1); - size_t testSize = testData.n_cols; - // Input training data. SetInputParam("training", inputData); SetInputParam("labels", labels); From ac89b49e27e7f3df8c23cd92249ff6a44a4be7ef Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 30 Jan 2018 19:06:31 -0500 Subject: [PATCH 073/113] Minor comment fixes. --- src/mlpack/bindings/python/print_input_processing.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/bindings/python/print_input_processing.hpp b/src/mlpack/bindings/python/print_input_processing.hpp index bb688ad463..3cdf096c0e 100644 --- a/src/mlpack/bindings/python/print_input_processing.hpp +++ b/src/mlpack/bindings/python/print_input_processing.hpp @@ -31,8 +31,8 @@ void PrintInputProcessing( const typename boost::disable_if>>::type* = 0) { - // The copy_all_inputs parameter must be handled first, and so is outside the - // scope of this code. + // The copy_all_inputs parameter must be handled first, and therefore is + // outside the scope of this code. if (d.name == "copy_all_inputs") return; @@ -179,7 +179,7 @@ void PrintInputProcessing( * except TypeError as e: * if type(param_name).__name__ == "ModelType": * SetParamPtr[Model]('param_name', ( param_name).modelptr, - * CLI.HasParam('copy_all_inputs')) TODO + * CLI.HasParam('copy_all_inputs')) * else: * raise e * CLI.SetPassed( 'param_name') From c34144853eed601fcacfa3c27e3c4918c23fe888 Mon Sep 17 00:00:00 2001 From: manish7294 Date: Wed, 31 Jan 2018 20:59:02 +0530 Subject: [PATCH 074/113] Added some more tests --- .../tests/main_tests/sparse_coding_test.cpp | 300 ++++++++++++++++-- 1 file changed, 277 insertions(+), 23 deletions(-) diff --git a/src/mlpack/tests/main_tests/sparse_coding_test.cpp b/src/mlpack/tests/main_tests/sparse_coding_test.cpp index f61d066205..c104bd0123 100644 --- a/src/mlpack/tests/main_tests/sparse_coding_test.cpp +++ b/src/mlpack/tests/main_tests/sparse_coding_test.cpp @@ -464,35 +464,22 @@ BOOST_AUTO_TEST_CASE(SparseCodingModelReuseTest) */ BOOST_AUTO_TEST_CASE(SparseCodingDiffMaxItrTest) { - mat inputData; - inputData.load("mnist_first250_training_4s_and_9s.arm"); + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset trainSet.csv!"); - // Shuffle input dataset. - inputData = shuffle(inputData); + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset testSet.csv!"); - // Generate test dataset. - mat testData; - testData = inputData.cols(450, 499); - - // Generate train dataset. - inputData.shed_cols(450, 499); - - // Generate initial dictionary. - SetInputParam("training", inputData); - SetInputParam("atoms", (int) 30); - SetInputParam("max_iterations", (int) 1); - SetInputParam("normalize", (bool) true); - - mlpackMain(); - - mat initialDictionary = - std::move(CLI::GetParam("dictionary")); + mat initialDictionary = inputData.cols(0, 1); // Train for max_iterations equals to 2. // Input data. SetInputParam("training", inputData); - SetInputParam("atoms", (int) 30); + SetInputParam("atoms", (int) 2); SetInputParam("initial_dictionary", initialDictionary); SetInputParam("max_iterations", (int) 2); SetInputParam("normalize", (bool) true); @@ -510,7 +497,7 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffMaxItrTest) // Input data. SetInputParam("training", std::move(inputData)); - SetInputParam("atoms", (int) 30); + SetInputParam("atoms", (int) 2); SetInputParam("initial_dictionary", std::move(initialDictionary)); SetInputParam("max_iterations", (int) 100); SetInputParam("normalize", (bool) true); @@ -527,4 +514,271 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffMaxItrTest) CLI::GetParam("codes")), codes.n_elem); } +/** + * Ensure that for different value of objective_tolerance + * outputs are different. + */ +BOOST_AUTO_TEST_CASE(SparseCodingDiffObjToleranceTest) +{ + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset testSet.csv!"); + + mat initialDictionary = inputData.cols(0, 1); + + // Train for default objective_tolerance. + + // Input data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 2); + SetInputParam("initial_dictionary", initialDictionary); + SetInputParam("test", testData); + + mlpackMain(); + + // Store outputs. + arma::mat dictionary = + std::move(CLI::GetParam("dictionary")); + arma::mat codes = + std::move(CLI::GetParam("codes")); + + // Train for objective_tolerance equals to 10000.0. + + // Input data. + SetInputParam("training", std::move(inputData)); + SetInputParam("atoms", (int) 2); + SetInputParam("initial_dictionary", std::move(initialDictionary)); + SetInputParam("objective_tolerance", (double) 10000.0); + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + // Check that initial outputs and final outputs + // using two models model are different. + BOOST_REQUIRE_LT(arma::accu(dictionary == + CLI::GetParam("dictionary")), dictionary.n_elem); + + BOOST_REQUIRE_LT(arma::accu(codes == + CLI::GetParam("codes")), codes.n_elem); +} + +/** + * Ensure that for different value of newton_tolerance + * outputs are different. + */ +BOOST_AUTO_TEST_CASE(SparseCodingDiffNewtonToleranceTest) +{ + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset testSet.csv!"); + + mat initialDictionary = inputData.cols(0, 1); + + // Train for default newton_tolerance. + + // Input data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 2); + SetInputParam("initial_dictionary", initialDictionary); + SetInputParam("test", testData); + + mlpackMain(); + + // Store outputs. + arma::mat dictionary = + std::move(CLI::GetParam("dictionary")); + arma::mat codes = + std::move(CLI::GetParam("codes")); + + // Train for newton_tolerance equals to 10000.0. + + // Input data. + SetInputParam("training", std::move(inputData)); + SetInputParam("atoms", (int) 2); + SetInputParam("initial_dictionary", std::move(initialDictionary)); + SetInputParam("newton_tolerance", (double) 10000.0); + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + // Check that initial outputs and final outputs + // using two models model are different. + BOOST_REQUIRE_LT(arma::accu(dictionary == + CLI::GetParam("dictionary")), dictionary.n_elem); + + BOOST_REQUIRE_LT(arma::accu(codes == + CLI::GetParam("codes")), codes.n_elem); +} + +/** + * Ensure that for different value of lambda1 + * outputs are different. + */ +BOOST_AUTO_TEST_CASE(SparseCodingDiffL1Test) +{ + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset testSet.csv!"); + + mat initialDictionary = inputData.cols(0, 1); + + // Train for default lambda1. + + // Input data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 2); + SetInputParam("initial_dictionary", initialDictionary); + SetInputParam("test", testData); + + mlpackMain(); + + // Store outputs. + arma::mat dictionary = + std::move(CLI::GetParam("dictionary")); + arma::mat codes = + std::move(CLI::GetParam("codes")); + + // Train for lambda1 equals to 10000.0. + + // Input data. + SetInputParam("training", std::move(inputData)); + SetInputParam("atoms", (int) 2); + SetInputParam("initial_dictionary", std::move(initialDictionary)); + SetInputParam("lambda1", (double) 10000.0); + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + // Check that initial outputs and final outputs + // using two models model are different. + BOOST_REQUIRE_LT(arma::accu(dictionary == + CLI::GetParam("dictionary")), dictionary.n_elem); + + BOOST_REQUIRE_LT(arma::accu(codes == + CLI::GetParam("codes")), codes.n_elem); +} + +/** + * Ensure that for different value of lambda2 + * outputs are different. + */ +BOOST_AUTO_TEST_CASE(SparseCodingDiffL2Test) +{ + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset testSet.csv!"); + + mat initialDictionary = inputData.cols(0, 1); + + // Train for default lambda2. + + // Input data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 2); + SetInputParam("initial_dictionary", initialDictionary); + SetInputParam("test", testData); + + mlpackMain(); + + // Store outputs. + arma::mat dictionary = + std::move(CLI::GetParam("dictionary")); + arma::mat codes = + std::move(CLI::GetParam("codes")); + + // Train for lambda2 equals to 10000.0. + + // Input data. + SetInputParam("training", std::move(inputData)); + SetInputParam("atoms", (int) 2); + SetInputParam("initial_dictionary", std::move(initialDictionary)); + SetInputParam("lambda2", (double) 10000.0); + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + // Check that initial outputs and final outputs + // using two models model are different. + BOOST_REQUIRE_LT(arma::accu(dictionary == + CLI::GetParam("dictionary")), dictionary.n_elem); + + BOOST_REQUIRE_LT(arma::accu(codes == + CLI::GetParam("codes")), codes.n_elem); +} + +/** + * Ensure that for different value of lambda1 & lambda2 + * outputs are different. + */ +BOOST_AUTO_TEST_CASE(SparseCodingDiffL1L2Test) +{ + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset testSet.csv!"); + + mat initialDictionary = inputData.cols(0, 1); + + // Train for default lambda2 & lambda1 equal to 10000.0. + + // Input data. + SetInputParam("training", inputData); + SetInputParam("atoms", (int) 2); + SetInputParam("lambda1", (double) 10000.0); + SetInputParam("initial_dictionary", initialDictionary); + SetInputParam("test", testData); + + mlpackMain(); + + // Store outputs. + arma::mat dictionary = + std::move(CLI::GetParam("dictionary")); + arma::mat codes = + std::move(CLI::GetParam("codes")); + + // Train for lambda1 EQUALS 0.0 & lambda2 equals to 10000.0. + + // Input data. + SetInputParam("training", std::move(inputData)); + SetInputParam("atoms", (int) 2); + SetInputParam("initial_dictionary", std::move(initialDictionary)); + SetInputParam("lambda1", (double) 0.0); + SetInputParam("lambda2", (double) 10000.0); + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + // Check that initial outputs and final outputs + // using two models model are different. + BOOST_REQUIRE_LT(arma::accu(dictionary == + CLI::GetParam("dictionary")), dictionary.n_elem); + + BOOST_REQUIRE_LT(arma::accu(codes == + CLI::GetParam("codes")), codes.n_elem); +} + BOOST_AUTO_TEST_SUITE_END(); From 4562f1c6b2bd3a665ca7e88993ea8d2d904bb2eb Mon Sep 17 00:00:00 2001 From: manish7294 Date: Wed, 31 Jan 2018 22:07:41 +0530 Subject: [PATCH 075/113] Optimized Tests --- .../tests/main_tests/sparse_coding_test.cpp | 226 ++++++++---------- 1 file changed, 94 insertions(+), 132 deletions(-) diff --git a/src/mlpack/tests/main_tests/sparse_coding_test.cpp b/src/mlpack/tests/main_tests/sparse_coding_test.cpp index c104bd0123..ff2015989e 100644 --- a/src/mlpack/tests/main_tests/sparse_coding_test.cpp +++ b/src/mlpack/tests/main_tests/sparse_coding_test.cpp @@ -48,40 +48,38 @@ BOOST_FIXTURE_TEST_SUITE(SparseCodingMainTest, SparseCodingTestFixture); */ BOOST_AUTO_TEST_CASE(SparseCodingOutputDimensionTest) { - mat inputData; - inputData.load("mnist_first250_training_4s_and_9s.arm"); + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - // Shuffle input dataset. - inputData = shuffle(inputData); + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); - // Generate test dataset. - mat testData; - testData = inputData.cols(450, 499); - - // Generate train dataset. - inputData.shed_cols(450, 499); + mat initialDictionary = inputData.cols(0, 1); // Input data. SetInputParam("training", std::move(inputData)); - SetInputParam("atoms", (int) 30); - SetInputParam("max_iterations", (int) 500); - SetInputParam("normalize", (bool) true); + SetInputParam("atoms", (int) 2); + SetInputParam("max_iterations", (int) 100); SetInputParam("test", std::move(testData)); mlpackMain(); // Check that number of output dictionary points are equals number of atoms. - BOOST_REQUIRE_EQUAL(CLI::GetParam("dictionary").n_cols, 30); + BOOST_REQUIRE_EQUAL(CLI::GetParam("dictionary").n_cols, 2); // Check that number of output dictionary rows equal number of input rows - // which equal 784 for each data point. - BOOST_REQUIRE_EQUAL(CLI::GetParam("dictionary").n_rows, 784); + // which equal 4 for each data point. + BOOST_REQUIRE_EQUAL(CLI::GetParam("dictionary").n_rows, 4); // Check that number of output points are equal to number of test points. - BOOST_REQUIRE_EQUAL(CLI::GetParam("codes").n_cols, 50); + // Test file contains 63 data points. + BOOST_REQUIRE_EQUAL(CLI::GetParam("codes").n_cols, 63); // Check that number of output codes rows equal number of atoms. - BOOST_REQUIRE_EQUAL(CLI::GetParam("codes").n_rows, 30); + BOOST_REQUIRE_EQUAL(CLI::GetParam("codes").n_rows, 2); } /** @@ -90,35 +88,22 @@ BOOST_AUTO_TEST_CASE(SparseCodingOutputDimensionTest) */ BOOST_AUTO_TEST_CASE(SparseCodingNormalizationTest) { - mat inputData; - inputData.load("mnist_first250_training_4s_and_9s.arm"); + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset iris_train!"); - // Shuffle input dataset. - inputData = shuffle(inputData); + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); - // Generate test dataset. - mat testData; - testData = inputData.cols(450, 499); - - // Generate train dataset. - inputData.shed_cols(450, 499); - - // Generate initial dictionary. - SetInputParam("training", inputData); - SetInputParam("atoms", (int) 30); - SetInputParam("max_iterations", (int) 10); - SetInputParam("normalize", (bool) true); - - mlpackMain(); - - mat initialDictionary = - std::move(CLI::GetParam("dictionary")); + mat initialDictionary = inputData.cols(0, 1); // Train for normalization set to true. // Input data. SetInputParam("training", inputData); - SetInputParam("atoms", (int) 30); + SetInputParam("atoms", (int) 2); SetInputParam("initial_dictionary", initialDictionary); SetInputParam("max_iterations", (int) 100); SetInputParam("normalize", (bool) true); @@ -147,7 +132,7 @@ BOOST_AUTO_TEST_CASE(SparseCodingNormalizationTest) // Input data. SetInputParam("training", std::move(inputData)); - SetInputParam("atoms", (int) 30); + SetInputParam("atoms", (int) 2); SetInputParam("initial_dictionary", std::move(initialDictionary)); SetInputParam("max_iterations", (int) 100); SetInputParam("test", std::move(testData)); @@ -167,8 +152,9 @@ BOOST_AUTO_TEST_CASE(SparseCodingNormalizationTest) */ BOOST_AUTO_TEST_CASE(SparseCodingBoundsTest) { - mat inputData; - inputData.load("mnist_first250_training_4s_and_9s.arm"); + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); // Test for L1 value. @@ -241,8 +227,9 @@ BOOST_AUTO_TEST_CASE(SparseCodingBoundsTest) */ BOOST_AUTO_TEST_CASE(SparseCodingReqAtomsTest) { - mat inputData; - inputData.load("mnist_first250_training_4s_and_9s.arm"); + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); // Input training data. SetInputParam("training", std::move(inputData)); @@ -258,22 +245,16 @@ BOOST_AUTO_TEST_CASE(SparseCodingReqAtomsTest) */ BOOST_AUTO_TEST_CASE(SparseCodingModelVerTest) { - mat inputData; - inputData.load("mnist_first250_training_4s_and_9s.arm"); + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - // Shuffle input dataset. - inputData = shuffle(inputData); + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); - // Input data. - SetInputParam("training", std::move(inputData)); - SetInputParam("atoms", (int) 30); - SetInputParam("max_iterations", (int) 10); - SetInputParam("normalize", (bool) true); - - mlpackMain(); - - mat initialDictionary = - std::move(CLI::GetParam("dictionary")); + mat initialDictionary = inputData.cols(0, 1); // Input trained model and initial_dictionary. SetInputParam("input_model", @@ -291,29 +272,22 @@ BOOST_AUTO_TEST_CASE(SparseCodingModelVerTest) */ BOOST_AUTO_TEST_CASE(SparseCodingAtomsVerTest) { - mat inputData; - inputData.load("mnist_first250_training_4s_and_9s.arm"); + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - // Shuffle input dataset. - inputData = shuffle(inputData); + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); - // Input data. - SetInputParam("training", inputData); - SetInputParam("atoms", (int) 30); - SetInputParam("max_iterations", (int) 10); - SetInputParam("normalize", (bool) true); - - mlpackMain(); - - mat initialDictionary = - std::move(CLI::GetParam("dictionary")); + mat initialDictionary = inputData.cols(0, 1); // 2 points. // Input data and initial_dictionary. SetInputParam("training", std::move(inputData)); SetInputParam("atoms", (int) 40); // Invalid. SetInputParam("initial_dictionary", std::move(initialDictionary)); SetInputParam("max_iterations", (int) 100); - SetInputParam("normalize", (bool) true); Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); @@ -326,29 +300,23 @@ BOOST_AUTO_TEST_CASE(SparseCodingAtomsVerTest) */ BOOST_AUTO_TEST_CASE(SparseCodingRowsVerTest) { - mat inputData; - inputData.load("mnist_first250_training_4s_and_9s.arm"); + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - // Shuffle input dataset. - inputData = shuffle(inputData); + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); - // Input data. - SetInputParam("training", inputData); - SetInputParam("atoms", (int) 30); - SetInputParam("max_iterations", (int) 100); - SetInputParam("normalize", (bool) true); - - mlpackMain(); - - mat initialDictionary = - std::move(CLI::GetParam("dictionary")); + mat initialDictionary = inputData.cols(0, 1); // Trim inputData. - inputData.shed_rows(100, 400); + inputData.shed_rows(1, 2); // Input data and initial_dictionary. SetInputParam("training", std::move(inputData)); // Invalid Data. - SetInputParam("atoms", (int) 30); + SetInputParam("atoms", (int) 2); SetInputParam("initial_dictionary", std::move(initialDictionary)); SetInputParam("max_iterations", (int) 100); SetInputParam("normalize", (bool) true); @@ -364,27 +332,24 @@ BOOST_AUTO_TEST_CASE(SparseCodingRowsVerTest) */ BOOST_AUTO_TEST_CASE(SparseCodingDataDimensionalityTest) { - mat inputData; - inputData.load("mnist_first250_training_4s_and_9s.arm"); + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - // Shuffle input dataset. - inputData = shuffle(inputData); + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); - // Generate test dataset. - mat testData; - testData = inputData.cols(450, 499); + mat initialDictionary = inputData.cols(0, 1); // Trim testData. - testData.shed_rows(100, 400); - - // Generate train dataset. - inputData.shed_cols(450, 499); + testData.shed_rows(1, 2); // Input data. SetInputParam("training", inputData); - SetInputParam("atoms", (int) 30); + SetInputParam("atoms", (int) 2); SetInputParam("max_iterations", (int) 100); - SetInputParam("normalize", (bool) true); SetInputParam("test", std::move(testData)); Log::Fatal.ignoreInput = true; @@ -397,22 +362,18 @@ BOOST_AUTO_TEST_CASE(SparseCodingDataDimensionalityTest) */ BOOST_AUTO_TEST_CASE(SparseCodingModelReuseTest) { - mat inputData; - inputData.load("mnist_first250_training_4s_and_9s.arm"); + arma::mat inputData; + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - // Shuffle input dataset. - inputData = shuffle(inputData); - - // Generate test dataset. - mat testData; - testData = inputData.cols(450, 499); - - // Generate train dataset. - inputData.shed_cols(450, 499); + // Load test dataset. + arma::mat testData; + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); // Input data. SetInputParam("training", inputData); - SetInputParam("atoms", (int) 30); + SetInputParam("atoms", (int) 2); SetInputParam("max_iterations", (int) 100); SetInputParam("normalize", (bool) true); SetInputParam("test", testData); @@ -440,17 +401,18 @@ BOOST_AUTO_TEST_CASE(SparseCodingModelReuseTest) mlpackMain(); // Check that number of output dictionary points are equals number of atoms. - BOOST_REQUIRE_EQUAL(CLI::GetParam("dictionary").n_cols, 30); + BOOST_REQUIRE_EQUAL(CLI::GetParam("dictionary").n_cols, 2); // Check that number of output dictionary rows equal number of input rows - // which equal 784 for each data point. - BOOST_REQUIRE_EQUAL(CLI::GetParam("dictionary").n_rows, 784); + // which equal 4 for each data point. + BOOST_REQUIRE_EQUAL(CLI::GetParam("dictionary").n_rows, 4); // Check that number of output points are equal to number of test points. - BOOST_REQUIRE_EQUAL(CLI::GetParam("codes").n_cols, 50); + // Test file contains 63 data points. + BOOST_REQUIRE_EQUAL(CLI::GetParam("codes").n_cols, 63); // Check that number of output codes rows equal number of atoms. - BOOST_REQUIRE_EQUAL(CLI::GetParam("codes").n_rows, 30); + BOOST_REQUIRE_EQUAL(CLI::GetParam("codes").n_rows, 2); // Check that initial outputs and final outputs // using two models model are same. @@ -466,12 +428,12 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffMaxItrTest) { arma::mat inputData; if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); // Load test dataset. arma::mat testData; if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset testSet.csv!"); + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); mat initialDictionary = inputData.cols(0, 1); @@ -522,12 +484,12 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffObjToleranceTest) { arma::mat inputData; if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); // Load test dataset. arma::mat testData; if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset testSet.csv!"); + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); mat initialDictionary = inputData.cols(0, 1); @@ -575,12 +537,12 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffNewtonToleranceTest) { arma::mat inputData; if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); // Load test dataset. arma::mat testData; if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset testSet.csv!"); + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); mat initialDictionary = inputData.cols(0, 1); @@ -628,12 +590,12 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffL1Test) { arma::mat inputData; if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); // Load test dataset. arma::mat testData; if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset testSet.csv!"); + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); mat initialDictionary = inputData.cols(0, 1); @@ -681,12 +643,12 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffL2Test) { arma::mat inputData; if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); // Load test dataset. arma::mat testData; if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset testSet.csv!"); + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); mat initialDictionary = inputData.cols(0, 1); @@ -734,12 +696,12 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffL1L2Test) { arma::mat inputData; if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset trainSet.csv!"); + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); // Load test dataset. arma::mat testData; if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset testSet.csv!"); + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); mat initialDictionary = inputData.cols(0, 1); From cd2775c0f062f6737ad28128fe0a0ee654a80dad Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Thu, 1 Feb 2018 20:04:45 +0530 Subject: [PATCH 076/113] AdaBoost binding tests --- src/mlpack/tests/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index 89a02af421..2becc81cd4 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -125,6 +125,7 @@ add_executable(mlpack_test vantage_point_tree_test.cpp main_tests/test_helper.hpp main_tests/emst_test.cpp + main_tests/adaboost_test.cpp main_tests/decision_tree_test.cpp main_tests/decision_stump_test.cpp main_tests/linear_regression_test.cpp From 75c959442ccf3b740f843bb8db17989db83a5a09 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Thu, 1 Feb 2018 20:05:49 +0530 Subject: [PATCH 077/113] AdaBoost binding tests --- src/mlpack/tests/main_tests/adaboost_test.cpp | 263 ++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 src/mlpack/tests/main_tests/adaboost_test.cpp diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp new file mode 100644 index 0000000000..c618c876bd --- /dev/null +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -0,0 +1,263 @@ +/** + * @file adaboost_test.cpp + * @author Nikhil Goel + * + * Test mlpackMain() of adaboost_main.cpp. + */ +#include + +#define BINDING_TYPE BINDING_TYPE_TEST +static const std::string testName = "AdaBoost"; + +#include +#include +#include "test_helper.hpp" +#include + +#include +#include "../test_tools.hpp" + +using namespace mlpack; + +struct AdaBoostTestFixture +{ + public: + AdaBoostTestFixture() + { + // Cache in the options for this program. + CLI::RestoreSettings(testName); + } + + ~AdaBoostTestFixture() + { + // Clear the settings. + CLI::ClearSettings(); + } +}; + +void ResetSetting() +{ + CLI::ClearSettings(); + CLI::RestoreSettings(testName); +} + +BOOST_FIXTURE_TEST_SUITE(AdaBoostMainTest, AdaBoostTestFixture); + +/** + * Check that number of output labels and number of input + * points are equal. + */ + +BOOST_AUTO_TEST_CASE(AdaBoostOutputDimensionTest) +{ + arma::mat trainData; + if (!data::Load("vc2.csv", trainData)) + BOOST_FAIL("Unable to load train dataset vc2.csv!"); + + arma::Row labels; + if (!data::Load("vc2_labels.txt", labels)) + BOOST_FAIL("Unable to load label dataset vc2_labels.txt!"); + + arma::mat testData; + if (!data::Load("vc2_test.csv", testData)) + BOOST_FAIL("Unable to load test dataset vc2.csv!"); + + size_t testSize = testData.n_cols; + + SetInputParam("training", std::move(trainData)); + SetInputParam("labels", std::move(labels)); + + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + // Check that number of predicted labels is equal to the input test points. + BOOST_REQUIRE_EQUAL(CLI::GetParam>("output").n_cols, testSize); + BOOST_REQUIRE_EQUAL(CLI::GetParam>("output").n_rows, 1); +} + +/** + * Ensure that saved model can be used again. + */ +BOOST_AUTO_TEST_CASE(AdaBoostModelReuseTest) +{ + arma::mat trainData; + if (!data::Load("vc2.csv", trainData)) + BOOST_FAIL("Unable to load train dataset vc2.csv!"); + + arma::Row labels; + if (!data::Load("vc2_labels.txt", labels)) + BOOST_FAIL("Unable to load label dataset vc2_labels.txt!"); + + arma::mat testData; + if (!data::Load("vc2_test.csv", testData)) + BOOST_FAIL("Unable to load test dataset vc2.csv!"); + + SetInputParam("training", std::move(trainData)); + SetInputParam("labels", std::move(labels)); + + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + arma::Row output; + output = std::move(CLI::GetParam>("output")); + + ResetSetting(); + + SetInputParam("test", std::move(testData)); + SetInputParam("input_model", std::move(CLI::GetParam("output_model"))); + + mlpackMain(); + + // Check that initial output and output using saved model are same. + CheckMatrices(output, CLI::GetParam>("output")); +} + +/** + * Test that iterations in adaboost is always non-negative. + */ +BOOST_AUTO_TEST_CASE(AdaBoostItrTest) +{ + arma::mat trainData; + if (!data::Load("trainSet.csv", trainData)) + BOOST_FAIL("Unable load train dataset trainSet.csv!"); + + SetInputParam("training", std::move(trainData)); + SetInputParam("iterations", (int) -1); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Check that the last dimension of the training set is + * used as labels when labels are not passed specifically + * and results are same from both label and without label models. + */ +BOOST_AUTO_TEST_CASE(AdaBoostWithoutLabelTest) +{ + // Train adaboost without providing labels. + arma::mat trainData; + if (!data::Load("trainSet.csv", trainData)) + BOOST_FAIL("Unable to load train dataset trainSet.csv!"); + + // Give labels. + arma::Row labels(trainData.n_cols); + for (size_t i = 0; i < trainData.n_cols; ++i) + labels[i] = trainData(trainData.n_rows - 1, i); + + arma::mat testData; + if (!data::Load("testSet.csv", testData)) + BOOST_FAIL("Unable to load test dataset testSet.csv!"); + + // Delete the last row containing labels from test dataset. + testData.shed_row(testData.n_rows - 1); + + SetInputParam("training", trainData); + + SetInputParam("test", testData); + + mlpackMain(); + + ResetSetting(); + + trainData.shed_row(trainData.n_rows - 1); + + arma::Row output; + output = std::move(CLI::GetParam>("output")); + + // Now train Adaboost with labels provided. + SetInputParam("training", std::move(trainData)); + SetInputParam("test", std::move(testData)); + SetInputParam("labels", std::move(labels)); + + mlpackMain(); + + // Check that initial output and final output matrix are same. + CheckMatrices(output, CLI::GetParam>("output")); +} + +/** + * Testing that only one of training data or pre-trained model is passed. + */ +BOOST_AUTO_TEST_CASE(AdaBoostTrainingDataOrModelTest) +{ + arma::mat trainData; + if (!data::Load("trainSet.csv", trainData)) + BOOST_FAIL("Unable to load train dataset trainSet.csv!"); + + SetInputParam("training", std::move(trainData)); + + mlpackMain(); + + SetInputParam("input_model", std::move(CLI::GetParam("output_model"))); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Weak learner should be either Decision Stump or Perceptron. + */ + +BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerTest) +{ + arma::mat trainData; + if (!data::Load("trainSet.csv", trainData)) + BOOST_FAIL("Unable to load train dataset trainSet.csv!"); + + SetInputParam("training", std::move(trainData)); + SetInputParam("weak_learner", std::string("decision tree")); + + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; +} + +/** + * Weak learner should be ignored if it is + * specified with an input model file. + */ +BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerIgnoredTest) +{ + arma::mat trainData; + if (!data::Load("vc2.csv", trainData)) + BOOST_FAIL("Unable to load train dataset vc2.csv!"); + + arma::Row labels; + if (!data::Load("vc2_labels.txt", labels)) + BOOST_FAIL("Unable to load label dataset vc2_labels.txt!"); + + arma::mat testData; + if (!data::Load("vc2_test.csv", testData)) + BOOST_FAIL("Unable to load test dataset vc2.csv!"); + + SetInputParam("training", std::move(trainData)); + SetInputParam("labels", std::move(labels)); + + SetInputParam("test", std::move(testData)); + + mlpackMain(); + + arma::Row output; + output = std::move(CLI::GetParam>("output")); + + ResetSetting(); + + // Default value is Decision Stump + SetInputParam("input_model", std::move(CLI::GetParam("output_model"))); + SetInputParam("weak_learner", std::string("perceptron")); + + const string weakLearner = CLI::GetParam("weak_learner"); + if (weakLearner == "perceptron") + { + Log::Fatal.ignoreInput = true; + BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); + Log::Fatal.ignoreInput = false; + } +} + +BOOST_AUTO_TEST_SUITE_END(); From d97f0eca1b32ebbdfef82a0fb6190c0637dc4a31 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Thu, 1 Feb 2018 20:18:55 +0530 Subject: [PATCH 078/113] Update for style check --- src/mlpack/tests/main_tests/adaboost_test.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index c618c876bd..173ac6d048 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -72,7 +72,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostOutputDimensionTest) mlpackMain(); // Check that number of predicted labels is equal to the input test points. - BOOST_REQUIRE_EQUAL(CLI::GetParam>("output").n_cols, testSize); + BOOST_REQUIRE_EQUAL(CLI::GetParam>("output").n_cols, + testSize); BOOST_REQUIRE_EQUAL(CLI::GetParam>("output").n_rows, 1); } @@ -106,7 +107,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostModelReuseTest) ResetSetting(); SetInputParam("test", std::move(testData)); - SetInputParam("input_model", std::move(CLI::GetParam("output_model"))); + SetInputParam("input_model", + std::move(CLI::GetParam("output_model"))); mlpackMain(); @@ -192,7 +194,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostTrainingDataOrModelTest) mlpackMain(); - SetInputParam("input_model", std::move(CLI::GetParam("output_model"))); + SetInputParam("input_model", + std::move(CLI::GetParam("output_model"))); Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); @@ -248,7 +251,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerIgnoredTest) ResetSetting(); // Default value is Decision Stump - SetInputParam("input_model", std::move(CLI::GetParam("output_model"))); + SetInputParam("input_model", + std::move(CLI::GetParam("output_model"))); SetInputParam("weak_learner", std::string("perceptron")); const string weakLearner = CLI::GetParam("weak_learner"); From ed0ce0933383d27123864c18fa110926568b6ab5 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Thu, 1 Feb 2018 20:21:45 +0530 Subject: [PATCH 079/113] Update for Style Checks --- src/mlpack/tests/main_tests/adaboost_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 173ac6d048..bf4c3b93ba 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostOutputDimensionTest) mlpackMain(); // Check that number of predicted labels is equal to the input test points. - BOOST_REQUIRE_EQUAL(CLI::GetParam>("output").n_cols, + BOOST_REQUIRE_EQUAL(CLI::GetParam>("output").n_cols, testSize); BOOST_REQUIRE_EQUAL(CLI::GetParam>("output").n_rows, 1); } From f66ca3c960ed1b1038246f88cff34696bb607078 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Thu, 1 Feb 2018 22:03:00 +0530 Subject: [PATCH 080/113] Fixed segmentation error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index bf4c3b93ba..0b665f7a72 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -103,12 +103,13 @@ BOOST_AUTO_TEST_CASE(AdaBoostModelReuseTest) arma::Row output; output = std::move(CLI::GetParam>("output")); + AdaBoost model = CLI::GetParam("output_model"); ResetSetting(); SetInputParam("test", std::move(testData)); - SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + SetInputParam("input_model", std::move(model)); + mlpackMain(); @@ -163,13 +164,13 @@ BOOST_AUTO_TEST_CASE(AdaBoostWithoutLabelTest) mlpackMain(); + arma::Row output; + output = std::move(CLI::GetParam>("output")); + ResetSetting(); trainData.shed_row(trainData.n_rows - 1); - arma::Row output; - output = std::move(CLI::GetParam>("output")); - // Now train Adaboost with labels provided. SetInputParam("training", std::move(trainData)); SetInputParam("test", std::move(testData)); @@ -246,13 +247,13 @@ BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerIgnoredTest) mlpackMain(); arma::Row output; + AdaBoost model = CLI::GetParam("output_model"); output = std::move(CLI::GetParam>("output")); ResetSetting(); // Default value is Decision Stump - SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + SetInputParam("input_model", std::move(model)); SetInputParam("weak_learner", std::string("perceptron")); const string weakLearner = CLI::GetParam("weak_learner"); From d39748049a8c0f6a02e6ba8aa676aab1d7a9a982 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Thu, 1 Feb 2018 22:04:41 +0530 Subject: [PATCH 081/113] Fixed Segmentation error From e7b9ff95ea4b2feaf8a794d3aefea6791b59f315 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Thu, 1 Feb 2018 23:02:30 +0530 Subject: [PATCH 082/113] Fixed an error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 0b665f7a72..b303d8aa6e 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -35,12 +35,6 @@ struct AdaBoostTestFixture } }; -void ResetSetting() -{ - CLI::ClearSettings(); - CLI::RestoreSettings(testName); -} - BOOST_FIXTURE_TEST_SUITE(AdaBoostMainTest, AdaBoostTestFixture); /** @@ -105,8 +99,9 @@ BOOST_AUTO_TEST_CASE(AdaBoostModelReuseTest) output = std::move(CLI::GetParam>("output")); AdaBoost model = CLI::GetParam("output_model"); - ResetSetting(); - + CLI::GetSingleton().Parameters()["training"].wasPassed = false; + CLI::GetSingleton().Parameters()["test"].wasPassed = false; + SetInputParam("test", std::move(testData)); SetInputParam("input_model", std::move(model)); @@ -167,8 +162,9 @@ BOOST_AUTO_TEST_CASE(AdaBoostWithoutLabelTest) arma::Row output; output = std::move(CLI::GetParam>("output")); - ResetSetting(); - + CLI::GetSingleton().Parameters()["training"].wasPassed = false; + CLI::GetSingleton().Parameters()["test"].wasPassed = false; + trainData.shed_row(trainData.n_rows - 1); // Now train Adaboost with labels provided. @@ -250,8 +246,9 @@ BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerIgnoredTest) AdaBoost model = CLI::GetParam("output_model"); output = std::move(CLI::GetParam>("output")); - ResetSetting(); - + CLI::GetSingleton().Parameters()["training"].wasPassed = false; + CLI::GetSingleton().Parameters()["test"].wasPassed = false; + // Default value is Decision Stump SetInputParam("input_model", std::move(model)); SetInputParam("weak_learner", std::string("perceptron")); From 283f1ee7ed25f9ecb56c332d1675960983b8616d Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Thu, 1 Feb 2018 23:05:46 +0530 Subject: [PATCH 083/113] Fixed style checks --- src/mlpack/tests/main_tests/adaboost_test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index b303d8aa6e..6365a2c311 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostModelReuseTest) CLI::GetSingleton().Parameters()["training"].wasPassed = false; CLI::GetSingleton().Parameters()["test"].wasPassed = false; - + SetInputParam("test", std::move(testData)); SetInputParam("input_model", std::move(model)); @@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostWithoutLabelTest) CLI::GetSingleton().Parameters()["training"].wasPassed = false; CLI::GetSingleton().Parameters()["test"].wasPassed = false; - + trainData.shed_row(trainData.n_rows - 1); // Now train Adaboost with labels provided. @@ -248,7 +248,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerIgnoredTest) CLI::GetSingleton().Parameters()["training"].wasPassed = false; CLI::GetSingleton().Parameters()["test"].wasPassed = false; - + // Default value is Decision Stump SetInputParam("input_model", std::move(model)); SetInputParam("weak_learner", std::string("perceptron")); From 326e2309a1fee2ce30a81b855da5c49707458c26 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Fri, 2 Feb 2018 00:22:41 +0530 Subject: [PATCH 084/113] Fixed memory issues --- src/mlpack/tests/main_tests/adaboost_test.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 6365a2c311..cfecf8fb42 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -97,14 +97,13 @@ BOOST_AUTO_TEST_CASE(AdaBoostModelReuseTest) arma::Row output; output = std::move(CLI::GetParam>("output")); - AdaBoost model = CLI::GetParam("output_model"); CLI::GetSingleton().Parameters()["training"].wasPassed = false; CLI::GetSingleton().Parameters()["test"].wasPassed = false; SetInputParam("test", std::move(testData)); - SetInputParam("input_model", std::move(model)); - + SetInputParam("input_model", + std::move(CLI::GetParam("output_model"))); mlpackMain(); @@ -159,6 +158,9 @@ BOOST_AUTO_TEST_CASE(AdaBoostWithoutLabelTest) mlpackMain(); + CLI::GetSingleton().Parameters()["training"].wasPassed = false; + CLI::GetSingleton().Parameters()["test"].wasPassed = false; + arma::Row output; output = std::move(CLI::GetParam>("output")); @@ -243,7 +245,6 @@ BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerIgnoredTest) mlpackMain(); arma::Row output; - AdaBoost model = CLI::GetParam("output_model"); output = std::move(CLI::GetParam>("output")); CLI::GetSingleton().Parameters()["training"].wasPassed = false; From 74afe2f0542b6792b553d77a8ef125ec9f37d9d4 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Fri, 2 Feb 2018 00:34:46 +0530 Subject: [PATCH 085/113] Fixed static code --- src/mlpack/tests/main_tests/adaboost_test.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index cfecf8fb42..244c2c37b9 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -164,9 +164,6 @@ BOOST_AUTO_TEST_CASE(AdaBoostWithoutLabelTest) arma::Row output; output = std::move(CLI::GetParam>("output")); - CLI::GetSingleton().Parameters()["training"].wasPassed = false; - CLI::GetSingleton().Parameters()["test"].wasPassed = false; - trainData.shed_row(trainData.n_rows - 1); // Now train Adaboost with labels provided. From 8b01dc2050c1f452ecaccbcdc8eddc9af52de4eb Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Fri, 2 Feb 2018 00:44:39 +0530 Subject: [PATCH 086/113] Fixed memory leak --- src/mlpack/tests/main_tests/adaboost_test.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 244c2c37b9..52d9ade607 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -248,7 +248,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerIgnoredTest) CLI::GetSingleton().Parameters()["test"].wasPassed = false; // Default value is Decision Stump - SetInputParam("input_model", std::move(model)); + SetInputParam("input_model", + std::move(CLI::GetParam("output_model"))); SetInputParam("weak_learner", std::string("perceptron")); const string weakLearner = CLI::GetParam("weak_learner"); From 090b2e429e271b1029c09f0c699a5992a25e8f4c Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Fri, 2 Feb 2018 02:14:43 +0530 Subject: [PATCH 087/113] Fixed a runtime error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 52d9ade607..21f618dda6 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -241,17 +241,18 @@ BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerIgnoredTest) mlpackMain(); - arma::Row output; - output = std::move(CLI::GetParam>("output")); - CLI::GetSingleton().Parameters()["training"].wasPassed = false; CLI::GetSingleton().Parameters()["test"].wasPassed = false; + CLI::GetSingleton().Parameters()["weak_learner"].wasPassed = false; // Default value is Decision Stump SetInputParam("input_model", std::move(CLI::GetParam("output_model"))); + SetInputParam("test", std::move(testData)); SetInputParam("weak_learner", std::string("perceptron")); + mlpackMain(); + const string weakLearner = CLI::GetParam("weak_learner"); if (weakLearner == "perceptron") { From 21330f4aec520bb1a9d649ce164ab33a0006633e Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Fri, 2 Feb 2018 03:17:51 +0530 Subject: [PATCH 088/113] AdaBoost Binding test --- src/mlpack/tests/main_tests/adaboost_test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 21f618dda6..d1d824e03a 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -99,6 +99,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostModelReuseTest) output = std::move(CLI::GetParam>("output")); CLI::GetSingleton().Parameters()["training"].wasPassed = false; + CLI::GetSingleton().Parameters()["labels"].wasPassed = false; CLI::GetSingleton().Parameters()["test"].wasPassed = false; SetInputParam("test", std::move(testData)); @@ -243,6 +244,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerIgnoredTest) CLI::GetSingleton().Parameters()["training"].wasPassed = false; CLI::GetSingleton().Parameters()["test"].wasPassed = false; + CLI::GetSingleton().Parameters()["labels"].wasPassed = false; CLI::GetSingleton().Parameters()["weak_learner"].wasPassed = false; // Default value is Decision Stump From 1693dadca3bab48e973155cdaa1e2c5ffd3f558b Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Fri, 2 Feb 2018 04:18:22 +0530 Subject: [PATCH 089/113] Adaboost binding test --- src/mlpack/tests/main_tests/adaboost_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index d1d824e03a..2006bb02b8 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostModelReuseTest) SetInputParam("training", std::move(trainData)); SetInputParam("labels", std::move(labels)); - SetInputParam("test", std::move(testData)); + SetInputParam("test", testData); mlpackMain(); @@ -238,7 +238,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerIgnoredTest) SetInputParam("training", std::move(trainData)); SetInputParam("labels", std::move(labels)); - SetInputParam("test", std::move(testData)); + SetInputParam("test", testData); mlpackMain(); From b394efdfc9bc192fef0522dff86b1f55b16e8992 Mon Sep 17 00:00:00 2001 From: manish7294 Date: Fri, 2 Feb 2018 13:32:51 +0530 Subject: [PATCH 090/113] Added Dataset Loading function --- .../tests/main_tests/sparse_coding_test.cpp | 105 +++++------------- 1 file changed, 27 insertions(+), 78 deletions(-) diff --git a/src/mlpack/tests/main_tests/sparse_coding_test.cpp b/src/mlpack/tests/main_tests/sparse_coding_test.cpp index ff2015989e..19ccb231db 100644 --- a/src/mlpack/tests/main_tests/sparse_coding_test.cpp +++ b/src/mlpack/tests/main_tests/sparse_coding_test.cpp @@ -42,6 +42,20 @@ struct SparseCodingTestFixture BOOST_FIXTURE_TEST_SUITE(SparseCodingMainTest, SparseCodingTestFixture); +/** + * Helper function to load datasets. + */ +void LoadData(arma::mat& inputData, arma::mat& testData) +{ + // Load train dataset. + if (!data::Load("iris_train.csv", inputData)) + BOOST_FAIL("Cannot load train dataset iris_train.csv!"); + + // Load test dataset. + if (!data::Load("iris_test.csv", testData)) + BOOST_FAIL("Cannot load test dataset iris_test.csv!"); +} + /** * Make sure that output points in dictionary equals number of * atoms passed and codes have desired dimension. @@ -49,13 +63,8 @@ BOOST_FIXTURE_TEST_SUITE(SparseCodingMainTest, SparseCodingTestFixture); BOOST_AUTO_TEST_CASE(SparseCodingOutputDimensionTest) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); @@ -89,13 +98,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingOutputDimensionTest) BOOST_AUTO_TEST_CASE(SparseCodingNormalizationTest) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); @@ -246,13 +250,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingReqAtomsTest) BOOST_AUTO_TEST_CASE(SparseCodingModelVerTest) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); @@ -273,13 +272,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingModelVerTest) BOOST_AUTO_TEST_CASE(SparseCodingAtomsVerTest) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); // 2 points. @@ -301,13 +295,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingAtomsVerTest) BOOST_AUTO_TEST_CASE(SparseCodingRowsVerTest) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); @@ -333,13 +322,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingRowsVerTest) BOOST_AUTO_TEST_CASE(SparseCodingDataDimensionalityTest) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); @@ -363,13 +347,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingDataDimensionalityTest) BOOST_AUTO_TEST_CASE(SparseCodingModelReuseTest) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); // Input data. SetInputParam("training", inputData); @@ -427,13 +406,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingModelReuseTest) BOOST_AUTO_TEST_CASE(SparseCodingDiffMaxItrTest) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); @@ -483,13 +457,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffMaxItrTest) BOOST_AUTO_TEST_CASE(SparseCodingDiffObjToleranceTest) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); @@ -536,13 +505,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffObjToleranceTest) BOOST_AUTO_TEST_CASE(SparseCodingDiffNewtonToleranceTest) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); @@ -589,13 +553,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffNewtonToleranceTest) BOOST_AUTO_TEST_CASE(SparseCodingDiffL1Test) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); @@ -642,13 +601,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffL1Test) BOOST_AUTO_TEST_CASE(SparseCodingDiffL2Test) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); @@ -695,13 +649,8 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffL2Test) BOOST_AUTO_TEST_CASE(SparseCodingDiffL1L2Test) { arma::mat inputData; - if (!data::Load("iris_train.csv", inputData)) - BOOST_FAIL("Cannot load train dataset iris_train.csv!"); - - // Load test dataset. arma::mat testData; - if (!data::Load("iris_test.csv", testData)) - BOOST_FAIL("Cannot load test dataset iris_test.csv!"); + LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); From 0cbaaf3c0dcf43e2af10fcf4566dab5318d7b93d Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Mon, 5 Feb 2018 10:52:18 +0530 Subject: [PATCH 091/113] Added tests --- src/mlpack/tests/main_tests/adaboost_test.cpp | 168 ++++++++++++++++-- 1 file changed, 150 insertions(+), 18 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 2006bb02b8..b39d93fe55 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -202,7 +202,6 @@ BOOST_AUTO_TEST_CASE(AdaBoostTrainingDataOrModelTest) /** * Weak learner should be either Decision Stump or Perceptron. */ - BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerTest) { arma::mat trainData; @@ -218,10 +217,9 @@ BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerTest) } /** - * Weak learner should be ignored if it is - * specified with an input model file. + * Different Weak learner should give different outputs. */ -BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerIgnoredTest) +BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) { arma::mat trainData; if (!data::Load("vc2.csv", trainData)) @@ -242,26 +240,160 @@ BOOST_AUTO_TEST_CASE(AdaBoostWeakLearnerIgnoredTest) mlpackMain(); - CLI::GetSingleton().Parameters()["training"].wasPassed = false; - CLI::GetSingleton().Parameters()["test"].wasPassed = false; - CLI::GetSingleton().Parameters()["labels"].wasPassed = false; + arma::Row output; + output = std::move(CLI::GetParam>("output")); + CLI::GetSingleton().Parameters()["weak_learner"].wasPassed = false; - // Default value is Decision Stump - SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); - SetInputParam("test", std::move(testData)); SetInputParam("weak_learner", std::string("perceptron")); mlpackMain(); - const string weakLearner = CLI::GetParam("weak_learner"); - if (weakLearner == "perceptron") - { - Log::Fatal.ignoreInput = true; - BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); - Log::Fatal.ignoreInput = false; - } + arma::Row outputPerceptron; + outputPerceptron = std::move(CLI::GetParam>("output")); + + CheckMatrices(output, outputPerceptron); +} + +/** + * Accuracy increases as Number of Iterations increases. + * (Or converges and remains same) + */ +BOOST_AUTO_TEST_CASE(AdaBoostDiffItrTest) +{ + arma::mat trainData; + if (!data::Load("vc2.csv", trainData)) + BOOST_FAIL("Unable to load train dataset vc2.csv!"); + + arma::Row labels; + if (!data::Load("vc2_labels.txt", labels)) + BOOST_FAIL("Unable to load label dataset vc2_labels.txt!"); + + arma::mat testData; + if (!data::Load("vc2_test.csv", testData)) + BOOST_FAIL("Unable to load test dataset vc2.csv!"); + + arma::Row testLabels; + if (!data::Load("vc2_test_labels.txt", testLabels)) + BOOST_FAIL("Unable to load labels for vc2__test_labels.txt"); + + //Iterations = 1 + SetInputParam("training", std::move(trainData)); + SetInputParam("labels", std::move(labels)); + SetInputParam("weak_learner", std::string("perceptron")); + SetInputParam("iterations", (int) 1); + + mlpackMain(); + + // Calculate accuracy. + arma::Row output; + CLI::GetParam("output_model").Classify(testData, + output); + + size_t correct = arma::accu(output == testLabels); + double accuracy1 = (double(correct) / double(testLabels.n_elem) * 100); + + //Iterations = 10 + SetInputParam("training", std::move(trainData)); + SetInputParam("labels", std::move(labels)); + SetInputParam("weak_learner", std::string("perceptron")); + SetInputParam("iterations", (int) 10); + + mlpackMain(); + + // Calculate accuracy. + CLI::GetParam("output_model").Classify(testData, + output); + + + correct = arma::accu(output == testLabels); + double accuracy10 = (double(correct) / double(testLabels.n_elem) * 100); + + //Iterations = 100 + SetInputParam("training", std::move(trainData)); + SetInputParam("labels", std::move(labels)); + SetInputParam("weak_learner", std::string("perceptron")); + SetInputParam("iterations", (int) 100); + + mlpackMain(); + + // Calculate accuracy. + CLI::GetParam("output_model").Classify(testData, + output); + + correct = arma::accu(output == testLabels); + double accuracy100 = (double(correct) / double(testLabels.n_elem) * 100); + + BOOST_REQUIRE(accuracy100 >= accuracy10 && accuracy10 >= accuracy1); +} + +/** + * Accuracy increases as tolerance decreases. + * (Execution Time also increases) + */ +BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) +{ + arma::mat trainData; + if (!data::Load("vc2.csv", trainData)) + BOOST_FAIL("Unable to load train dataset vc2.csv!"); + + arma::Row labels; + if (!data::Load("vc2_labels.txt", labels)) + BOOST_FAIL("Unable to load label dataset vc2_labels.txt!"); + + arma::mat testData; + if (!data::Load("vc2_test.csv", testData)) + BOOST_FAIL("Unable to load test dataset vc2.csv!"); + + arma::Row testLabels; + if (!data::Load("vc2_test_labels.txt", testLabels)) + BOOST_FAIL("Unable to load labels for vc2__test_labels.txt"); + + //tolerance = 1e-5 + SetInputParam("training", std::move(trainData)); + SetInputParam("labels", std::move(labels)); + SetInputParam("tolerance", (double) 1e-5); + + mlpackMain(); + + // Calculate accuracy. + arma::Row output; + CLI::GetParam("output_model").Classify(testData, + output); + + size_t correct = arma::accu(output == testLabels); + double accuracy1 = (double(correct) / double(testLabels.n_elem) * 100); + + //Iterations = 0.1 + SetInputParam("training", std::move(trainData)); + SetInputParam("labels", std::move(labels)); + SetInputParam("tolerance", (double) 0.1); + + mlpackMain(); + + // Calculate accuracy. + CLI::GetParam("output_model").Classify(testData, + output); + + + correct = arma::accu(output == testLabels); + double accuracy2 = (double(correct) / double(testLabels.n_elem) * 100); + + //tolerance = 0.5 + SetInputParam("training", std::move(trainData)); + SetInputParam("labels", std::move(labels)); + SetInputParam("tolerance", (double) 0.5); + + mlpackMain(); + + // Calculate accuracy. + CLI::GetParam("output_model").Classify(testData, + output); + + correct = arma::accu(output == testLabels); + double accuracy3 = (double(correct) / double(testLabels.n_elem) * 100); + + BOOST_REQUIRE(accuracy1 >= accuracy2 && accuracy2 >= accuracy3); } BOOST_AUTO_TEST_SUITE_END(); From 8f33fd5145f454fc37ffdd78f5549b365699551e Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Mon, 5 Feb 2018 10:56:14 +0530 Subject: [PATCH 092/113] Fixed Style check --- src/mlpack/tests/main_tests/adaboost_test.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index b39d93fe55..fcf134aa05 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -277,7 +277,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffItrTest) if (!data::Load("vc2_test_labels.txt", testLabels)) BOOST_FAIL("Unable to load labels for vc2__test_labels.txt"); - //Iterations = 1 + // Iterations = 1 SetInputParam("training", std::move(trainData)); SetInputParam("labels", std::move(labels)); SetInputParam("weak_learner", std::string("perceptron")); @@ -293,7 +293,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffItrTest) size_t correct = arma::accu(output == testLabels); double accuracy1 = (double(correct) / double(testLabels.n_elem) * 100); - //Iterations = 10 + // Iterations = 10 SetInputParam("training", std::move(trainData)); SetInputParam("labels", std::move(labels)); SetInputParam("weak_learner", std::string("perceptron")); @@ -309,7 +309,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffItrTest) correct = arma::accu(output == testLabels); double accuracy10 = (double(correct) / double(testLabels.n_elem) * 100); - //Iterations = 100 + // Iterations = 100 SetInputParam("training", std::move(trainData)); SetInputParam("labels", std::move(labels)); SetInputParam("weak_learner", std::string("perceptron")); @@ -349,7 +349,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) if (!data::Load("vc2_test_labels.txt", testLabels)) BOOST_FAIL("Unable to load labels for vc2__test_labels.txt"); - //tolerance = 1e-5 + // tolerance = 1e-5 SetInputParam("training", std::move(trainData)); SetInputParam("labels", std::move(labels)); SetInputParam("tolerance", (double) 1e-5); @@ -364,7 +364,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) size_t correct = arma::accu(output == testLabels); double accuracy1 = (double(correct) / double(testLabels.n_elem) * 100); - //Iterations = 0.1 + // tolerance = 0.1 SetInputParam("training", std::move(trainData)); SetInputParam("labels", std::move(labels)); SetInputParam("tolerance", (double) 0.1); @@ -379,7 +379,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) correct = arma::accu(output == testLabels); double accuracy2 = (double(correct) / double(testLabels.n_elem) * 100); - //tolerance = 0.5 + // tolerance = 0.5 SetInputParam("training", std::move(trainData)); SetInputParam("labels", std::move(labels)); SetInputParam("tolerance", (double) 0.5); From 6da6e662f216b8a80a2882fbdd3616623c37b083 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Mon, 5 Feb 2018 12:48:02 +0530 Subject: [PATCH 093/113] Fixed an error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index fcf134aa05..52c87ceee5 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -243,8 +243,6 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) arma::Row output; output = std::move(CLI::GetParam>("output")); - CLI::GetSingleton().Parameters()["weak_learner"].wasPassed = false; - SetInputParam("weak_learner", std::string("perceptron")); mlpackMain(); @@ -252,7 +250,12 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) arma::Row outputPerceptron; outputPerceptron = std::move(CLI::GetParam>("output")); - CheckMatrices(output, outputPerceptron); + for (size_t i = 0; i < output.n_elem; ++i) + if(output[i] != outputPerceptron[i]) + { + BOOST_REQUIRE_NE(output[i], outputPerceptron[i]); + break; + } } /** @@ -324,7 +327,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffItrTest) correct = arma::accu(output == testLabels); double accuracy100 = (double(correct) / double(testLabels.n_elem) * 100); - BOOST_REQUIRE(accuracy100 >= accuracy10 && accuracy10 >= accuracy1); + BOOST_REQUIRE_LE(accuracy1, accuracy10); + BOOST_REQUIRE_LE(accuracy10, accuracy100); } /** @@ -349,10 +353,10 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) if (!data::Load("vc2_test_labels.txt", testLabels)) BOOST_FAIL("Unable to load labels for vc2__test_labels.txt"); - // tolerance = 1e-5 + // tolerance = 0.001 SetInputParam("training", std::move(trainData)); SetInputParam("labels", std::move(labels)); - SetInputParam("tolerance", (double) 1e-5); + SetInputParam("tolerance", (double) 0.001); mlpackMain(); @@ -364,6 +368,20 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) size_t correct = arma::accu(output == testLabels); double accuracy1 = (double(correct) / double(testLabels.n_elem) * 100); + // tolerance = 0.01 + SetInputParam("training", std::move(trainData)); + SetInputParam("labels", std::move(labels)); + SetInputParam("tolerance", (double) 0.01); + + mlpackMain(); + + // Calculate accuracy. + CLI::GetParam("output_model").Classify(testData, + output); + + correct = arma::accu(output == testLabels); + double accuracy2 = (double(correct) / double(testLabels.n_elem) * 100); + // tolerance = 0.1 SetInputParam("training", std::move(trainData)); SetInputParam("labels", std::move(labels)); @@ -371,21 +389,6 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) mlpackMain(); - // Calculate accuracy. - CLI::GetParam("output_model").Classify(testData, - output); - - - correct = arma::accu(output == testLabels); - double accuracy2 = (double(correct) / double(testLabels.n_elem) * 100); - - // tolerance = 0.5 - SetInputParam("training", std::move(trainData)); - SetInputParam("labels", std::move(labels)); - SetInputParam("tolerance", (double) 0.5); - - mlpackMain(); - // Calculate accuracy. CLI::GetParam("output_model").Classify(testData, output); @@ -393,7 +396,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) correct = arma::accu(output == testLabels); double accuracy3 = (double(correct) / double(testLabels.n_elem) * 100); - BOOST_REQUIRE(accuracy1 >= accuracy2 && accuracy2 >= accuracy3); + BOOST_REQUIRE_LE(accuracy1, accuracy2); + BOOST_REQUIRE_LE(accuracy2, accuracy3); } BOOST_AUTO_TEST_SUITE_END(); From 2bc095e665678663cdc1b97644028da5a2590808 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Mon, 5 Feb 2018 12:57:35 +0530 Subject: [PATCH 094/113] fixed style check error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 52c87ceee5..912d561b34 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -251,7 +251,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) outputPerceptron = std::move(CLI::GetParam>("output")); for (size_t i = 0; i < output.n_elem; ++i) - if(output[i] != outputPerceptron[i]) + if (output[i] != outputPerceptron[i]) { BOOST_REQUIRE_NE(output[i], outputPerceptron[i]); break; From 286ab59731432670a7d3503e6d49898caef6a0ac Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Mon, 5 Feb 2018 14:07:06 +0530 Subject: [PATCH 095/113] fixed memory error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 912d561b34..3f09251297 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -250,7 +250,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) arma::Row outputPerceptron; outputPerceptron = std::move(CLI::GetParam>("output")); - for (size_t i = 0; i < output.n_elem; ++i) + for (size_t i = 0; i < output.n_rows; ++i) if (output[i] != outputPerceptron[i]) { BOOST_REQUIRE_NE(output[i], outputPerceptron[i]); From b598bc8a810ac490bd6c3e06250bf3293f3d24c3 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Mon, 5 Feb 2018 20:19:32 +0530 Subject: [PATCH 096/113] Fix for memory error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 3f09251297..e7d28e4619 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -233,7 +233,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) if (!data::Load("vc2_test.csv", testData)) BOOST_FAIL("Unable to load test dataset vc2.csv!"); - SetInputParam("training", std::move(trainData)); + SetInputParam("training", trainData); SetInputParam("labels", std::move(labels)); SetInputParam("test", testData); @@ -251,11 +251,13 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) outputPerceptron = std::move(CLI::GetParam>("output")); for (size_t i = 0; i < output.n_rows; ++i) + { if (output[i] != outputPerceptron[i]) { BOOST_REQUIRE_NE(output[i], outputPerceptron[i]); break; } + } } /** @@ -281,8 +283,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffItrTest) BOOST_FAIL("Unable to load labels for vc2__test_labels.txt"); // Iterations = 1 - SetInputParam("training", std::move(trainData)); - SetInputParam("labels", std::move(labels)); + SetInputParam("training", trainData); + SetInputParam("labels", labels); SetInputParam("weak_learner", std::string("perceptron")); SetInputParam("iterations", (int) 1); @@ -297,8 +299,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffItrTest) double accuracy1 = (double(correct) / double(testLabels.n_elem) * 100); // Iterations = 10 - SetInputParam("training", std::move(trainData)); - SetInputParam("labels", std::move(labels)); + SetInputParam("training", trainData); + SetInputParam("labels", labels); SetInputParam("weak_learner", std::string("perceptron")); SetInputParam("iterations", (int) 10); @@ -313,8 +315,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffItrTest) double accuracy10 = (double(correct) / double(testLabels.n_elem) * 100); // Iterations = 100 - SetInputParam("training", std::move(trainData)); - SetInputParam("labels", std::move(labels)); + SetInputParam("training", trainData); + SetInputParam("labels", labels); SetInputParam("weak_learner", std::string("perceptron")); SetInputParam("iterations", (int) 100); @@ -354,8 +356,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) BOOST_FAIL("Unable to load labels for vc2__test_labels.txt"); // tolerance = 0.001 - SetInputParam("training", std::move(trainData)); - SetInputParam("labels", std::move(labels)); + SetInputParam("training", trainData); + SetInputParam("labels", labels); SetInputParam("tolerance", (double) 0.001); mlpackMain(); @@ -369,8 +371,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) double accuracy1 = (double(correct) / double(testLabels.n_elem) * 100); // tolerance = 0.01 - SetInputParam("training", std::move(trainData)); - SetInputParam("labels", std::move(labels)); + SetInputParam("training", trainData); + SetInputParam("labels", labels); SetInputParam("tolerance", (double) 0.01); mlpackMain(); @@ -383,8 +385,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) double accuracy2 = (double(correct) / double(testLabels.n_elem) * 100); // tolerance = 0.1 - SetInputParam("training", std::move(trainData)); - SetInputParam("labels", std::move(labels)); + SetInputParam("training", trainData); + SetInputParam("labels", labels); SetInputParam("tolerance", (double) 0.1); mlpackMain(); From 9612890ed350c0fbb547424e9c88c676e3f5a747 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Mon, 5 Feb 2018 20:58:58 +0530 Subject: [PATCH 097/113] Fixed an error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index e7d28e4619..90397fcc4b 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -250,7 +250,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) arma::Row outputPerceptron; outputPerceptron = std::move(CLI::GetParam>("output")); - for (size_t i = 0; i < output.n_rows; ++i) + for (size_t i = 0; i < output.n_elem; ++i) { if (output[i] != outputPerceptron[i]) { From 94c07f903da4bc35dd25663cbef5febe11c9c4d7 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Mon, 5 Feb 2018 22:00:45 +0530 Subject: [PATCH 098/113] Update to handle changes in #1214 --- src/mlpack/tests/main_tests/adaboost_test.cpp | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 90397fcc4b..43848292d0 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -31,6 +31,7 @@ struct AdaBoostTestFixture ~AdaBoostTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; @@ -104,7 +105,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostModelReuseTest) SetInputParam("test", std::move(testData)); SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + CLI::GetParam("output_model")); mlpackMain(); @@ -165,6 +166,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostWithoutLabelTest) arma::Row output; output = std::move(CLI::GetParam>("output")); + bindings::tests::CleanMemory(); + trainData.shed_row(trainData.n_rows - 1); // Now train Adaboost with labels provided. @@ -192,7 +195,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostTrainingDataOrModelTest) mlpackMain(); SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + CLI::GetParam("output_model")); Log::Fatal.ignoreInput = true; BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error); @@ -234,7 +237,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) BOOST_FAIL("Unable to load test dataset vc2.csv!"); SetInputParam("training", trainData); - SetInputParam("labels", std::move(labels)); + SetInputParam("labels", labels); SetInputParam("test", testData); @@ -243,6 +246,8 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) arma::Row output; output = std::move(CLI::GetParam>("output")); + bindings::tests::CleanMemory(); + SetInputParam("weak_learner", std::string("perceptron")); mlpackMain(); @@ -292,12 +297,14 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffItrTest) // Calculate accuracy. arma::Row output; - CLI::GetParam("output_model").Classify(testData, + CLI::GetParam("output_model")->Classify(testData, output); size_t correct = arma::accu(output == testLabels); double accuracy1 = (double(correct) / double(testLabels.n_elem) * 100); + bindings::tests::CleanMemory(); + // Iterations = 10 SetInputParam("training", trainData); SetInputParam("labels", labels); @@ -307,13 +314,14 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffItrTest) mlpackMain(); // Calculate accuracy. - CLI::GetParam("output_model").Classify(testData, + CLI::GetParam("output_model")->Classify(testData, output); - correct = arma::accu(output == testLabels); double accuracy10 = (double(correct) / double(testLabels.n_elem) * 100); + bindings::tests::CleanMemory(); + // Iterations = 100 SetInputParam("training", trainData); SetInputParam("labels", labels); @@ -323,7 +331,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffItrTest) mlpackMain(); // Calculate accuracy. - CLI::GetParam("output_model").Classify(testData, + CLI::GetParam("output_model")->Classify(testData, output); correct = arma::accu(output == testLabels); @@ -364,12 +372,14 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) // Calculate accuracy. arma::Row output; - CLI::GetParam("output_model").Classify(testData, + CLI::GetParam("output_model")->Classify(testData, output); size_t correct = arma::accu(output == testLabels); double accuracy1 = (double(correct) / double(testLabels.n_elem) * 100); + bindings::tests::CleanMemory(); + // tolerance = 0.01 SetInputParam("training", trainData); SetInputParam("labels", labels); @@ -378,12 +388,14 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) mlpackMain(); // Calculate accuracy. - CLI::GetParam("output_model").Classify(testData, + CLI::GetParam("output_model")->Classify(testData, output); correct = arma::accu(output == testLabels); double accuracy2 = (double(correct) / double(testLabels.n_elem) * 100); + bindings::tests::CleanMemory(); + // tolerance = 0.1 SetInputParam("training", trainData); SetInputParam("labels", labels); @@ -392,7 +404,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffTolTest) mlpackMain(); // Calculate accuracy. - CLI::GetParam("output_model").Classify(testData, + CLI::GetParam("output_model")->Classify(testData, output); correct = arma::accu(output == testLabels); From c107ffc1c52c1b2e732327183b3626313a5630b1 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 5 Feb 2018 11:39:43 -0500 Subject: [PATCH 099/113] Update test to handle memory as per #1214, and fix a few leaks in sparse_coding_main.cpp. --- .../sparse_coding/sparse_coding_main.cpp | 20 +++++-- .../tests/main_tests/sparse_coding_test.cpp | 58 ++++++++++--------- 2 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/mlpack/methods/sparse_coding/sparse_coding_main.cpp b/src/mlpack/methods/sparse_coding/sparse_coding_main.cpp index 87a2cd278f..e4b561f530 100644 --- a/src/mlpack/methods/sparse_coding/sparse_coding_main.cpp +++ b/src/mlpack/methods/sparse_coding/sparse_coding_main.cpp @@ -188,14 +188,21 @@ static void mlpackMain() // Validate size of initial dictionary. if (sc->Dictionary().n_cols != sc->Atoms()) { - Log::Fatal << "The initial dictionary has " << sc->Dictionary().n_cols + const size_t dictAtoms = sc->Dictionary().n_cols; + const size_t atoms = sc->Atoms(); + if (!CLI::HasParam("input_model")) + delete sc; + Log::Fatal << "The initial dictionary has " << dictAtoms << " atoms, but the number of atoms was specified to be " - << sc->Atoms() << "!" << endl; + << atoms << "!" << endl; } if (sc->Dictionary().n_rows != matX.n_rows) { - Log::Fatal << "The initial dictionary has " << sc->Dictionary().n_rows + const size_t dim = sc->Dictionary().n_rows; + if (!CLI::HasParam("input_model")) + delete sc; + Log::Fatal << "The initial dictionary has " << dim << " dimensions, but the data has " << matX.n_rows << " dimensions!" << endl; } @@ -216,10 +223,15 @@ static void mlpackMain() mat matY = std::move(CLI::GetParam("test")); if (matY.n_rows != sc->Dictionary().n_rows) + { + const size_t dim = sc->Dictionary().n_rows; + if (!CLI::HasParam("input_model")) + delete sc; Log::Fatal << "Model was trained with a dimensionality of " - << sc->Dictionary().n_rows << ", but test data '" + << dim << ", but test data '" << CLI::GetPrintableParam("test") << "' have a " << "dimensionality of " << matY.n_rows << "!" << endl; + } // Normalize each point if the user asked for it. if (CLI::HasParam("normalize")) diff --git a/src/mlpack/tests/main_tests/sparse_coding_test.cpp b/src/mlpack/tests/main_tests/sparse_coding_test.cpp index 19ccb231db..103c8fb366 100644 --- a/src/mlpack/tests/main_tests/sparse_coding_test.cpp +++ b/src/mlpack/tests/main_tests/sparse_coding_test.cpp @@ -36,6 +36,7 @@ struct SparseCodingTestFixture ~SparseCodingTestFixture() { // Clear the settings. + bindings::tests::CleanMemory(); CLI::ClearSettings(); } }; @@ -116,14 +117,14 @@ BOOST_AUTO_TEST_CASE(SparseCodingNormalizationTest) mlpackMain(); // Store outputs. - arma::mat dictionary = - std::move(CLI::GetParam("dictionary")); + arma::mat dictionary = CLI::GetParam("dictionary"); arma::mat codes = - std::move(CLI::GetParam("codes")); + std::move(CLI::GetParam("codes")); // Train for normalization set to false. // Reset passed parameters. + bindings::tests::CleanMemory(); CLI::GetSingleton().Parameters()["normalize"].wasPassed = false; // Normalize train dataset. @@ -174,6 +175,7 @@ BOOST_AUTO_TEST_CASE(SparseCodingBoundsTest) // Test for L2 value. // Input training data. + bindings::tests::CleanMemory(); SetInputParam("training", inputData); SetInputParam("atoms", (int) 10); SetInputParam("lambda2", (double) -1.0); @@ -185,6 +187,7 @@ BOOST_AUTO_TEST_CASE(SparseCodingBoundsTest) // Test for max_iterations. // Input training data. + bindings::tests::CleanMemory(); SetInputParam("training", inputData); SetInputParam("atoms", (int) 10); SetInputParam("max_iterations", (int) -1.0); @@ -196,6 +199,7 @@ BOOST_AUTO_TEST_CASE(SparseCodingBoundsTest) // Test for objective_tolerance. // Input training data. + bindings::tests::CleanMemory(); SetInputParam("training", inputData); SetInputParam("atoms", (int) 10); SetInputParam("objective_tolerance", (double) -1.0); @@ -207,6 +211,7 @@ BOOST_AUTO_TEST_CASE(SparseCodingBoundsTest) // Test for newton_tolerance. // Input training data. + bindings::tests::CleanMemory(); SetInputParam("training", inputData); SetInputParam("atoms", (int) 10); SetInputParam("newton_tolerance", (double) -1.0); @@ -254,10 +259,10 @@ BOOST_AUTO_TEST_CASE(SparseCodingModelVerTest) LoadData(inputData, testData); mat initialDictionary = inputData.cols(0, 1); + SparseCoding* c = new SparseCoding(); // Input trained model and initial_dictionary. - SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + SetInputParam("input_model", c); SetInputParam("initial_dictionary", std::move(initialDictionary)); Log::Fatal.ignoreInput = true; @@ -361,9 +366,9 @@ BOOST_AUTO_TEST_CASE(SparseCodingModelReuseTest) // Store outputs. arma::mat dictionary = - std::move(CLI::GetParam("dictionary")); + std::move(CLI::GetParam("dictionary")); arma::mat codes = - std::move(CLI::GetParam("codes")); + std::move(CLI::GetParam("codes")); // Reset passed parameters. CLI::GetSingleton().Parameters()["training"].wasPassed = false; @@ -372,8 +377,7 @@ BOOST_AUTO_TEST_CASE(SparseCodingModelReuseTest) // Input data. SetInputParam("max_iterations", (int) 100); - SetInputParam("input_model", - std::move(CLI::GetParam("output_model"))); + SetInputParam("input_model", CLI::GetParam("output_model")); SetInputParam("normalize", (bool) true); SetInputParam("test", std::move(testData)); @@ -424,14 +428,14 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffMaxItrTest) mlpackMain(); // Store outputs. - arma::mat dictionary = - std::move(CLI::GetParam("dictionary")); + arma::mat dictionary = CLI::GetParam("dictionary"); arma::mat codes = - std::move(CLI::GetParam("codes")); + std::move(CLI::GetParam("codes")); // Train for max_iterations equals to 100. // Input data. + bindings::tests::CleanMemory(); SetInputParam("training", std::move(inputData)); SetInputParam("atoms", (int) 2); SetInputParam("initial_dictionary", std::move(initialDictionary)); @@ -473,14 +477,14 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffObjToleranceTest) mlpackMain(); // Store outputs. - arma::mat dictionary = - std::move(CLI::GetParam("dictionary")); + arma::mat dictionary = CLI::GetParam("dictionary"); arma::mat codes = - std::move(CLI::GetParam("codes")); + std::move(CLI::GetParam("codes")); // Train for objective_tolerance equals to 10000.0. // Input data. + bindings::tests::CleanMemory(); SetInputParam("training", std::move(inputData)); SetInputParam("atoms", (int) 2); SetInputParam("initial_dictionary", std::move(initialDictionary)); @@ -521,14 +525,14 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffNewtonToleranceTest) mlpackMain(); // Store outputs. - arma::mat dictionary = - std::move(CLI::GetParam("dictionary")); + arma::mat dictionary = CLI::GetParam("dictionary"); arma::mat codes = - std::move(CLI::GetParam("codes")); + std::move(CLI::GetParam("codes")); // Train for newton_tolerance equals to 10000.0. // Input data. + bindings::tests::CleanMemory(); SetInputParam("training", std::move(inputData)); SetInputParam("atoms", (int) 2); SetInputParam("initial_dictionary", std::move(initialDictionary)); @@ -569,14 +573,14 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffL1Test) mlpackMain(); // Store outputs. - arma::mat dictionary = - std::move(CLI::GetParam("dictionary")); + arma::mat dictionary = CLI::GetParam("dictionary"); arma::mat codes = - std::move(CLI::GetParam("codes")); + std::move(CLI::GetParam("codes")); // Train for lambda1 equals to 10000.0. // Input data. + bindings::tests::CleanMemory(); SetInputParam("training", std::move(inputData)); SetInputParam("atoms", (int) 2); SetInputParam("initial_dictionary", std::move(initialDictionary)); @@ -617,14 +621,14 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffL2Test) mlpackMain(); // Store outputs. - arma::mat dictionary = - std::move(CLI::GetParam("dictionary")); + arma::mat dictionary = CLI::GetParam("dictionary"); arma::mat codes = - std::move(CLI::GetParam("codes")); + std::move(CLI::GetParam("codes")); // Train for lambda2 equals to 10000.0. // Input data. + bindings::tests::CleanMemory(); SetInputParam("training", std::move(inputData)); SetInputParam("atoms", (int) 2); SetInputParam("initial_dictionary", std::move(initialDictionary)); @@ -666,14 +670,14 @@ BOOST_AUTO_TEST_CASE(SparseCodingDiffL1L2Test) mlpackMain(); // Store outputs. - arma::mat dictionary = - std::move(CLI::GetParam("dictionary")); + arma::mat dictionary = CLI::GetParam("dictionary"); arma::mat codes = - std::move(CLI::GetParam("codes")); + std::move(CLI::GetParam("codes")); // Train for lambda1 EQUALS 0.0 & lambda2 equals to 10000.0. // Input data. + bindings::tests::CleanMemory(); SetInputParam("training", std::move(inputData)); SetInputParam("atoms", (int) 2); SetInputParam("initial_dictionary", std::move(initialDictionary)); From 7444e2f27be7c37b945a65736432ed127baea7bd Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Mon, 5 Feb 2018 23:10:09 +0530 Subject: [PATCH 100/113] Fixed memory error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 43848292d0..6e7da6dd95 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -238,7 +238,6 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) SetInputParam("training", trainData); SetInputParam("labels", labels); - SetInputParam("test", testData); mlpackMain(); @@ -248,6 +247,13 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) bindings::tests::CleanMemory(); + CLI::GetSingleton().Parameters()["training"].wasPassed = false; + CLI::GetSingleton().Parameters()["labels"].wasPassed = false; + CLI::GetSingleton().Parameters()["test"].wasPassed = false; + + SetInputParam("training", trainData); + SetInputParam("labels", labels); + SetInputParam("test", testData); SetInputParam("weak_learner", std::string("perceptron")); mlpackMain(); @@ -257,11 +263,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) for (size_t i = 0; i < output.n_elem; ++i) { - if (output[i] != outputPerceptron[i]) - { BOOST_REQUIRE_NE(output[i], outputPerceptron[i]); - break; - } } } From daf80950bee3b0648b8b624f6c0cce6a8142cad7 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Mon, 5 Feb 2018 23:37:31 +0530 Subject: [PATCH 101/113] fixed a logic error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 6e7da6dd95..3391ee9e72 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -261,10 +261,18 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) arma::Row outputPerceptron; outputPerceptron = std::move(CLI::GetParam>("output")); + int flag = 0; + for (size_t i = 0; i < output.n_elem; ++i) { - BOOST_REQUIRE_NE(output[i], outputPerceptron[i]); + if (output[i] != outputPerceptron[i]) + { + int flag = 1; + break; + } } + BOOST_REQUIRE_EQUAL(flag, 1) +} } /** From 6a0123c798b2a5d2d683dc9af3aa166bc5458281 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Mon, 5 Feb 2018 23:41:08 +0530 Subject: [PATCH 102/113] Fixed an error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 3391ee9e72..1c6075201f 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -271,7 +271,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) break; } } - BOOST_REQUIRE_EQUAL(flag, 1) + BOOST_REQUIRE_EQUAL(flag, 1); } } From e138521300eea40931c1e4e9bb877bced5ee115c Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Mon, 5 Feb 2018 23:53:01 +0530 Subject: [PATCH 103/113] Fixed an error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 1c6075201f..2f8d37fc6f 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -267,7 +267,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) { if (output[i] != outputPerceptron[i]) { - int flag = 1; + flag = 1; break; } } From 32e138f1ff498bc5a65dcec9042cca67220a0f19 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Tue, 6 Feb 2018 00:40:34 +0530 Subject: [PATCH 104/113] Fixed build error --- src/mlpack/tests/main_tests/adaboost_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 2f8d37fc6f..d9832307db 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -273,7 +273,6 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) } BOOST_REQUIRE_EQUAL(flag, 1); } -} /** * Accuracy increases as Number of Iterations increases. From b087ff21b4aeb83dc58639f2d80c70fd0ee81492 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 6 Feb 2018 08:49:08 -0500 Subject: [PATCH 105/113] Don't use Armadillo internal API. --- src/mlpack/core/data/CMakeLists.txt | 1 + src/mlpack/core/data/is_naninf.hpp | 71 +++++++++++++++++++++++++ src/mlpack/core/data/load_arff_impl.hpp | 3 +- 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/mlpack/core/data/is_naninf.hpp diff --git a/src/mlpack/core/data/CMakeLists.txt b/src/mlpack/core/data/CMakeLists.txt index ba2fb682da..705ea5fa4e 100644 --- a/src/mlpack/core/data/CMakeLists.txt +++ b/src/mlpack/core/data/CMakeLists.txt @@ -6,6 +6,7 @@ set(SOURCES extension.hpp format.hpp has_serialize.hpp + is_naninf.hpp load_csv.hpp load_csv.cpp load.hpp diff --git a/src/mlpack/core/data/is_naninf.hpp b/src/mlpack/core/data/is_naninf.hpp new file mode 100644 index 0000000000..3efa4da411 --- /dev/null +++ b/src/mlpack/core/data/is_naninf.hpp @@ -0,0 +1,71 @@ +/** + * @file is_naninf.hpp + * @author Ryan Curtin + * + * This is an adapted version of Conrad Sanderson's implementation of + * arma::diskio::convert_naninf() from Armadillo. It is here so as to avoid + * using Armadillo internal functionality. + */ +#ifndef MLPACK_CORE_DATA_HAS_NANINF_HPP +#define MLPACK_CORE_DATA_HAS_NANINF_HPP + +#include + +namespace mlpack { +namespace data { + +/** + * See if the token is a NaN or an Inf, and if so, set the value accordingly and + * return a boolean representing whether or not it is. + */ +template +inline bool IsNaNInf(T& val, const std::string& token) +{ + // See if the token represents a NaN or Inf. + if ((token.length() == 3) || (token.length() == 4)) + { + const bool neg = (token[0] == '-'); + const bool pos = (token[0] == '+'); + + const size_t offset = ((neg || pos) && (token.length() == 4)) ? 1 : 0; + + const std::string token2 = token.substr(offset, 3); + + if ((token2 == "inf") || (token2 == "Inf") || (token2 == "INF")) + { + if (std::numeric_limits::has_infinity) + { + if (!neg) + val = std::numeric_limits::infinity(); + else + val = -std::numeric_limits::infinity(); + } + else + { + if (!neg) + val = std::numeric_limits::max(); + else + val = -std::numeric_limits::max(); + } + + return true; + } + else if ((token2 == "nan") || (token2 == "Nan") || (token2 == "NaN") || + (token2 == "NAN") ) + { + if (std::numeric_limits::has_quiet_NaN) + val = std::numeric_limits::quiet_NaN(); + else + val = T(0); + + return true; + } + } + + return false; +} + +} // namespace data +} // namespace mlpack + +#endif diff --git a/src/mlpack/core/data/load_arff_impl.hpp b/src/mlpack/core/data/load_arff_impl.hpp index 578e07b048..b7d3549b42 100644 --- a/src/mlpack/core/data/load_arff_impl.hpp +++ b/src/mlpack/core/data/load_arff_impl.hpp @@ -16,6 +16,7 @@ #include "load_arff.hpp" #include +#include "is_naninf.hpp" namespace mlpack { namespace data { @@ -197,7 +198,7 @@ void LoadARFF(const std::string& filename, if (token.fail()) { // Check for NaN or inf. - if (!arma::diskio::convert_naninf(val, token.str())) + if (!IsNaNInf(val, token.str())) { // Okay, it's not NaN or inf. If it's '?', we issue a specific // error, otherwise we issue a general error. From 347f68155a960c2b99efb7530f7854efb167274a Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Tue, 6 Feb 2018 21:34:53 +0530 Subject: [PATCH 106/113] Added name and email --- COPYRIGHT.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index b29dded095..79e41b787c 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -87,6 +87,7 @@ Copyright: Copyright 2017, Manish Kumar Copyright 2017, Haritha Sreedharan Nair Copyright 2017&2018, Sourabh Varshney + Copyright 2018, Nikhil Goel License: BSD-3-clause All rights reserved. From b860d6302da34cc5028c367830cacec76a406545 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Tue, 6 Feb 2018 21:35:46 +0530 Subject: [PATCH 107/113] added name and email --- src/mlpack/core.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mlpack/core.hpp b/src/mlpack/core.hpp index 902f5b02d1..918421a6e7 100644 --- a/src/mlpack/core.hpp +++ b/src/mlpack/core.hpp @@ -230,6 +230,7 @@ * - Manish Kumar * - Haritha Sreedharan Nair * - Sourabh Varshney + * - Nikhil Goel */ // First, include all of the prerequisites. From a5a8abb098a98a17655b0bc5059b83d1e3177fcb Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Tue, 6 Feb 2018 21:37:37 +0530 Subject: [PATCH 108/113] Changed to a cleaner code --- src/mlpack/tests/main_tests/adaboost_test.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index d9832307db..25ca77f7fd 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -261,17 +261,7 @@ BOOST_AUTO_TEST_CASE(AdaBoostDiffWeakLearnerOutputTest) arma::Row outputPerceptron; outputPerceptron = std::move(CLI::GetParam>("output")); - int flag = 0; - - for (size_t i = 0; i < output.n_elem; ++i) - { - if (output[i] != outputPerceptron[i]) - { - flag = 1; - break; - } - } - BOOST_REQUIRE_EQUAL(flag, 1); + BOOST_REQUIRE_GT(arma::accu(output != outputPerceptron), 1); } /** From 4f664d208d32898496182264e63d6aa23d234e13 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Tue, 6 Feb 2018 22:20:28 +0100 Subject: [PATCH 109/113] Correct comment about the approximation of the base-e exponential function. --- src/mlpack/methods/ann/layer/log_softmax_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/log_softmax_impl.hpp b/src/mlpack/methods/ann/layer/log_softmax_impl.hpp index 8e50fdf4c7..d4ca9c53ae 100644 --- a/src/mlpack/methods/ann/layer/log_softmax_impl.hpp +++ b/src/mlpack/methods/ann/layer/log_softmax_impl.hpp @@ -32,8 +32,8 @@ void LogSoftMax::Forward( arma::mat maxInput = arma::repmat(arma::max(input), input.n_rows, 1); output = (maxInput - input); - // Approximation of the hyperbolic tangent. The acuracy however is - // about 0.00001 lower as using tanh. Credits go to Leon Bottou. + // Approximation of the base-e exponential function. The acuracy however is + // about 0.00001 lower as using exp. Credits go to Leon Bottou. output.transform([](double x) { //! Fast approximation of exp(-x) for x positive. From ad8e39143edf27637be9019f5a7f5e611e2daf88 Mon Sep 17 00:00:00 2001 From: nikhilgoel1997 Date: Wed, 7 Feb 2018 09:08:12 +0530 Subject: [PATCH 110/113] removed extra space --- src/mlpack/tests/main_tests/adaboost_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/tests/main_tests/adaboost_test.cpp b/src/mlpack/tests/main_tests/adaboost_test.cpp index 25ca77f7fd..4d4a3e197a 100644 --- a/src/mlpack/tests/main_tests/adaboost_test.cpp +++ b/src/mlpack/tests/main_tests/adaboost_test.cpp @@ -42,7 +42,6 @@ BOOST_FIXTURE_TEST_SUITE(AdaBoostMainTest, AdaBoostTestFixture); * Check that number of output labels and number of input * points are equal. */ - BOOST_AUTO_TEST_CASE(AdaBoostOutputDimensionTest) { arma::mat trainData; From 69a85243ee0db8453aed144613f8f7892d846bce Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Wed, 7 Feb 2018 10:24:33 -0500 Subject: [PATCH 111/113] Simplify to ternary operator. --- src/mlpack/core/data/is_naninf.hpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/mlpack/core/data/is_naninf.hpp b/src/mlpack/core/data/is_naninf.hpp index 3efa4da411..a307039a66 100644 --- a/src/mlpack/core/data/is_naninf.hpp +++ b/src/mlpack/core/data/is_naninf.hpp @@ -35,17 +35,13 @@ inline bool IsNaNInf(T& val, const std::string& token) { if (std::numeric_limits::has_infinity) { - if (!neg) - val = std::numeric_limits::infinity(); - else - val = -std::numeric_limits::infinity(); + val = (!neg) ? std::numeric_limits::infinity() : + -std::numeric_limits::infinity(); } else { - if (!neg) - val = std::numeric_limits::max(); - else - val = -std::numeric_limits::max(); + val = (!neg) ? std::numeric_limits::max() : + -std::numeric_limits::max(); } return true; From a1dd075b8e6e806e6119d6c8f3033b67a8dc0c0f Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Wed, 7 Feb 2018 11:52:35 -0500 Subject: [PATCH 112/113] Remove debugging lines. --- .appveyor.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 085bde6e86..dae15df614 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -6,16 +6,11 @@ environment: VSVER: Visual Studio 14 2015 Win64 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 VSVER: Visual Studio 15 2017 Win64 -# APPVEYOR_RDP_PASSWORD: 'testing12345Aa!>>' configuration: Release os: Visual Studio 2015 -#init: -# - ps: reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 0 /f -# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - install: - ps: nuget install boost -o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0 - ps: nuget install boost_unit_test_framework-vc140 -o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0 @@ -64,11 +59,7 @@ test_script: - ps: cp C:\projects\mlpack\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.* C:\projects\mlpack\build\ - cd "%APPVEYOR_BUILD_FOLDER%/build/" - Release\mlpack_test.exe --report_level=detailed --log_level=test_suite --log_format=XML > mlpack_test.xml & exit 0 -# - ctest -C Release --output-on-failure - # upload results to AppVeyor + # Attempt to upload results to AppVeyor. - ps: | $wc = New-Object 'System.Net.WebClient' $wc.UploadFile("https://ci.appveyor.com/api/testresults/xunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\mlpack_test.xml)) - -#on_finish: -# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) From 38d2155f75f73b79b5746a6b6918c362e0c9040d Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Thu, 8 Feb 2018 01:59:24 +0100 Subject: [PATCH 113/113] Add parameter to avoid division by zero (numerical stability). --- .../optimizers/problems/bukin_function.cpp | 5 +++-- .../optimizers/problems/bukin_function.hpp | 19 ++++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/mlpack/core/optimizers/problems/bukin_function.cpp b/src/mlpack/core/optimizers/problems/bukin_function.cpp index 6ec6edf2e1..fba6d32191 100644 --- a/src/mlpack/core/optimizers/problems/bukin_function.cpp +++ b/src/mlpack/core/optimizers/problems/bukin_function.cpp @@ -15,7 +15,8 @@ using namespace mlpack; using namespace mlpack::optimization; using namespace mlpack::optimization::test; -BukinFunction::BukinFunction() { /* Nothing to do here */ } +BukinFunction::BukinFunction(const double epsilon) : epsilon(epsilon) +{ /* Nothing to do here */ } void BukinFunction::Shuffle() { /* Nothing to do here */ } @@ -48,7 +49,7 @@ void BukinFunction::Gradient(const arma::mat& coordinates, const double x2 = coordinates(1); gradient.set_size(2, 1); - gradient(0) = (0.01 * (x1 + 10)) / std::abs(x1 + 10) - + gradient(0) = (0.01 * (x1 + 10.0)) / (std::abs(x1 + 10.0) + epsilon) - (x1 * (x2 - 0.01 * std::pow(x1, 2))) / std::pow(std::abs(x2 - 0.01 * std::pow(x1, 2)), 1.5); gradient(1) = (50 * (x2 - 0.01 * std::pow(x1, 2))) / diff --git a/src/mlpack/core/optimizers/problems/bukin_function.hpp b/src/mlpack/core/optimizers/problems/bukin_function.hpp index 782a0583ac..5c14ebd5e6 100644 --- a/src/mlpack/core/optimizers/problems/bukin_function.hpp +++ b/src/mlpack/core/optimizers/problems/bukin_function.hpp @@ -44,8 +44,12 @@ namespace test { class BukinFunction { public: - //! Initialize the BukinFunction. - BukinFunction(); + /* + * Initialize the BukinFunction. + * + * @param epsilon Coefficient to avoid division by zero (numerical stability). + */ + BukinFunction(const double epsilon = 1e-8); /** * Shuffle the order of function visitation. This may be called by the @@ -57,7 +61,7 @@ class BukinFunction size_t NumFunctions() const { return 1; } //! Get the starting point. - arma::mat GetInitialPoint() const { return arma::mat("-10; 2.0"); } + arma::mat GetInitialPoint() const { return arma::mat("-10; -2.0"); } /* * Evaluate a function for a particular batch-size. @@ -97,6 +101,15 @@ class BukinFunction * @param gradient The function gradient. */ void Gradient(const arma::mat& coordinates, arma::mat& gradient); + + //! Get the value used for numerical stability. + double Epsilon() const { return epsilon; } + //! Modify the value used for numerical stability. + double& Epsilon() { return epsilon; } + + private: + //! The value used for numerical stability. + double epsilon; }; } // namespace test