Merge pull request #2195 from kartikdutt18/Add-Adaptive-Pooling

Addition of Adaptive Pooling (mean and max).
This commit is contained in:
Ryan Birmingham
2020-05-03 15:09:12 -04:00
committed by GitHub
12 changed files with 770 additions and 19 deletions
+2 -1
View File
@@ -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).
@@ -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
@@ -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 <mlpack/prereqs.hpp>
#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<size_t, size_t>& 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<typename eT>
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& 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<typename eT>
void Backward(const arma::Mat<eT>& input,
const arma::Mat<eT>& gy,
arma::Mat<eT>& 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<typename Archive>
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<InputDataType, OutputDataType> 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
@@ -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<typename InputDataType, typename OutputDataType>
AdaptiveMaxPooling<InputDataType, OutputDataType>::AdaptiveMaxPooling()
{
// Nothing to do here.
}
template <typename InputDataType, typename OutputDataType>
AdaptiveMaxPooling<InputDataType, OutputDataType>::AdaptiveMaxPooling(
const size_t outputWidth,
const size_t outputHeight) :
AdaptiveMaxPooling(std::tuple<size_t, size_t>(outputWidth, outputHeight))
{
// Nothing to do here.
}
template <typename InputDataType, typename OutputDataType>
AdaptiveMaxPooling<InputDataType, OutputDataType>::AdaptiveMaxPooling(
const std::tuple<size_t, size_t>& outputShape):
outputWidth(std::get<0>(outputShape)),
outputHeight(std::get<1>(outputShape)),
reset(false)
{
poolingLayer = ann::MaxPooling<>(0, 0);
}
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void AdaptiveMaxPooling<InputDataType, OutputDataType>::Forward(
const arma::Mat<eT>& input, arma::Mat<eT>& output)
{
if (!reset)
{
IntializeAdaptivePadding();
reset = true;
}
poolingLayer.Forward(input, output);
}
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void AdaptiveMaxPooling<InputDataType, OutputDataType>::Backward(
const arma::Mat<eT>& input,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g)
{
poolingLayer.Backward(input, gy, g);
}
template<typename InputDataType, typename OutputDataType>
template<typename Archive>
void AdaptiveMaxPooling<InputDataType, OutputDataType>::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
@@ -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 <mlpack/prereqs.hpp>
#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<size_t, size_t>& 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<typename eT>
void Forward(const arma::Mat<eT>& input, arma::Mat<eT>& 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<typename eT>
void Backward(const arma::Mat<eT>& input,
const arma::Mat<eT>& gy,
arma::Mat<eT>& 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<typename Archive>
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<InputDataType, OutputDataType> 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
@@ -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<typename InputDataType, typename OutputDataType>
AdaptiveMeanPooling<InputDataType, OutputDataType>::AdaptiveMeanPooling()
{
// Nothing to do here.
}
template <typename InputDataType, typename OutputDataType>
AdaptiveMeanPooling<InputDataType, OutputDataType>::AdaptiveMeanPooling(
const size_t outputWidth,
const size_t outputHeight) :
AdaptiveMeanPooling(std::tuple<size_t, size_t>(outputWidth, outputHeight))
{
// Nothing to do here.
}
template <typename InputDataType, typename OutputDataType>
AdaptiveMeanPooling<InputDataType, OutputDataType>::AdaptiveMeanPooling(
const std::tuple<size_t, size_t>& outputShape):
outputWidth(std::get<0>(outputShape)),
outputHeight(std::get<1>(outputShape)),
reset(false)
{
poolingLayer = ann::MeanPooling<>(0, 0);
}
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void AdaptiveMeanPooling<InputDataType, OutputDataType>::Forward(
const arma::Mat<eT>& input, arma::Mat<eT>& output)
{
if (!reset)
{
IntializeAdaptivePadding();
reset = true;
}
poolingLayer.Forward(input, output);
}
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void AdaptiveMeanPooling<InputDataType, OutputDataType>::Backward(
const arma::Mat<eT>& input,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g)
{
poolingLayer.Backward(input, gy, g);
}
template<typename InputDataType, typename OutputDataType>
template<typename Archive>
void AdaptiveMeanPooling<InputDataType, OutputDataType>::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
+2
View File
@@ -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"
@@ -36,6 +36,8 @@
#include <mlpack/methods/ann/layer/multiply_constant.hpp>
#include <mlpack/methods/ann/layer/max_pooling.hpp>
#include <mlpack/methods/ann/layer/mean_pooling.hpp>
#include <mlpack/methods/ann/layer/adaptive_max_pooling.hpp>
#include <mlpack/methods/ann/layer/adaptive_mean_pooling.hpp>
#include <mlpack/methods/ann/layer/parametric_relu.hpp>
#include <mlpack/methods/ann/layer/reinforce_normal.hpp>
#include <mlpack/methods/ann/layer/reparametrization.hpp>
@@ -179,6 +181,16 @@ template <typename InputDataType,
>
class WeightNorm;
template <typename InputDataType,
typename OutputDataType
>
class AdaptiveMaxPooling;
template <typename InputDataType,
typename OutputDataType
>
class AdaptiveMeanPooling;
using MoreTypes = boost::variant<
Recurrent<arma::mat, arma::mat>*,
RecurrentAttention<arma::mat, arma::mat>*,
@@ -194,6 +206,8 @@ using MoreTypes = boost::variant<
template <typename... CustomLayers>
using LayerTypes = boost::variant<
AdaptiveMaxPooling<arma::mat, arma::mat>*,
AdaptiveMeanPooling<arma::mat, arma::mat>*,
Add<arma::mat, arma::mat>*,
AddMerge<arma::mat, arma::mat>*,
AtrousConvolution<NaiveConvolution<ValidConvolution>,
+9 -9
View File
@@ -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<typename Archive>
void serialize(Archive& ar, const unsigned int /* version */);
@@ -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<typename Archive>
void serialize(Archive& ar, const unsigned int /* version */);
+22
View File
@@ -30,6 +30,28 @@ class LayerNameVisitor : public boost::static_visitor<std::string>
{
}
/**
* 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.
*
+197
View File
@@ -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<size_t, size_t>(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<size_t, size_t>(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<size_t, size_t>(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<size_t, size_t>(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();