mlpack
convolution_impl.hpp
Go to the documentation of this file.
1 
12 #ifndef MLPACK_METHODS_ANN_LAYER_CONVOLUTION_IMPL_HPP
13 #define MLPACK_METHODS_ANN_LAYER_CONVOLUTION_IMPL_HPP
14 
15 // In case it hasn't yet been included.
16 #include "convolution.hpp"
17 
18 namespace mlpack {
19 namespace ann {
20 
21 template<
22  typename ForwardConvolutionRule,
23  typename BackwardConvolutionRule,
24  typename GradientConvolutionRule,
25  typename InputDataType,
26  typename OutputDataType
27 >
28 Convolution<
29  ForwardConvolutionRule,
30  BackwardConvolutionRule,
31  GradientConvolutionRule,
32  InputDataType,
33  OutputDataType
35 {
36  // Nothing to do here.
37 }
38 
39 template<
40  typename ForwardConvolutionRule,
41  typename BackwardConvolutionRule,
42  typename GradientConvolutionRule,
43  typename InputDataType,
44  typename OutputDataType
45 >
47  ForwardConvolutionRule,
48  BackwardConvolutionRule,
49  GradientConvolutionRule,
50  InputDataType,
51  OutputDataType
53  const size_t inSize,
54  const size_t outSize,
55  const size_t kernelWidth,
56  const size_t kernelHeight,
57  const size_t strideWidth,
58  const size_t strideHeight,
59  const size_t padW,
60  const size_t padH,
61  const size_t inputWidth,
62  const size_t inputHeight,
63  const std::string& paddingType) :
65  inSize,
66  outSize,
67  kernelWidth,
68  kernelHeight,
69  strideWidth,
70  strideHeight,
71  std::tuple<size_t, size_t>(padW, padW),
72  std::tuple<size_t, size_t>(padH, padH),
73  inputWidth,
74  inputHeight,
75  paddingType)
76 {
77  // Nothing to do here.
78 }
79 
80 template<
81  typename ForwardConvolutionRule,
82  typename BackwardConvolutionRule,
83  typename GradientConvolutionRule,
84  typename InputDataType,
85  typename OutputDataType
86 >
88  ForwardConvolutionRule,
89  BackwardConvolutionRule,
90  GradientConvolutionRule,
91  InputDataType,
92  OutputDataType
94  const size_t inSize,
95  const size_t outSize,
96  const size_t kernelWidth,
97  const size_t kernelHeight,
98  const size_t strideWidth,
99  const size_t strideHeight,
100  const std::tuple<size_t, size_t>& padW,
101  const std::tuple<size_t, size_t>& padH,
102  const size_t inputWidth,
103  const size_t inputHeight,
104  const std::string& paddingType) :
105  inSize(inSize),
106  outSize(outSize),
107  kernelWidth(kernelWidth),
108  kernelHeight(kernelHeight),
109  strideWidth(strideWidth),
110  strideHeight(strideHeight),
111  padWLeft(std::get<0>(padW)),
112  padWRight(std::get<1>(padW)),
113  padHBottom(std::get<1>(padH)),
114  padHTop(std::get<0>(padH)),
115  inputWidth(inputWidth),
116  inputHeight(inputHeight),
117  outputWidth(0),
118  outputHeight(0)
119 {
120  weights.set_size(WeightSize(), 1);
121 
122  // Transform paddingType to lowercase.
123  const std::string paddingTypeLow = util::ToLower(paddingType);
124 
125  if (paddingTypeLow == "valid")
126  {
127  padWLeft = 0;
128  padWRight = 0;
129  padHTop = 0;
130  padHBottom = 0;
131  }
132  else if (paddingTypeLow == "same")
133  {
134  InitializeSamePadding();
135  }
136 
137  padding = ann::Padding<>(padWLeft, padWRight, padHTop, padHBottom);
138 }
139 
140 template<
141  typename ForwardConvolutionRule,
142  typename BackwardConvolutionRule,
143  typename GradientConvolutionRule,
144  typename InputDataType,
145  typename OutputDataType
146 >
147 void Convolution<
148  ForwardConvolutionRule,
149  BackwardConvolutionRule,
150  GradientConvolutionRule,
151  InputDataType,
152  OutputDataType
153 >::Reset()
154 {
155  weight = arma::cube(weights.memptr(), kernelWidth, kernelHeight,
156  outSize * inSize, false, false);
157  bias = arma::mat(weights.memptr() + weight.n_elem,
158  outSize, 1, false, false);
159 }
160 
161 template<
162  typename ForwardConvolutionRule,
163  typename BackwardConvolutionRule,
164  typename GradientConvolutionRule,
165  typename InputDataType,
166  typename OutputDataType
167 >
168 template<typename eT>
169 void Convolution<
170  ForwardConvolutionRule,
171  BackwardConvolutionRule,
172  GradientConvolutionRule,
173  InputDataType,
174  OutputDataType
175 >::Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output)
176 {
177  batchSize = input.n_cols;
178  arma::cube inputTemp(const_cast<arma::Mat<eT>&>(input).memptr(),
179  inputWidth, inputHeight, inSize * batchSize, false, false);
180 
181  if (padWLeft != 0 || padWRight != 0 || padHTop != 0 || padHBottom != 0)
182  {
183  inputPaddedTemp.set_size(inputTemp.n_rows + padWLeft + padWRight,
184  inputTemp.n_cols + padHTop + padHBottom, inputTemp.n_slices);
185 
186  for (size_t i = 0; i < inputTemp.n_slices; ++i)
187  {
188  padding.Forward(inputTemp.slice(i), inputPaddedTemp.slice(i));
189  }
190  }
191 
192  size_t wConv = ConvOutSize(inputWidth, kernelWidth, strideWidth, padWLeft,
193  padWRight);
194  size_t hConv = ConvOutSize(inputHeight, kernelHeight, strideHeight, padHTop,
195  padHBottom);
196 
197  output.set_size(wConv * hConv * outSize, batchSize);
198  outputTemp = arma::Cube<eT>(output.memptr(), wConv, hConv,
199  outSize * batchSize, false, false);
200  outputTemp.zeros();
201 
202  for (size_t outMap = 0, outMapIdx = 0, batchCount = 0; outMap <
203  outSize * batchSize; outMap++)
204  {
205  if (outMap != 0 && outMap % outSize == 0)
206  {
207  batchCount++;
208  outMapIdx = 0;
209  }
210 
211  for (size_t inMap = 0; inMap < inSize; inMap++, outMapIdx++)
212  {
213  arma::Mat<eT> convOutput;
214 
215  if (padWLeft != 0 || padWRight != 0 || padHTop != 0 || padHBottom != 0)
216  {
217  ForwardConvolutionRule::Convolution(inputPaddedTemp.slice(inMap +
218  batchCount * inSize), weight.slice(outMapIdx), convOutput,
219  strideWidth, strideHeight);
220  }
221  else
222  {
223  ForwardConvolutionRule::Convolution(inputTemp.slice(inMap +
224  batchCount * inSize), weight.slice(outMapIdx), convOutput,
225  strideWidth, strideHeight);
226  }
227 
228  outputTemp.slice(outMap) += convOutput;
229  }
230 
231  outputTemp.slice(outMap) += bias(outMap % outSize);
232  }
233 
234  outputWidth = outputTemp.n_rows;
235  outputHeight = outputTemp.n_cols;
236 }
237 
238 template<
239  typename ForwardConvolutionRule,
240  typename BackwardConvolutionRule,
241  typename GradientConvolutionRule,
242  typename InputDataType,
243  typename OutputDataType
244 >
245 template<typename eT>
246 void Convolution<
247  ForwardConvolutionRule,
248  BackwardConvolutionRule,
249  GradientConvolutionRule,
250  InputDataType,
251  OutputDataType
253  const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
254 {
255  arma::cube mappedError(((arma::Mat<eT>&) gy).memptr(), outputWidth,
256  outputHeight, outSize * batchSize, false, false);
257 
258  g.set_size(inputWidth * inputHeight * inSize, batchSize);
259  gTemp = arma::Cube<eT>(g.memptr(), inputWidth, inputHeight,
260  inSize * batchSize, false, false);
261  gTemp.zeros();
262 
263  for (size_t outMap = 0, outMapIdx = 0, batchCount = 0; outMap <
264  outSize * batchSize; outMap++)
265  {
266  if (outMap != 0 && outMap % outSize == 0)
267  {
268  batchCount++;
269  outMapIdx = 0;
270  }
271 
272  for (size_t inMap = 0; inMap < inSize; inMap++, outMapIdx++)
273  {
274  arma::Mat<eT> output, rotatedFilter;
275  Rotate180(weight.slice(outMapIdx), rotatedFilter);
276 
277  BackwardConvolutionRule::Convolution(mappedError.slice(outMap),
278  rotatedFilter, output, strideWidth, strideHeight);
279 
280  if (padWLeft != 0 || padWRight != 0 || padHTop != 0 || padHBottom != 0)
281  {
282  gTemp.slice(inMap + batchCount * inSize) += output.submat(padWLeft,
283  padHTop, padWLeft + gTemp.n_rows - 1, padHTop + gTemp.n_cols - 1);
284  }
285  else
286  {
287  gTemp.slice(inMap + batchCount * inSize) += output;
288  }
289  }
290  }
291 }
292 
293 template<
294  typename ForwardConvolutionRule,
295  typename BackwardConvolutionRule,
296  typename GradientConvolutionRule,
297  typename InputDataType,
298  typename OutputDataType
299 >
300 template<typename eT>
301 void Convolution<
302  ForwardConvolutionRule,
303  BackwardConvolutionRule,
304  GradientConvolutionRule,
305  InputDataType,
306  OutputDataType
307 >::Gradient(
308  const arma::Mat<eT>& input,
309  const arma::Mat<eT>& error,
310  arma::Mat<eT>& gradient)
311 {
312  arma::cube mappedError(((arma::Mat<eT>&) error).memptr(), outputWidth,
313  outputHeight, outSize * batchSize, false, false);
314  arma::cube inputTemp(((arma::Mat<eT>&) input).memptr(), inputWidth,
315  inputHeight, inSize * batchSize, false, false);
316 
317  gradient.set_size(weights.n_elem, 1);
318  gradientTemp = arma::Cube<eT>(gradient.memptr(), weight.n_rows,
319  weight.n_cols, weight.n_slices, false, false);
320  gradientTemp.zeros();
321 
322  for (size_t outMap = 0, outMapIdx = 0, batchCount = 0; outMap <
323  outSize * batchSize; outMap++)
324  {
325  if (outMap != 0 && outMap % outSize == 0)
326  {
327  batchCount++;
328  outMapIdx = 0;
329  }
330 
331  for (size_t inMap = 0; inMap < inSize; inMap++, outMapIdx++)
332  {
333  arma::Mat<eT> inputSlice;
334  if (padWLeft != 0 || padWRight != 0 || padHTop != 0 || padHBottom != 0)
335  {
336  inputSlice = inputPaddedTemp.slice(inMap + batchCount * inSize);
337  }
338  else
339  {
340  inputSlice = inputTemp.slice(inMap + batchCount * inSize);
341  }
342 
343  arma::Mat<eT> deltaSlice = mappedError.slice(outMap);
344 
345  arma::Mat<eT> output;
346  GradientConvolutionRule::Convolution(inputSlice, deltaSlice,
347  output, strideWidth, strideHeight);
348 
349  if (gradientTemp.n_rows < output.n_rows ||
350  gradientTemp.n_cols < output.n_cols)
351  {
352  gradientTemp.slice(outMapIdx) += output.submat(0, 0,
353  gradientTemp.n_rows - 1, gradientTemp.n_cols - 1);
354  }
355  else if (gradientTemp.n_rows > output.n_rows ||
356  gradientTemp.n_cols > output.n_cols)
357  {
358  gradientTemp.slice(outMapIdx).submat(0, 0, output.n_rows - 1,
359  output.n_cols - 1) += output;
360  }
361  else
362  {
363  gradientTemp.slice(outMapIdx) += output;
364  }
365  }
366 
367  gradient.submat(weight.n_elem + (outMap % outSize), 0, weight.n_elem +
368  (outMap % outSize), 0) = arma::accu(mappedError.slice(outMap));
369  }
370 }
371 
372 template<
373  typename ForwardConvolutionRule,
374  typename BackwardConvolutionRule,
375  typename GradientConvolutionRule,
376  typename InputDataType,
377  typename OutputDataType
378 >
379 template<typename Archive>
380 void Convolution<
381  ForwardConvolutionRule,
382  BackwardConvolutionRule,
383  GradientConvolutionRule,
384  InputDataType,
385  OutputDataType
386 >::serialize(Archive& ar, const uint32_t /* version*/)
387 {
388  ar(CEREAL_NVP(inSize));
389  ar(CEREAL_NVP(outSize));
390  ar(CEREAL_NVP(batchSize));
391  ar(CEREAL_NVP(kernelWidth));
392  ar(CEREAL_NVP(kernelHeight));
393  ar(CEREAL_NVP(strideWidth));
394  ar(CEREAL_NVP(strideHeight));
395  ar(CEREAL_NVP(padWLeft));
396  ar(CEREAL_NVP(padWRight));
397  ar(CEREAL_NVP(padHBottom));
398  ar(CEREAL_NVP(padHTop));
399  ar(CEREAL_NVP(inputWidth));
400  ar(CEREAL_NVP(inputHeight));
401  ar(CEREAL_NVP(outputWidth));
402  ar(CEREAL_NVP(outputHeight));
403  ar(CEREAL_NVP(padding));
404 
405  if (cereal::is_loading<Archive>())
406  {
407  weights.set_size((outSize * inSize * kernelWidth * kernelHeight) + outSize,
408  1);
409  }
410 }
411 
412 template<
413  typename ForwardConvolutionRule,
414  typename BackwardConvolutionRule,
415  typename GradientConvolutionRule,
416  typename InputDataType,
417  typename OutputDataType
418 >
419 void Convolution<
420  ForwardConvolutionRule,
421  BackwardConvolutionRule,
422  GradientConvolutionRule,
423  InputDataType,
424  OutputDataType
425 >::InitializeSamePadding()
426 {
427  /*
428  * Using O = (W - F + 2P) / s + 1;
429  */
430  size_t totalVerticalPadding = (strideWidth - 1) * inputWidth + kernelWidth -
431  strideWidth;
432  size_t totalHorizontalPadding = (strideHeight - 1) * inputHeight +
433  kernelHeight - strideHeight;
434 
435  padWLeft = totalVerticalPadding / 2;
436  padWRight = totalVerticalPadding - totalVerticalPadding / 2;
437  padHTop = totalHorizontalPadding / 2;
438  padHBottom = totalHorizontalPadding - totalHorizontalPadding / 2;
439 }
440 
441 } // namespace ann
442 } // namespace mlpack
443 
444 #endif
Linear algebra utility functions, generally performed on matrices or vectors.
Definition: cv.hpp:1
Implementation of the Padding module class.
Definition: layer_types.hpp:87
size_t WeightSize() const
Get size of weights for the layer.
Definition: convolution.hpp:286
Definition: pointer_wrapper.hpp:23
Implementation of the Convolution class.
Definition: convolution.hpp:77
OutputDataType const & Gradient() const
Get the gradient.
Definition: convolution.hpp:215
void serialize(Archive &ar, const uint32_t)
Serialize the layer.
Definition: convolution_impl.hpp:386
void Forward(const arma::Mat< eT > &input, arma::Mat< eT > &output)
Ordinary feed forward pass of a neural network, evaluating the function f(x) by propagating the activ...
Definition: convolution_impl.hpp:175
Convolution()
Create the Convolution object.
Definition: convolution_impl.hpp:34
void Forward(const arma::Mat< eT > &input, arma::Mat< eT > &output)
Ordinary feed forward pass of a neural network, evaluating the function f(x) by propagating the activ...
Definition: padding_impl.hpp:44
void Backward(const arma::Mat< eT > &, const arma::Mat< eT > &gy, arma::Mat< eT > &g)
Ordinary feed backward pass of a neural network, calculating the function f(x) by propagating x backw...
Definition: convolution_impl.hpp:252