aten/src/ATen/native/cudnn/Conv.cpp
// Backward and transpose are algorithmically equivalent, but they
// compute their geometry differently.  In a backwards, you knew what
// the original size of the input tensor was, so you can cache that
// geometry and fill it directly.  In transposed convolution, it is
// more conventional to not explicitly specify the output (previously
// input) size, and compute it.  This, however, leaves a degree of
// freedom; this degree of freedom is resolved using the
// output_padding parameter.  Both of these interfaces are equivalent,
// but they are differently convenient depending on the use case.
Backward and transpose are algorithmically equivalent, but they
compute their geometry differently.  In a backwards, you knew what
the original size of the input tensor was, so you can cache that
geometry and fill it directly.  In transposed convolution, it is
more conventional to not explicitly specify the output (previously
input) size, and compute it.  This, however, leaves a degree of
freedom; this degree of freedom is resolved using the
output_padding parameter.  Both of these interfaces are equivalent,
but they are differently convenient depending on the use case.
Backward and transpose are algorithmically equivalent but they compute their geometry differently . In a backwards you knew what the original size of the input tensor was so you can cache that geometry and fill it directly . In transposed convolution it is more conventional to not explicitly specify the output ( previously input ) size and compute it . This however leaves a degree of freedom ; this degree of freedom is resolved using the output_padding parameter . Both of these interfaces are equivalent but they are differently convenient depending on the use case .
Tensor cudnn_convolution_backward_input(
    CheckedFrom c,
    IntList input_size, const TensorArg& grad_output, const TensorArg& weight,
    IntList padding, IntList stride, IntList dilation, int64_t groups,
    bool benchmark, bool deterministic)
{
  checkAllSameType(c, {grad_output, weight});
  checkAllSameGPU(c, {grad_output, weight});
  auto grad_input_t = grad_output->type().tensor(input_size);
  TensorArg grad_input{ grad_input_t, "result", 0 };
  convolution_shape_check(c, grad_input, weight, grad_output, padding, stride, dilation, groups);
  Tensor weight_contig = weight->contiguous();
#if CUDNN_VERSION < 7000
  for (int i = 0; i < groups; i++) {
    raw_cudnn_convolution_backward_input_out(
        narrowGroup(*grad_input, input_channels_dim, i, groups),
        narrowGroup(*grad_output, output_channels_dim, i, groups),
        narrowGroup(weight_contig, weight_output_channels_dim, i, groups),
        padding, stride, dilation, 1, benchmark, deterministic);
  }
#else
  raw_cudnn_convolution_backward_input_out(
      *grad_input, *grad_output, weight_contig,
      padding, stride, dilation, groups, benchmark, deterministic);
#endif
  return *grad_input;
}
Tensor cudnn_convolution_backward_input ( CheckedFrom c , IntList input_size , const TensorArg & grad_output , const TensorArg & weight , IntList padding , IntList stride , IntList dilation , int64_t groups , bool benchmark , bool deterministic ) { checkAllSameType ( c , { grad_output , weight } ) ; checkAllSameGPU ( c , { grad_output , weight } ) ; auto grad_input_t = grad_output -> type ( ) . tensor ( input_size ) ; TensorArg grad_input { grad_input_t , " " , 0 } ; convolution_shape_check ( c , grad_input , weight , grad_output , padding , stride , dilation , groups ) ; Tensor weight_contig = weight -> contiguous ( ) ; #if CUDNN_VERSION < 7000 for ( int i = 0 ; i < groups ; i ++ ) { raw_cudnn_convolution_backward_input_out ( narrowGroup ( * grad_input , input_channels_dim , i , groups ) , narrowGroup ( * grad_output , output_channels_dim , i , groups ) , narrowGroup ( weight_contig , weight_output_channels_dim , i , groups ) , padding , stride , dilation , 1 , benchmark , deterministic ) ; } #else raw_cudnn_convolution_backward_input_out ( * grad_input , * grad_output , weight_contig , padding , stride , dilation , groups , benchmark , deterministic ) ; #endif return * grad_input ; }
Backward and transpose are algorithmically equivalent, but they
compute their geometry differently.
Backward and transpose are algorithmically equivalent but they compute their geometry differently .
// Avoid "grad_input" when this is being used as transposed convolution // See #4500