fixed size bug in convolution

And fixed bug in padding layer
This commit is contained in:
Shubham Agrawal
2022-08-20 02:10:16 +08:00
parent e77d9e298c
commit d2940a69f9
6 changed files with 115 additions and 74 deletions
@@ -377,6 +377,9 @@ class ConvolutionType : public Layer<MatType>
//! Locally-stored padding layer.
ann::Padding padding;
//! Locally-stored padding layer for backward pass.
ann::Padding paddingBackward;
//! Type of padding.
std::string paddingType;
@@ -384,6 +387,12 @@ class ConvolutionType : public Layer<MatType>
size_t inMaps;
//! Locally-cached higher-order input dimensions.
size_t higherInDimensions;
//! Locally-stored apparent width.
size_t apparentWidth;
//! Locally-stored apparent height.
size_t apparentHeight;
}; // class Convolution
// Standard Convolution layer.
@@ -130,9 +130,12 @@ ConvolutionType<
padHTop(other.padHTop),
useBias(other.useBias),
padding(other.padding),
paddingBackward(other.paddingBackward),
paddingType(other.paddingType),
inMaps(other.inMaps),
higherInDimensions(other.higherInDimensions)
higherInDimensions(other.higherInDimensions),
apparentWidth(other.apparentWidth),
apparentHeight(other.apparentHeight)
{
// Nothing to do.
}
@@ -161,9 +164,12 @@ ConvolutionType<
padHTop(std::move(other.padHTop)),
useBias(std::move(other.useBias)),
padding(std::move(other.padding)),
paddingBackward(std::move(other.paddingBackward)),
paddingType(std::move(other.paddingType)),
inMaps(std::move(other.inMaps)),
higherInDimensions(std::move(other.higherInDimensions))
higherInDimensions(std::move(other.higherInDimensions)),
apparentWidth(std::move(other.apparentWidth)),
apparentHeight(std::move(other.apparentHeight))
{
// Nothing to do.
}
@@ -201,9 +207,12 @@ ConvolutionType<
padHTop = other.padHTop;
useBias = other.useBias;
padding = other.padding;
paddingBackward = other.paddingBackward;
paddingType = other.paddingType;
inMaps = other.inMaps;
higherInDimensions = other.higherInDimensions;
apparentWidth = other.apparentWidth;
apparentHeight = other.apparentHeight;
}
return *this;
@@ -242,9 +251,12 @@ ConvolutionType<
padHTop = std::move(other.padHTop);
useBias = std::move(other.useBias);
padding = std::move(other.padding);
paddingBackward = std::move(other.paddingBackward);
paddingType = std::move(other.paddingType);
inMaps = std::move(other.inMaps);
higherInDimensions = std::move(other.higherInDimensions);
apparentWidth = std::move(other.apparentWidth);
apparentHeight = std::move(other.apparentHeight);
}
return *this;
@@ -380,7 +392,8 @@ void ConvolutionType<
arma::Cube<typename MatType::elem_type> dilatedMappedError;
if (strideHeight == 1 && strideWidth == 1)
{
dilatedMappedError = mappedError;
MakeAlias(dilatedMappedError, mappedError.memptr(),
mappedError.n_rows, mappedError.n_cols, mappedError.n_slices);
}
else
{
@@ -407,6 +420,12 @@ void ConvolutionType<
Rotate180(weight.slice(map), rotatedFilters.slice(map));
}
MatType output(apparentWidth * apparentHeight * inMaps * higherInDimensions,
batchSize, arma::fill::zeros);
arma::Cube<typename MatType::elem_type> outputCube;
MakeAlias(outputCube, output.memptr(), apparentWidth, apparentHeight,
inMaps * higherInDimensions * batchSize);
// See Forward() for the overall iteration strategy.
for (size_t offset = 0; offset < (higherInDimensions * batchSize); ++offset)
{
@@ -418,36 +437,38 @@ void ConvolutionType<
for (size_t inMap = 0; inMap < (size_t) inMaps; ++inMap)
{
// Iterate over output maps.
MatType output;
for (size_t outMap = 0; outMap < maps; ++outMap)
{
BackwardConvolutionRule::Convolution(
dilatedMappedError.slice(outMap + fullOutputOffset),
rotatedFilters.slice((outMap * inMaps) + inMap),
output,
outputCube.slice(inMap + fullInputOffset),
1,
1,
1,
1,
outMap > 0);
}
// If the stride width or height is greater than 1, then we have to
// insert columns and rows into the convolution output.
MatType& curGTemp = gTemp.slice(inMap + fullInputOffset);
if (usingPadding)
{
curGTemp = output.submat(
padWLeft,
padHTop,
padWLeft + gTemp.n_rows - 1,
padHTop + gTemp.n_cols - 1);
}
else
{
curGTemp = output;
true);
}
}
}
MatType temp(padding.OutputDimensions()[0] * padding.OutputDimensions()[1] * inMaps * higherInDimensions,
batchSize);
arma::Cube<typename MatType::elem_type> tempCube;
MakeAlias(tempCube, temp.memptr(), padding.OutputDimensions()[0],
padding.OutputDimensions()[1], inMaps * higherInDimensions * batchSize);
paddingBackward.Forward(output, temp);
if (usingPadding)
{
gTemp = tempCube.tube(
padWLeft,
padHTop,
padWLeft + gTemp.n_rows - 1,
padHTop + gTemp.n_cols - 1);
}
else
{
gTemp = tempCube;
}
}
template<
@@ -482,6 +503,13 @@ void ConvolutionType<
const_cast<MatType&>(usingPadding ? inputPadded : input).memptr(),
paddedRows, paddedCols, inMaps * batchSize, false, false);
MatType temp(apparentWidth * apparentHeight * inMaps * higherInDimensions,
batchSize);
arma::Cube<typename MatType::elem_type> tempCube;
MakeAlias(tempCube, temp.memptr(), apparentWidth, apparentHeight,
inMaps * higherInDimensions * batchSize);
paddingBackward.Backward(input, usingPadding ? inputPadded : input, temp);
// We will make an alias for the gradient, but note that this is only for the
// convolution map weights! The bias will be handled by direct accesses into
// `gradient`.
@@ -501,17 +529,15 @@ void ConvolutionType<
MatType& curError = mappedError.slice(outMap + fullOutputOffset);
for (size_t inMap = 0; inMap < inMaps; ++inMap)
{
MatType output;
GradientConvolutionRule::Convolution(
inputTemp.slice(inMap + fullInputOffset),
tempCube.slice(inMap + fullInputOffset),
curError,
output,
gradientTemp.slice((outMap * inMaps) + inMap),
1,
1,
strideWidth,
strideHeight);
gradientTemp.slice((outMap * inMaps) + inMap) += output;
strideHeight,
true);
}
if (useBias)
@@ -570,6 +596,13 @@ void ConvolutionType<
this->outputDimensions[i] = this->inputDimensions[i];
}
apparentWidth = (this->outputDimensions[0] - 1) * strideWidth + kernelWidth;
apparentHeight = (this->outputDimensions[1] - 1) * strideHeight + kernelHeight;
paddingBackward = ann::Padding(0, padding.OutputDimensions()[0] - apparentWidth, 0, padding.OutputDimensions()[1] - apparentHeight);
paddingBackward.InputDimensions() = std::vector<size_t>({ apparentWidth, apparentHeight, inMaps * higherInDimensions });
paddingBackward.ComputeOutputDimensions();
this->outputDimensions[2] = maps;
}
+27 -27
View File
@@ -107,43 +107,43 @@ void PaddingType<MatType>::Forward(const MatType& input, MatType& output)
output.n_cols, false, true);
// Set the padding parts to 0.
if (padWLeft > 0)
if (padHTop > 0)
{
reshapedOutput.tube(0,
0,
reshapedOutput.n_rows - 1,
padWLeft - 1).zeros();
padHTop - 1).zeros();
}
if (padHTop > 0)
if (padWLeft > 0)
{
reshapedOutput.tube(0,
padWLeft,
padHTop - 1,
padWLeft + this->inputDimensions[1] - 1).zeros();
}
if (padWRight > 0)
{
reshapedOutput.tube(0,
padWLeft + this->inputDimensions[1],
reshapedOutput.n_rows - 1,
reshapedOutput.n_cols - 1).zeros();
padHTop,
padWLeft - 1,
padHTop + this->inputDimensions[1] - 1).zeros();
}
if (padHBottom > 0)
{
reshapedOutput.tube(padHTop + this->inputDimensions[0],
padWLeft,
reshapedOutput.tube(0,
padHTop + this->inputDimensions[1],
reshapedOutput.n_rows - 1,
padWLeft + this->inputDimensions[1] - 1).zeros();
reshapedOutput.n_cols - 1).zeros();
}
if (padWRight > 0)
{
reshapedOutput.tube(padWLeft + this->inputDimensions[0],
padHTop,
reshapedOutput.n_rows - 1,
padHTop + this->inputDimensions[1] - 1).zeros();
}
// Copy the input matrix.
reshapedOutput.tube(padHTop,
padWLeft,
padHTop + this->inputDimensions[0] - 1,
padWLeft + this->inputDimensions[1] - 1) = reshapedInput;
reshapedOutput.tube(padWLeft,
padHTop,
padWLeft + this->inputDimensions[0] - 1,
padHTop + this->inputDimensions[1] - 1) = reshapedInput;
}
template<typename MatType>
@@ -161,10 +161,10 @@ void PaddingType<MatType>::Backward(
this->inputDimensions[0], this->inputDimensions[1], totalInMaps *
g.n_cols, false, true);
reshapedG = reshapedGy.tube(padHTop,
padWLeft,
padHTop + this->inputDimensions[0] - 1,
padWLeft + this->inputDimensions[1] - 1);
reshapedG = reshapedGy.tube(padWLeft,
padHTop,
padWLeft + this->inputDimensions[0] - 1,
padHTop + this->inputDimensions[1] - 1);
}
template<typename MatType>
@@ -172,8 +172,8 @@ void PaddingType<MatType>::ComputeOutputDimensions()
{
this->outputDimensions = this->inputDimensions;
this->outputDimensions[0] += padHTop + padHBottom;
this->outputDimensions[1] += padWLeft + padWRight;
this->outputDimensions[0] += padWLeft + padWRight;
this->outputDimensions[1] += padHTop + padHBottom;
// Higher dimensions remain unchanged. But, we will cache the product of
// these higher dimensions.
@@ -85,29 +85,29 @@ TEST_CASE("PaddingTest", "[ConvolutionalNetworktest]")
model.Forward(X, results);
// Ensure that things are correctly padded.
arma::cube reshapedResults(results.memptr(), 35, 31, results.n_cols, false,
arma::cube reshapedResults(results.memptr(), 31, 35, results.n_cols, false,
true);
for (size_t i = 0; i < reshapedResults.n_slices; ++i)
{
// Check left.
for (size_t j = 0; j < reshapedResults.n_rows; ++j)
REQUIRE(reshapedResults(j, 0, i) == 0.0);
for (size_t j = 0; j < reshapedResults.n_cols; ++j)
REQUIRE(reshapedResults(0, j, i) == 0.0);
// Check top.
for (size_t j = 0; j < 3; ++j)
for (size_t k = 0; k < reshapedResults.n_cols; ++k)
REQUIRE(reshapedResults(j, k, i) == 0.0);
for (size_t k = 0; k < reshapedResults.n_rows; ++k)
REQUIRE(reshapedResults(k, j, i) == 0.0);
// Check bottom.
for (size_t j = 31; j < reshapedResults.n_rows; ++j)
for (size_t k = 0; k < reshapedResults.n_cols; ++k)
REQUIRE(reshapedResults(j, k, i) == 0.0);
for (size_t j = 31; j < reshapedResults.n_cols; ++j)
for (size_t k = 0; k < reshapedResults.n_rows; ++k)
REQUIRE(reshapedResults(k, j, i) == 0.0);
// Check right.
for (size_t j = 0; j < reshapedResults.n_rows; ++j)
for (size_t k = 29; k < reshapedResults.n_cols; ++k)
REQUIRE(reshapedResults(j, k, i) == 0.0);
for (size_t j = 0; j < reshapedResults.n_cols; ++j)
for (size_t k = 29; k < reshapedResults.n_rows; ++k)
REQUIRE(reshapedResults(k, j, i) == 0.0);
}
}
@@ -80,8 +80,7 @@ void CheckCopyFunction(ModelType* network1,
template<typename MatType = arma::mat, typename ModelType>
void CheckMoveFunction(ModelType* network1,
MatType& trainData,
MatType& trainLabels,
const size_t maxEpochs)
MatType& trainLabels)
{
ens::RMSProp opt(0.01, 32, 0.88, 1e-8, trainData.n_cols, -1);
network1->Train(trainData, trainLabels, opt);
@@ -150,7 +149,7 @@ TEST_CASE("CheckCopyMovingVanillaNetworkTest", "[FeedForwardNetworkTest]")
CheckCopyFunction(model, trainData, trainLabels);
// Check whether move constructor is working or not.
CheckMoveFunction(model1, trainData, trainLabels, 1);
CheckMoveFunction(model1, trainData, trainLabels);
}
/**
@@ -184,7 +183,7 @@ TEST_CASE("CheckCopyMovingLinear3DNetworkTest", "[FeedForwardNetworkTest]")
CheckCopyFunction(model, trainData, trainLabels);
// Check whether move constructor is working or not.
CheckMoveFunction(model1, trainData, trainLabels, 1);
CheckMoveFunction(model1, trainData, trainLabels);
}
/**
@@ -215,7 +214,7 @@ TEST_CASE("CheckCopyMovingNoisyLinearTest", "[FeedForwardNetworkTest]")
model2->Add<LogSoftMax>();
// Check whether move constructor is working or not.
CheckMoveFunction(model2, input, output, 1);
CheckMoveFunction(model2, input, output);
}
/**
@@ -261,7 +260,7 @@ TEST_CASE("CheckCopyMovingConcatenateTest", "[FeedForwardNetworkTest]")
model2->Add<LogSoftMax>();
// Check whether move constructor is working or not.
CheckMoveFunction(model2, input, output, 1);
CheckMoveFunction(model2, input, output);
}
/**
@@ -295,7 +294,7 @@ TEST_CASE("CheckCopyMovingDropoutNetworkTest", "[FeedForwardNetworkTest]")
CheckCopyFunction(model, trainData, trainLabels);
// Check whether move constructor is working or not.
CheckMoveFunction(model1, trainData, trainLabels, 1);
CheckMoveFunction(model1, trainData, trainLabels);
}
/**
@@ -342,7 +341,7 @@ TEST_CASE("CheckCopyMovingVanillaNetworkTestNoBias", "[FeedForwardNetworkTest]")
CheckCopyFunction<>(model, trainData, trainLabels);
// Check whether move constructor is working or not.
CheckMoveFunction<>(model1, trainData, trainLabels, 1);
CheckMoveFunction<>(model1, trainData, trainLabels);
}
/**
+1 -1
View File
@@ -43,7 +43,7 @@ TEST_CASE("SimplePaddingLayerTest", "[ANNLayerTest]")
output.randu();
module.Forward(input, output);
REQUIRE(arma::accu(input) == Approx(arma::accu(output)));
REQUIRE(output.n_rows == (9 * 8)); // 2x5 --> 9x8
REQUIRE(output.n_rows == (5 * 12)); // 2x5 --> 5x12
// Test the Backward function.
delta.set_size(input.n_rows, input.n_cols);