diff --git a/HISTORY.md b/HISTORY.md index 7ae74ad6f1..f516fd8834 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,6 @@ ### mlpack ?.?.? ###### ????-??-?? + * Add adaptive max pooling and adaptive mean pooling layers (#2195). ### mlpack 3.3.1 ###### 2020-04-29 @@ -82,7 +83,7 @@ * Add CELU activation function (#2191) - * Add Log-Hyperbolic-Cosine Loss function (#2207) + * Add Log-Hyperbolic-Cosine Loss function (#2207). * Change neural network types to avoid unnecessary use of rvalue references (#2259). diff --git a/src/mlpack/methods/ann/layer/CMakeLists.txt b/src/mlpack/methods/ann/layer/CMakeLists.txt index 2cc3e3fb98..78b77b2a09 100644 --- a/src/mlpack/methods/ann/layer/CMakeLists.txt +++ b/src/mlpack/methods/ann/layer/CMakeLists.txt @@ -5,6 +5,10 @@ set(SOURCES add_impl.hpp add_merge.hpp add_merge_impl.hpp + adaptive_max_pooling.hpp + adaptive_max_pooling_impl.hpp + adaptive_mean_pooling.hpp + adaptive_mean_pooling_impl.hpp alpha_dropout.hpp alpha_dropout_impl.hpp atrous_convolution.hpp diff --git a/src/mlpack/methods/ann/layer/adaptive_max_pooling.hpp b/src/mlpack/methods/ann/layer/adaptive_max_pooling.hpp new file mode 100644 index 0000000000..302b61f368 --- /dev/null +++ b/src/mlpack/methods/ann/layer/adaptive_max_pooling.hpp @@ -0,0 +1,168 @@ +/** + * @file adaptive_max_pooling.hpp + * @author Kartik Dutt + * + * Definition of the AdaptiveMaxPooling 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_ADAPTIVE_MAX_POOLING_HPP +#define MLPACK_METHODS_ANN_LAYER_ADAPTIVE_MAX_POOLING_HPP + +#include +#include "layer_types.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * Implementation of the AdaptiveMaxPooling layer. + * + * @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 AdaptiveMaxPooling +{ + public: + //! Create the AdaptiveMaxPooling object. + AdaptiveMaxPooling(); + + /** + * Create the AdaptiveMaxPooling object. + * + * @param outputWidth Width of the output. + * @param outputHeight Height of the output. + */ + AdaptiveMaxPooling(const size_t outputWidth, + const size_t outputHeight); + + /** + * Create the AdaptiveMaxPooling object. + * + * @param outputShape A two-value tuple indicating width and height of the output. + */ + AdaptiveMaxPooling(const std::tuple& outputShape); + + /** + * Ordinary feed forward pass of a neural network, evaluating the function + * f(x) by propagating the activity forward through f. + * + * @param input Input data used for evaluating the specified function. + * @param output Resulting output activation. + */ + template + void Forward(const arma::Mat& input, arma::Mat& output); + + /** + * Ordinary feed backward pass of a neural network, using 3rd-order tensors as + * input, calculating the function f(x) by propagating x backwards through f. + * Using the results from the feed forward pass. + * + * @param input The propagated input activation. + * @param gy The backpropagated error. + * @param g The calculated gradient. + */ + template + void Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g); + + //! Get the output parameter. + const OutputDataType& OutputParameter() const + { return poolingLayer.OutputParameter(); } + + //! Modify the output parameter. + OutputDataType& OutputParameter() { return poolingLayer.OutputParameter(); } + + //! Get the delta. + const OutputDataType& Delta() const { return poolingLayer.Delta(); } + //! Modify the delta. + OutputDataType& Delta() { return poolingLayer.Delta(); } + + //! Get the input width. + size_t InputWidth() const { return poolingLayer.InputWidth(); } + //! Modify the input width. + size_t& InputWidth() { return poolingLayer.InputWidth(); } + + //! Get the input height. + size_t InputHeight() const { return poolingLayer.InputHeight(); } + //! Modify the input height. + size_t& InputHeight() { return poolingLayer.InputHeight(); } + + //! Get the output width. + size_t OutputWidth() const { return outputWidth; } + //! Modify the output width. + size_t& OutputWidth() { return outputWidth; } + + //! Get the output height. + size_t OutputHeight() const { return outputHeight; } + //! Modify the output height. + size_t& OutputHeight() { return outputHeight; } + + //! Get the input size. + size_t InputSize() const { return poolingLayer.InputSize(); } + + //! Get the output size. + size_t OutputSize() const { return poolingLayer.OutputSize(); } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const unsigned int version); + + private: + /** + * Initialize Kernel Size and Stride for Adaptive Pooling. + */ + void IntializeAdaptivePadding() + { + poolingLayer.StrideWidth() = std::floor(poolingLayer.InputWidth() / + outputWidth); + poolingLayer.StrideHeight() = std::floor(poolingLayer.InputHeight() / + outputHeight); + + poolingLayer.KernelWidth() = poolingLayer.InputWidth() - + (outputWidth - 1) * poolingLayer.StrideWidth(); + poolingLayer.KernelHeight() = poolingLayer.InputHeight() - + (outputHeight - 1) * poolingLayer.StrideHeight(); + + if (poolingLayer.KernelHeight() <= 0 || poolingLayer.KernelWidth() <= 0 || + poolingLayer.StrideWidth() <= 0 || poolingLayer.StrideHeight() <= 0) + { + Log::Fatal << "Given output shape (" << outputWidth << ", " + << outputHeight << ") is not possible for given input shape (" + << poolingLayer.InputWidth() << ", " << poolingLayer.InputHeight() + << ")." << std::endl; + } + } + + //! Locally stored MaxPooling Object. + MaxPooling poolingLayer; + + //! Locally-stored output width. + size_t outputWidth; + + //! Locally-stored output height. + size_t outputHeight; + + //! Locally-stored reset parameter used to initialize the layer once. + bool reset; +}; // class AdaptiveMaxPooling + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "adaptive_max_pooling_impl.hpp" + +#endif diff --git a/src/mlpack/methods/ann/layer/adaptive_max_pooling_impl.hpp b/src/mlpack/methods/ann/layer/adaptive_max_pooling_impl.hpp new file mode 100644 index 0000000000..c0c4266f93 --- /dev/null +++ b/src/mlpack/methods/ann/layer/adaptive_max_pooling_impl.hpp @@ -0,0 +1,87 @@ +/** + * @file adaptive_max_pooling_impl.hpp + * @author Kartik Dutt + * + * Implementation of the Adaptive Max Pooling layer 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_ADAPTIVE_MAX_POOLING_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_ADAPTIVE_MAX_POOLING_IMPL_HPP + +// In case it hasn't yet been included. +#include "adaptive_max_pooling.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +AdaptiveMaxPooling::AdaptiveMaxPooling() +{ + // Nothing to do here. +} + +template +AdaptiveMaxPooling::AdaptiveMaxPooling( + const size_t outputWidth, + const size_t outputHeight) : + AdaptiveMaxPooling(std::tuple(outputWidth, outputHeight)) +{ + // Nothing to do here. +} + +template +AdaptiveMaxPooling::AdaptiveMaxPooling( + const std::tuple& outputShape): + outputWidth(std::get<0>(outputShape)), + outputHeight(std::get<1>(outputShape)), + reset(false) +{ + poolingLayer = ann::MaxPooling<>(0, 0); +} + +template +template +void AdaptiveMaxPooling::Forward( + const arma::Mat& input, arma::Mat& output) +{ + if (!reset) + { + IntializeAdaptivePadding(); + reset = true; + } + + poolingLayer.Forward(input, output); +} + +template +template +void AdaptiveMaxPooling::Backward( + const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g) +{ + poolingLayer.Backward(input, gy, g); +} + +template +template +void AdaptiveMaxPooling::serialize( + Archive& ar, + const unsigned int version) +{ + ar & BOOST_SERIALIZATION_NVP(outputWidth); + ar & BOOST_SERIALIZATION_NVP(outputHeight); + ar & BOOST_SERIALIZATION_NVP(reset); + + if (version > 0) + ar & BOOST_SERIALIZATION_NVP(poolingLayer); +} + +} // namespace ann +} // namespace mlpack + +#endif diff --git a/src/mlpack/methods/ann/layer/adaptive_mean_pooling.hpp b/src/mlpack/methods/ann/layer/adaptive_mean_pooling.hpp new file mode 100644 index 0000000000..703a9e3084 --- /dev/null +++ b/src/mlpack/methods/ann/layer/adaptive_mean_pooling.hpp @@ -0,0 +1,169 @@ +/** + * @file adaptive_mean_pooling.hpp + * @author Kartik Dutt + * + * Definition of the AdaptiveMeanPooling layer 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_ADAPTIVE_MEAN_POOLING_HPP +#define MLPACK_METHODS_ANN_LAYER_ADAPTIVE_MEAN_POOLING_HPP + +#include +#include "layer_types.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * Implementation of the AdaptiveMeanPooling. + * + * @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 AdaptiveMeanPooling +{ + public: + //! Create the AdaptiveMeanPooling object. + AdaptiveMeanPooling(); + + /** + * Create the AdaptiveMeanPooling object. + * + * @param outputWidth Width of the output. + * @param outputHeight Height of the output. + */ + AdaptiveMeanPooling(const size_t outputWidth, + const size_t outputHeight); + + /** + * Create the AdaptiveMeanPooling object. + * + * @param outputShape A two-value tuple indicating width and height of the output. + */ + AdaptiveMeanPooling(const std::tuple& outputShape); + + /** + * Ordinary feed forward pass of a neural network, evaluating the function + * f(x) by propagating the activity forward through f. + * + * @param input Input data used for evaluating the specified function. + * @param output Resulting output activation. + */ + template + void Forward(const arma::Mat& input, arma::Mat& output); + + /** + * Ordinary feed backward pass of a neural network, using 3rd-order tensors as + * input, calculating the function f(x) by propagating x backwards through f. + * Using the results from the feed forward pass. + * + * @param input The propagated input activation. + * @param gy The backpropagated error. + * @param g The calculated gradient. + */ + template + void Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g); + + //! Get the output parameter. + const OutputDataType& OutputParameter() const + { return poolingLayer.OutputParameter(); } + + //! Modify the output parameter. + OutputDataType& OutputParameter() { return poolingLayer.OutputParameter(); } + + //! Get the delta. + const OutputDataType& Delta() const { return poolingLayer.Delta(); } + //! Modify the delta. + OutputDataType& Delta() { return poolingLayer.Delta(); } + + //! Get the input width. + size_t InputWidth() const { return poolingLayer.InputWidth(); } + //! Modify the input width. + size_t& InputWidth() { return poolingLayer.InputWidth(); } + + //! Get the input height. + size_t InputHeight() const { return poolingLayer.InputHeight(); } + //! Modify the input height. + size_t& InputHeight() { return poolingLayer.InputHeight(); } + + //! Get the output width. + size_t OutputWidth() const { return outputWidth; } + //! Modify the output width. + size_t& OutputWidth() { return outputWidth; } + + //! Get the output height. + size_t OutputHeight() const { return outputHeight; } + //! Modify the output height. + size_t& OutputHeight() { return outputHeight; } + + //! Get the input size. + size_t InputSize() const { return poolingLayer.InputSize(); } + + //! Get the output size. + size_t OutputSize() const { return poolingLayer.OutputSize(); } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const unsigned int version); + + private: + /** + * Initialize Kernel Size and Stride for Adaptive Pooling. + */ + void IntializeAdaptivePadding() + { + poolingLayer.StrideWidth() = std::floor(poolingLayer.InputWidth() / + outputWidth); + poolingLayer.StrideHeight() = std::floor(poolingLayer.InputHeight() / + outputHeight); + + poolingLayer.KernelWidth() = poolingLayer.InputWidth() - + (outputWidth - 1) * poolingLayer.StrideWidth(); + poolingLayer.KernelHeight() = poolingLayer.InputHeight() - + (outputHeight - 1) * poolingLayer.StrideHeight(); + + if (poolingLayer.KernelHeight() <= 0 || poolingLayer.KernelWidth() <= 0 || + poolingLayer.StrideWidth() <= 0 || poolingLayer.StrideHeight() <= 0) + { + Log::Fatal << "Given output shape (" << outputWidth << ", " + << outputHeight << ") is not possible for given input shape (" + << poolingLayer.InputWidth() << ", " << poolingLayer.InputHeight() + << ")." << std::endl; + } + } + + //! Locally stored MeanPooling Object. + MeanPooling poolingLayer; + + //! Locally-stored output width. + size_t outputWidth; + + //! Locally-stored output height. + size_t outputHeight; + + //! Locally-stored reset parameter used to initialize the layer once. + bool reset; +}; // class AdaptiveMeanPooling + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "adaptive_mean_pooling_impl.hpp" + +#endif diff --git a/src/mlpack/methods/ann/layer/adaptive_mean_pooling_impl.hpp b/src/mlpack/methods/ann/layer/adaptive_mean_pooling_impl.hpp new file mode 100644 index 0000000000..6cf2c5116c --- /dev/null +++ b/src/mlpack/methods/ann/layer/adaptive_mean_pooling_impl.hpp @@ -0,0 +1,87 @@ +/** + * @file adaptive_mean_pooling_impl.hpp + * @author Kartik Dutt + * + * Implementation of the Adaptive Mean Pooling layer 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_ADAPTIVE_MEAN_POOLING_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_ADAPTIVE_MEAN_POOLING_IMPL_HPP + +// In case it hasn't yet been included. +#include "adaptive_mean_pooling.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +AdaptiveMeanPooling::AdaptiveMeanPooling() +{ + // Nothing to do here. +} + +template +AdaptiveMeanPooling::AdaptiveMeanPooling( + const size_t outputWidth, + const size_t outputHeight) : + AdaptiveMeanPooling(std::tuple(outputWidth, outputHeight)) +{ + // Nothing to do here. +} + +template +AdaptiveMeanPooling::AdaptiveMeanPooling( + const std::tuple& outputShape): + outputWidth(std::get<0>(outputShape)), + outputHeight(std::get<1>(outputShape)), + reset(false) +{ + poolingLayer = ann::MeanPooling<>(0, 0); +} + +template +template +void AdaptiveMeanPooling::Forward( + const arma::Mat& input, arma::Mat& output) +{ + if (!reset) + { + IntializeAdaptivePadding(); + reset = true; + } + + poolingLayer.Forward(input, output); +} + +template +template +void AdaptiveMeanPooling::Backward( + const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g) +{ + poolingLayer.Backward(input, gy, g); +} + +template +template +void AdaptiveMeanPooling::serialize( + Archive& ar, + const unsigned int version) +{ + ar & BOOST_SERIALIZATION_NVP(outputWidth); + ar & BOOST_SERIALIZATION_NVP(outputHeight); + ar & BOOST_SERIALIZATION_NVP(reset); + + if (version > 0) + ar & BOOST_SERIALIZATION_NVP(poolingLayer); +} + +} // namespace ann +} // namespace mlpack + +#endif diff --git a/src/mlpack/methods/ann/layer/layer.hpp b/src/mlpack/methods/ann/layer/layer.hpp index 44cc8b667f..a9b1380933 100644 --- a/src/mlpack/methods/ann/layer/layer.hpp +++ b/src/mlpack/methods/ann/layer/layer.hpp @@ -13,6 +13,8 @@ #define MLPACK_METHODS_ANN_LAYER_LAYER_HPP #include "add.hpp" +#include "adaptive_max_pooling.hpp" +#include "adaptive_mean_pooling.hpp" #include "add_merge.hpp" #include "alpha_dropout.hpp" #include "atrous_convolution.hpp" diff --git a/src/mlpack/methods/ann/layer/layer_types.hpp b/src/mlpack/methods/ann/layer/layer_types.hpp index 5a07c59016..70e6ddef3f 100644 --- a/src/mlpack/methods/ann/layer/layer_types.hpp +++ b/src/mlpack/methods/ann/layer/layer_types.hpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include #include @@ -179,6 +181,16 @@ template class WeightNorm; +template +class AdaptiveMaxPooling; + +template +class AdaptiveMeanPooling; + using MoreTypes = boost::variant< Recurrent*, RecurrentAttention*, @@ -194,6 +206,8 @@ using MoreTypes = boost::variant< template using LayerTypes = boost::variant< + AdaptiveMaxPooling*, + AdaptiveMeanPooling*, Add*, AddMerge*, AtrousConvolution, diff --git a/src/mlpack/methods/ann/layer/max_pooling.hpp b/src/mlpack/methods/ann/layer/max_pooling.hpp index 3f3af81949..48a05e8c06 100644 --- a/src/mlpack/methods/ann/layer/max_pooling.hpp +++ b/src/mlpack/methods/ann/layer/max_pooling.hpp @@ -104,24 +104,24 @@ class MaxPooling //! Modify the delta. OutputDataType& Delta() { return delta; } - //! Get the width. + //! Get the input width. size_t InputWidth() const { return inputWidth; } - //! Modify the width. + //! Modify the input width. size_t& InputWidth() { return inputWidth; } - //! Get the height. + //! Get the input height. size_t InputHeight() const { return inputHeight; } - //! Modify the height. + //! Modify the input height. size_t& InputHeight() { return inputHeight; } - //! Get the width. + //! Get the output width. size_t OutputWidth() const { return outputWidth; } - //! Modify the width. + //! Modify the output width. size_t& OutputWidth() { return outputWidth; } - //! Get the height. + //! Get the output height. size_t OutputHeight() const { return outputHeight; } - //! Modify the height. + //! Modify the output height. size_t& OutputHeight() { return outputHeight; } //! Get the input size. @@ -161,7 +161,7 @@ class MaxPooling bool& Deterministic() { return deterministic; } /** - * Serialize the layer + * Serialize the layer. */ template void serialize(Archive& ar, const unsigned int /* version */); diff --git a/src/mlpack/methods/ann/layer/mean_pooling.hpp b/src/mlpack/methods/ann/layer/mean_pooling.hpp index 34c3a811e2..f1368eb078 100644 --- a/src/mlpack/methods/ann/layer/mean_pooling.hpp +++ b/src/mlpack/methods/ann/layer/mean_pooling.hpp @@ -84,24 +84,24 @@ class MeanPooling //! Modify the delta. OutputDataType& Delta() { return delta; } - //! Get the width. + //! Get the intput width. size_t const& InputWidth() const { return inputWidth; } - //! Modify the width. + //! Modify the input width. size_t& InputWidth() { return inputWidth; } - //! Get the height. + //! Get the input height. size_t const& InputHeight() const { return inputHeight; } - //! Modify the height. + //! Modify the input height. size_t& InputHeight() { return inputHeight; } - //! Get the width. + //! Get the output width. size_t const& OutputWidth() const { return outputWidth; } - //! Modify the width. + //! Modify the output width. size_t& OutputWidth() { return outputWidth; } - //! Get the height. + //! Get the output height. size_t const& OutputHeight() const { return outputHeight; } - //! Modify the height. + //! Modify the output height. size_t& OutputHeight() { return outputHeight; } //! Get the input size. @@ -141,7 +141,7 @@ class MeanPooling bool& Deterministic() { return deterministic; } /** - * Serialize the layer + * Serialize the layer. */ template void serialize(Archive& ar, const unsigned int /* version */); diff --git a/src/mlpack/methods/ann/layer_names.hpp b/src/mlpack/methods/ann/layer_names.hpp index ea1150b14e..a3671a6837 100644 --- a/src/mlpack/methods/ann/layer_names.hpp +++ b/src/mlpack/methods/ann/layer_names.hpp @@ -30,6 +30,28 @@ class LayerNameVisitor : public boost::static_visitor { } + /** + * Return the name of the given layer of type AdaptiveMaxPooling as string. + * + * @param Given layer of type AdaptiveMaxPooling. + * @return The string representation of the layer. + */ + std::string LayerString(AdaptiveMaxPooling<> * /*layer*/) const + { + return "adaptivemaxpooling"; + } + + /** + * Return the name of the given layer of type AdaptiveMeanPooling as string. + * + * @param Given layer of type AdaptiveMeanPooling. + * @return The string representation of the layer. + */ + std::string LayerString(AdaptiveMeanPooling<> * /*layer*/) const + { + return "adaptivemeanpooling"; + } + /** * Return the name of the given layer of type AtrousConvolution as a string. * diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index c064d61d9a..839b99ce6b 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -3117,4 +3117,201 @@ BOOST_AUTO_TEST_CASE(MaxPoolingTestCase) BOOST_REQUIRE_EQUAL(output.n_elem, 4); BOOST_REQUIRE_EQUAL(output.n_cols, 1); } + +/** + * Simple test for Adaptive pooling for Max Pooling layer. + */ +BOOST_AUTO_TEST_CASE(AdaptiveMaxPoolingTestCase) +{ + // For rectangular input. + arma::mat input = arma::mat(12, 1); + arma::mat output, delta; + + input.zeros(); + input(0) = 1; + input(1) = 2; + input(2) = 3; + input(3) = input(8) = 7; + input(4) = 4; + input(5) = 5; + input(6) = input(7) = 6; + input(10) = 8; + input(11) = 9; + // Output-Size should be 2 x 2. + // Square output. + AdaptiveMaxPooling<> module1(2, 2); + module1.InputHeight() = 3; + module1.InputWidth() = 4; + module1.Forward(input, output); + // Calculated using torch.nn.AdaptiveMaxPool2d(). + BOOST_REQUIRE_EQUAL(arma::accu(output), 28); + BOOST_REQUIRE_EQUAL(output.n_elem, 4); + BOOST_REQUIRE_EQUAL(output.n_cols, 1); + // Test the Backward Function. + module1.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 28.0); + + // For Square input. + input = arma::mat(9, 1); + input.zeros(); + input(0) = 6; + input(1) = 3; + input(2) = 9; + input(3) = 3; + input(6) = 3; + // Output-Size should be 1 x 2. + // Rectangular output. + AdaptiveMaxPooling<> module2(2, 1); + module2.InputHeight() = 3; + module2.InputWidth() = 3; + module2.Forward(input, output); + // Calculated using torch.nn.AdaptiveMaxPool2d(). + BOOST_REQUIRE_EQUAL(arma::accu(output), 15.0); + BOOST_REQUIRE_EQUAL(output.n_elem, 2); + BOOST_REQUIRE_EQUAL(output.n_cols, 1); + // Test the Backward Function. + module2.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 15.0); + + // For Square input. + input = arma::mat(16, 1); + input.zeros(); + input(0) = 6; + input(1) = 3; + input(2) = 9; + input(4) = 3; + input(8) = 3; + // Output-Size should be 3 x 3. + // Square output. + AdaptiveMaxPooling<> module3(std::tuple(3, 3)); + module3.InputHeight() = 4; + module3.InputWidth() = 4; + module3.Forward(input, output); + // Calculated using torch.nn.AdaptiveMaxPool2d(). + BOOST_REQUIRE_EQUAL(arma::accu(output), 30.0); + BOOST_REQUIRE_EQUAL(output.n_elem, 9); + BOOST_REQUIRE_EQUAL(output.n_cols, 1); + // Test the Backward Function. + module3.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 30.0); + + // For Rectangular input. + input = arma::mat(20, 1); + input.zeros(); + input(0) = 1; + input(1) = 1; + input(3) = 1; + // Output-Size should be 2 x 2. + // Square output. + AdaptiveMaxPooling<> module4(std::tuple(2, 2)); + module4.InputHeight() = 4; + module4.InputWidth() = 5; + module4.Forward(input, output); + // Calculated using torch.nn.AdaptiveMaxPool2d(). + BOOST_REQUIRE_EQUAL(arma::accu(output), 2); + BOOST_REQUIRE_EQUAL(output.n_elem, 4); + BOOST_REQUIRE_EQUAL(output.n_cols, 1); + // Test the Backward Function. + module4.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 2.0); +} + +/** + * Simple test for Adaptive pooling for Mean Pooling layer. + */ +BOOST_AUTO_TEST_CASE(AdaptiveMeanPoolingTestCase) +{ + // For rectangular input. + arma::mat input = arma::mat(12, 1); + arma::mat output, delta; + + input.zeros(); + input(0) = 1; + input(1) = 2; + input(2) = 3; + input(3) = input(8) = 7; + input(4) = 4; + input(5) = 5; + input(6) = input(7) = 6; + input(10) = 8; + input(11) = 9; + // Output-Size should be 2 x 2. + // Square output. + AdaptiveMeanPooling<> module1(2, 2); + module1.InputHeight() = 3; + module1.InputWidth() = 4; + module1.Forward(input, output); + // Calculated using torch.nn.AdaptiveAvgPool2d(). + BOOST_REQUIRE_EQUAL(arma::accu(output), 19.75); + BOOST_REQUIRE_EQUAL(output.n_elem, 4); + BOOST_REQUIRE_EQUAL(output.n_cols, 1); + // Test the Backward Function. + module1.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 7.0); + + // For Square input. + input = arma::mat(9, 1); + input.zeros(); + input(0) = 6; + input(1) = 3; + input(2) = 9; + input(3) = 3; + input(6) = 3; + // Output-Size should be 1 x 2. + // Rectangular output. + AdaptiveMeanPooling<> module2(1, 2); + module2.InputHeight() = 3; + module2.InputWidth() = 3; + module2.Forward(input, output); + // Calculated using torch.nn.AdaptiveAvgPool2d(). + BOOST_REQUIRE_EQUAL(arma::accu(output), 4.5); + BOOST_REQUIRE_EQUAL(output.n_elem, 2); + BOOST_REQUIRE_EQUAL(output.n_cols, 1); + // Test the Backward Function. + module2.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 0.0); + + // For Square input. + input = arma::mat(16, 1); + input.zeros(); + input(0) = 6; + input(1) = 3; + input(2) = 9; + input(4) = 3; + input(8) = 3; + // Output-Size should be 3 x 3. + // Square output. + AdaptiveMeanPooling<> module3(std::tuple(3, 3)); + module3.InputHeight() = 4; + module3.InputWidth() = 4; + module3.Forward(input, output); + // Calculated using torch.nn.AdaptiveAvgPool2d(). + BOOST_REQUIRE_EQUAL(arma::accu(output), 10.5); + BOOST_REQUIRE_EQUAL(output.n_elem, 9); + BOOST_REQUIRE_EQUAL(output.n_cols, 1); + // Test the Backward Function. + module3.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 10.5); + + // For Rectangular input. + input = arma::mat(24, 1); + input.zeros(); + input(0) = 3; + input(1) = 3; + input(4) = 3; + // Output-Size should be 3 x 3. + // Square output. + AdaptiveMeanPooling<> module4(std::tuple(3, 3)); + module4.InputHeight() = 4; + module4.InputWidth() = 6; + module4.Forward(input, output); + // Calculated using torch.nn.AdaptiveAvgPool2d(). + BOOST_REQUIRE_EQUAL(arma::accu(output), 2.25); + BOOST_REQUIRE_EQUAL(output.n_elem, 9); + BOOST_REQUIRE_EQUAL(output.n_cols, 1); + // Test the Backward Function. + module4.Backward(input, output, delta); + BOOST_REQUIRE_EQUAL(arma::accu(delta), 1.5); +} + BOOST_AUTO_TEST_SUITE_END();