mlpack
transposed_convolution_impl.hpp
Go to the documentation of this file.
1 
13 #ifndef MLPACK_METHODS_ANN_LAYER_TRANSPOSED_CONVOLUTION_IMPL_HPP
14 #define MLPACK_METHODS_ANN_LAYER_TRANSPOSED_CONVOLUTION_IMPL_HPP
15 
16 // In case it hasn't yet been included.
18 
19 namespace mlpack {
20 namespace ann {
21 
22 template<
23  typename ForwardConvolutionRule,
24  typename BackwardConvolutionRule,
25  typename GradientConvolutionRule,
26  typename InputDataType,
27  typename OutputDataType
28 >
29 TransposedConvolution<
30  ForwardConvolutionRule,
31  BackwardConvolutionRule,
32  GradientConvolutionRule,
33  InputDataType,
34  OutputDataType
36 {
37  // Nothing to do here.
38 }
39 
40 template<
41  typename ForwardConvolutionRule,
42  typename BackwardConvolutionRule,
43  typename GradientConvolutionRule,
44  typename InputDataType,
45  typename OutputDataType
46 >
48  ForwardConvolutionRule,
49  BackwardConvolutionRule,
50  GradientConvolutionRule,
51  InputDataType,
52  OutputDataType
54  const size_t inSize,
55  const size_t outSize,
56  const size_t kernelWidth,
57  const size_t kernelHeight,
58  const size_t strideWidth,
59  const size_t strideHeight,
60  const size_t padW,
61  const size_t padH,
62  const size_t inputWidth,
63  const size_t inputHeight,
64  const size_t outputWidth,
65  const size_t outputHeight,
66  const std::string& paddingType) :
68  inSize,
69  outSize,
70  kernelWidth,
71  kernelHeight,
72  strideWidth,
73  strideHeight,
74  std::tuple<size_t, size_t>(padW, padW),
75  std::tuple<size_t, size_t>(padH, padH),
76  inputWidth,
77  inputHeight,
78  outputWidth,
79  outputHeight,
80  paddingType)
81 {
82  // Nothing to do here.
83 }
84 
85 template<
86  typename ForwardConvolutionRule,
87  typename BackwardConvolutionRule,
88  typename GradientConvolutionRule,
89  typename InputDataType,
90  typename OutputDataType
91 >
93  ForwardConvolutionRule,
94  BackwardConvolutionRule,
95  GradientConvolutionRule,
96  InputDataType,
97  OutputDataType
99  const size_t inSize,
100  const size_t outSize,
101  const size_t kernelWidth,
102  const size_t kernelHeight,
103  const size_t strideWidth,
104  const size_t strideHeight,
105  const std::tuple<size_t, size_t>& padW,
106  const std::tuple<size_t, size_t>& padH,
107  const size_t inputWidth,
108  const size_t inputHeight,
109  const size_t outputWidth,
110  const size_t outputHeight,
111  const std::string& paddingType) :
112  inSize(inSize),
113  outSize(outSize),
114  kernelWidth(kernelWidth),
115  kernelHeight(kernelHeight),
116  strideWidth(strideWidth),
117  strideHeight(strideHeight),
118  padWLeft(std::get<0>(padW)),
119  padWRight(std::get<1>(padW)),
120  padHBottom(std::get<1>(padH)),
121  padHTop(std::get<0>(padH)),
122  inputWidth(inputWidth),
123  inputHeight(inputHeight),
124  outputWidth(outputWidth),
125  outputHeight(outputHeight)
126 {
127  weights.set_size(WeightSize(), 1);
128  // Transform paddingType to lowercase.
129  const std::string paddingTypeLow = util::ToLower(paddingType);
130 
131  if (paddingTypeLow == "valid")
132  {
133  // Set Padding to 0.
134  padWLeft = 0;
135  padWRight = 0;
136  padHTop = 0;
137  padHBottom = 0;
138  }
139  else if (paddingTypeLow == "same")
140  {
141  InitializeSamePadding();
142  }
143 
144  const size_t totalPadWidth = padWLeft + padWRight;
145  const size_t totalPadHeight = padHTop + padHBottom;
146 
147  aW = (outputWidth + totalPadWidth - kernelWidth) % strideWidth;
148  aH = (outputHeight + totalPadHeight - kernelHeight) % strideHeight;
149 
150  const size_t padWidthLeftForward = kernelWidth - padWLeft - 1;
151  const size_t padHeightTopForward = kernelHeight - padHTop - 1;
152  const size_t padWidthRightForward = kernelWidth - padWRight - 1;
153  const size_t padHeightBottomtForward = kernelHeight - padHBottom - 1;
154 
155  paddingForward = ann::Padding<>(padWidthLeftForward,
156  padWidthRightForward + aW, padHeightTopForward,
157  padHeightBottomtForward + aH);
158  paddingBackward = ann::Padding<>(padWLeft, padWRight, padHTop, padHBottom);
159 
160  // Check if the output height and width are possible given the other
161  // parameters of the layer.
162  if (outputWidth != 0 && outputHeight != 0 &&
163  (outputWidth != strideWidth * (inputWidth - 1) +
164  aW + kernelWidth - totalPadWidth ||
165  outputHeight != strideHeight * (inputHeight - 1) +
166  aH + kernelHeight - totalPadHeight))
167  {
168  Log::Fatal << "The output width / output height is not possible given "
169  << "the other parameters of the layer." << std::endl;
170  }
171 }
172 
173 template<
174  typename ForwardConvolutionRule,
175  typename BackwardConvolutionRule,
176  typename GradientConvolutionRule,
177  typename InputDataType,
178  typename OutputDataType
179 >
181  ForwardConvolutionRule,
182  BackwardConvolutionRule,
183  GradientConvolutionRule,
184  InputDataType,
185  OutputDataType
186 >::Reset()
187 {
188  weight = arma::cube(weights.memptr(), kernelWidth, kernelHeight,
189  outSize * inSize, false, false);
190  bias = arma::mat(weights.memptr() + weight.n_elem,
191  outSize, 1, false, false);
192 }
193 
194 template<
195  typename ForwardConvolutionRule,
196  typename BackwardConvolutionRule,
197  typename GradientConvolutionRule,
198  typename InputDataType,
199  typename OutputDataType
200 >
201 template<typename eT>
203  ForwardConvolutionRule,
204  BackwardConvolutionRule,
205  GradientConvolutionRule,
206  InputDataType,
207  OutputDataType
208 >::Forward(const arma::Mat<eT>& input, arma::Mat<eT>& output)
209 {
210  batchSize = input.n_cols;
211  arma::cube inputTemp(const_cast<arma::Mat<eT>&>(input).memptr(),
212  inputWidth, inputHeight, inSize * batchSize, false, false);
213 
214  if (strideWidth > 1 || strideHeight > 1)
215  {
216  InsertZeros(inputTemp, strideWidth, strideHeight, inputExpandedTemp);
217 
218  if (paddingForward.PadWLeft() != 0 || paddingForward.PadWRight() != 0 ||
219  paddingForward.PadHTop() != 0 || paddingForward.PadHBottom() != 0)
220  {
221  inputPaddedTemp.set_size(inputExpandedTemp.n_rows +
222  paddingForward.PadWLeft() + paddingForward.PadWRight(),
223  inputExpandedTemp.n_cols + paddingForward.PadHTop() +
224  paddingForward.PadHBottom(), inputExpandedTemp.n_slices);
225 
226  for (size_t i = 0; i < inputExpandedTemp.n_slices; ++i)
227  {
228  paddingForward.Forward(inputExpandedTemp.slice(i),
229  inputPaddedTemp.slice(i));
230  }
231  }
232  else
233  {
234  inputPaddedTemp = arma::Cube<eT>(inputExpandedTemp.memptr(),
235  inputExpandedTemp.n_rows, inputExpandedTemp.n_cols,
236  inputExpandedTemp.n_slices, false, false);;
237  }
238  }
239  else if (paddingForward.PadWLeft() != 0 ||
240  paddingForward.PadWRight() != 0 ||
241  paddingForward.PadHTop() != 0 ||
242  paddingForward.PadHBottom() != 0)
243  {
244  inputPaddedTemp.set_size(inputTemp.n_rows + paddingForward.PadWLeft() +
245  paddingForward.PadWRight(), inputTemp.n_cols +
246  paddingForward.PadHTop() + paddingForward.PadHBottom(),
247  inputTemp.n_slices);
248 
249  for (size_t i = 0; i < inputTemp.n_slices; ++i)
250  {
251  paddingForward.Forward(inputTemp.slice(i), inputPaddedTemp.slice(i));
252  }
253  }
254 
255  output.set_size(outputWidth * outputHeight * outSize, batchSize);
256  outputTemp = arma::Cube<eT>(output.memptr(), outputWidth, outputHeight,
257  outSize * batchSize, false, false);
258  outputTemp.zeros();
259 
260  for (size_t outMap = 0, outMapIdx = 0, batchCount = 0; outMap <
261  outSize * batchSize; outMap++)
262  {
263  if (outMap != 0 && outMap % outSize == 0)
264  {
265  batchCount++;
266  outMapIdx = 0;
267  }
268 
269  for (size_t inMap = 0; inMap < inSize; inMap++, outMapIdx++)
270  {
271  arma::Mat<eT> convOutput, rotatedFilter;
272  Rotate180(weight.slice(outMapIdx), rotatedFilter);
273 
274  if (strideWidth > 1 ||
275  strideHeight > 1 ||
276  paddingForward.PadWLeft() != 0 ||
277  paddingForward.PadWRight() != 0 ||
278  paddingForward.PadHTop() != 0 ||
279  paddingForward.PadHBottom() != 0)
280  {
281  ForwardConvolutionRule::Convolution(inputPaddedTemp.slice(inMap +
282  batchCount * inSize), rotatedFilter, convOutput, 1, 1);
283  }
284  else
285  {
286  ForwardConvolutionRule::Convolution(inputTemp.slice(inMap +
287  batchCount * inSize), rotatedFilter, convOutput, 1, 1);
288  }
289 
290  outputTemp.slice(outMap) += convOutput;
291  }
292 
293  outputTemp.slice(outMap) += bias(outMap % outSize);
294  }
295 }
296 
297 template<
298  typename ForwardConvolutionRule,
299  typename BackwardConvolutionRule,
300  typename GradientConvolutionRule,
301  typename InputDataType,
302  typename OutputDataType
303 >
304 template<typename eT>
306  ForwardConvolutionRule,
307  BackwardConvolutionRule,
308  GradientConvolutionRule,
309  InputDataType,
310  OutputDataType
312  const arma::Mat<eT>& /* input */, const arma::Mat<eT>& gy, arma::Mat<eT>& g)
313 {
314  arma::Cube<eT> mappedError(((arma::Mat<eT>&) gy).memptr(), outputWidth,
315  outputHeight, outSize * batchSize, false, false);
316  arma::Cube<eT> mappedErrorPadded;
317  if (paddingBackward.PadWLeft() != 0 || paddingBackward.PadWRight() != 0 ||
318  paddingBackward.PadHTop() != 0 || paddingBackward.PadHBottom() != 0)
319  {
320  mappedErrorPadded.set_size(mappedError.n_rows +
321  paddingBackward.PadWLeft() + paddingBackward.PadWRight(),
322  mappedError.n_cols + paddingBackward.PadHTop() +
323  paddingBackward.PadHBottom(), mappedError.n_slices);
324 
325  for (size_t i = 0; i < mappedError.n_slices; ++i)
326  {
327  paddingBackward.Forward(mappedError.slice(i),
328  mappedErrorPadded.slice(i));
329  }
330  }
331  g.set_size(inputWidth * inputHeight * inSize, batchSize);
332  gTemp = arma::Cube<eT>(g.memptr(), inputWidth, inputHeight, inSize *
333  batchSize, false, false);
334 
335  gTemp.zeros();
336 
337  for (size_t outMap = 0, outMapIdx = 0, batchCount = 0; outMap <
338  outSize * batchSize; outMap++)
339  {
340  if (outMap != 0 && outMap % outSize == 0)
341  {
342  batchCount++;
343  outMapIdx = 0;
344  }
345 
346  for (size_t inMap = 0; inMap < inSize; inMap++, outMapIdx++)
347  {
348  arma::Mat<eT> output;
349 
350  if (paddingBackward.PadWLeft() != 0 || paddingBackward.PadWRight() != 0 ||
351  paddingBackward.PadHTop() != 0 || paddingBackward.PadHBottom() != 0)
352  {
353  BackwardConvolutionRule::Convolution(mappedErrorPadded.slice(outMap),
354  weight.slice(outMapIdx), output, strideWidth, strideHeight);
355  }
356  else
357  {
358  BackwardConvolutionRule::Convolution(mappedError.slice(outMap),
359  weight.slice(outMapIdx), output, strideWidth, strideHeight);
360  }
361 
362  gTemp.slice(inMap + batchCount * inSize) += output;
363  }
364  }
365 }
366 
367 template<
368  typename ForwardConvolutionRule,
369  typename BackwardConvolutionRule,
370  typename GradientConvolutionRule,
371  typename InputDataType,
372  typename OutputDataType
373 >
374 template<typename eT>
376  ForwardConvolutionRule,
377  BackwardConvolutionRule,
378  GradientConvolutionRule,
379  InputDataType,
380  OutputDataType
381 >::Gradient(
382  const arma::Mat<eT>& input,
383  const arma::Mat<eT>& error,
384  arma::Mat<eT>& gradient)
385 {
386  arma::Cube<eT> mappedError(((arma::Mat<eT>&) error).memptr(), outputWidth,
387  outputHeight, outSize * batchSize, false, false);
388  arma::cube inputTemp(const_cast<arma::Mat<eT>&>(input).memptr(),
389  inputWidth, inputHeight, inSize * batchSize, false, false);
390 
391  gradient.set_size(weights.n_elem, 1);
392  gradientTemp = arma::Cube<eT>(gradient.memptr(), weight.n_rows,
393  weight.n_cols, weight.n_slices, false, false);
394  gradientTemp.zeros();
395 
396  arma::Mat<eT> inputSlice, output, deltaSlice, rotatedOutput;
397 
398  for (size_t outMap = 0, outMapIdx = 0, batchCount = 0; outMap <
399  outSize * batchSize; outMap++)
400  {
401  if (outMap != 0 && outMap % outSize == 0)
402  {
403  batchCount++;
404  outMapIdx = 0;
405  }
406 
407  deltaSlice = mappedError.slice(outMap);
408 
409  for (size_t inMap = 0; inMap < inSize; inMap++, outMapIdx++)
410  {
411  if (strideWidth > 1 ||
412  strideHeight > 1 ||
413  paddingForward.PadWLeft() != 0 ||
414  paddingForward.PadWRight() != 0 ||
415  paddingForward.PadHTop() != 0 ||
416  paddingForward.PadHBottom() != 0)
417  {
418  inputSlice = inputPaddedTemp.slice(inMap + batchCount * inSize);
419  }
420  else
421  {
422  inputSlice = inputTemp.slice(inMap + batchCount * inSize);
423  }
424 
425  GradientConvolutionRule::Convolution(inputSlice, deltaSlice,
426  output, 1, 1);
427  Rotate180(output, rotatedOutput);
428  gradientTemp.slice(outMapIdx) += rotatedOutput;
429  }
430 
431  gradient.submat(weight.n_elem + (outMap % outSize), 0, weight.n_elem +
432  (outMap % outSize), 0) = arma::accu(mappedError.slices(outMap, outMap));
433  }
434 }
435 
436 template<
437  typename ForwardConvolutionRule,
438  typename BackwardConvolutionRule,
439  typename GradientConvolutionRule,
440  typename InputDataType,
441  typename OutputDataType
442 >
443 template<typename Archive>
445  ForwardConvolutionRule,
446  BackwardConvolutionRule,
447  GradientConvolutionRule,
448  InputDataType,
449  OutputDataType
450 >::serialize(Archive& ar, const uint32_t /* version */)
451 {
452  ar(CEREAL_NVP(inSize));
453  ar(CEREAL_NVP(outSize));
454  ar(CEREAL_NVP(batchSize));
455  ar(CEREAL_NVP(kernelWidth));
456  ar(CEREAL_NVP(kernelHeight));
457  ar(CEREAL_NVP(strideWidth));
458  ar(CEREAL_NVP(strideHeight));
459  ar(CEREAL_NVP(padWLeft));
460  ar(CEREAL_NVP(padWRight));
461  ar(CEREAL_NVP(padHBottom));
462  ar(CEREAL_NVP(padHTop));
463  ar(CEREAL_NVP(inputWidth));
464  ar(CEREAL_NVP(inputHeight));
465  ar(CEREAL_NVP(outputWidth));
466  ar(CEREAL_NVP(outputHeight));
467  ar(CEREAL_NVP(paddingForward));
468  ar(CEREAL_NVP(paddingBackward));
469 
470  if (cereal::is_loading<Archive>())
471  {
472  weights.set_size((outSize * inSize * kernelWidth * kernelHeight) + outSize,
473  1);
474  size_t totalPadWidth = padWLeft + padWRight;
475  size_t totalPadHeight = padHTop + padHBottom;
476  aW = (outputWidth + kernelWidth - totalPadWidth - 2) % strideWidth;
477  aH = (outputHeight + kernelHeight - totalPadHeight - 2) % strideHeight;
478  }
479 }
480 
481 template<
482  typename ForwardConvolutionRule,
483  typename BackwardConvolutionRule,
484  typename GradientConvolutionRule,
485  typename InputDataType,
486  typename OutputDataType
487 >
489  ForwardConvolutionRule,
490  BackwardConvolutionRule,
491  GradientConvolutionRule,
492  InputDataType,
493  OutputDataType
494 >::InitializeSamePadding(){
503  const size_t totalHorizontalPadding = (strideWidth - 1) * inputWidth +
504  kernelWidth - strideWidth;
505  const size_t totalVerticalPadding = (strideHeight - 1) * inputHeight +
506  kernelHeight - strideHeight;
507 
508  padWLeft = totalVerticalPadding / 2;
509  padWRight = totalVerticalPadding - totalVerticalPadding / 2;
510  padHTop = totalHorizontalPadding / 2;
511  padHBottom = totalHorizontalPadding - totalHorizontalPadding / 2;
512 }
513 
514 } // namespace ann
515 } // namespace mlpack
516 
517 #endif
void serialize(Archive &ar, const uint32_t)
Serialize the layer.
Definition: transposed_convolution_impl.hpp:450
static MLPACK_EXPORT util::PrefixedOutStream Fatal
Prints fatal messages prefixed with [FATAL], then terminates the program.
Definition: log.hpp:90
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
Implementation of the Transposed Convolution class.
Definition: layer_types.hpp:188
OutputDataType const & Gradient() const
Get the gradient.
Definition: transposed_convolution.hpp:207
Definition: pointer_wrapper.hpp:23
size_t PadWLeft() const
Get the left padding width.
Definition: padding.hpp:89
size_t PadWRight() const
Get the right padding width.
Definition: padding.hpp:94
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: transposed_convolution_impl.hpp:311
TransposedConvolution()
Create the Transposed Convolution object.
Definition: transposed_convolution_impl.hpp:35
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
size_t WeightSize() const
Get the size of the weight matrix.
Definition: transposed_convolution.hpp:284
size_t PadHTop() const
Get the top padding width.
Definition: padding.hpp:99
size_t PadHBottom() const
Get the bottom padding width.
Definition: padding.hpp:104
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: transposed_convolution_impl.hpp:208