From ec06bcbbffc4f6cdb49af7c269b5acd85db5db87 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 25 Jan 2022 22:44:34 -0500 Subject: [PATCH] Start implementing copy and move constructors correctly. --- src/mlpack/methods/ann/layer/add.hpp | 12 ++++ src/mlpack/methods/ann/layer/add_impl.hpp | 42 ++++++++++++++ .../methods/ann/layer/alpha_dropout.hpp | 16 ++++- .../methods/ann/layer/alpha_dropout_impl.hpp | 58 +++++++++++++++++++ src/mlpack/methods/ann/layer/base_layer.hpp | 6 ++ src/mlpack/methods/ann/layer/concatenate.hpp | 12 ++++ .../methods/ann/layer/concatenate_impl.hpp | 45 ++++++++++++++ src/mlpack/methods/ann/layer/convolution.hpp | 8 +-- .../methods/ann/layer/convolution_impl.hpp | 58 ++++++++++++++++++- src/mlpack/methods/ann/layer/layer.hpp | 51 +++++++++++++--- src/mlpack/methods/ann/layer/linear.hpp | 14 +++++ src/mlpack/methods/ann/layer/linear_impl.hpp | 56 ++++++++++++++++++ 12 files changed, 362 insertions(+), 16 deletions(-) diff --git a/src/mlpack/methods/ann/layer/add.hpp b/src/mlpack/methods/ann/layer/add.hpp index 8cb1a1958c..f825df0169 100644 --- a/src/mlpack/methods/ann/layer/add.hpp +++ b/src/mlpack/methods/ann/layer/add.hpp @@ -45,6 +45,18 @@ class AddType : public Layer //! Clone the AddType object. This handles polymorphism correctly. AddType* Clone() const { return new AddType(*this); } + // Virtual destructor. + virtual ~AddType(); + + //! Copy the given AddType layer. + AddType(const AddType& other); + //! Take ownership of the given AddType layer. + AddType(AddType&& other); + //! Copy the given AddType layer. + AddType& operator=(const AddType& other); + //! Take ownership of the given AddType layer. + AddType& operator=(AddType&& other); + /** * Ordinary feed forward pass of a neural network, evaluating the function * f(x) by propagating the activity forward through f. diff --git a/src/mlpack/methods/ann/layer/add_impl.hpp b/src/mlpack/methods/ann/layer/add_impl.hpp index 84520779e7..762993d2cf 100644 --- a/src/mlpack/methods/ann/layer/add_impl.hpp +++ b/src/mlpack/methods/ann/layer/add_impl.hpp @@ -25,6 +25,48 @@ AddType::AddType() : outSize(0) // Nothing to do. } +template +AddType::AddType(const AddType& other) : + Layer(other), + outSize(other.outSize) +{ + // Nothing to do. +} + +template +AddType::AddType(AddType&& other) : + Layer(std::move(other)), + outSize(std::move(other.outSize)) +{ + // Nothing to do. +} + +template +AddType& +AddType::operator=(const AddType& other) +{ + if (&other != this) + { + Layer::operator=(other); + outSize = other.outSize; + } + + return *this; +} + +template +AddType& +AddType::operator=(AddType&& other) +{ + if (&other != this) + { + Layer::operator=(std::move(other)); + outSIze = std::move(other.outSize); + } + + return *this; +} + template void AddType::Forward( const InputType& input, OutputType& output) diff --git a/src/mlpack/methods/ann/layer/alpha_dropout.hpp b/src/mlpack/methods/ann/layer/alpha_dropout.hpp index 4b62662b7c..dff4f83d73 100644 --- a/src/mlpack/methods/ann/layer/alpha_dropout.hpp +++ b/src/mlpack/methods/ann/layer/alpha_dropout.hpp @@ -45,8 +45,8 @@ namespace ann /** Artificial Neural Network. */ { * @tparam OutputType Type of the output data (arma::colvec, arma::mat, * arma::sp_mat or arma::cube). */ -template +template class AlphaDropout : public Layer { public: @@ -64,6 +64,18 @@ class AlphaDropout : public Layer */ AlphaDropout* Clone() const { return new AlphaDropout(*this); } + // Virtual destructor. + virtual ~AlphaDropout() { } + + //! Copy the given AlphaDropout layer. + AlphaDropout(const AlphaDropout& other); + //! Take ownership of the given AlphaDropout layer. + AlphaDropout(AlphaDropout&& other); + //! Copy the given AlphaDropout layer. + AlphaDropout& operator=(const AlphaDropout& other); + //! Take ownership of the given AlphaDropout layer. + AlphaDropout& operator=(AlphaDropout&& other); + /** * Ordinary feed forward pass of the alpha_dropout layer. * diff --git a/src/mlpack/methods/ann/layer/alpha_dropout_impl.hpp b/src/mlpack/methods/ann/layer/alpha_dropout_impl.hpp index 75f80bf74f..6e392a1ad1 100644 --- a/src/mlpack/methods/ann/layer/alpha_dropout_impl.hpp +++ b/src/mlpack/methods/ann/layer/alpha_dropout_impl.hpp @@ -32,6 +32,64 @@ AlphaDropout::AlphaDropout( Ratio(ratio); } +template +AlphaDropout::AlphaDropout(const AlphaDropout& other) : + Layer(other), + mask(other.mask), + ratio(other.ratio), + alphaDash(other.alphaDash), + a(other.a), + b(other.b) +{ + // Nothing to do. +} + +template +AlphaDropout::AlphaDropout(AlphaDropout&& other) : + Layer(std::move(other)), + mask(std::move(other.mask)), + ratio(std::move(other.ratio)), + alphaDash(std::move(other.alphaDash)), + a(std::move(other.a)), + b(std::move(other.b)) +{ + // Nothing to do. +} + +template +AlphaDropout& +AlphaDropout::operator=(const AlphaDropout& other) +{ + if (&other != this) + { + Layer::operator=(other); + mask = other.mask; + ratio = other.ratio; + alphaDash = other.alphaDash; + a = other.a; + b = other.b; + } + + return *this; +} + +template +AlphaDropout& +AlphaDropout::operator=(AlphaDropout&& other) +{ + if (&other != this) + { + Layer::operator=(std::move(other)); + mask = std::move(other.mask); + ratio = std::move(other.ratio); + alphaDash = std::move(other.alphaDash); + a = std::move(other.a); + b = std::move(other.b); + } + + return *this; +} + template void AlphaDropout::Forward( const InputType& input, OutputType& output) diff --git a/src/mlpack/methods/ann/layer/base_layer.hpp b/src/mlpack/methods/ann/layer/base_layer.hpp index 3fe6cb5111..b9c912b2e0 100644 --- a/src/mlpack/methods/ann/layer/base_layer.hpp +++ b/src/mlpack/methods/ann/layer/base_layer.hpp @@ -79,6 +79,12 @@ class BaseLayer : public Layer // Nothing to do here. } + // Virtual destructor. + virtual ~BaseLayer() { } + + // No copy constructor or operators needed here, since the class has no + // members. + //! Clone the BaseLayer object. This handles polymorphism correctly. BaseLayer* Clone() const { return new BaseLayer(*this); } diff --git a/src/mlpack/methods/ann/layer/concatenate.hpp b/src/mlpack/methods/ann/layer/concatenate.hpp index 9bc2117e77..11a57f8ab9 100644 --- a/src/mlpack/methods/ann/layer/concatenate.hpp +++ b/src/mlpack/methods/ann/layer/concatenate.hpp @@ -49,6 +49,18 @@ class ConcatenateType : public Layer //! Clone the ConcatenateType object. This handles polymorphism correctly. ConcatenateType* Clone() const { return new ConcatenateType(*this); } + // Virtual destructor. + virtual ~ConcatenateType() { } + + //! Copy the given ConcatenateType layer. + ConcatenateType(const ConcatenateType& other); + //! Take ownership of the given ConcatenateType layer. + ConcatenateType(ConcatenateType&& other); + //! Copy the given ConcatenateType layer. + ConcatenateType& operator=(const ConcatenateType& other); + //! Take ownership of the given ConcatenateType layer. + ConcatenateType& operator=(ConcatenateType&& other); + /** * Ordinary feed forward pass of a neural network, evaluating the function * f(x) by propagating the activity forward through f. diff --git a/src/mlpack/methods/ann/layer/concatenate_impl.hpp b/src/mlpack/methods/ann/layer/concatenate_impl.hpp index c83bf305ee..cd2727313e 100644 --- a/src/mlpack/methods/ann/layer/concatenate_impl.hpp +++ b/src/mlpack/methods/ann/layer/concatenate_impl.hpp @@ -27,6 +27,51 @@ ConcatenateType(const InputType& concat) : // Nothing to do here. } +template +ConcatenateType:: +ConcatenateType(const ConcatenateType& other) : + Layer(other), + concat(other.concat) +{ + // Nothing to do. +} + +template +ConcatenateType:: +ConcatenateType(ConcatenateType&& other) : + Layer(std::move(other)), + concat(other.concat) +{ + // Nothing to do. +} + +template +ConcatenateType& +ConcatenateType::operator=(const ConcatenateType& other) +{ + if (&other != this) + { + Layer::operator=(other); + concat = other.concat; + } + + return *this; +} + +template +ConcatenateType& +ConcatenateType::operator=(ConcatenateType&& other) +{ + if (&other != this) + { + Layer::operator=(std::move(other)); + concat = std::move(other.concat); + } + + return *this; + } +} + template void ConcatenateType::Forward( const InputType& input, OutputType& output) diff --git a/src/mlpack/methods/ann/layer/convolution.hpp b/src/mlpack/methods/ann/layer/convolution.hpp index e79aa9ebbe..ce6abc454f 100644 --- a/src/mlpack/methods/ann/layer/convolution.hpp +++ b/src/mlpack/methods/ann/layer/convolution.hpp @@ -132,16 +132,16 @@ class ConvolutionType : public Layer ConvolutionType* Clone() const { return new ConvolutionType(*this); } //! Copy constructor. -// ConvolutionType(const ConvolutionType& layer); + ConvolutionType(const ConvolutionType& layer); //! Move constructor. -// ConvolutionType(ConvolutionType&&); + ConvolutionType(ConvolutionType&&); //! Copy assignment operator. -// ConvolutionType& operator=(const ConvolutionType& layer); + ConvolutionType& operator=(const ConvolutionType& layer); //! Move assignment operator. -// ConvolutionType& operator=(ConvolutionType&& layer); + ConvolutionType& operator=(ConvolutionType&& layer); /* * Set the weight and bias term. diff --git a/src/mlpack/methods/ann/layer/convolution_impl.hpp b/src/mlpack/methods/ann/layer/convolution_impl.hpp index 4a958c9e76..ac40084736 100644 --- a/src/mlpack/methods/ann/layer/convolution_impl.hpp +++ b/src/mlpack/methods/ann/layer/convolution_impl.hpp @@ -107,7 +107,63 @@ ConvolutionType< this->paddingType = util::ToLower(paddingTypeIn); } -// TODO: copy/move constructor/operator +template< + typename ForwardConvolutionRule, + typename BackwardConvolutionRule, + typename GradientConvolutionRule, + typename InputType, + typename OutputType +> +ConvolutionType< + ForwardConvolutionRule, + BackwardConvolutionRule, + GradientConvolutionRule, + InputType, + OutputType +>::ConvolutionType(const ConvolutionType& other) : + Layer(other), + maps(other.maps), + kernelWidth(other.kernelWidth), + kernelHeight(other.kernelHeight), + strideWidth(other.strideWidth), + strideHeight(other.strideHeight), + padWLeft(other.padWLeft), + padWRight(other.padWRight), + padHBottom(other.padHBottom), + padHTop(other.padHTop), + paddingType(other.paddingType) +{ + // Nothing to do. +} + +template< + typename ForwardConvolutionRule, + typename BackwardConvolutionRule, + typename GradientConvolutionRule, + typename InputType, + typename OutputType +> +ConvolutionType< + ForwardConvolutionRule, + BackwardConvolutionRule, + GradientConvolutionRule, + InputType, + OutputType +>::ConvolutionType(ConvolutionType&& other) : + Layer(std::move(other)), + maps(other.maps), + kernelWidth(other.kernelWidth), + kernelHeight(other.kernelHeight), + strideWidth(other.strideWidth), + strideHeight(other.strideHeight), + padWLeft(other.padWLeft), + padWRight(other.padWRight), + padHBottom(other.padHBottom), + padHTop(other.padHTop), + paddingType(std::move(other.paddingType)) +{ + // Nothing to do. +} template< typename ForwardConvolutionRule, diff --git a/src/mlpack/methods/ann/layer/layer.hpp b/src/mlpack/methods/ann/layer/layer.hpp index 47324fc941..f0a01b82c6 100644 --- a/src/mlpack/methods/ann/layer/layer.hpp +++ b/src/mlpack/methods/ann/layer/layer.hpp @@ -60,25 +60,58 @@ class Layer { public: //! Default constructor. - Layer() : validOutputDimensions(false) { /* Nothing to do here */ } + Layer() : validOutputDimensions(false), training(false) + { /* Nothing to do here */ } //! Default deconstructor. virtual ~Layer() { } - //! Copy constructor. - Layer(const Layer& /* layer */) { /* Nothing to do here */ } + //! Copy constructor. This is not responsible for copying weights! + Layer(const Layer& layer) : + inputDimensions(layer.inputDimensions), + outputDimensions(layer.outputDimensions), + validOutputDimensions(layer.validOutputDimensions), + training(layer.training) + { } //! Make a copy of the object. virtual Layer* Clone() const = 0; - //! Move constructor. - Layer(Layer&& /* layer */) { /* Nothing to do here */ } + //! Move constructor. This is not responsible for moving weights! + Layer(Layer&& layer) : + inputDimensions(std::move(layer.inputDimensions)), + outputDimensions(std::move(layer.outputDimensions)), + validOutputDimensions(std::move(layer.validOutputDimensions)), + training(std::move(layer.training)) + { } - //! Copy assignment operator. - virtual Layer& operator=(const Layer& /* layer */) { return *this; } + //! Copy assignment operator. This is not responsible for copying weights! + virtual Layer& operator=(const Layer& layer) + { + if (&layer != this) + { + inputDimensions = layer.inputDimensions; + outputDimensions = layer.outputDimensions; + validOutputDimensions = layer.validOutputDimensions; + training = layer.training; + } - //! Move assignment operator. - virtual Layer& operator=(Layer&& /* layer */) { return *this; } + return *this; + } + + //! Move assignment operator. This is not responsible for moving weights! + virtual Layer& operator=(Layer&& layer) + { + if (&layer != this) + { + inputDimensions = std::move(layer.inputDimensions); + outputDimensions = std::move(layer.outputDimensions); + validOutputDimensions = std::move(layer.validOutputDimensions); + training = std::move(layer.training); + } + + return *this; + } /** * Takes an input object, and computes the corresponding output of the layer. diff --git a/src/mlpack/methods/ann/layer/linear.hpp b/src/mlpack/methods/ann/layer/linear.hpp index a030f87f4a..8c1a843123 100644 --- a/src/mlpack/methods/ann/layer/linear.hpp +++ b/src/mlpack/methods/ann/layer/linear.hpp @@ -60,9 +60,23 @@ class LinearType: public Layer LinearType(const size_t outSize, RegularizerType regularizer = RegularizerType()); + virtual ~LinearType() { } + //! Clone the LinearType object. This handles polymorphism correctly. LinearType* Clone() const { return new LinearType(*this); } + //! Copy the other Linear layer (but not weights). + LinearType(const LinearType& layer); + + //! Take ownership of the members of the other Linear layer (but not weights). + LinearType(LinearType&& layer); + + //! Copy the other Linear layer (but not weights). + LinearType& operator=(const LinearType& layer); + + //! Take ownership of the members of the other Linear layer (but not weights). + LinearType& operator=(LinearType&& layer); + /** * Reset the layer parameter (weights and bias). The method is called to * assign the allocated memory to the internal learnable parameters. diff --git a/src/mlpack/methods/ann/layer/linear_impl.hpp b/src/mlpack/methods/ann/layer/linear_impl.hpp index e62fb99829..414215b670 100644 --- a/src/mlpack/methods/ann/layer/linear_impl.hpp +++ b/src/mlpack/methods/ann/layer/linear_impl.hpp @@ -40,6 +40,62 @@ LinearType::LinearType( weights.set_size(WeightSize(), 1); } +// Copy constructor. +template +LinearType::LinearType( + const LinearType& layer) : + Layer(layer), + inSize(layer.inSize), + outSize(layer.outSize), + regularizer(layer.regularizer) +{ + // Nothing else to do. +} + +// Move constructor. +template +LinearType::LinearType( + LinearType&& layer) : + Layer(std::move(layer)), + inSize(std::move(layer.inSize)), + outSize(std::move(layer.outSize)), + regularizer(std::move(layer.regularizer)) +{ + // Nothing else to do. +} + +template +LinearType& +LinearType::operator=( + const LinearType& layer) +{ + if (&layer != this) + { + Layer::operator=(layer); + inSize = layer.inSize; + outSize = layer.outSize; + regularizer = layer.regularizer; + } + + return *this; +} + +template +LinearType& +LinearType::operator=( + LinearType&& layer) +{ + if (&layer != this) + { + Layer::operator=(std::move(layer)); + inSize = std::move(layer.inSize); + outSize = std::move(layer.outSize); + regularizer = std::move(layer.regularizer); + } + + return *this; +} + template void LinearType::SetWeights( typename OutputType::elem_type* weightsPtr)