diff --git a/.ci/ci.yaml b/.ci/ci.yaml index 739ba9906c..e0654b49e1 100644 --- a/.ci/ci.yaml +++ b/.ci/ci.yaml @@ -57,23 +57,6 @@ jobs: steps: - template: macos-steps.yaml -- job: WindowsVS14 - timeoutInMinutes: 360 - displayName: Windows VS14 - pool: - vmImage: vs2015-win2012r2 - strategy: - matrix: - Plain: - CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF' - CMakeGenerator: '-G "Visual Studio 14 2015 Win64"' - MSBuildVersion: '14.0' - ArchiveNoLibs: 'mlpack-windows-vs14-no-libs.zip' - ArchiveLibs: 'mlpack-windows-vs14.zip' - ArchiveTests: 'mlpack_test-vs14.xml' - steps: - - template: windows-steps.yaml - - job: WindowsVS15 timeoutInMinutes: 360 displayName: Windows VS15 diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index ce5c944e0d..db423bb3b8 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -130,6 +130,7 @@ Copyright: Copyright 2020, Saraansh Tandon Copyright 2020, Gaurav Singh Copyright 2020, Lakshya Ojha + Copyright 2020, Bisakh Mondal License: BSD-3-clause All rights reserved. diff --git a/HISTORY.md b/HISTORY.md index c93dcba0eb..bcd3e5fac6 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,9 @@ ### mlpack ?.?.? ###### ????-??-?? + * Templated return type of `Forward function` of loss functions (#2339). + + * Added `R2 Score` regression metric (#2323). + * Added `mean squared logarithmic error` loss function for neural networks (#2210). diff --git a/doc/tutorials/reinforcement_learning/reinforcement_learning.txt b/doc/tutorials/reinforcement_learning/reinforcement_learning.txt index 1c837ef070..a91dc27671 100644 --- a/doc/tutorials/reinforcement_learning/reinforcement_learning.txt +++ b/doc/tutorials/reinforcement_learning/reinforcement_learning.txt @@ -1,6 +1,7 @@ /*! @file rl.txt @author Sriram S K +@author Joel Joseph @brief Tutorial for how to use the Reinforcement Learning module in mlpack. @page rltutorial Reinforcement Learning Tutorial @@ -29,6 +30,7 @@ This tutorial is split into the following sections: - \ref environment_rltut - \ref agent_components_rltut - \ref q_learning_rltut + - \ref async_learning_rltut - \ref further_rltut @section environment_rltut Reinforcement Learning Environments @@ -231,9 +233,167 @@ to have converged when the average return reaches a predetermined value (i.e. > Conversely, if the average return does not go beyond that amount even after a thousand episodes, we can conclude that the agent will not converge and exit the training loop. +@section async_learning_rltut + +In 2016, Researchers at Deepmind and University of Montreal published their paper +"Asynchronous Methods for Deep Reinforcement Learning". In it they described asynchronous +variants of four standard reinforcement learning algorithms: + - One-Step SARSA + - One-Step Q-Learning + - N-Step Q-Learning + - Advantage Actor-Critic(A3C) + +Online RL algorithms and Deep Neural Networks make an unstable combination because of the +non-stationary and correlated nature of online updates. Although this is solved by Experience Replay, +it has several drawbacks: it uses more memory and computation per real interaction; and it requires +off-policy learning algorithms. + +Asynchronous methods, instead of experience replay, asynchronously executes multiple agents +in parallel, on multiple instances of the environment, which solves all the above problems. + +Here, we demonstrate Asynchronous Learning methods in mlpack through the training of an async +agent. Asynchronous learning involves training several agents simultaneously. Here, each of the +agents are referred to as "workers". Currently mlpack has One-Step Q-Learning worker, N-Step +Q-Learning worker and One-Step SARSA worker. + +Let's examine the sample code in chunks. + +Apart from the includes used for the q-learning example, two more have to be included: + +@code +#include +#include +@endcode + +Here we don't use experience replay, and instead of a single policy, we use three different +policies, each corresponding to its worker. Number of workers created, depends on the number of +policies given in the Aggregated Policy. The column vector contains the probability distribution +for each child policy. We should make sure its size is same as the number of policies and the sum +of its elements is equal to 1. + +@code +AggregatedPolicy> policy({GreedyPolicy(0.7, 5000, 0.1), + GreedyPolicy(0.7, 5000, 0.01), + GreedyPolicy(0.7, 5000, 0.5)}, + arma::colvec("0.4 0.3 0.3")); +@endcode + +Now, we will create the "OneStepQLearning" agent. We could have used "NStepQLearning" or "OneStepSarsa" +here according to our requirement. + +@code +OneStepQLearning + agent(std::move(config), std::move(model), std::move(policy)); +@endcode + +Here, unlike the Q-Learning example, instead of the entire while loop, we use the Train method of the Asynchronous +Learning class inside a for loop. 100 training episodes will take around 50 seconds. + +@code +for (int i = 0; i < 100; i++) +{ + agent.Train(measure); +} +@endcode + +What is "measure" here? It is a lambda function which returns a boolean value (indicating the end of training) +and accepts the episode return (total reward of a deterministic test episode) as parameter. +So, let's create that. + +@code +arma::vec returns(20, arma::fill::zeros); +size_t position = 0; +size_t episode = 0; + +auto measure = [&returns, &position, &episode](double episodeReturn) +{ + if(episode > 10000) return true; + + returns[position++] = episodeReturn; + position = position % returns.n_elem; + episode++; + + std::cout << "Episode No.: " << episode + << "; Episode Return: " << episodeReturn + << "; Average Return: " << arma::mean(returns) << endl; +}; +@endcode + +This will train three different agents on three CPU threads asynchronously and use this data to update the +action value estimate. +Voila, thats all there is to it. + +Here is the full code to try this right away: + +@code +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace mlpack; +using namespace mlpack::ann; +using namespace mlpack::rl; +int main() +{ + // Set up the network. + FFN, GaussianInitialization> model(MeanSquaredError<>(), GaussianInitialization(0, 0.001)); + model.Add>(4, 128); + model.Add>(); + model.Add>(128, 128); + model.Add>(); + model.Add>(128, 2); + + AggregatedPolicy> policy({GreedyPolicy(0.7, 5000, 0.1), + GreedyPolicy(0.7, 5000, 0.01), + GreedyPolicy(0.7, 5000, 0.5)}, + arma::colvec("0.4 0.3 0.3")); + + TrainingConfig config; + config.StepSize() = 0.01; + config.Discount() = 0.9; + config.TargetNetworkSyncInterval() = 100; + config.ExplorationSteps() = 100; + config.DoubleQLearning() = false; + config.StepLimit() = 200; + + OneStepQLearning + agent(std::move(config), std::move(model), std::move(policy)); + + arma::vec returns(20, arma::fill::zeros); + size_t position = 0; + size_t episode = 0; + + auto measure = [&returns, &position, &episode](double episodeReturn) + { + if(episode > 10000) return true; + + returns[position++] = episodeReturn; + position = position % returns.n_elem; + episode++; + + std::cout << "Episode No.: " << episode + << "; Episode Return: " << episodeReturn + << "; Average Return: " << arma::mean(returns) << endl; + }; + + for (int i = 0; i < 100; i++) + { + agent.Train(measure); + } +} +@endcode + @section further_rltut Further documentation For further documentation on the rl classes, consult the \ref mlpack::rl "complete API documentation". -*/ \ No newline at end of file +*/ diff --git a/src/mlpack/core/cv/metrics/CMakeLists.txt b/src/mlpack/core/cv/metrics/CMakeLists.txt index 4cf1027874..b9edacaf9a 100644 --- a/src/mlpack/core/cv/metrics/CMakeLists.txt +++ b/src/mlpack/core/cv/metrics/CMakeLists.txt @@ -13,6 +13,8 @@ set(SOURCES precision_impl.hpp recall.hpp recall_impl.hpp + r2_score.hpp + r2_score_impl.hpp ) # Add directory name to sources. diff --git a/src/mlpack/core/cv/metrics/r2_score.hpp b/src/mlpack/core/cv/metrics/r2_score.hpp new file mode 100644 index 0000000000..6fcac955aa --- /dev/null +++ b/src/mlpack/core/cv/metrics/r2_score.hpp @@ -0,0 +1,76 @@ +/** + * @file r2_score.hpp + * @author Bisakh Mondal + * + * The R^2 (Coefficient of determination) regression metric. + * + * 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_CV_METRICS_R2SCORE_HPP +#define MLPACK_CORE_CV_METRICS_R2SCORE_HPP + +#include + +namespace mlpack { +namespace cv { + +/** + * The R2 Score is a metric of performance for regression algorithms + * that represents the proportion of variance (here y) that has been + * explained by the independent variables in the model. It provides + * an indication of goodness of fit and therefore a measure of how + * well unseen samples are likely to be predicted by the model, + * through the proportion of explained variance. + * As R2 Score is dataset dependent it can have wide range of values. The + * best possible score is @f$R^2 =1.0@f$. Values of R2 outside the range + * 0 to 1 can occur when the model fits the data worse than a horizontal + * hyperplane. This would occur when the wrong model was chosen, or + * nonsensical constraints were applied by mistake. A model which + * predicts exactly the expected value of y, disregarding the input + * features, gets a R2 Score equals to 0.0. + * If a model predicts @f$ \hat{y}_i $@f of the @f$ i $@f-th sample for a true + * @f$ y_i $@f for total n samples, the R2 Score is calculated by + * @f{eqnarray*}{ + * R^{2} \left( y, \hat{y} \right) &=& 1-\frac{\sum_{i=1}^{n} + * \left( y_i - \hat{y_i} \right)^2 } + * {\sum_{i=1}^{n} \left( y_i - \bar{y}\right)^2}\\ + * @f} + * + * where @f$ \bar{y} = frac{1}{y}\sum_{i=1}^{n} y_i $@f. + * For example, a model having R2Score = 0.85, explains 85 \% variability of + * the response data around its mean. + */ +class R2Score +{ + public: + /** + * Run prediction and calculate the R squared error. + * + * @param model A regression model. + * @param data Column-major data containing test items. + * @param responses Ground truth (correct) target values for the test items, + * should be either a row vector or a column-major matrix. + * @return calculated R2 Score. + */ + template + static double Evaluate(MLAlgorithm& model, + const DataType& data, + const ResponsesType& responses); + + /** + * Information for hyper-parameter tuning code. It indicates that we want + * to maximize the measurement. + */ + static const bool NeedsMinimization = false; +}; + +} // namespace cv +} // namespace mlpack + +// Include implementation. +#include "r2_score_impl.hpp" + +#endif diff --git a/src/mlpack/core/cv/metrics/r2_score_impl.hpp b/src/mlpack/core/cv/metrics/r2_score_impl.hpp new file mode 100644 index 0000000000..86c57e11fb --- /dev/null +++ b/src/mlpack/core/cv/metrics/r2_score_impl.hpp @@ -0,0 +1,55 @@ +/** + * @file r2_score_impl.hpp + * @author Bisakh Mondal + * + * The implementation of the class R2Score. + * + * 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_CV_METRICS_R2SCORE_IMPL_HPP +#define MLPACK_CORE_CV_METRICS_R2SCORE_IMPL_HPP + +namespace mlpack { +namespace cv { + +template +double R2Score::Evaluate(MLAlgorithm& model, + const DataType& data, + const ResponsesType& responses) +{ + if (data.n_cols != responses.n_cols) + { + std::ostringstream oss; + oss << "R2Score::Evaluate(): number of points (" << data.n_cols << ") " + << "does not match number of responses (" << responses.n_cols << ")!" + << std::endl; + throw std::invalid_argument(oss.str()); + } + + ResponsesType predictedResponses; + // Taking Predicted Output from the model. + model.Predict(data, predictedResponses); + // Mean value of response. + double meanResponses = arma::mean(responses); + + // Calculate the numerator i.e. residual sum of squares. + double residualSumSquared = arma::accu(arma::square(responses - + predictedResponses)); + + // Calculate the denominator i.e.total sum of squares. + double totalSumSquared = arma::accu(arma::square(responses - meanResponses)); + + // Handling undefined R2 Score when both denominator and numerator is 0.0. + if (residualSumSquared == 0.0) + return totalSumSquared ? 1.0 : DBL_MIN; + + return 1 - residualSumSquared / totalSumSquared; +} + +} // namespace cv +} // namespace mlpack + +#endif diff --git a/src/mlpack/methods/ann/loss_functions/cross_entropy_error.hpp b/src/mlpack/methods/ann/loss_functions/cross_entropy_error.hpp index 3041ae3099..1811f99998 100644 --- a/src/mlpack/methods/ann/loss_functions/cross_entropy_error.hpp +++ b/src/mlpack/methods/ann/loss_functions/cross_entropy_error.hpp @@ -49,7 +49,8 @@ class CrossEntropyError * @param target The target vector. */ template - double Forward(const InputType& input, const TargetType& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. diff --git a/src/mlpack/methods/ann/loss_functions/cross_entropy_error_impl.hpp b/src/mlpack/methods/ann/loss_functions/cross_entropy_error_impl.hpp index 9c6d73e481..7d0d80357b 100644 --- a/src/mlpack/methods/ann/loss_functions/cross_entropy_error_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/cross_entropy_error_impl.hpp @@ -27,8 +27,10 @@ CrossEntropyError::CrossEntropyError( template template -double CrossEntropyError::Forward( - const InputType& input, const TargetType& target) +typename InputType::elem_type +CrossEntropyError::Forward( + const InputType& input, + const TargetType& target) { return -arma::accu(target % arma::log(input + eps) + (1. - target) % arma::log(1. - input + eps)); diff --git a/src/mlpack/methods/ann/loss_functions/dice_loss.hpp b/src/mlpack/methods/ann/loss_functions/dice_loss.hpp index a30618e424..42551388aa 100644 --- a/src/mlpack/methods/ann/loss_functions/dice_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/dice_loss.hpp @@ -62,7 +62,8 @@ class DiceLoss * @param target The target vector. */ template - double Forward(const InputType& input, const TargetType& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. diff --git a/src/mlpack/methods/ann/loss_functions/dice_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/dice_loss_impl.hpp index 708c1102f7..904d699c21 100644 --- a/src/mlpack/methods/ann/loss_functions/dice_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/dice_loss_impl.hpp @@ -27,8 +27,9 @@ DiceLoss::DiceLoss( template template -double DiceLoss::Forward( - const InputType& input, const TargetType& target) +typename InputType::elem_type DiceLoss::Forward( + const InputType& input, + const TargetType& target) { return 1 - ((2 * arma::accu(target % input) + smooth) / (arma::accu(target % target) + arma::accu( diff --git a/src/mlpack/methods/ann/loss_functions/earth_mover_distance.hpp b/src/mlpack/methods/ann/loss_functions/earth_mover_distance.hpp index 0683715bd4..71c0aa8e4b 100644 --- a/src/mlpack/methods/ann/loss_functions/earth_mover_distance.hpp +++ b/src/mlpack/methods/ann/loss_functions/earth_mover_distance.hpp @@ -45,7 +45,8 @@ class EarthMoverDistance * @param target The target vector. */ template - double Forward(const InputType& input, const TargetType& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. diff --git a/src/mlpack/methods/ann/loss_functions/earth_mover_distance_impl.hpp b/src/mlpack/methods/ann/loss_functions/earth_mover_distance_impl.hpp index 9ba7ac8f47..44d5e24c4e 100644 --- a/src/mlpack/methods/ann/loss_functions/earth_mover_distance_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/earth_mover_distance_impl.hpp @@ -26,8 +26,10 @@ EarthMoverDistance::EarthMoverDistance() template template -double EarthMoverDistance::Forward( - const InputType& input, const TargetType& target) +typename InputType::elem_type +EarthMoverDistance::Forward( + const InputType& input, + const TargetType& target) { return -arma::accu(target % input); } diff --git a/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss.hpp b/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss.hpp index bcb9b17d6d..3e3eac19ec 100644 --- a/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss.hpp @@ -48,7 +48,8 @@ class HingeEmbeddingLoss * @param target Target data to compare with. */ template - double Forward(const InputType& input, const TargetType& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. diff --git a/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss_impl.hpp index b0e71632cb..f3f420b3ca 100644 --- a/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/hinge_embedding_loss_impl.hpp @@ -27,8 +27,10 @@ HingeEmbeddingLoss::HingeEmbeddingLoss() template template -double HingeEmbeddingLoss::Forward( - const InputType& input, const TargetType& target) +typename InputType::elem_type +HingeEmbeddingLoss::Forward( + const InputType& input, + const TargetType& target) { TargetType temp = target - (target == 0); return (arma::accu(arma::max(1-input % temp, 0.))) / target.n_elem; diff --git a/src/mlpack/methods/ann/loss_functions/huber_loss.hpp b/src/mlpack/methods/ann/loss_functions/huber_loss.hpp index 9a18cfea1b..60e8d96b10 100644 --- a/src/mlpack/methods/ann/loss_functions/huber_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/huber_loss.hpp @@ -52,7 +52,8 @@ class HuberLoss * @param target The target vector. */ template - double Forward(const InputType& input, const TargetType& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. diff --git a/src/mlpack/methods/ann/loss_functions/huber_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/huber_loss_impl.hpp index 25da492bcf..c9c5ee9145 100644 --- a/src/mlpack/methods/ann/loss_functions/huber_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/huber_loss_impl.hpp @@ -30,13 +30,15 @@ HuberLoss::HuberLoss( template template -double HuberLoss::Forward( - const InputType& input, const TargetType& target) +typename InputType::elem_type +HuberLoss::Forward(const InputType& input, + const TargetType& target) { - double loss = 0; + typedef typename InputType::elem_type ElemType; + ElemType loss = 0; for (size_t i = 0; i < input.n_elem; ++i) { - const double absError = std::abs(target[i] - input[i]); + const ElemType absError = std::abs(target[i] - input[i]); loss += absError > delta ? delta * (absError - 0.5 * delta) : 0.5 * std::pow(absError, 2); } @@ -50,13 +52,16 @@ void HuberLoss::Backward( const TargetType& target, OutputType& output) { + typedef typename InputType::elem_type ElemType; + output.set_size(size(input)); for (size_t i = 0; i < output.n_elem; ++i) { - const double absError = std::abs(target[i] - input[i]); + const ElemType absError = std::abs(target[i] - input[i]); output[i] = absError > delta ? - delta * (target[i] - input[i]) / absError : input[i] - target[i]; - if (mean) output[i] /= output.n_elem; + if (mean) + output[i] /= output.n_elem; } } diff --git a/src/mlpack/methods/ann/loss_functions/kl_divergence.hpp b/src/mlpack/methods/ann/loss_functions/kl_divergence.hpp index ad39d16c62..4640dce43e 100644 --- a/src/mlpack/methods/ann/loss_functions/kl_divergence.hpp +++ b/src/mlpack/methods/ann/loss_functions/kl_divergence.hpp @@ -60,7 +60,8 @@ class KLDivergence * @param target Target data to compare with. */ template - double Forward(const InputType& input, const TargetType& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. diff --git a/src/mlpack/methods/ann/loss_functions/kl_divergence_impl.hpp b/src/mlpack/methods/ann/loss_functions/kl_divergence_impl.hpp index dc72dc1645..bc9b44ea09 100644 --- a/src/mlpack/methods/ann/loss_functions/kl_divergence_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/kl_divergence_impl.hpp @@ -28,8 +28,9 @@ KLDivergence::KLDivergence(const bool takeMean) : template template -double KLDivergence::Forward( - const InputType& input, const TargetType& target) +typename InputType::elem_type +KLDivergence::Forward(const InputType& input, + const TargetType& target) { if (takeMean) { diff --git a/src/mlpack/methods/ann/loss_functions/log_cosh_loss.hpp b/src/mlpack/methods/ann/loss_functions/log_cosh_loss.hpp index d528157b11..2fc859c5c7 100644 --- a/src/mlpack/methods/ann/loss_functions/log_cosh_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/log_cosh_loss.hpp @@ -20,7 +20,7 @@ namespace ann /** Artificial Neural Network. */ { /** * The Log-Hyperbolic-Cosine loss function is often used to improve - * variational auto encoder. This function is the log of hyperbolic + * variational auto encoder. This function is the log of hyperbolic * cosine of difference between true values and predicted values. * * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, @@ -55,7 +55,8 @@ class LogCoshLoss * @param target Target data to compare with. */ template - double Forward(const InputType& input, const TargetType& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. diff --git a/src/mlpack/methods/ann/loss_functions/log_cosh_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/log_cosh_loss_impl.hpp index 5de18340e6..1fd13c922f 100644 --- a/src/mlpack/methods/ann/loss_functions/log_cosh_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/log_cosh_loss_impl.hpp @@ -28,8 +28,9 @@ LogCoshLoss::LogCoshLoss(const double a) : template template -double LogCoshLoss::Forward( - const InputType& input, const TargetType& target) +typename InputType::elem_type +LogCoshLoss::Forward(const InputType& input, + const TargetType& target) { return arma::accu(arma::log(arma::cosh(a * (target - input)))) / a; } diff --git a/src/mlpack/methods/ann/loss_functions/mean_bias_error.hpp b/src/mlpack/methods/ann/loss_functions/mean_bias_error.hpp index 40418980d3..a238ac50cb 100644 --- a/src/mlpack/methods/ann/loss_functions/mean_bias_error.hpp +++ b/src/mlpack/methods/ann/loss_functions/mean_bias_error.hpp @@ -45,7 +45,8 @@ class MeanBiasError * @param target The target vector. */ template - double Forward(const InputType& input, const TargetType& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. diff --git a/src/mlpack/methods/ann/loss_functions/mean_bias_error_impl.hpp b/src/mlpack/methods/ann/loss_functions/mean_bias_error_impl.hpp index 8488ae487a..9d014585f4 100644 --- a/src/mlpack/methods/ann/loss_functions/mean_bias_error_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/mean_bias_error_impl.hpp @@ -27,8 +27,9 @@ MeanBiasError::MeanBiasError() template template -double MeanBiasError::Forward( - const InputType& input, const TargetType& target) +typename InputType::elem_type +MeanBiasError::Forward(const InputType& input, + const TargetType& target) { return arma::accu(target - input) / target.n_cols; } diff --git a/src/mlpack/methods/ann/loss_functions/mean_squared_error.hpp b/src/mlpack/methods/ann/loss_functions/mean_squared_error.hpp index 6dc6642a0d..0315c10b5c 100644 --- a/src/mlpack/methods/ann/loss_functions/mean_squared_error.hpp +++ b/src/mlpack/methods/ann/loss_functions/mean_squared_error.hpp @@ -46,7 +46,8 @@ class MeanSquaredError * @param target The target vector. */ template - double Forward(const InputType& input, const TargetType& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. diff --git a/src/mlpack/methods/ann/loss_functions/mean_squared_error_impl.hpp b/src/mlpack/methods/ann/loss_functions/mean_squared_error_impl.hpp index d7203b2499..81cf2281cf 100644 --- a/src/mlpack/methods/ann/loss_functions/mean_squared_error_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/mean_squared_error_impl.hpp @@ -26,8 +26,10 @@ MeanSquaredError::MeanSquaredError() template template -double MeanSquaredError::Forward( - const InputType& input, const TargetType& target) +typename InputType::elem_type +MeanSquaredError::Forward( + const InputType& input, + const TargetType& target) { return arma::accu(arma::square(input - target)) / target.n_cols; } diff --git a/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error.hpp b/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error.hpp index 54b74d17d5..49b94d1d4f 100644 --- a/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error.hpp +++ b/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error.hpp @@ -45,7 +45,8 @@ class MeanSquaredLogarithmicError * @param target The target vector. */ template - double Forward(const InputType& input, const TargetType& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. diff --git a/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error_impl.hpp b/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error_impl.hpp index 4a2aa75d8a..92ead103a7 100644 --- a/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/mean_squared_logarithmic_error_impl.hpp @@ -27,8 +27,10 @@ MeanSquaredLogarithmicError template template -double MeanSquaredLogarithmicError::Forward( - const InputType& input, const TargetType& target) +typename InputType::elem_type +MeanSquaredLogarithmicError::Forward( + const InputType& input, + const TargetType& target) { return arma::accu(arma::square(arma::log(1. + target) - arma::log(1. + input))) / target.n_cols; diff --git a/src/mlpack/methods/ann/loss_functions/negative_log_likelihood.hpp b/src/mlpack/methods/ann/loss_functions/negative_log_likelihood.hpp index 200fa1c5f3..6c28321cb9 100644 --- a/src/mlpack/methods/ann/loss_functions/negative_log_likelihood.hpp +++ b/src/mlpack/methods/ann/loss_functions/negative_log_likelihood.hpp @@ -48,7 +48,8 @@ class NegativeLogLikelihood * between 1 and the number of classes. */ template - double Forward(const InputType& input, const TargetType& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. The negative log diff --git a/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp b/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp index d006b17912..1eb47280c5 100644 --- a/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp @@ -26,10 +26,13 @@ NegativeLogLikelihood::NegativeLogLikelihood() template template -double NegativeLogLikelihood::Forward( - const InputType& input, const TargetType& target) +typename InputType::elem_type +NegativeLogLikelihood::Forward( + const InputType& input, + const TargetType& target) { - double output = 0; + typedef typename InputType::elem_type ElemType; + ElemType output = 0; for (size_t i = 0; i < input.n_cols; ++i) { size_t currentTarget = target(i) - 1; diff --git a/src/mlpack/methods/ann/loss_functions/reconstruction_loss.hpp b/src/mlpack/methods/ann/loss_functions/reconstruction_loss.hpp index d8c775efc0..7d7c8e7da6 100644 --- a/src/mlpack/methods/ann/loss_functions/reconstruction_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/reconstruction_loss.hpp @@ -49,7 +49,8 @@ class ReconstructionLoss * @param target The target matrix. */ template - double Forward(const InputType& input, const TargetType& target); + typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. diff --git a/src/mlpack/methods/ann/loss_functions/reconstruction_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/reconstruction_loss_impl.hpp index 02ea50f4a7..b47d5bfcdb 100644 --- a/src/mlpack/methods/ann/loss_functions/reconstruction_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/reconstruction_loss_impl.hpp @@ -30,7 +30,8 @@ ReconstructionLoss< template template -double ReconstructionLoss::Forward( +typename InputType::elem_type +ReconstructionLoss::Forward( const InputType& input, const TargetType& target) { dist = DistType(input); diff --git a/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error.hpp b/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error.hpp index fec584de8c..0d70d2d29d 100644 --- a/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error.hpp +++ b/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error.hpp @@ -64,8 +64,8 @@ class SigmoidCrossEntropyError * @param target The target vector. */ template - inline double Forward(const InputType& input, - const TargetType& target); + inline typename InputType::elem_type Forward(const InputType& input, + const TargetType& target); /** * Ordinary feed backward pass of a neural network. * diff --git a/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error_impl.hpp b/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error_impl.hpp index 1ab976874a..e5cf69188c 100644 --- a/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/sigmoid_cross_entropy_error_impl.hpp @@ -29,10 +29,13 @@ SigmoidCrossEntropyError template template -inline double SigmoidCrossEntropyError::Forward( - const InputType& input, const TargetType& target) +inline typename InputType::elem_type +SigmoidCrossEntropyError::Forward( + const InputType& input, + const TargetType& target) { - double maximum = 0; + typedef typename InputType::elem_type ElemType; + ElemType maximum = 0; for (size_t i = 0; i < input.n_elem; ++i) { maximum += std::max(input[i], 0.0) + diff --git a/src/mlpack/tests/cv_test.cpp b/src/mlpack/tests/cv_test.cpp index b4182ac1fb..4210065887 100644 --- a/src/mlpack/tests/cv_test.cpp +++ b/src/mlpack/tests/cv_test.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -164,6 +165,28 @@ BOOST_AUTO_TEST_CASE(MSETest) BOOST_REQUIRE_CLOSE(MSE::Evaluate(lr, data, responses), expectedMSE, 1e-5); } +/** + * Test the R squared metric (R2 Score). + */ +BOOST_AUTO_TEST_CASE(R2ScoreTest) +{ + // Making two points that define the linear function f(x) = x - 1. + arma::mat trainingData("0 1"); + arma::rowvec trainingResponses("-1 0"); + + LinearRegression lr(trainingData, trainingResponses); + + // Making five responses that are the output of regression function f(x) + // with some responses having a slight deviation of 0.005. + // Mean Responses = (1 + 2 + 3 + 6 + 8)/5 = 4. + arma::mat data("2 3 4 7 9"); + arma::rowvec responses("1 2.005 3 6.005 8.005"); + + double expectedR2 = 0.99999779; + + BOOST_REQUIRE_CLOSE(R2Score::Evaluate(lr, data, responses), expectedR2, 1e-5); +} + /** * Test the mean squared error with matrix responses. */