From 47dd33db7704fcb58effd8e8fcf3c58e1b69ef2f Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Mon, 4 May 2015 19:31:29 +0200 Subject: [PATCH] Refactor conv connection to support 3rd order tensors. --- .../ann/connections/conv_connection.hpp | 198 +++++++++++------- 1 file changed, 121 insertions(+), 77 deletions(-) diff --git a/src/mlpack/methods/ann/connections/conv_connection.hpp b/src/mlpack/methods/ann/connections/conv_connection.hpp index 835fdc525c..5a0a5b05b7 100644 --- a/src/mlpack/methods/ann/connections/conv_connection.hpp +++ b/src/mlpack/methods/ann/connections/conv_connection.hpp @@ -1,33 +1,35 @@ /** * @file cnn_conv_connection.hpp * @author Shangtong Zhang + * @author Marcus Edel * - * Implementation of the convolutional connection - * between input layer and output layer. + * Implementation of the convolutional connection between input layer and output + * layer. */ #ifndef __MLPACK_METHODS_ANN_CONNECTIONS_CONV_CONNECTION_HPP #define __MLPACK_METHODS_ANN_CONNECTIONS_CONV_CONNECTION_HPP #include -#include -#include -#include -#include +#include +#include +#include +#include namespace mlpack{ namespace ann /** Artificial Neural Network. */{ + /** - * Implementation of the convolutional connection class. - * The convolutional connection performs convolution between input layer - * and output layer. - * Convolution is applied to every neuron in input layer. - * The kernel used for convolution is stored in @weights. + * Implementation of the convolutional connection class. The convolutional + * connection performs convolution between input layer and output layer. + * Convolution is applied to every neuron in input layer. The kernel used for + * convolution is stored in @weights. * * Users can design their own convolution rule (ForwardConvolutionRule) - * to perform forward process. But once user-defined forward convolution is used, - * users have to design special BackwardConvolutionRule and GradientConvolutionRule - * to perform backward process and calculate gradient corresponding to - * ForwardConvolutionRule, aimed to guarantee the correctness of error flow. + * to perform forward process. But once user-defined forward convolution is + * used, users have to design special BackwardConvolutionRule and + * GradientConvolutionRule to perform backward process and calculate gradient + * corresponding to ForwardConvolutionRule, aimed to guarantee the correctness + * of error flow. * * @tparam InputLayerType Type of the connected input layer. * @tparam OutputLayerType Type of the connected output layer. @@ -36,123 +38,165 @@ namespace ann /** Artificial Neural Network. */{ * @tparam ForwardConvolutionRule Convolution to perform forward process. * @tparam BackwardConvolutionRule Convolution to perform backward process. * @tparam GradientConvolutionRule Convolution to calculate gradient. - * @tparam MatType Type of data (arma::mat or arma::sp_mat). + * @tparam DataType Type of data (arma::mat, arma::sp_mat or arma::cube). */ template< typename InputLayerType, typename OutputLayerType, - typename OptimizerType, - class WeightInitRule = NguyenWidrowInitialization<>, - typename ForwardConvolutionRule = ValidConvolution, - typename BackwardConvolutionRule = ValidConvolution, - typename GradientConvolutionRule = RotatedKernelFullConvolution, - typename MatType = arma::mat + typename OptimizerType = SteepestDescent<>, + class WeightInitRule = RandomInitialization, + typename ForwardConvolutionRule = NaiveConvolution, + typename BackwardConvolutionRule = NaiveConvolution, + typename GradientConvolutionRule = NaiveConvolution, + typename DataType = arma::cube > class ConvConnection { public: /** * Create the ConvConnection object using the specified input layer, output - * layer, optimizer and weight initialize rule. + * layer, optimizer and weight initialization rule. * * @param InputLayerType The input layer which is connected with the output * layer. * @param OutputLayerType The output layer which is connected with the input * layer. - * @param OptimizerType The optimizer used to update the weights matrix. - * @param weightsRows The number of rows of convolutional kernel. - * @param weightsCols The number of cols of convolutional kernel. - * @param WeightInitRule The weights initialize rule used to initialize the - * weights matrix. + * @param filterRows The number of rows of the convolutional kernel. + * @param filterCols The number of cols of the convolutional kernel. + * @param OptimizerType The optimizer used to update the weight matrix. + * @param WeightInitRule The weights initialization rule used to initialize + * the weights matrix. */ ConvConnection(InputLayerType& inputLayer, OutputLayerType& outputLayer, + const size_t filterRows, + const size_t filterCols, OptimizerType& optimizer, - size_t weightsRows, - size_t weightsCols, WeightInitRule weightInitRule = WeightInitRule()) : - inputLayer(inputLayer), outputLayer(outputLayer), optimizer(optimizer) + inputLayer(inputLayer), + outputLayer(outputLayer), + optimizer(&optimizer), + ownsOptimizer(false) { - weightInitRule.Initialize(weights, weightsRows, weightsCols); - gradient = arma::zeros(weightsRows, weightsCols); + weightInitRule.Initialize(weights, filterRows, filterCols, + outputLayer.LayerSlices()); } - + /** - * Ordinary feed forward pass of a neural network, - * Apply convolution to every neuron in input layer and - * put the output in the output layer. + * Create the ConvConnection object using the specified input layer, output + * layer, optimizer and weight initialization rule. + * + * @param InputLayerType The input layer which is connected with the output + * layer. + * @param OutputLayerType The output layer which is connected with the input + * layer. + * @param filterRows The number of rows of the convolutional kernel. + * @param filterCols The number of cols of the convolutional kernel. + * @param WeightInitRule The weights initialization rule used to initialize + * the weights matrix. */ - void FeedForward(const MatType& input) + ConvConnection(InputLayerType& inputLayer, + OutputLayerType& outputLayer, + const size_t filterRows, + const size_t filterCols, + WeightInitRule weightInitRule = WeightInitRule()) : + inputLayer(inputLayer), + outputLayer(outputLayer), + optimizer(new OptimizerType()), + ownsOptimizer(true) { - MatType output(outputLayer.InputActivation().n_rows, - outputLayer.InputActivation().n_cols); - ForwardConvolutionRule::conv(input, weights, output); + weightInitRule.Initialize(weights, filterRows, filterCols, + outputLayer.LayerSlices()); + } + + /** + * Delete the conv connection object and its optimizer. + */ + ~ConvConnection() + { + if (ownsOptimizer) + delete optimizer; + } + + /** + * Ordinary feed forward pass of a neural network. Apply convolution to every + * neuron in input layer and put the output in the output layer. + */ + template + void FeedForward(const InputType& input) + { + DataType output; + ForwardConvolutionRule::Convolution(input, weights, output); outputLayer.InputActivation() += output; } - + /** - * Ordinary feed backward pass of a neural network. - * Pass the error from output layer to input layer and - * calculate the delta of kernel weights. + * Ordinary feed backward pass of a neural network. Pass the error from output + * layer to input layer and calculate the delta of kernel weights. + * * @param error The backpropagated error. */ - void FeedBackward(const MatType& error) + void FeedBackward(const DataType& error) { - BackwardConvolutionRule::conv(inputLayer.InputActivation(), error, gradient); - GradientConvolutionRule::conv(weights, error, delta); - inputLayer.Delta() += delta; + BackwardConvolutionRule::conv(weights, error, delta); } - + + /* + * Calculate the gradient using the output delta and the input activation. + * + * @param gradient The calculated gradient. + */ + void Gradient(DataType& gradient) + { + GradientConvolutionRule::Convolution(inputLayer.InputActivation(), + outputLayer.Delta(), gradient); + } + //! Get the convolution kernel. - MatType& Weights() const { return weights; } + DataType& Weights() const { return weights; } //! Modify the convolution kernel. - MatType& Weights() { return weights; } - + DataType& Weights() { return weights; } + //! Get the input layer. InputLayerType& InputLayer() const { return inputLayer; } //! Modify the input layer. InputLayerType& InputLayer() { return inputLayer; } - + //! Get the output layer. OutputLayerType& OutputLayer() const { return outputLayer; } //! Modify the output layer. OutputLayerType& OutputLayer() { return outputLayer; } - + //! Get the optimzer. - OptimizerType& Optimzer() const { return optimizer; } + OptimizerType& Optimzer() const { return *optimizer; } //! Modify the optimzer. - OptimizerType& Optimzer() { return optimizer; } - + OptimizerType& Optimzer() { return *optimizer; } + //! Get the passed error in backward propagation. - MatType& Delta() const { return delta; } + DataType& Delta() const { return delta; } //! Modify the passed error in backward propagation. - MatType& Delta() { return delta; } - - //! Get the gradient of kernel. - MatType& Gradient() const { return gradient; } - //! Modify the gradient of kernel. - MatType& Gradient() { return gradient; } - + DataType& Delta() { return delta; } + private: //! Locally-stored kernel weights. - MatType weights; - + DataType weights; + //! Locally-stored inputlayer. InputLayerType& inputLayer; - + //! Locally-stored outputlayer. OutputLayerType& outputLayer; - + //! Locally-stored optimizer. - OptimizerType& optimizer; - + OptimizerType* optimizer; + + //! Parameter that indicates if the class owns a optimizer object. + bool ownsOptimizer; + //! Locally-stored passed error in backward propagation. - MatType delta; - - //! Locally-stored gradient of kernel weights. - MatType gradient; + DataType delta; };// class ConvConnection - + }; // namespace ann }; // namespace mlpack