Pytorch: non-positive stride is not supported

I have some MRI scans, where each scan is a set of 31 RGB images. The dimensions of the input data are (Channels, Depth, Height, Width). The images are png, and each scan is a folder containing its 31 images.

I created a custom Dataset class:

class TrainImages(Dataset):
    def __init__(self, csv_file, root_dir, transform=None):
        self.annotations = pd.read_csv(csv_file)
        self.root_dir = root_dir
        self.transform = transform

    def __len__(self):
        return len(self.annotations)

    def __getitem__(self, index):
        img_path = os.path.join(self.root_dir, str(self.annotations.iloc[index, 0]).zfill(5))
        image = torch.from_numpy(np.array([np.array(Image.open(os.path.join(str(img_path),"rgb-"+str(i)+".png"))) for i in range(31)]).transpose(3,0,1,2).astype(np.float32))
        y_label = torch.tensor(int(self.annotations.iloc[index, 1]))
        
        return (image, y_label)

Then, I created a small 3D CNN class:

class CNN2(nn.Module):
    def __init__(self):
        super(CNN2, self).__init__()        
        self.conv_layer1 = self._conv_layer(3, 12)


    def _conv_layer(self, in_c, out_c, conv_kernel_size=3, padding=0):
        layer = nn.Sequential(
        nn.Conv3d(in_c, out_c, conv_kernel_size, padding),
        )
        
        return layer
    
    
    def forward(self, x):
        out = self.conv_layer1(x)
        
        return out

Then, I tried to feed one scan into the CNN2 object:

    x=torch.unsqueeze(dataset[0][0], 0)
    x.shape #torch.Size([1, 3, 31, 512, 512])
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    data = x.to(device)
    model = CNN2().to(device)
    model(x)

But it produces this error:

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-24-c89306854a22> in <module>
      1 model = CNN_test().to(device)
----> 2 model(x)

/opt/conda/lib/python3.7/site-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
    725             result = self._slow_forward(*input, **kwargs)
    726         else:
--> 727             result = self.forward(*input, **kwargs)
    728         for hook in itertools.chain(
    729                 _global_forward_hooks.values(),

<ipython-input-22-ac66ca7a2459> in forward(self, x)
     14 
     15     def forward(self, x):
---> 16         out = self.conv_layer1(x)
     17 
     18         return out

/opt/conda/lib/python3.7/site-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
    725             result = self._slow_forward(*input, **kwargs)
    726         else:
--> 727             result = self.forward(*input, **kwargs)
    728         for hook in itertools.chain(
    729                 _global_forward_hooks.values(),

/opt/conda/lib/python3.7/site-packages/torch/nn/modules/container.py in forward(self, input)
    115     def forward(self, input):
    116         for module in self:
--> 117             input = module(input)
    118         return input
    119 

/opt/conda/lib/python3.7/site-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
    725             result = self._slow_forward(*input, **kwargs)
    726         else:
--> 727             result = self.forward(*input, **kwargs)
    728         for hook in itertools.chain(
    729                 _global_forward_hooks.values(),

/opt/conda/lib/python3.7/site-packages/torch/nn/modules/conv.py in forward(self, input)
    571                             self.dilation, self.groups)
    572         return F.conv3d(input, self.weight, self.bias, self.stride,
--> 573                         self.padding, self.dilation, self.groups)
    574 
    575 

RuntimeError: non-positive stride is not supported

However, when I just create a Conv3D object and pass the same scan in, no error results:

x=torch.unsqueeze(dataset[0][0], 0)
m=nn.Conv3d(3,12,3)
out=m(x)

I think the error might have to do with the dimensions of the input data, but I don’t understand what “non-positive stride” means. I’m also confused why no error occurs when I just pass the data into a Conv3D object, but an error occurs when I pass the same data into an instance of the CNN class that does the same thing.

Answer

The issue is not with your input shape, it has to do with your layer initialization. You have essentially defined your 3D convolution with this line:

nn.Conv3d(in_c, out_c, conv_kernel_size, padding)

The issue is nn.Conv3d function head is the following:

torch.nn.Conv3d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros', device=None, dtype=None)

Notice how stride is placed before padding. In your code, variable padding ends up being assigned to the stride argument.

To solve the issue, you can specify the argument name with a keyword argument, i.e. padding=padding. This disambiguates the issue with positional arguments stride and padding.

class CNN2(nn.Module):
    def __init__(self):
        super(CNN2, self).__init__()        
        self.conv_layer1 = self._conv_layer(3, 12)

    def _conv_layer(self, in_c, out_c, conv_kernel_size=3, padding=0):
        layer = nn.Sequential(
          nn.Conv3d(in_c, out_c, conv_kernel_size, padding=padding))
        return layer
    
    def forward(self, x):
        out = self.conv_layer1(x)
        return out