changes acc to suggestions

This commit is contained in:
Shubham Agrawal
2022-08-06 19:30:37 +05:30
parent c14b1146ad
commit 3190ec0be2
3 changed files with 128 additions and 34 deletions
@@ -28,38 +28,19 @@ namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
/**
* Implementation of the Grouped Convolution class. The Grouped Convolution
* class represents a single layer of a neural network.
* Example usage:
*
* Suppose we want to pass a matrix M (2744x100) to a `Convolution` layer;
* in this example, `M` was obtained from "flattening" 100 images (or Mel
* cepstral coefficients, if we talk about speech, or whatever you like) of
* dimension 196x14. In other words, the first 196 columns of each row of M
* will be made of the 196 columns of the first row of each of the 100 images
* (or Mel cepstral coefficients). Then the next 295 columns of M (196 - 393)
* will be made of the 196 columns of the second row of the 100 images (or Mel
* cepstral coefficients), etc. Given that the size of our 2-D input images is
* 196x14, the parameters for our `Convolution` layer will be something like
* this:
*
* ```
* GroupedConvolution<> c(1, // Number of input activation maps.
* 14, // Number of output activation maps.
* 3, // Filter width.
* 3, // Filter height.
* 1, // Number of groups.
* 1, // Stride along width.
* 1, // Stride along height.
* 0, // Padding width.
* 0, // Padding height.
* 196, // Input width.
* 14); // Input height.
* ```
*
* This `Convolution<>` layer will treat each column of the input matrix `M` as
* a 2-D image (or object) of the original 196x14 size, using this as the input
* for the 14 filters of this example.
* Implementation of the Grouped Convolution class.
*
* For information on convolution, please refer to the convolution layer.
*
* A Grouped Convolution uses a group of convolutions - multiple kernels per
* layer - resulting in multiple channel outputs per layer. This leads to wider
* networks helping a network learn a varied set of low level and high level
* features. The original motivation of using Grouped Convolutions in AlexNet
* was to distribute the model over multiple GPUs as an engineering compromise.
* But later, with models such as ResNeXt, it was shown this module could be
* used to improve classification accuracy. Specifically by exposing a new
* dimension through grouped convolutions, cardinality (the size of set of
* transformations), we can increase accuracy by increasing it.
*
* The `groups` parameter controls the connections between inputs and outputs.
* inMaps and outMaps must both be divisible by groups.
@@ -70,6 +51,19 @@ namespace ann /** Artificial Neural Network. */ {
* the output channels, and both subsequently concatenated.
* At groups= inMaps, each input channel is convolved with its own set of
* filters (of size \frac{\text{out\_channels}}{\text{in\_channels}}).
*
* For more information, kindly refer to the following paper.
*
* Paper for Grouped Convolution.
*
* @code
* @article{Huang2018,
* author = {Gao Huang, Shichen Liu, Laurens van der Maaten, Kilian Q. Weinberger},
* title = {CondenseNet: An Efficient DenseNet Using Learned Group Convolutions},
* year = {2018},
* url = {https://openaccess.thecvf.com/content_cvpr_2018/papers/Huang_CondenseNet_An_Efficient_CVPR_2018_paper.pdf}
* }
* @endcode
*
* @tparam ForwardConvolutionRule Convolution to perform forward process.
* @tparam BackwardConvolutionRule Convolution to perform backward process.
@@ -608,8 +608,9 @@ void GroupedConvolutionType<
if ((inMaps % groups != 0) || (maps % groups != 0))
{
Log::Fatal << "Both input maps and output maps should be divisible by "
<< "groups." << std::endl;
Log::Fatal << "Both input maps (" << inMaps << ") and output maps ("
<< maps << ") should be divisible by groups (" << groups << ")!"
<< std::endl;
}
// Compute and cache the total number of input maps.
@@ -68,6 +68,105 @@ TEST_CASE("GroupedConvolutionLayerTest", "[ANNLayerTest]")
REQUIRE(arma::accu(delta) == Approx(686.7855224609).epsilon(1e-5));
}
/**
* Test for testing equivalence of grouped convolution (groups = 1)
* with convolution layer.
*/
TEST_CASE("GroupedConvolutionEquivalenceTest", "[ANNLayerTest]")
{
arma::mat input, output, outputG;
// The input test matrix is of the form 3 x 2 x 2 x 2 where
// number of images are 3 and number of feature maps are 2.
input = { { 1, 446, 42 },
{ 2, 16, 63 },
{ 3, 13, 63 },
{ 4, 21, 21 },
{ 1, 13, 11 },
{ 32, 45, 42 },
{ 22, 16 , 63 },
{ 32, 13 , 42 } };
Convolution layer(2, 2, 2, 1, 1, 0, 0);
layer.InputDimensions() = std::vector<size_t>({ 2, 2, 2 });
layer.ComputeOutputDimensions();
arma::mat layerWeights(layer.WeightSize(), 1);
layerWeights(0) = 0.23757622;
layerWeights(1) = -0.11899071;
layerWeights(2) = 0.10450475;
layerWeights(3) = -0.1303806;
layerWeights(4) = -0.34706244;
layerWeights(5) = -0.09472395;
layerWeights(6) = 0.04117536;
layerWeights(7) = -0.23012237;
layerWeights(8) = -0.02827594;
layerWeights(9) = -0.24280427;
layerWeights(10) = 0.33375624;
layerWeights(11) = -0.12285174;
layerWeights(12) = -0.05546845;
layerWeights(13) = -0.01502632;
layerWeights(14) = -0.25894147;
layerWeights(15) = -0.2283206;
layerWeights(16) = 0.3204123974;
layerWeights(17) = 0.2334779799;
layer.SetWeights(layerWeights.memptr());
output.set_size(layer.OutputSize(), 3);
GroupedConvolution layerG(2, 2, 2, 1, 1, 1, 0, 0);
layerG.InputDimensions() = std::vector<size_t>({ 2, 2, 2 });
layerG.ComputeOutputDimensions();
arma::mat layerWeightsG(layerG.WeightSize(), 1);
layerWeightsG(0) = 0.23757622;
layerWeightsG(1) = -0.11899071;
layerWeightsG(2) = 0.10450475;
layerWeightsG(3) = -0.1303806;
layerWeightsG(4) = -0.34706244;
layerWeightsG(5) = -0.09472395;
layerWeightsG(6) = 0.04117536;
layerWeightsG(7) = -0.23012237;
layerWeightsG(8) = -0.02827594;
layerWeightsG(9) = -0.24280427;
layerWeightsG(10) = 0.33375624;
layerWeightsG(11) = -0.12285174;
layerWeightsG(12) = -0.05546845;
layerWeightsG(13) = -0.01502632;
layerWeightsG(14) = -0.25894147;
layerWeightsG(15) = -0.2283206;
layerWeightsG(16) = 0.3204123974;
layerWeightsG(17) = 0.2334779799;
layerG.SetWeights(layerWeightsG.memptr());
outputG.set_size(layerG.OutputSize(), 3);
layer.Forward(input, output);
layerG.Forward(input, outputG);
// Value calculated using torch.nn.Conv2d().
CheckMatrices(output, outputG);
REQUIRE(arma::accu(output) == Approx(12.6755657196).epsilon(1e-5));
REQUIRE(arma::accu(outputG) == Approx(12.6755657196).epsilon(1e-5));
arma::mat delta, deltaG;
delta.set_size(8, 3);
deltaG.set_size(8, 3);
layer.Backward(input, output, delta);
layerG.Backward(input, outputG, deltaG);
CheckMatrices(delta, deltaG);
REQUIRE(arma::accu(delta) == Approx(-1.9237523079).epsilon(1e-5));
REQUIRE(arma::accu(deltaG) == Approx(-1.9237523079).epsilon(1e-5));
}
TEST_CASE("EdgeCaseFailGroupedConvolutionTest", "[ANNLayerTest]")
{
GroupedConvolution layer(2, 2, 2, 0, 1, 1, 0, 0);
layer.InputDimensions() = std::vector<size_t>({ 2, 2, 2 });
REQUIRE_THROWS(layer.ComputeOutputDimensions());
GroupedConvolution layer2(3, 2, 2, 2, 1, 1, 0, 0);
layer2.InputDimensions() = std::vector<size_t>({ 2, 2, 2 });
REQUIRE_THROWS(layer2.ComputeOutputDimensions());
}
/**
* Grouped Convolution layer numerical gradient test.
*/