From 8a1909fc67a8bdeceb6241b341ade2cdc32fb494 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Sun, 5 Apr 2020 20:46:33 +0530 Subject: [PATCH 01/15] adding poisson nll loss --- HISTORY.md | 4 + .../methods/ann/loss_functions/CMakeLists.txt | 2 + .../ann/loss_functions/poisson_nll_loss.hpp | 143 ++++++++++++++++++ .../loss_functions/poisson_nll_loss_impl.hpp | 95 ++++++++++++ src/mlpack/tests/loss_functions_test.cpp | 47 +++++- 5 files changed, 289 insertions(+), 2 deletions(-) create mode 100644 src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp create mode 100644 src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp diff --git a/HISTORY.md b/HISTORY.md index e3ec4739a5..60354fbcd2 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -15,6 +15,10 @@ * Added `R2 Score` regression metric (#2323). + * Added `poisson negative log likelihood` loss function (#2196). + + * Added `huber` loss function (#2199). + * Added `mean squared logarithmic error` loss function for neural networks (#2210). diff --git a/src/mlpack/methods/ann/loss_functions/CMakeLists.txt b/src/mlpack/methods/ann/loss_functions/CMakeLists.txt index 3c813eda8f..058455c5b2 100644 --- a/src/mlpack/methods/ann/loss_functions/CMakeLists.txt +++ b/src/mlpack/methods/ann/loss_functions/CMakeLists.txt @@ -27,6 +27,8 @@ set(SOURCES negative_log_likelihood_impl.hpp log_cosh_loss.hpp log_cosh_loss_impl.hpp + poisson_nll_loss.hpp + poisson_nll_loss_impl.hpp reconstruction_loss.hpp reconstruction_loss_impl.hpp sigmoid_cross_entropy_error.hpp diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp new file mode 100644 index 0000000000..11aed1989c --- /dev/null +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp @@ -0,0 +1,143 @@ +/** + * @file poisson_nll_loss.hpp + * @author Mrityunjay Tripathi + * + * Definition of the Poisson Negative Log Likelihood class. + * + * 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_POISSON_NLL_LOSS_HPP +#define MLPACK_METHODS_ANN_LAYER_POISSON_NLL_LOSS_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * Implementation of the Poisson Negative Log Likelihood loss. This loss + * function expects input for each class. It also expects a class index, + * in the range between 1 and the number of classes, as target when calling + * the Forward function. + * + * @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 PoissonNLLLoss +{ + public: + /** + * Create the PoissonNLLLoss object. + * + * @param logInput If true the loss is computed as exp(input) - target*input, + * if false then the loss is input - target * log(input + eps). + * @param full Boolean value that determines whether to include Stirling's + * approximation term. + * @param eps A small value to prevent 0 in denominators and logarithms. + * @param reduction When true, mean loss is computed otherwise total loss. + */ + PoissonNLLLoss(const bool logInput = true, + const bool full = false, + const double eps = 1e-08, + const bool reduction = true); + + /** + * Computes the Poisson Negative log likelihood. + * + * @param input Input data used for evaluating the specified function. + * @param target The target vector, that contains the class index in the range + * between 1 and the number of classes. + */ + template + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); + + /** + * Ordinary feed backward pass of a neural network. The Poisson Negative Log + * Likelihood loss function expects the input for each class. + * It expects a class index, in the range between 1 and the number of classes, + * as target when calling the Forward function. + * + * @param input The propagated input activation. + * @param target The target vector, that contains the class index in the range + * between 1 and the number of classes. + * @param output The calculated error. + */ + template + void Backward(const InputType& input, + const TargetType& target, + OutputType& 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 value of logInput. + bool LogInput() const { return logInput; } + //! Modify the value of logInput. + bool& LogInput() { return logInput; } + + //! Get the value of full. + bool Full() const { return full; } + //! Modify the value of full. + bool& Full() { return full; } + + //! Get the value of eps. + double Eps() const { return eps; } + //! Modify the value of eps. + double& Eps() { return eps; } + + //! Get the value of reduction. + bool Reduction() const { return reduction; } + //! Modify the value of reduction. + bool& Reduction() { return reduction; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored input parameter object. + InputDataType inputParameter; + + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! Boolean value that tells if logits are given as input. + bool logInput; + + //! Boolean value that determines whether to include Stirling's + // approximation term. + bool full; + + //! Small value required to prevent 0 in logarithms and denominators. + double eps; + + //! Boolean value that tells if mean has to be taken. + bool reduction; +}; // class PoissonNLLLoss + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "poisson_nll_loss_impl.hpp" + +#endif diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp new file mode 100644 index 0000000000..ab97b0b1de --- /dev/null +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp @@ -0,0 +1,95 @@ +/** + * @file poisson_nll_loss_impl.hpp + * @author Mrityunjay Tripathi + * + * Implementation of the Poisson Negative Log Likelihood class. + * + * 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_POISSON_NLL_LOSS_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_POISSON_NLL_LOSS_IMPL_HPP + + +// In case it hasn't yet been included. +#include "poisson_nll_loss.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +PoissonNLLLoss::PoissonNLLLoss( + const bool logInput, + const bool full, + const double eps, + const bool reduction): + logInput(logInput), + full(full), + eps(eps), + reduction(reduction) +{ + // Nothing to do here. +} + +template +template +typename InputType::elem_type +PoissonNLLLoss::Forward( + const InputType& input, + const TargetType& target) +{ + InputType loss; + loss.set_size(size(input)); + + if (logInput) + loss = arma::exp(input) - target % input; + else + loss = input - target % arma::log(input + eps); + + if (full) + { + const auto mask = target > 1.0; + const InputType approx = target % arma::log(target) - target + + 0.5 * arma::log(2 * M_PI * target); + loss.elem(arma::find(mask)) += approx.elem(arma::find(mask)); + } + + return reduction ? arma::accu(loss) / loss.n_elem : arma::accu(loss); +} + +template +template +void PoissonNLLLoss::Backward( + const InputType& input, + const TargetType& target, + OutputType& output) +{ + output.set_size(size(input)); + + if (logInput) + output = (arma::exp(input) - target); + else + output = (1 - target / (input + eps)); + + if (reduction) + output = output / output.n_elem; +} + +template +template +void PoissonNLLLoss::serialize( + Archive& ar, + const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(logInput); + ar & BOOST_SERIALIZATION_NVP(full); + ar & BOOST_SERIALIZATION_NVP(eps); + ar & BOOST_SERIALIZATION_NVP(reduction); +} + +} // namespace ann +} // namespace mlpack + +#endif diff --git a/src/mlpack/tests/loss_functions_test.cpp b/src/mlpack/tests/loss_functions_test.cpp index ff3035d376..c68126abd3 100644 --- a/src/mlpack/tests/loss_functions_test.cpp +++ b/src/mlpack/tests/loss_functions_test.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -64,9 +65,51 @@ BOOST_AUTO_TEST_CASE(HuberLossTest) // Sum of Expected Output = -0.07125. double expectedOutputSum = arma::accu(output); BOOST_REQUIRE_CLOSE_FRACTION(expectedOutputSum, -0.07125, 0.00001); +} - BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); - BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); +/** + * Poisson Negative Log Likelihood Loss function test. + */ +BOOST_AUTO_TEST_CASE(PoissonNLLLossTest) +{ + arma::mat input, target; + arma::mat output1, output2; + arma::mat expOutput1, expOutput2; + PoissonNLLLoss<> module1; + PoissonNLLLoss<> module2; + module2.Full() = true; + module2.Reduction() = false; + + // Test the Forward function on a user generated input. + input = arma::mat("1.0 1.0 1.9 1.6 -1.9 3.7 -1.0 0.5"); + target = arma::mat("1.0 3.0 1.0 2.0 1.0 4.0 2.0 1.0"); + + double loss1 = module1.Forward(input, target); + double loss2 = module2.Forward(input, target); + BOOST_REQUIRE_CLOSE_FRACTION(loss1, 4.8986, 0.0001); + BOOST_REQUIRE_CLOSE_FRACTION(loss2, 45.4139, 0.0001); + + // Test the Backward function. + module1.Backward(input, target, output1); + module2.Backward(input, target, output2); + + expOutput1 = arma::mat("0.214785 -0.0352148 0.710737 0.369129 \ + -0.106304 4.55591 -0.204015 0.0810902"); + expOutput2 = arma::mat("1.71828 -0.281718 5.68589 2.95303\ + -0.850431 36.4473 -1.63212 0.648721"); + + + BOOST_REQUIRE_EQUAL(output1.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output1.n_cols, input.n_cols); + + BOOST_REQUIRE_EQUAL(output2.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output2.n_cols, input.n_cols); + + for (size_t i = 0; i < expOutput1.n_elem; ++i) + { + BOOST_REQUIRE_CLOSE_FRACTION(output1[i], expOutput1[i], 0.0001); + BOOST_REQUIRE_CLOSE_FRACTION(output2[i], expOutput2[i], 0.0001); + } } /** From 24673caf2059b033a3ad28c4423ebdd22fd4c8d0 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi <35535378+mrityunjay-tripathi@users.noreply.github.com> Date: Wed, 10 Jun 2020 06:35:27 +0530 Subject: [PATCH 02/15] use Co-authored-by: Mikhail Lozhnikov --- src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp index 11aed1989c..4ad11a3eb9 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp @@ -1,5 +1,5 @@ /** - * @file poisson_nll_loss.hpp + * @file methods/ann/loss_functions/poisson_nll_loss.hpp * @author Mrityunjay Tripathi * * Definition of the Poisson Negative Log Likelihood class. From 911e09b672f98b60b14716eecc3a89aa984bff72 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi <35535378+mrityunjay-tripathi@users.noreply.github.com> Date: Wed, 10 Jun 2020 06:36:12 +0530 Subject: [PATCH 03/15] use class name in class description Co-authored-by: Mikhail Lozhnikov --- src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp index 4ad11a3eb9..471aadc119 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp @@ -2,7 +2,7 @@ * @file methods/ann/loss_functions/poisson_nll_loss.hpp * @author Mrityunjay Tripathi * - * Definition of the Poisson Negative Log Likelihood class. + * Definition of the PoissonNLLLoss class. * * 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 From 918707fdabeff22d3dc9a9c28abf400cffe829e3 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi <35535378+mrityunjay-tripathi@users.noreply.github.com> Date: Wed, 10 Jun 2020 06:37:19 +0530 Subject: [PATCH 04/15] LaTeX format in parameter description Co-authored-by: Mikhail Lozhnikov --- src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp index 471aadc119..4418d8b64f 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp @@ -38,8 +38,8 @@ class PoissonNLLLoss /** * Create the PoissonNLLLoss object. * - * @param logInput If true the loss is computed as exp(input) - target*input, - * if false then the loss is input - target * log(input + eps). + * @param logInput If true the loss is computed as \f$ \exp(input) - target \cdot input \f$, + * if false then the loss is \f$ input - target \cdot \log(input + eps) \f$. * @param full Boolean value that determines whether to include Stirling's * approximation term. * @param eps A small value to prevent 0 in denominators and logarithms. From 43d8310a50f831c4eebb76ea523d04a105d264ad Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Wed, 10 Jun 2020 08:20:09 +0530 Subject: [PATCH 05/15] changes in description --- .../ann/loss_functions/poisson_nll_loss.hpp | 27 +++++++++++-------- .../loss_functions/poisson_nll_loss_impl.hpp | 12 ++++----- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp index 4418d8b64f..648e27f132 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp @@ -2,7 +2,8 @@ * @file methods/ann/loss_functions/poisson_nll_loss.hpp * @author Mrityunjay Tripathi * - * Definition of the PoissonNLLLoss class. + * Definition of the PoissonNLLLoss class. It is the negative log likelihood of + * the Poisson distribution. * * mlpack is free software; you may redistribute it and/or modify it under the * terms of the 3-clause BSD license. You should have received a copy of the @@ -18,7 +19,7 @@ namespace mlpack { namespace ann /** Artificial Neural Network. */ { /** - * Implementation of the Poisson Negative Log Likelihood loss. This loss + * Implementation of the Poisson negative log likelihood loss. This loss * function expects input for each class. It also expects a class index, * in the range between 1 and the number of classes, as target when calling * the Forward function. @@ -35,11 +36,15 @@ template < class PoissonNLLLoss { public: + //! Data type of each element of InputDataType. + typedef typename InputDataType::elem_type ElemType; + /** * Create the PoissonNLLLoss object. * - * @param logInput If true the loss is computed as \f$ \exp(input) - target \cdot input \f$, - * if false then the loss is \f$ input - target \cdot \log(input + eps) \f$. + * @param logInput If true the loss is computed as + * \f$ \exp(input) - target \cdot input \f$, if false then the loss is + * \f$ input - target \cdot \log(input + eps) \f$. * @param full Boolean value that determines whether to include Stirling's * approximation term. * @param eps A small value to prevent 0 in denominators and logarithms. @@ -47,19 +52,19 @@ class PoissonNLLLoss */ PoissonNLLLoss(const bool logInput = true, const bool full = false, - const double eps = 1e-08, + const ElemType eps = 1e-08, const bool reduction = true); /** - * Computes the Poisson Negative log likelihood. + * Computes the Poisson negative log likelihood Loss. * * @param input Input data used for evaluating the specified function. * @param target The target vector, that contains the class index in the range * between 1 and the number of classes. */ template - typename InputType::elem_type Forward(const InputType& input, - const TargetType& target); + ElemType Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. The Poisson Negative Log @@ -98,9 +103,9 @@ class PoissonNLLLoss bool& Full() { return full; } //! Get the value of eps. - double Eps() const { return eps; } + ElemType Eps() const { return eps; } //! Modify the value of eps. - double& Eps() { return eps; } + ElemType& Eps() { return eps; } //! Get the value of reduction. bool Reduction() const { return reduction; } @@ -128,7 +133,7 @@ class PoissonNLLLoss bool full; //! Small value required to prevent 0 in logarithms and denominators. - double eps; + ElemType eps; //! Boolean value that tells if mean has to be taken. bool reduction; diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp index ab97b0b1de..a756fc8c4d 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp @@ -1,8 +1,8 @@ /** - * @file poisson_nll_loss_impl.hpp + * @file methods/ann/loss_functions/poisson_nll_loss_impl.hpp * @author Mrityunjay Tripathi * - * Implementation of the Poisson Negative Log Likelihood class. + * Implementation of the PoissonNLLLoss class. * * 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 @@ -30,18 +30,16 @@ PoissonNLLLoss::PoissonNLLLoss( eps(eps), reduction(reduction) { - // Nothing to do here. + Log::Assert(eps >= 0, "Epsilon (eps) must be greater than or equal to zero."); } template template -typename InputType::elem_type -PoissonNLLLoss::Forward( +ElemType PoissonNLLLoss::Forward( const InputType& input, const TargetType& target) { - InputType loss; - loss.set_size(size(input)); + InputType loss(arma::size(input)); if (logInput) loss = arma::exp(input) - target % input; From 45c730c94efdcc1d9dd980b4b2cf5d7683a9eb72 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Wed, 10 Jun 2020 10:36:44 +0530 Subject: [PATCH 06/15] fix type error --- src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp index a756fc8c4d..e4e7bca76f 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp @@ -23,7 +23,7 @@ template PoissonNLLLoss::PoissonNLLLoss( const bool logInput, const bool full, - const double eps, + const ElemType eps, const bool reduction): logInput(logInput), full(full), From f61db138140a5188006973bf807de4764a95828d Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Wed, 10 Jun 2020 11:07:31 +0530 Subject: [PATCH 07/15] fix type error --- .../ann/loss_functions/poisson_nll_loss.hpp | 15 ++++++--------- .../ann/loss_functions/poisson_nll_loss_impl.hpp | 5 +++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp index 648e27f132..aa20502d46 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp @@ -36,9 +36,6 @@ template < class PoissonNLLLoss { public: - //! Data type of each element of InputDataType. - typedef typename InputDataType::elem_type ElemType; - /** * Create the PoissonNLLLoss object. * @@ -52,7 +49,7 @@ class PoissonNLLLoss */ PoissonNLLLoss(const bool logInput = true, const bool full = false, - const ElemType eps = 1e-08, + const typename InputDataType::elem_type eps = 1e-08, const bool reduction = true); /** @@ -63,8 +60,8 @@ class PoissonNLLLoss * between 1 and the number of classes. */ template - ElemType Forward(const InputType& input, - const TargetType& target); + typename InputDataType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. The Poisson Negative Log @@ -103,9 +100,9 @@ class PoissonNLLLoss bool& Full() { return full; } //! Get the value of eps. - ElemType Eps() const { return eps; } + typename InputDataType::elem_type Eps() const { return eps; } //! Modify the value of eps. - ElemType& Eps() { return eps; } + typename InputDataType::elem_type& Eps() { return eps; } //! Get the value of reduction. bool Reduction() const { return reduction; } @@ -133,7 +130,7 @@ class PoissonNLLLoss bool full; //! Small value required to prevent 0 in logarithms and denominators. - ElemType eps; + typename InputDataType::elem_type eps; //! Boolean value that tells if mean has to be taken. bool reduction; diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp index e4e7bca76f..1aa0154cb8 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp @@ -23,7 +23,7 @@ template PoissonNLLLoss::PoissonNLLLoss( const bool logInput, const bool full, - const ElemType eps, + const typename InputDataType::elem_type eps, const bool reduction): logInput(logInput), full(full), @@ -35,7 +35,8 @@ PoissonNLLLoss::PoissonNLLLoss( template template -ElemType PoissonNLLLoss::Forward( +typename InputDataType::elem_type +PoissonNLLLoss::Forward( const InputType& input, const TargetType& target) { From 0226b3f8dbef788c1ef08c333ea627185ae2abfc Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Wed, 10 Jun 2020 16:45:20 +0530 Subject: [PATCH 08/15] added description of accessor methods --- .../ann/loss_functions/poisson_nll_loss.hpp | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp index aa20502d46..444a186d86 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp @@ -89,24 +89,32 @@ class PoissonNLLLoss //! Modify the output parameter. OutputDataType& OutputParameter() { return outputParameter; } - //! Get the value of logInput. + //! Get the value of logInput. logInput is a boolean value that tells if + //! logits are given as input. bool LogInput() const { return logInput; } - //! Modify the value of logInput. + //! Modify the value of logInput. logInput is a boolean value that tells if + //! logits are given as input. bool& LogInput() { return logInput; } - //! Get the value of full. + //! Get the value of full. full is a boolean value that determines whether to + //! include Stirling's approximation term. bool Full() const { return full; } - //! Modify the value of full. + //! Modify the value of full. full is a boolean value that determines whether + //! to include Stirling's approximation term. bool& Full() { return full; } - //! Get the value of eps. + //! Get the value of eps. eps is a small value required to prevent 0 in + //! logarithms and denominators. typename InputDataType::elem_type Eps() const { return eps; } - //! Modify the value of eps. + //! Modify the value of eps. eps is a small value required to prevent 0 in + //! logarithms and denominators. typename InputDataType::elem_type& Eps() { return eps; } - //! Get the value of reduction. + //! Get the value of reduction. reduction is a boolean value that tells if + //! mean of the total loss has to be taken. bool Reduction() const { return reduction; } - //! Modify the value of reduction. + //! Modify the value of reduction. reduction is a boolean value that tells if + //! mean of the total loss has to be taken. bool& Reduction() { return reduction; } /** @@ -129,10 +137,10 @@ class PoissonNLLLoss // approximation term. bool full; - //! Small value required to prevent 0 in logarithms and denominators. + //! eps is a small value required to prevent 0 in logarithms and denominators. typename InputDataType::elem_type eps; - //! Boolean value that tells if mean has to be taken. + //! Boolean value that tells if mean of the total loss has to be taken. bool reduction; }; // class PoissonNLLLoss From 9fc610159dacc0714888884167fd598532a5e0ba Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi <35535378+mrityunjay-tripathi@users.noreply.github.com> Date: Mon, 29 Jun 2020 18:54:58 +0530 Subject: [PATCH 09/15] correction in header guards Co-authored-by: Mikhail Lozhnikov --- src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp | 4 ++-- .../methods/ann/loss_functions/poisson_nll_loss_impl.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp index 444a186d86..0c831273fc 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp @@ -10,8 +10,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_POISSON_NLL_LOSS_HPP -#define MLPACK_METHODS_ANN_LAYER_POISSON_NLL_LOSS_HPP +#ifndef MLPACK_METHODS_ANN_LOSS_FUNCTIONS_POISSON_NLL_LOSS_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTIONS_POISSON_NLL_LOSS_HPP #include diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp index 1aa0154cb8..53086c4584 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp @@ -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_POISSON_NLL_LOSS_IMPL_HPP -#define MLPACK_METHODS_ANN_LAYER_POISSON_NLL_LOSS_IMPL_HPP +#ifndef MLPACK_METHODS_ANN_LOSS_FUNCTIONS_POISSON_NLL_LOSS_IMPL_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTIONS_POISSON_NLL_LOSS_IMPL_HPP // In case it hasn't yet been included. From 48593332dc1170db6057297d8f3f6469dfbf6b94 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Mon, 29 Jun 2020 19:29:13 +0530 Subject: [PATCH 10/15] reverting back changes in unrelated code by mistake --- src/mlpack/tests/loss_functions_test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mlpack/tests/loss_functions_test.cpp b/src/mlpack/tests/loss_functions_test.cpp index 86b911a3c7..61a5a66b7e 100644 --- a/src/mlpack/tests/loss_functions_test.cpp +++ b/src/mlpack/tests/loss_functions_test.cpp @@ -65,6 +65,9 @@ BOOST_AUTO_TEST_CASE(HuberLossTest) // Sum of Expected Output = -0.07125. double expectedOutputSum = arma::accu(output); BOOST_REQUIRE_CLOSE_FRACTION(expectedOutputSum, -0.07125, 0.00001); + + BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols); } /** From 4b944c5a391735d3dc0bbb2b98283d2bf7029a7d Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Tue, 30 Jun 2020 22:52:21 +0530 Subject: [PATCH 11/15] adding more tests --- src/mlpack/tests/loss_functions_test.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/mlpack/tests/loss_functions_test.cpp b/src/mlpack/tests/loss_functions_test.cpp index 61a5a66b7e..7532ea68cf 100644 --- a/src/mlpack/tests/loss_functions_test.cpp +++ b/src/mlpack/tests/loss_functions_test.cpp @@ -76,12 +76,11 @@ BOOST_AUTO_TEST_CASE(HuberLossTest) BOOST_AUTO_TEST_CASE(PoissonNLLLossTest) { arma::mat input, target; - arma::mat output1, output2; - arma::mat expOutput1, expOutput2; + arma::mat output1, output2, output3; + arma::mat expOutput1, expOutput2, expOutput3; PoissonNLLLoss<> module1; - PoissonNLLLoss<> module2; - module2.Full() = true; - module2.Reduction() = false; + PoissonNLLLoss<> module2(true, true, 1e-08, false); + PoissonNLLLoss<> module3(true, true, 1e-08, true); // Test the Forward function on a user generated input. input = arma::mat("1.0 1.0 1.9 1.6 -1.9 3.7 -1.0 0.5"); @@ -89,17 +88,22 @@ BOOST_AUTO_TEST_CASE(PoissonNLLLossTest) double loss1 = module1.Forward(input, target); double loss2 = module2.Forward(input, target); + double loss3 = module3.Forward(input, target); BOOST_REQUIRE_CLOSE_FRACTION(loss1, 4.8986, 0.0001); BOOST_REQUIRE_CLOSE_FRACTION(loss2, 45.4139, 0.0001); + BOOST_REQUIRE_CLOSE_FRACTION(loss3, 5.6767, 0.0001); // Test the Backward function. module1.Backward(input, target, output1); module2.Backward(input, target, output2); + module3.Backward(input, target, output3); expOutput1 = arma::mat("0.214785 -0.0352148 0.710737 0.369129 \ -0.106304 4.55591 -0.204015 0.0810902"); expOutput2 = arma::mat("1.71828 -0.281718 5.68589 2.95303\ -0.850431 36.4473 -1.63212 0.648721"); + expOutput3 = arma::mat("0.214785 -0.035215 0.710737 0.369129 \ + -0.106304 4.555913 -0.204015 0.081090"); BOOST_REQUIRE_EQUAL(output1.n_rows, input.n_rows); @@ -108,10 +112,14 @@ BOOST_AUTO_TEST_CASE(PoissonNLLLossTest) BOOST_REQUIRE_EQUAL(output2.n_rows, input.n_rows); BOOST_REQUIRE_EQUAL(output2.n_cols, input.n_cols); + BOOST_REQUIRE_EQUAL(output3.n_rows, input.n_rows); + BOOST_REQUIRE_EQUAL(output3.n_cols, input.n_cols); + for (size_t i = 0; i < expOutput1.n_elem; ++i) { BOOST_REQUIRE_CLOSE_FRACTION(output1[i], expOutput1[i], 0.0001); BOOST_REQUIRE_CLOSE_FRACTION(output2[i], expOutput2[i], 0.0001); + BOOST_REQUIRE_CLOSE_FRACTION(output3[i], expOutput3[i], 0.0001); } } From 71eb4eda69c2108da0772e83db4dc00b02d77cf2 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Tue, 30 Jun 2020 23:20:29 +0530 Subject: [PATCH 12/15] check if probs are in range [0, 1] --- .../methods/ann/loss_functions/poisson_nll_loss.hpp | 12 ++++++++++++ .../ann/loss_functions/poisson_nll_loss_impl.hpp | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp index 0c831273fc..a636774ef5 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp @@ -124,6 +124,18 @@ class PoissonNLLLoss void serialize(Archive& ar, const unsigned int /* version */); private: + //! Check if the probabilities lie in the range [0, 1]. + template + void CheckProbs(const arma::Mat& probs) + { + for (size_t i = 0; i < probs.size(); ++i) + { + if (probs[i] > 1.0 || probs[i] < 0.0) + Log::Fatal << "Probabilities cannot be greater than 1 " + << "or smaller than 0." << std::endl; + } + } + //! Locally-stored input parameter object. InputDataType inputParameter; diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp index 53086c4584..ce56d06a41 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp @@ -45,7 +45,10 @@ PoissonNLLLoss::Forward( if (logInput) loss = arma::exp(input) - target % input; else + { + CheckProbs(input); loss = input - target % arma::log(input + eps); + } if (full) { @@ -70,7 +73,10 @@ void PoissonNLLLoss::Backward( if (logInput) output = (arma::exp(input) - target); else + { + CheckProbs(input); output = (1 - target / (input + eps)); + } if (reduction) output = output / output.n_elem; From a547d43145c5197ea46a5cee8017895aab8a5b05 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Tue, 30 Jun 2020 23:50:23 +0530 Subject: [PATCH 13/15] adding tests for logInput = false --- src/mlpack/tests/loss_functions_test.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/mlpack/tests/loss_functions_test.cpp b/src/mlpack/tests/loss_functions_test.cpp index 7532ea68cf..2d4de449f1 100644 --- a/src/mlpack/tests/loss_functions_test.cpp +++ b/src/mlpack/tests/loss_functions_test.cpp @@ -75,28 +75,37 @@ BOOST_AUTO_TEST_CASE(HuberLossTest) */ BOOST_AUTO_TEST_CASE(PoissonNLLLossTest) { - arma::mat input, target; - arma::mat output1, output2, output3; - arma::mat expOutput1, expOutput2, expOutput3; + arma::mat input, target, input4, target4; + arma::mat output1, output2, output3, output4; + arma::mat expOutput1, expOutput2, expOutput3, expOutput4; PoissonNLLLoss<> module1; PoissonNLLLoss<> module2(true, true, 1e-08, false); PoissonNLLLoss<> module3(true, true, 1e-08, true); + PoissonNLLLoss<> module4(false, true, 1e-08, true); // Test the Forward function on a user generated input. input = arma::mat("1.0 1.0 1.9 1.6 -1.9 3.7 -1.0 0.5"); target = arma::mat("1.0 3.0 1.0 2.0 1.0 4.0 2.0 1.0"); + // Input required for module 4. Probs are in range [0, 1]. + input4 = arma::mat("0.658502 0.445627 0.667651 0.310549 \ + 0.589540 0.052568 0.549769 0.381504 "); + target4 = arma::mat("1.0 3.0 1.0 2.0 1.0 4.0 2.0 1.0"); + double loss1 = module1.Forward(input, target); double loss2 = module2.Forward(input, target); double loss3 = module3.Forward(input, target); + double loss4 = module4.Forward(input4, target4); BOOST_REQUIRE_CLOSE_FRACTION(loss1, 4.8986, 0.0001); BOOST_REQUIRE_CLOSE_FRACTION(loss2, 45.4139, 0.0001); BOOST_REQUIRE_CLOSE_FRACTION(loss3, 5.6767, 0.0001); + BOOST_REQUIRE_CLOSE_FRACTION(loss4, 3.742157, 0.0001); // Test the Backward function. module1.Backward(input, target, output1); module2.Backward(input, target, output2); module3.Backward(input, target, output3); + module4.Backward(input4, target4, output4); expOutput1 = arma::mat("0.214785 -0.0352148 0.710737 0.369129 \ -0.106304 4.55591 -0.204015 0.0810902"); @@ -104,7 +113,8 @@ BOOST_AUTO_TEST_CASE(PoissonNLLLossTest) -0.850431 36.4473 -1.63212 0.648721"); expOutput3 = arma::mat("0.214785 -0.035215 0.710737 0.369129 \ -0.106304 4.555913 -0.204015 0.081090"); - + expOutput4 = arma::mat("-0.064825 -0.716511 -0.062224 -0.680027 \ + -0.087030 -9.386517 -0.329736 -0.202650"); BOOST_REQUIRE_EQUAL(output1.n_rows, input.n_rows); BOOST_REQUIRE_EQUAL(output1.n_cols, input.n_cols); @@ -115,11 +125,15 @@ BOOST_AUTO_TEST_CASE(PoissonNLLLossTest) BOOST_REQUIRE_EQUAL(output3.n_rows, input.n_rows); BOOST_REQUIRE_EQUAL(output3.n_cols, input.n_cols); + BOOST_REQUIRE_EQUAL(output4.n_rows, input4.n_rows); + BOOST_REQUIRE_EQUAL(output4.n_cols, input4.n_cols); + for (size_t i = 0; i < expOutput1.n_elem; ++i) { BOOST_REQUIRE_CLOSE_FRACTION(output1[i], expOutput1[i], 0.0001); BOOST_REQUIRE_CLOSE_FRACTION(output2[i], expOutput2[i], 0.0001); BOOST_REQUIRE_CLOSE_FRACTION(output3[i], expOutput3[i], 0.0001); + BOOST_REQUIRE_CLOSE_FRACTION(output4[i], expOutput4[i], 0.0001); } } From 6638cf72bf5db4819c549f9ce50eff7c3ca709a9 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Wed, 1 Jul 2020 11:35:55 +0530 Subject: [PATCH 14/15] remove check from Backward --- .../methods/ann/loss_functions/poisson_nll_loss_impl.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp index ce56d06a41..e2be523939 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp @@ -73,10 +73,7 @@ void PoissonNLLLoss::Backward( if (logInput) output = (arma::exp(input) - target); else - { - CheckProbs(input); output = (1 - target / (input + eps)); - } if (reduction) output = output / output.n_elem; From 661bcfd3ebdd2be1e350e3acd8ed9b7da59959b6 Mon Sep 17 00:00:00 2001 From: Mrityunjay Tripathi Date: Fri, 3 Jul 2020 22:47:34 +0530 Subject: [PATCH 15/15] change variable name reduction to mean --- .../ann/loss_functions/poisson_nll_loss.hpp | 14 +++++++------- .../ann/loss_functions/poisson_nll_loss_impl.hpp | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp index a636774ef5..bdb331f5e5 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss.hpp @@ -45,12 +45,12 @@ class PoissonNLLLoss * @param full Boolean value that determines whether to include Stirling's * approximation term. * @param eps A small value to prevent 0 in denominators and logarithms. - * @param reduction When true, mean loss is computed otherwise total loss. + * @param mean When true, mean loss is computed otherwise total loss. */ PoissonNLLLoss(const bool logInput = true, const bool full = false, const typename InputDataType::elem_type eps = 1e-08, - const bool reduction = true); + const bool mean = true); /** * Computes the Poisson negative log likelihood Loss. @@ -110,12 +110,12 @@ class PoissonNLLLoss //! logarithms and denominators. typename InputDataType::elem_type& Eps() { return eps; } - //! Get the value of reduction. reduction is a boolean value that tells if + //! Get the value of mean. It's a boolean value that tells if //! mean of the total loss has to be taken. - bool Reduction() const { return reduction; } - //! Modify the value of reduction. reduction is a boolean value that tells if + bool Mean() const { return mean; } + //! Modify the value of mean. It's a boolean value that tells if //! mean of the total loss has to be taken. - bool& Reduction() { return reduction; } + bool& Mean() { return mean; } /** * Serialize the layer. @@ -153,7 +153,7 @@ class PoissonNLLLoss typename InputDataType::elem_type eps; //! Boolean value that tells if mean of the total loss has to be taken. - bool reduction; + bool mean; }; // class PoissonNLLLoss } // namespace ann diff --git a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp index e2be523939..8a69494203 100644 --- a/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/poisson_nll_loss_impl.hpp @@ -24,11 +24,11 @@ PoissonNLLLoss::PoissonNLLLoss( const bool logInput, const bool full, const typename InputDataType::elem_type eps, - const bool reduction): + const bool mean): logInput(logInput), full(full), eps(eps), - reduction(reduction) + mean(mean) { Log::Assert(eps >= 0, "Epsilon (eps) must be greater than or equal to zero."); } @@ -58,7 +58,7 @@ PoissonNLLLoss::Forward( loss.elem(arma::find(mask)) += approx.elem(arma::find(mask)); } - return reduction ? arma::accu(loss) / loss.n_elem : arma::accu(loss); + return mean ? arma::accu(loss) / loss.n_elem : arma::accu(loss); } template @@ -75,7 +75,7 @@ void PoissonNLLLoss::Backward( else output = (1 - target / (input + eps)); - if (reduction) + if (mean) output = output / output.n_elem; } @@ -88,7 +88,7 @@ void PoissonNLLLoss::serialize( ar & BOOST_SERIALIZATION_NVP(logInput); ar & BOOST_SERIALIZATION_NVP(full); ar & BOOST_SERIALIZATION_NVP(eps); - ar & BOOST_SERIALIZATION_NVP(reduction); + ar & BOOST_SERIALIZATION_NVP(mean); } } // namespace ann