Repository: pytorch/pytorch

Issue:
output_padding argument is ignored in deconvolution, leading to cudnn errors
The following snippet produces an error in deconvolution:
```.py
import torch
import torch.nn as nn
from torch.autograd import Variable

conv = nn.Conv3d(1,8, kernel_size=3, padding=1, stride = 2)
conv = conv.cuda()
deconv = nn.ConvTranspose3d(8,1, kernel_size=3, stride=2, output_padding=-1)
deconv = deconv.cuda()

x = Variable(torch.randn(8,1,64,64,64).cuda(), requires_grad=True)
#ok
for i in range(10):
    out = conv(x)
    err = out.sum()
    err.backward()

print("deconv")

#error
x = Variable(torch.randn(8,8,32,32,32).cuda(), requires_grad=True)

for i in range(10):
    out = deconv(x)
    err = out.sum()
    err.backward()
```
The issue is, in the deconvolution case padding is not passed to convolution descriptor, ltraces for the failing and passing cudnnGetConvolutionBackwardDataAlgorithm below, padding is 1 for passing and 0 for failing. 
```
[pid 21910] _C.cpython-35m-x86_64-linux-gnu.so->cudnnGetConvolutionBackwardDataAlgorithm(0xffff7fffffff, { CUDNN_DATA_FLOAT, 0, [ 5, 8, 1, 3... ], CUDNN_TENSOR_NCHW }, { CUDNN_DATA_FLOAT, 0, 5, [ 2097152, 0, 8, 8... ], [ 0, 0, 262144, 32768... ] }, { CUDNN_CROSS_CORRELATION, CUDNN_DATA_FLOAT, 3, [ 0, 0, 0, 0... ], [ 2, 2, 2, 0... ], [ 1, 1, 1, 0... ] }, { CUDNN_DATA_FLOAT, 0, 5, [ 2097152, 0, 8, 1... ], [ 0, 0, 262144, 262144... ] }, 1, 0, 0 <unfinished ...>
[pid 21917] _C.cpython-35m-x86_64-linux-gnu.so->cudnnGetConvolutionBackwardDataAlgorithm(0xffff7fffffff, { CUDNN_DATA_FLOAT, 0, [ 5, 8, 1, 3... ], CUDNN_TENSOR_NCHW }, { CUDNN_DATA_FLOAT, 0, 5, [ 2097152, 0, 8, 8... ], [ 0, 0, 262144, 32768... ] }, { CUDNN_CROSS_CORRELATION, CUDNN_DATA_FLOAT, 3, [ 1, 1, 1, 0... ], [ 2, 2, 2, 0... ], [ 1, 1, 1, 0... ] }, { CUDNN_DATA_FLOAT, 0, 5, [ 2097152, 0, 8, 1... ], [ 0, 0, 262144, 262144... ] }, 1, 0, 0 <unfinished ...>
```
Also, there seems to be no way of disabling cudnn at runtime, torch.backends.cudnn.enabled is no longer checked for convolutions: https://github.com/pytorch/pytorch/blob/master/torch/csrc/autograd/functions/convolution.cpp#L108-L110


Discussion:
It turns out that cudnn breaks only for negative values of output_padding. While I certainly could add checks for that, does that mean that regular padding should be checked for negative values too? Cudnn would break in this case also (regular padding being negative), and no checks are performed currently. @albanD, @abweiss, how common is negative padding in transposed convolutions?
yes, could you add negative checks for regular padding too, thank you.
In transposed convolutions, negative padding is common (i wouldn't say fairly common)

Resolving patch:
diff --git a/torch/nn/functional.py b/torch/nn/functional.py
--- a/torch/nn/functional.py
+++ b/torch/nn/functional.py
@@ -35,7 +35,7 @@ def conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1,
         >>> F.conv2d(inputs, filters, padding=1)
     """
     f = ConvNd(_pair(stride), _pair(padding), _pair(dilation), False,
-               _pair(0), groups, torch.backends.cudnn.benchmark)
+               _pair(0), groups, torch.backends.cudnn.benchmark, torch.backends.cudnn.enabled)
     return f(input, weight, bias)
 
 
@@ -58,7 +58,7 @@ def conv1d(input, weight, bias=None, stride=1, padding=0, dilation=1,
         >>> F.conv1d(inputs, filters)
     """
     f = ConvNd(_single(stride), _single(padding), _single(dilation), False,
-               _single(0), groups, torch.backends.cudnn.benchmark)
+               _single(0), groups, torch.backends.cudnn.benchmark, torch.backends.cudnn.enabled)
     return f(input, weight, bias)
 
 
@@ -84,14 +84,14 @@ def conv3d(input, weight, bias=None, stride=1, padding=0, dilation=1,
         >>> F.conv3d(inputs, filters)
     """
     f = ConvNd(_triple(stride), _triple(padding), _triple(dilation), False,
-               _triple(0), groups, torch.backends.cudnn.benchmark)
+               _triple(0), groups, torch.backends.cudnn.benchmark, torch.backends.cudnn.enabled)
     return f(input, weight, bias)
 
 
 def conv_transpose1d(input, weight, bias=None, stride=1, padding=0,
                      output_padding=0, groups=1):
     f = ConvNd(_single(stride), _single(padding), _single(1), True,
-               _single(output_padding), groups, torch.backends.cudnn.benchmark)
+               _single(output_padding), groups, torch.backends.cudnn.benchmark, torch.backends.cudnn.enabled)
     return f(input, weight, bias)
 
 
@@ -116,7 +116,7 @@ def conv_transpose2d(input, weight, bias=None, stride=1, padding=0,
           added to the output. Can be a single number or a tuple. Default: 0
     """
     f = ConvNd(_pair(stride), _pair(padding), _pair(1), True,
-               _pair(output_padding), groups, torch.backends.cudnn.benchmark)
+               _pair(output_padding), groups, torch.backends.cudnn.benchmark, torch.backends.cudnn.enabled)
     return f(input, weight, bias)
 
 
@@ -137,7 +137,7 @@ def conv_transpose3d(input, weight, bias=None, stride=1, padding=0,
           tuple (padh x padw). Default: 0
     """
     f = ConvNd(_triple(stride), _triple(padding), _triple(1), True,
-               _triple(output_padding), groups, torch.backends.cudnn.benchmark)
+               _triple(output_padding), groups, torch.backends.cudnn.benchmark, torch.backends.cudnn.enabled)
     return f(input, weight, bias)
 
 
@@ -385,7 +385,7 @@ def linear(input, weight, bias=None):
 
 def batch_norm(input, running_mean, running_var, weight=None, bias=None,
                training=False, momentum=0.1, eps=1e-5):
-    f = torch._C._functions.BatchNorm(running_mean, running_var, training, momentum, eps)
+    f = torch._C._functions.BatchNorm(running_mean, running_var, training, momentum, eps, torch.backends.cudnn.enabled)
     return f(input, weight, bias)
 
 


Test patch: