@@ -225,7 +225,8 @@ namespace internal {
225225 const shape2& strides,
226226 padding pad_type,
227227 std::size_t input_shape_height,
228- std::size_t input_shape_width)
228+ std::size_t input_shape_width,
229+ bool transposed)
229230 {
230231 // https://www.tensorflow.org/api_guides/python/nn#Convolution
231232 const int filter_height = static_cast <int >(filter_shape.height_ );
@@ -242,15 +243,27 @@ namespace internal {
242243 out_height = fplus::ceil (static_cast <float >(in_height) / static_cast <float >(strides_y) - 0.001 );
243244 out_width = fplus::ceil (static_cast <float >(in_width) / static_cast <float >(strides_x) - 0.001 );
244245 } else {
245- out_height = fplus::ceil (static_cast <float >(in_height - filter_height + 1 ) / static_cast <float >(strides_y) - 0.001 );
246- out_width = fplus::ceil (static_cast <float >(in_width - filter_width + 1 ) / static_cast <float >(strides_x) - 0.001 );
246+ if (transposed) {
247+ out_height = fplus::ceil (static_cast <float >(in_height + filter_height - 1 ) / static_cast <float >(strides_y) - 0.001 );
248+ out_width = fplus::ceil (static_cast <float >(in_width + filter_width - 1 ) / static_cast <float >(strides_x) - 0.001 );
249+ } else {
250+ out_height = fplus::ceil (static_cast <float >(in_height - filter_height + 1 ) / static_cast <float >(strides_y) - 0.001 );
251+ out_width = fplus::ceil (static_cast <float >(in_width - filter_width + 1 ) / static_cast <float >(strides_x) - 0.001 );
252+ }
247253 }
248254
249255 int pad_top = 0 ;
250256 int pad_bottom = 0 ;
251257 int pad_left = 0 ;
252258 int pad_right = 0 ;
253259
260+ if (transposed) {
261+ pad_top = filter_height - 1 ;
262+ pad_bottom = filter_height - 1 ;
263+ pad_left = filter_width - 1 ;
264+ pad_right = filter_width - 1 ;
265+ }
266+
254267 if (pad_type == padding::same) {
255268 int pad_along_height = 0 ;
256269 int pad_along_width = 0 ;
@@ -296,7 +309,7 @@ namespace internal {
296309
297310 const auto conv_cfg = preprocess_convolution (
298311 filter_mat.filter_shape_ .without_depth (),
299- strides, pad_type, input.shape ().height_ , input.shape ().width_ );
312+ strides, pad_type, input.shape ().height_ , input.shape ().width_ , false );
300313
301314 // The padding step usually (on a VGG19 net) only takes about 1% of the overall runtime.
302315 // So the increased code complexity of doing it inside the convolution step
@@ -312,5 +325,32 @@ namespace internal {
312325 in_padded);
313326 }
314327
328+ inline tensor convolve_transposed (
329+ const shape2& strides,
330+ const padding& pad_type,
331+ const convolution_filter_matrices& filter_mat,
332+ const tensor& input)
333+ {
334+ assertion (filter_mat.filter_shape_ .depth_ == input.shape ().depth_ ,
335+ " invalid filter depth" );
336+
337+ const auto input_dilated = dilate_tensor (strides, input, pad_type == padding::same);
338+
339+ const auto conv_cfg = preprocess_convolution (
340+ filter_mat.filter_shape_ .without_depth (),
341+ shape2 (1 , 1 ), pad_type, input_dilated.shape ().height_ , input_dilated.shape ().width_ ,
342+ true );
343+
344+ const auto in_padded = pad_tensor (0 , 0 , 0 ,
345+ conv_cfg.pad_top_ , conv_cfg.pad_bottom_ , conv_cfg.pad_left_ , conv_cfg.pad_right_ ,
346+ input_dilated);
347+
348+ return convolve_accumulative (
349+ conv_cfg.out_height_ , conv_cfg.out_width_ ,
350+ 1 , 1 ,
351+ filter_mat,
352+ in_padded);
353+ }
354+
315355}
316356}
0 commit comments