Adding copy constructor in convolution layer (#3067)

* Adding copy constructor in convolution layer

* Adding space in the end

* Adding Spaces
This commit is contained in:
Himanshu Pathak
2021-10-05 09:05:59 +05:30
committed by GitHub
parent 1ed59878da
commit 5d7304677f
3 changed files with 307 additions and 0 deletions
@@ -140,6 +140,18 @@ class Convolution
const size_t inputHeight = 0,
const std::string& paddingType = "None");
//! Copy constructor.
Convolution(const Convolution& layer);
//! Move constructor.
Convolution(Convolution&&);
//! Copy assignment operator.
Convolution& operator=(const Convolution& layer);
//! Move assignment operator.
Convolution& operator=(Convolution&& layer);
/*
* Set the weight and bias term.
*/
@@ -137,6 +137,167 @@ Convolution<
padding = ann::Padding<>(padWLeft, padWRight, padHTop, padHBottom);
}
template<
typename ForwardConvolutionRule,
typename BackwardConvolutionRule,
typename GradientConvolutionRule,
typename InputDataType,
typename OutputDataType
>
Convolution<
ForwardConvolutionRule,
BackwardConvolutionRule,
GradientConvolutionRule,
InputDataType,
OutputDataType
>::Convolution(
const Convolution& layer) :
inSize(layer.inSize),
outSize(layer.outSize),
kernelWidth(layer.kernelWidth),
kernelHeight(layer.kernelHeight),
strideWidth(layer.strideWidth),
strideHeight(layer.strideHeight),
padWLeft(layer.padWLeft),
padWRight(layer.padWRight),
padHBottom(layer.padHBottom),
padHTop(layer.padHTop),
inputWidth(layer.inputWidth),
inputHeight(layer.inputHeight),
outputWidth(layer.outputWidth),
outputHeight(layer.outputHeight),
padding(layer.padding),
weights(layer.weights)
{
// Nothing to do here.
}
template<
typename ForwardConvolutionRule,
typename BackwardConvolutionRule,
typename GradientConvolutionRule,
typename InputDataType,
typename OutputDataType
>
Convolution<
ForwardConvolutionRule,
BackwardConvolutionRule,
GradientConvolutionRule,
InputDataType,
OutputDataType
>::Convolution(
Convolution&& layer) :
inSize(0),
outSize(0),
kernelWidth(layer.kernelWidth),
kernelHeight(layer.kernelHeight),
strideWidth(layer.strideWidth),
strideHeight(layer.strideHeight),
padWLeft(layer.padWLeft),
padWRight(layer.padWRight),
padHBottom(layer.padHBottom),
padHTop(layer.padHTop),
inputWidth(layer.inputWidth),
inputHeight(layer.inputHeight),
outputWidth(layer.outputWidth),
outputHeight(layer.outputHeight),
padding(std::move(layer.padding)),
weights(std::move(layer.weights))
{
// Nothing to do here.
}
template<
typename ForwardConvolutionRule,
typename BackwardConvolutionRule,
typename GradientConvolutionRule,
typename InputDataType,
typename OutputDataType
>
Convolution<
ForwardConvolutionRule,
BackwardConvolutionRule,
GradientConvolutionRule,
InputDataType,
OutputDataType
>&
Convolution<
ForwardConvolutionRule,
BackwardConvolutionRule,
GradientConvolutionRule,
InputDataType,
OutputDataType
>::
operator=(const Convolution& layer)
{
if (this != &layer)
{
inSize = layer.inSize;
outSize = layer.outSize;
kernelWidth = layer.kernelWidth;
kernelHeight = layer.kernelHeight;
strideWidth = layer.strideWidth;
strideHeight = layer.strideHeight;
padWLeft = layer.padWLeft;
padWRight = layer.padWRight;
padHBottom = layer.padHBottom;
padHTop = layer.padHTop;
inputWidth = layer.inputWidth;
inputHeight = layer.inputHeight;
outputWidth = layer.outputWidth;
outputHeight = layer.outputHeight;
padding = layer.padding;
weights = layer.weights;
}
return *this;
}
template<
typename ForwardConvolutionRule,
typename BackwardConvolutionRule,
typename GradientConvolutionRule,
typename InputDataType,
typename OutputDataType
>
Convolution<
ForwardConvolutionRule,
BackwardConvolutionRule,
GradientConvolutionRule,
InputDataType,
OutputDataType
>&
Convolution<
ForwardConvolutionRule,
BackwardConvolutionRule,
GradientConvolutionRule,
InputDataType,
OutputDataType
>::
operator=(Convolution&& layer)
{
if (this != &layer)
{
inSize = layer.inSize;
outSize = layer.outSize;
kernelWidth = layer.kernelWidth;
kernelHeight = layer.kernelHeight;
strideWidth = layer.strideWidth;
strideHeight = layer.strideHeight;
padWLeft = layer.padWLeft;
padWRight = layer.padWRight;
padHBottom = layer.padHBottom;
padHTop = layer.padHTop;
inputWidth = layer.inputWidth;
inputHeight = layer.inputHeight;
outputWidth = layer.outputWidth;
outputHeight = layer.outputHeight;
padding = std::move(layer.padding);
weights = std::move(layer.weights);
}
return *this;
}
template<
typename ForwardConvolutionRule,
typename BackwardConvolutionRule,
@@ -25,6 +25,51 @@
using namespace mlpack;
using namespace mlpack::ann;
// network1 should be allocated with `new`, and trained on some data.
template<typename MatType = arma::mat, typename ModelType>
void CheckCopyFunction(ModelType* network1,
MatType& trainData,
MatType& trainLabels,
const size_t maxEpochs)
{
ens::RMSProp opt(0.01, 1, 0.88, 1e-8, maxEpochs * trainData.n_cols, -1);
network1->Train(trainData, trainLabels, opt);
arma::mat predictions1;
network1->Predict(trainData, predictions1);
FFN<> network2;
network2 = *network1;
delete network1;
// Deallocating all of network1's memory, so that network2 does not use any
// of that memory.
arma::mat predictions2;
network2.Predict(trainData, predictions2);
CheckMatrices(predictions1, predictions2);
}
// network1 should be allocated with `new`, and trained on some data.
template<typename MatType = arma::mat, typename ModelType>
void CheckMoveFunction(ModelType* network1,
MatType& trainData,
MatType& trainLabels,
const size_t maxEpochs)
{
ens::RMSProp opt(0.01, 1, 0.88, 1e-8, maxEpochs * trainData.n_cols, -1);
network1->Train(trainData, trainLabels, opt);
arma::mat predictions1;
network1->Predict(trainData, predictions1);
FFN<> network2(std::move(*network1));
delete network1;
// Deallocating all of network1's memory, so that network2 does not use any
// of that memory.
arma::mat predictions2;
network2.Predict(trainData, predictions2);
CheckMatrices(predictions1, predictions2);
}
/**
* Train the vanilla network on a larger dataset.
*/
@@ -124,3 +169,92 @@ TEST_CASE("VanillaNetworkTest", "[ConvolutionalNetworkTest]")
REQUIRE(success == true);
}
/**
* Train the vanilla network on a larger dataset.
*/
TEST_CASE("CheckCopyVanillaNetworkTest", "[ConvolutionalNetworkTest]")
{
arma::mat X;
X.load("mnist_first250_training_4s_and_9s.arm");
// Normalize each point since these are images.
arma::uword nPoints = X.n_cols;
for (arma::uword i = 0; i < nPoints; ++i)
{
X.col(i) /= norm(X.col(i), 2);
}
// Build the target matrix.
arma::mat Y = arma::zeros<arma::mat>(1, nPoints);
for (size_t i = 0; i < nPoints; ++i)
{
if (i < nPoints / 2)
{
// Assign label "0" to all samples with digit = 4
Y(i) = 0;
}
else
{
// Assign label "1" to all samples with digit = 9
Y(i) = 1;
}
}
/*
* Construct a convolutional neural network with a 28x28x1 input layer,
* 24x24x8 convolution layer, 12x12x8 pooling layer, 8x8x12 convolution layer
* and a 4x4x12 pooling layer which is fully connected with the output layer.
* The network structure looks like:
*
* Input Convolution Pooling Convolution Pooling Output
* Layer Layer Layer Layer Layer Layer
*
* +---+ +---+ +---+ +---+
* | +---+ | +---+ | +---+ | +---+
* +---+ | | +---+ | | +---+ | | +---+ | | +---+ +---+
* | | | | | | | | | | | | | | | | | | | |
* | +--> +-+ | +--> +-+ | +--> +-+ | +--> +-+ | +--> | |
* | | +-+ | +-+ | +-+ | +-+ | | |
* +---+ +---+ +---+ +---+ +---+ +---+
*/
// It isn't guaranteed that the network will converge in the specified number
// of iterations using random weights. If this works 1 of 5 times, I'm fine
// with that. All I want to know is that the network is able to escape from
// local minima and to solve the task.
FFN<NegativeLogLikelihood<>, RandomInitialization> *model = new FFN<NegativeLogLikelihood<>, RandomInitialization>;
model->Add<Convolution<> >(1, 8, 5, 5, 1, 1, 0, 0, 28, 28);
model->Add<ReLULayer<> >();
model->Add<MaxPooling<> >(8, 8, 2, 2);
model->Add<Convolution<> >(8, 12, 2, 2);
model->Add<ReLULayer<> >();
model->Add<MaxPooling<> >(2, 2, 2, 2);
model->Add<Linear<> >(192, 20);
model->Add<ReLULayer<> >();
model->Add<Linear<> >(20, 10);
model->Add<ReLULayer<> >();
model->Add<Linear<> >(10, 2);
model->Add<LogSoftMax<> >();
FFN<NegativeLogLikelihood<>, RandomInitialization> *model1 = new FFN<NegativeLogLikelihood<>, RandomInitialization>;
model1->Add<Convolution<> >(1, 8, 5, 5, 1, 1, 0, 0, 28, 28);
model1->Add<ReLULayer<> >();
model1->Add<MaxPooling<> >(8, 8, 2, 2);
model1->Add<Convolution<> >(8, 12, 2, 2);
model1->Add<ReLULayer<> >();
model1->Add<MaxPooling<> >(2, 2, 2, 2);
model1->Add<Linear<> >(192, 20);
model1->Add<ReLULayer<> >();
model1->Add<Linear<> >(20, 10);
model1->Add<ReLULayer<> >();
model1->Add<Linear<> >(10, 2);
model1->Add<LogSoftMax<> >();
// Check whether copy constructor is working or not.
CheckCopyFunction<>(model, X, Y, 8);
// Check whether move constructor is working or not.
CheckMoveFunction<>(model1, X, Y, 8);
}