Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/torch/nn.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Leonard <nick@nikopia.org>2014-11-25 05:17:52 +0300
committernicholas-leonard <nick@nikopia.org>2014-11-25 07:08:09 +0300
commit70f542492cbde0cf7f16afc915a3b8b674b77bd0 (patch)
tree477c4c8e9e50c0ecae31ca4f1214abc52148cbe6
parentd232b6f3bedda4f5151248e81d2cc75123ab509b (diff)
SpatialAveragePooling
-rw-r--r--SpatialAveragePooling.lua20
-rwxr-xr-xdoc/convolution.md12
-rw-r--r--generic/SpatialAveragePooling.c190
-rw-r--r--init.c5
-rw-r--r--init.lua1
-rw-r--r--test.lua69
6 files changed, 292 insertions, 5 deletions
diff --git a/SpatialAveragePooling.lua b/SpatialAveragePooling.lua
new file mode 100644
index 0000000..13b6b45
--- /dev/null
+++ b/SpatialAveragePooling.lua
@@ -0,0 +1,20 @@
+local SpatialAveragePooling, parent = torch.class('nn.SpatialAveragePooling', 'nn.Module')
+
+function SpatialAveragePooling:__init(kW, kH, dW, dH)
+ parent.__init(self)
+
+ self.kW = kW
+ self.kH = kH
+ self.dW = dW or 1
+ self.dH = dH or 1
+end
+
+function SpatialAveragePooling:updateOutput(input)
+ return input.nn.SpatialAveragePooling_updateOutput(self, input)
+end
+
+function SpatialAveragePooling:updateGradInput(input, gradOutput)
+ if self.gradInput then
+ return input.nn.SpatialAveragePooling_updateGradInput(self, input, gradOutput)
+ end
+end
diff --git a/doc/convolution.md b/doc/convolution.md
index 5571b19..c65222d 100755
--- a/doc/convolution.md
+++ b/doc/convolution.md
@@ -12,6 +12,7 @@ A convolution is an integral that expresses the amount of overlap of one functio
* [SpatialConvolution](#nn.SpatialConvolution) : a 2D convolution over an input image ;
* [SpatialSubSampling](#nn.SpatialSubSampling) : a 2D sub-sampling over an input image ;
* [SpatialMaxPooling](#nn.SpatialMaxPooling) : a 2D max-pooling operation over an input image ;
+ * [SpatialAveragePooling](#nn.SpatialAveragePooling) : a 2D average-pooling operation over an input image ;
* [SpatialLPPooling](#nn.SpatialLPPooling) : computes the `p` norm in a convolutional manner on a set of input images ;
* [SpatialConvolutionMap](#nn.SpatialConvolutionMap) : a 2D convolution that uses a generic connection table ;
* [SpatialZeroPadding](#nn.SpatialZeroPadding) : padds a feature map with specified number of zeros ;
@@ -356,6 +357,17 @@ Applies 2D max-pooling operation in `kWxkH` regions by step size
`dWxdH` steps. The number of output features is equal to the number of
input planes.
+<a name="nn.SpatialAveragePooling"/>
+### SpatialAveragePooling ###
+
+```lua
+module = nn.SpatialAveragePooling(kW, kH [, dW, dH])
+```
+
+Applies 2D average-pooling operation in `kWxkH` regions by step size
+`dWxdH` steps. The number of output features is equal to the number of
+input planes.
+
<a name="nn.SpatialSubSampling"/>
### SpatialSubSampling ###
diff --git a/generic/SpatialAveragePooling.c b/generic/SpatialAveragePooling.c
new file mode 100644
index 0000000..2052d05
--- /dev/null
+++ b/generic/SpatialAveragePooling.c
@@ -0,0 +1,190 @@
+#ifndef TH_GENERIC_FILE
+#define TH_GENERIC_FILE "generic/SpatialAveragePooling.c"
+#else
+
+static int nn_(SpatialAveragePooling_updateOutput)(lua_State *L)
+{
+ THTensor *input = luaT_checkudata(L, 2, torch_Tensor);
+ int kW = luaT_getfieldcheckint(L, 1, "kW");
+ int kH = luaT_getfieldcheckint(L, 1, "kH");
+ int dW = luaT_getfieldcheckint(L, 1, "dW");
+ int dH = luaT_getfieldcheckint(L, 1, "dH");
+
+ THTensor *output = luaT_getfieldcheckudata(L, 1, "output", torch_Tensor);
+
+ real *output_data;
+ real *input_data;
+
+ int dimw = 2;
+ int dimh = 1;
+ int dimc = 0;
+ long nbatch = 1;
+
+ long inputWidth;
+ long inputHeight;
+ long outputWidth;
+ long outputHeight;
+ long nInputPlane; // number of channels (or colors)
+
+ long k;
+
+ luaL_argcheck(L, input->nDimension == 3 || input->nDimension == 4, 2, "3D or 4D(batch mode) tensor expected");
+
+ if (input->nDimension == 4) {
+ nbatch = input->size[0];
+ dimw++;
+ dimh++;
+ dimc++;
+ }
+
+ inputWidth = input->size[dimw];
+ inputHeight = input->size[dimh];
+ nInputPlane = input->size[dimc];
+ outputWidth = (inputWidth - kW) / dW + 1;
+ outputHeight = (inputHeight - kH) / dH + 1;
+
+ luaL_argcheck(L, inputWidth >= kW && inputHeight >= kH, 2, "input image smaller than kernel size");
+
+ if (input->nDimension == 3)
+ THTensor_(resize3d)(output, nInputPlane, outputHeight, outputWidth);
+ else
+ THTensor_(resize4d)(output, input->size[0], nInputPlane, outputHeight, outputWidth);
+
+ input = THTensor_(newContiguous)(input);
+ input_data = THTensor_(data)(input);
+ output_data = THTensor_(data)(output);
+
+#pragma omp parallel for private(k)
+ for(k = 0; k < nInputPlane; k++)
+ {
+ long p;
+ for(p = 0; p < nbatch; p++)
+ {
+ long xx, yy;
+ /* For all output pixels... */
+ real *ptr_output = output_data + p*nInputPlane*outputWidth*outputHeight + k*outputWidth*outputHeight;
+ long i;
+ for(i = 0; i < outputWidth*outputHeight; i++)
+ ptr_output[i] = 0;
+
+ for(yy = 0; yy < outputHeight; yy++)
+ {
+ for(xx = 0; xx < outputWidth; xx++)
+ {
+ /* Compute the mean of the input image... */
+ real *ptr_input = input_data + p*nInputPlane*inputWidth*inputHeight + k*inputWidth*inputHeight + yy*dH*inputWidth+xx*dW;
+ real sum = 0;
+ long kx, ky;
+
+ for(ky = 0; ky < kH; ky++)
+ {
+ for(kx = 0; kx < kW; kx++)
+ sum += ptr_input[kx];
+ ptr_input += inputWidth; /* next input line */
+ }
+ /* Update output */
+ *ptr_output++ += sum;
+ }
+ }
+ }
+ }
+ THTensor_(free)(input);
+
+ return 1;
+}
+
+static int nn_(SpatialAveragePooling_updateGradInput)(lua_State *L)
+{
+ THTensor *input = luaT_checkudata(L, 2, torch_Tensor);
+ THTensor *gradOutput = luaT_checkudata(L, 3, torch_Tensor);
+ int kW = luaT_getfieldcheckint(L, 1, "kW");
+ int kH = luaT_getfieldcheckint(L, 1, "kH");
+ int dW = luaT_getfieldcheckint(L, 1, "dW");
+ int dH = luaT_getfieldcheckint(L, 1, "dH");
+ THTensor *gradInput = luaT_getfieldcheckudata(L, 1, "gradInput", torch_Tensor);
+
+ int dimw = 2;
+ int dimh = 1;
+ int dimc = 0;
+ long nbatch = 1;
+
+ long inputWidth;
+ long inputHeight;
+ long outputWidth;
+ long outputHeight;
+ long nInputPlane; // number of channels (or colors)
+
+ real *gradOutput_data;
+ real *input_data, *gradInput_data;
+
+ long k;
+
+ if (input->nDimension == 4) {
+ nbatch = input->size[0];
+ dimw++;
+ dimh++;
+ dimc++;
+ }
+
+ inputWidth = input->size[dimw];
+ inputHeight = input->size[dimh];
+ nInputPlane = input->size[dimc];
+ outputWidth = (inputWidth - kW) / dW + 1;
+ outputHeight = (inputHeight - kH) / dH + 1;
+
+ input_data = THTensor_(data)(input);
+
+ THTensor_(resizeAs)(gradInput, input);
+ gradInput_data = THTensor_(data)(gradInput);
+ gradOutput_data = THTensor_(data)(gradOutput);
+
+#pragma omp parallel for private(k)
+ for(k = 0; k < nInputPlane; k++)
+ {
+ long p;
+ for(p = 0; p < nbatch; p++)
+ {
+ real *ptr_gradOutput = gradOutput_data + p*nInputPlane*outputHeight*outputWidth + k*outputWidth*outputHeight;
+ long xx, yy;
+
+ real* ptr_gi = gradInput_data + p*nInputPlane*inputWidth*inputHeight + k*inputWidth*inputHeight;
+ long i;
+ for(i=0; i<inputWidth*inputHeight; i++)
+ ptr_gi[i] = 0.0;
+
+ for(yy = 0; yy < outputHeight; yy++)
+ {
+ for(xx = 0; xx < outputWidth; xx++)
+ {
+ real *ptr_gradInput = gradInput_data + p*nInputPlane*inputWidth*inputHeight + k*inputWidth*inputHeight + yy*dH*inputWidth+xx*dW;
+ real z = *ptr_gradOutput++;
+ long kx, ky;
+
+ for(ky = 0; ky < kH; ky++)
+ {
+ for(kx = 0; kx < kW; kx++)
+ ptr_gradInput[kx] += z;
+ ptr_gradInput += inputWidth;
+ }
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+static const struct luaL_Reg nn_(SpatialAveragePooling__) [] = {
+ {"SpatialAveragePooling_updateOutput", nn_(SpatialAveragePooling_updateOutput)},
+ {"SpatialAveragePooling_updateGradInput", nn_(SpatialAveragePooling_updateGradInput)},
+ {NULL, NULL}
+};
+
+static void nn_(SpatialAveragePooling_init)(lua_State *L)
+{
+ luaT_pushmetatable(L, torch_Tensor);
+ luaT_registeratname(L, nn_(SpatialAveragePooling__), "nn");
+ lua_pop(L,1);
+}
+
+#endif
diff --git a/init.c b/init.c
index 9f820e6..2704973 100644
--- a/init.c
+++ b/init.c
@@ -98,6 +98,9 @@
#include "generic/SpatialMaxPooling.c"
#include "THGenerateFloatTypes.h"
+#include "generic/SpatialAveragePooling.c"
+#include "THGenerateFloatTypes.h"
+
#include "generic/VolumetricConvolution.c"
#include "THGenerateFloatTypes.h"
@@ -155,6 +158,7 @@ int luaopen_libnn(lua_State *L)
nn_FloatSpatialConvolutionMap_init(L);
nn_FloatSpatialSubSampling_init(L);
nn_FloatSpatialMaxPooling_init(L);
+ nn_FloatSpatialAveragePooling_init(L);
nn_FloatVolumetricConvolution_init(L);
nn_FloatVolumetricMaxPooling_init(L);
nn_FloatMultiMarginCriterion_init(L);
@@ -193,6 +197,7 @@ int luaopen_libnn(lua_State *L)
nn_DoubleSpatialConvolutionMap_init(L);
nn_DoubleSpatialSubSampling_init(L);
nn_DoubleSpatialMaxPooling_init(L);
+ nn_DoubleSpatialAveragePooling_init(L);
nn_DoubleVolumetricConvolution_init(L);
nn_DoubleVolumetricMaxPooling_init(L);
nn_DoubleMultiMarginCriterion_init(L);
diff --git a/init.lua b/init.lua
index fde8e74..0ab72a8 100644
--- a/init.lua
+++ b/init.lua
@@ -74,6 +74,7 @@ include('SpatialSubSampling.lua')
include('SpatialMaxPooling.lua')
include('SpatialMaxPoolingCUDA.lua')
include('SpatialLPPooling.lua')
+include('SpatialAveragePooling.lua')
include('TemporalConvolution.lua')
include('TemporalSubSampling.lua')
include('TemporalMaxPooling.lua')
diff --git a/test.lua b/test.lua
index ed7fd21..4615b23 100644
--- a/test.lua
+++ b/test.lua
@@ -1349,7 +1349,6 @@ function nntest.SpatialSubSampling()
'error on bias [%s]', t))
end
- --verbose = true
local batch = math.random(2,5)
outi = math.random(4,8)
outj = math.random(4,8)
@@ -1358,10 +1357,6 @@ function nntest.SpatialSubSampling()
module = nn.SpatialSubSampling(from, ki, kj, si, sj)
input = torch.Tensor(batch,from,inj,ini):zero()
--- print(from, to, ki, kj, si, sj, batch, ini, inj)
--- print(module.weight:size())
--- print(module.gradWeight:size())
-
local err = jac.testJacobian(module, input)
mytester:assertlt(err, precision, 'batch error on state ')
@@ -1427,6 +1422,70 @@ function nntest.SpatialMaxPooling()
end
+function nntest.SpatialAveragePooling()
+ local from = math.random(1,6)
+ local ki = math.random(1,5)
+ local kj = math.random(1,5)
+ local si = math.random(1,4)
+ local sj = math.random(1,4)
+ local outi = math.random(6,10)
+ local outj = math.random(6,10)
+ local ini = (outi-1)*si+ki
+ local inj = (outj-1)*sj+kj
+ local module = nn.SpatialAveragePooling(ki, kj, si, sj)
+ local input = torch.Tensor(from, inj, ini):zero()
+
+ local err = jac.testJacobian(module, input)
+ mytester:assertlt(err, precision, 'error on state ')
+
+ local ferr, berr = jac.testIO(module, input)
+ mytester:asserteq(ferr, 0, torch.typename(module) .. ' - i/o forward err ')
+ mytester:asserteq(berr, 0, torch.typename(module) .. ' - i/o backward err ')
+
+ local sap = nn.SpatialSubSampling(from, ki, kj, si, sj)
+ sap.weight:fill(1.0)
+ sap.bias:fill(0.0)
+
+ local output = module:forward(input)
+ local gradInput = module:backward(input, output)
+ local output2 = sap:forward(input)
+ local gradInput2 = sap:updateGradInput(input, output)
+
+ mytester:assertTensorEq(output, output2, 0.000001, torch.typename(module) .. ' forward err ')
+ mytester:assertTensorEq(gradInput, gradInput2, 0.000001, torch.typename(module) .. ' backward err ')
+
+ local batch = math.random(2,5)
+ outi = math.random(4,8)
+ outj = math.random(4,8)
+ ini = (outi-1)*si+ki
+ inj = (outj-1)*sj+kj
+ module = nn.SpatialAveragePooling(ki, kj, si, sj)
+ input = torch.Tensor(batch,from,inj,ini):zero()
+
+ local err = jac.testJacobian(module, input)
+ mytester:assertlt(err, precision, 'batch error on state ')
+
+ local ferr, berr = jac.testIO(module, input)
+ mytester:asserteq(0, ferr, torch.typename(module) .. ' - i/o forward err ')
+ mytester:asserteq(0, berr, torch.typename(module) .. ' - i/o backward err ')
+
+ local ferr, berr = jac.testIO(module, input)
+ mytester:asserteq(ferr, 0, torch.typename(module) .. ' - i/o forward err (Batch) ')
+ mytester:asserteq(berr, 0, torch.typename(module) .. ' - i/o backward err (Batch) ')
+
+ local sap = nn.SpatialSubSampling(from, ki, kj, si, sj)
+ sap.weight:fill(1.0)
+ sap.bias:fill(0.0)
+
+ local output = module:forward(input)
+ local gradInput = module:backward(input, output)
+ local output2 = sap:forward(input)
+ local gradInput2 = sap:updateGradInput(input, output)
+
+ mytester:assertTensorEq(output, output2, 0.000001, torch.typename(module) .. ' forward err (Batch) ')
+ mytester:assertTensorEq(gradInput, gradInput2, 0.000001, torch.typename(module) .. ' backward err (Batch) ')
+end
+
function nntest.SpatialLPPooling()
local fanin = math.random(1,4)
local osizex = math.random(1,4)