Can you combine 3d and 2d convolutions in the same network?

I am trying to train a custom network in which there is a combination of 2D and 3D convolutional layers.
I am getting an RuntimeError: cuDNN error: CUDNN_STATUS_INTERNAL_ERROR error when loss.backward() is computed.

loss.backward()
File “/usr/local/lib/python3.7/site-packages/torch/tensor.py”, line 166, in backward
torch.autograd.backward(self, gradient, retain_graph, create_graph)
File “/usr/local/lib/python3.7/site-packages/torch/autograd/init.py”, line 99, in backward
allow_unreachable=True) # allow_unreachable flag
RuntimeError: cuDNN error: CUDNN_STATUS_INTERNAL_ERROR

Is this because there is a problem with backward gradient computation when combining 3d and 2D conv layers or should I look for a problem somewhere else?

If I set torch.backends.cudnn.enabled = False nothing changes .

Had no issues with it on an Nvidia 3090 RTX GPU with a modified UNet that has two branches, one for 2d and one for 3d here:

Can you post your model?

1 Like

class ResNet(nn.Module):
def init(self, dataset, depth, num_classes, bottleneck=False):
super(ResNet, self).init()
self.dataset = dataset

  blocks ={18: BasicBlock, 34: BasicBlock, 50: Bottleneck, 101: Bottleneck, 152: Bottleneck, 200: Bottleneck}
  layers ={18: [2, 2, 2, 2], 34: [3, 4, 6, 3], 50: [3, 4, 6, 3], 101: [3, 4, 23, 3], 152: [3, 8, 36, 3], 200: [3, 24, 36, 3]}
  assert layers[depth], 'invalid detph for ResNet (depth should be one of 18, 34, 50, 101, 152, and 200)'

  self.inplanes = 64
  self.conv1_3d = nn.Conv3d(3, self.inplanes, kernel_size=3, stride=1, padding=1, bias=False)
  self.aveadpool1_3d = nn.AdaptiveAvgPool3d((128,128,1))
  self.conv1 = nn.Conv2d(self.inplanes, self.inplanes, kernel_size=7, stride=2, padding=3, bias=False)
  self.bn1 = nn.BatchNorm2d(64)
  self.relu = nn.ReLU(inplace=True)
  self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
  self.layer1 = self._make_layer(blocks[depth], 64, layers[depth][0])
  self.layer2 = self._make_layer(blocks[depth], 128, layers[depth][1], stride=2)
  self.dropout20 = nn.Dropout(p=0.2)
  self.layer3 = self._make_layer(blocks[depth], 256, layers[depth][2], stride=2)
  self.dropout30 = nn.Dropout(p=0.3)
  self.layer4 = self._make_layer(blocks[depth], 512, layers[depth][3], stride=2)
  self.dropout40 = nn.Dropout(p=0.4)
  

  # self.avgpool = nn.AvgPool2d(7)
  self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
  self.dropout50 = nn.Dropout(p=0.5)
  self.fc = nn.Linear(512 * blocks[depth].expansion, num_classes)
    for m in self.modules():
        if isinstance(m, nn.Conv2d):
            n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
            m.weight.data.normal_(0, math.sqrt(2. / n))
        if isinstance(m, nn.Conv3d):
            n = m.kernel_size[0] * m.kernel_size[1] *m.kernel_size[2]* m.out_channels
            m.weight.data.normal_(0, math.sqrt(2. / n))
        elif isinstance(m, nn.BatchNorm2d):
            m.weight.data.fill_(1)
            m.bias.data.zero_()

def _make_layer(self, block, planes, blocks, stride=1):
    downsample = None
    if stride != 1 or self.inplanes != planes * block.expansion:
        downsample = nn.Sequential(
            nn.Conv2d(self.inplanes, planes * block.expansion,
                      kernel_size=1, stride=stride, bias=False),
            nn.BatchNorm2d(planes * block.expansion),
        )

    layers = []
    layers.append(block(self.inplanes, planes, stride, downsample))
    self.inplanes = planes * block.expansion
    for i in range(1, blocks):
        layers.append(block(self.inplanes, planes))

    return nn.Sequential(*layers)

def forward(self, x):
    
  x = self.conv1_3d(x)
  x = self.aveadpool1_3d(x)
  x = torch.squeeze(x, -1)
  x = self.conv1(x)
  x = self.bn1(x)
  x = self.relu(x)
  x = self.maxpool(x)

  x = self.layer1(x)
  x = self.layer2(x)
  #x = self.dropout20(x)
  x = self.layer3(x)
  #x = self.dropout30(x)
  x = self.layer4(x)
  #x = self.dropout40(x)
  
  x = self.avgpool(x)
  x = self.dropout50(x)
  x = x.view(x.size(0), -1)
  x = self.fc(x)


    return x

Your self.conv1 layer looks like the suspect. Or at least a culprit.

self.conv1 = nn.Conv2d(self.inplanes, self.inplanes, kernel_size=7, stride=2, padding=3, bias=False)

You have size 128, 128 going in. With a stride of 2, you end up with 127/2 and that doesn’t yield an integer.

1 Like

I updated my version of pytorch to 1.10 and it started working.