diff --git a/HISTORY.md b/HISTORY.md index 50f3f92efd..a851154847 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,8 @@ ### mlpack ?.?.? ###### ????-??-?? + * Adapt HardTanH layer (#3454). + * Adapt Softmin layer for new neural network API (#3437). * Adapt PReLU layer for new neural network API (#3420). diff --git a/src/mlpack/methods/ann/layer/not_adapted/hard_tanh.hpp b/src/mlpack/methods/ann/layer/hard_tanh.hpp similarity index 82% rename from src/mlpack/methods/ann/layer/not_adapted/hard_tanh.hpp rename to src/mlpack/methods/ann/layer/hard_tanh.hpp index 5f58aa2d3c..61c985cb17 100644 --- a/src/mlpack/methods/ann/layer/not_adapted/hard_tanh.hpp +++ b/src/mlpack/methods/ann/layer/hard_tanh.hpp @@ -1,6 +1,7 @@ /** * @file methods/ann/layer/hard_tanh.hpp * @author Dhawal Arora + * @author Vaibhav Pathak * * Definition and implementation of the HardTanH layer. * @@ -44,8 +45,8 @@ namespace mlpack { * to also be in this type. The type also allows the computation and weight * type to differ from the input type (Default: arma::mat). */ -template -class HardTanHType : public Layer +template +class HardTanHType : public Layer { public: /** @@ -57,6 +58,20 @@ class HardTanHType : public Layer * @param minValue Range of the linear region minimum value. */ HardTanHType(const double maxValue = 1, const double minValue = -1); + + virtual ~HardTanHType() { } + + //! Copy the other HardTanH layer + HardTanHType(const HardTanHType& layer); + + //! Take ownership of the members of the other HardTanH Layer + HardTanHType(HardTanHType&& layer); + + //! Copy the other HardTanH layer + HardTanHType& operator=(const HardTanHType& layer); + + //! Take ownership of the members of the other HardTanH Layer + HardTanHType& operator=(HardTanHType&& layer); //! Clone the HardTanHType object. This handles polymorphism correctly. HardTanHType* Clone() const { return new HardTanHType(*this); } @@ -68,7 +83,7 @@ class HardTanHType : public Layer * @param input Input data used for evaluating the specified function. * @param output Resulting output activation. */ - void Forward(const InputType& input, OutputType& output); + void Forward(const MatType& input, MatType& output); /** * Ordinary feed backward pass of a neural network, calculating the function @@ -79,7 +94,7 @@ class HardTanHType : public Layer * @param gy The backpropagated error. * @param g The calculated gradient. */ - void Backward(const InputType& input, const OutputType& gy, OutputType& g); + void Backward(const MatType& input, const MatType& gy, MatType& g); //! Get the maximum value. double const& MaxValue() const { return maxValue; } @@ -108,7 +123,7 @@ class HardTanHType : public Layer // Convenience typedefs. // Standard HardTanH layer. -typedef HardTanHType HardTanH; +typedef HardTanHType HardTanH; } // namespace mlpack diff --git a/src/mlpack/methods/ann/layer/hard_tanh_impl.hpp b/src/mlpack/methods/ann/layer/hard_tanh_impl.hpp new file mode 100644 index 0000000000..9b631ba6e1 --- /dev/null +++ b/src/mlpack/methods/ann/layer/hard_tanh_impl.hpp @@ -0,0 +1,119 @@ +/** + * @file methods/ann/layer/hard_tanh_impl.hpp + * @author Dhawal Arora + * @author Vaibhav Pathak + * + * Implementation and implementation of the HardTanH layer. + * + * 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_HARD_TANH_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_HARD_TANH_IMPL_HPP + +// In case it hasn't yet been included. +#include "hard_tanh.hpp" + +namespace mlpack { + +template +HardTanHType::HardTanHType( + const double maxValue, + const double minValue) : + Layer(), + maxValue(maxValue), + minValue(minValue) +{ + // Nothing to do here. +} + +template +HardTanHType::HardTanHType(const HardTanHType& layer) : + Layer(layer), + maxValue(layer.maxValue), + minValue(layer.minValue) +{ + // Nothing to do here. +} + +template +HardTanHType::HardTanHType(HardTanHType&& layer) : + Layer(std::move(layer)), + maxValue(std::move(layer.maxValue)), + minValue(std::move(layer.minValue)) +{ + // Nothing to do here. +} + +template +HardTanHType& HardTanHType::operator=(const HardTanHType& layer) +{ + if (&layer != this) + { + Layer::operator=(layer); + maxValue = layer.maxValue; + minValue = layer.minValue; + } + + return *this; +} + +template +HardTanHType& HardTanHType::operator=(HardTanHType&& layer) +{ + if (&layer != this) + { + Layer::operator=(std::move(layer)); + maxValue = std::move(layer.maxValue); + minValue = std::move(layer.minValue); + } + + return *this; +} +template +void HardTanHType::Forward( + const MatType& input, MatType& output) +{ + #pragma omp parallel for + for (size_t i = 0; i < input.n_elem; ++i) + { + output(i) = (input(i) > maxValue ? maxValue : + (input(i) < minValue ? minValue : input(i))); + } +} + +template +void HardTanHType::Backward( + const MatType& input, const MatType& gy, MatType& g) +{ + g = gy; + + #pragma omp parallel for + for (size_t i = 0; i < input.n_elem; ++i) + { + // input should not have any values greater than maxValue + // and lesser than minValue + if (input(i) <= minValue || input(i) >= maxValue) + { + g(i) = 0; + } + } +} + +template +template +void HardTanHType::serialize( + Archive& ar, + const uint32_t /* version */) +{ + ar(cereal::base_class>(this)); + + ar(CEREAL_NVP(maxValue)); + ar(CEREAL_NVP(minValue)); +} + +} // namespace mlpack + +#endif diff --git a/src/mlpack/methods/ann/layer/layer_types.hpp b/src/mlpack/methods/ann/layer/layer_types.hpp index dc12f47d7f..5d348a14b1 100644 --- a/src/mlpack/methods/ann/layer/layer_types.hpp +++ b/src/mlpack/methods/ann/layer/layer_types.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/src/mlpack/methods/ann/layer/not_adapted/hard_tanh_impl.hpp b/src/mlpack/methods/ann/layer/not_adapted/hard_tanh_impl.hpp deleted file mode 100644 index 129a061008..0000000000 --- a/src/mlpack/methods/ann/layer/not_adapted/hard_tanh_impl.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @file methods/ann/layer/hard_tanh_impl.hpp - * @author Dhawal Arora - * - * Implementation and implementation of the HardTanH layer. - * - * 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_HARD_TANH_IMPL_HPP -#define MLPACK_METHODS_ANN_LAYER_HARD_TANH_IMPL_HPP - -// In case it hasn't yet been included. -#include "hard_tanh.hpp" - -namespace mlpack { - -template -HardTanHType::HardTanHType( - const double maxValue, - const double minValue) : - maxValue(maxValue), - minValue(minValue) -{ - // Nothing to do here. -} - -template -void HardTanHType::Forward( - const InputType& input, OutputType& output) -{ - for (size_t i = 0; i < input.n_elem; ++i) - { - output(i) = (output(i) > maxValue ? maxValue : - (output(i) < minValue ? minValue : output(i))); - } -} - -template -void HardTanHType::Backward( - const InputType& input, const OutputType& gy, OutputType& g) -{ - g = gy; - for (size_t i = 0; i < input.n_elem; ++i) - { - if (input(i) < minValue || input(i) > maxValue) - { - g(i) = 0; - } - } -} - -template -template -void HardTanHType::serialize( - Archive& ar, - const uint32_t /* version */) -{ - ar(cereal::base_class>(this)); - - ar(CEREAL_NVP(maxValue)); - ar(CEREAL_NVP(minValue)); -} - -} // namespace mlpack - -#endif diff --git a/src/mlpack/methods/ann/layer/serialization.hpp b/src/mlpack/methods/ann/layer/serialization.hpp index 5819a5d604..c8daf52a71 100644 --- a/src/mlpack/methods/ann/layer/serialization.hpp +++ b/src/mlpack/methods/ann/layer/serialization.hpp @@ -69,6 +69,7 @@ CEREAL_REGISTER_TYPE(mlpack::RBFType<__VA_ARGS__>); \ CEREAL_REGISTER_TYPE(mlpack::SoftmaxType<__VA_ARGS__>); \ CEREAL_REGISTER_TYPE(mlpack::SoftminType<__VA_ARGS__>); \ + CEREAL_REGISTER_TYPE(mlpack::HardTanHType<__VA_ARGS__>); \ CEREAL_REGISTER_MLPACK_LAYERS(arma::mat); diff --git a/src/mlpack/tests/ann/layer/hard_tanh.cpp b/src/mlpack/tests/ann/layer/hard_tanh.cpp new file mode 100644 index 0000000000..2276981cac --- /dev/null +++ b/src/mlpack/tests/ann/layer/hard_tanh.cpp @@ -0,0 +1,58 @@ +/* + * @file tests/ann/layer/hard_tanh.cpp + * @author Vaibhav Pathak + * + * Tests the hard_tanh layer + * + */ + +#include +#include + +#include "../../test_catch_tools.hpp" +#include "../../catch.hpp" +#include "../../serialization.hpp" +#include "../ann_test_tools.hpp" + +using namespace mlpack; + +/** + * Simple HardTanH module test + */ + +TEST_CASE("SimpleHardTanHTest", "[ANNLayerTest]") +{ + arma::mat output, gy, g; + arma::mat input = {{-1.3743, -0.5565, 0.2742, -0.0151, -1.4871}, + {1.5797, -4.2711, -2.2505, -1.7105, -1.2544}, + {0.4023, 0.5676, 2.3100, 1.6658, -0.1907}, + {0.1897, 0.9097, 0.1418, -1.5349, 0.1225}, + {-0.1101, -3.3656, -5.4033, -2.2240, -3.3235}}; + arma::mat actualOutput = {{-1.0000, -0.5565, 0.2742, -0.0151, -1.0000}, + {1.0000, -1.0000, -1.0000, -1.0000, -1.0000}, + {0.4023, 0.5676, 1.0000, 1.0000, -0.1907}, + {0.1897, 0.9097, 0.1418, -1.0000, 0.1225}, + {-0.1101, -1.0000, -1.0000, -1.0000, -1.0000}}; + + HardTanH module; + + output.set_size(5,5); + // Test the Forward function + module.Forward(input, output); + REQUIRE(arma::accu(output - actualOutput) == Approx(0).epsilon(1e-4)); + + arma::mat delta = {{0 , 1.0, 1.0, 1.0, 0.0}, + {0 , 0 , 0 , 0.0, 0.0}, + {1.0, 1.0, 0 , 0.0, 1.0}, + {1.0, 1.0, 1.0, 0.0, 1.0}, + {1.0, 0 , 0.0, 0.0, 0.0}}; + + gy.set_size(5,5); + gy.fill(1); + g.set_size(5,5); + + //Test the Backward function + module.Backward(output, gy, g); + REQUIRE(arma::accu(g - delta) == Approx(0).epsilon(1e-4)); +} + diff --git a/src/mlpack/tests/ann/layer_test.cpp b/src/mlpack/tests/ann/layer_test.cpp index 73456b23e9..32bb25425b 100644 --- a/src/mlpack/tests/ann/layer_test.cpp +++ b/src/mlpack/tests/ann/layer_test.cpp @@ -26,6 +26,7 @@ #include "layer/concatenate.cpp" #include "layer/dropout.cpp" #include "layer/grouped_convolution.cpp" +#include "layer/hard_tanh.cpp" #include "layer/identity.cpp" #include "layer/linear3d.cpp" #include "layer/linear_no_bias.cpp"