Pytorch:不支持非正步幅

Pytorch: non-positive stride is not supported

我有一些 MRI 扫描,其中每次扫描都是一组 31 个 RGB 图像。输入数据的维度是(通道、深度、高度、宽度)。图像为 png,每次扫描都是一个包含其 31 个图像的文件夹。

我创建了一个自定义数据集 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)

然后,我创建了一个小型 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

然后,我尝试将一次扫描输入 CNN2 对象:

    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)

但是它产生了这个错误:

---------------------------------------------------------------------------
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

然而,当我刚刚创建一个 Conv3D 对象并传入相同的扫描时,没有错误结果:

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

我认为错误可能与输入数据的维度有关,但我不明白“非正步幅”是什么意思。我也很困惑,为什么当我将数据传递给 Conv3D 对象时没有发生错误,但是当我将相同的数据传递给 CNN class 的实例时却发生错误做同样的事情。

问题不在于您的输入形状,它与您的图层初始化有关。您基本上已经使用此行定义了 3D 卷积:

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

问题是nn.Conv3d函数头如下:

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)

注意 stride 是如何放在 padding 之前的。在您的代码中,变量 padding 最终被分配给 stride 参数。

要解决这个问题,您可以使用关键字参数指定参数名称, padding=padding。这消除了位置参数 stridepadding.

的歧义
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