Repository: open-mmlab/mmcv

Issue:
DetectoRS don't support pytorch version>=1.5
> 
  File "/jizhi/jizhi2/worker/trainer/mmdet/models/backbones/resnet.py", line 632, in forward
    x = res_layer(x)
  File "/usr/local/lib64/python3.6/site-packages/torch/nn/modules/module.py", line 722, in _call_impl
    result = self.forward(*input, **kwargs)
  File "/usr/local/lib64/python3.6/site-packages/torch/nn/modules/container.py", line 117, in forward
    input = module(input)
  File "/usr/local/lib64/python3.6/site-packages/torch/nn/modules/module.py", line 722, in _call_impl
    result = self.forward(*input, **kwargs)
  File "/jizhi/jizhi2/worker/trainer/mmdet/models/backbones/resnet.py", line 296, in forward
    out = _inner_forward(x)
  File "/jizhi/jizhi2/worker/trainer/mmdet/models/backbones/resnet.py", line 273, in _inner_forward
    out = self.conv2(out)
  File "/usr/local/lib64/python3.6/site-packages/torch/nn/modules/module.py", line 722, in _call_impl
    result = self.forward(*input, **kwargs)
  File "/usr/local/lib64/python3.6/site-packages/mmcv/ops/saconv.py", line 105, in forward
    out_s = super().conv2d_forward(x, weight)
AttributeError: 'super' object has no attribute 'conv2d_forward'

This is a PyTorch version problem, the PyTorch 1.5 has changed its internal API.


Discussion:
Thanks for reporting the error. `conv2d_forward` is changed to `_conv_forward` in latest versions of pytorch.
Would you like to create a pr to fix that?

Resolving patch:
diff --git a/mmcv/ops/saconv.py b/mmcv/ops/saconv.py
--- a/mmcv/ops/saconv.py
+++ b/mmcv/ops/saconv.py
@@ -4,6 +4,7 @@
 
 from mmcv.cnn import CONV_LAYERS, ConvAWS2d, constant_init
 from mmcv.ops.deform_conv import deform_conv2d
+from mmcv.utils import TORCH_VERSION
 
 
 @CONV_LAYERS.register_module(name='SAC')
@@ -102,7 +103,10 @@ def forward(self, x):
             out_s = deform_conv2d(x, offset, weight, self.stride, self.padding,
                                   self.dilation, self.groups, 1)
         else:
-            out_s = super().conv2d_forward(x, weight)
+            if TORCH_VERSION < '1.5.0' or TORCH_VERSION == 'parrots':
+                out_s = super().conv2d_forward(x, weight)
+            else:
+                out_s = super()._conv_forward(x, weight)
         ori_p = self.padding
         ori_d = self.dilation
         self.padding = tuple(3 * p for p in self.padding)
@@ -113,7 +117,10 @@ def forward(self, x):
             out_l = deform_conv2d(x, offset, weight, self.stride, self.padding,
                                   self.dilation, self.groups, 1)
         else:
-            out_l = super().conv2d_forward(x, weight)
+            if TORCH_VERSION < '1.5.0' or TORCH_VERSION == 'parrots':
+                out_l = super().conv2d_forward(x, weight)
+            else:
+                out_l = super()._conv_forward(x, weight)
         out = switch * out_s + (1 - switch) * out_l
         self.padding = ori_p
         self.dilation = ori_d


Test patch:
diff --git a/tests/test_ops/test_saconv.py b/tests/test_ops/test_saconv.py
new file mode 100644
--- /dev/null
+++ b/tests/test_ops/test_saconv.py
@@ -0,0 +1,46 @@
+import pytest
+import torch
+import torch.nn as nn
+
+from mmcv.ops import SAConv2d
+
+
+def test_sacconv():
+
+    # test with normal cast
+    x = torch.rand(1, 3, 256, 256)
+    saconv = SAConv2d(3, 5, kernel_size=3, padding=1)
+    sac_out = saconv(x)
+    refer_conv = nn.Conv2d(3, 5, kernel_size=3, padding=1)
+    refer_out = refer_conv(x)
+    assert sac_out.shape == refer_out.shape
+
+    # test with dilation >= 2
+    dalited_saconv = SAConv2d(3, 5, kernel_size=3, padding=2, dilation=2)
+    dalited_sac_out = dalited_saconv(x)
+    refer_conv = nn.Conv2d(3, 5, kernel_size=3, padding=2, dilation=2)
+    refer_out = refer_conv(x)
+    assert dalited_sac_out.shape == refer_out.shape
+
+    # test with deform
+    deform_saconv = SAConv2d(3, 5, kernel_size=3, padding=1, use_deform=True)
+    if torch.cuda.is_available():
+        x = torch.rand(1, 3, 256, 256).cuda()
+        deform_saconv = SAConv2d(
+            3, 5, kernel_size=3, padding=1, use_deform=True).cuda()
+        deform_sac_out = deform_saconv(x).cuda()
+        refer_conv = nn.Conv2d(3, 5, kernel_size=3, padding=1).cuda()
+        refer_out = refer_conv(x)
+        assert deform_sac_out.shape == refer_out.shape
+    else:
+        with pytest.raises(RuntimeError):
+            # deform conv is not implemented on cpu
+            deform_saconv(x)
+
+    # test with groups >= 2
+    x = torch.rand(1, 4, 256, 256)
+    group_saconv = SAConv2d(4, 4, kernel_size=3, padding=1, groups=2)
+    group_sac_out = group_saconv(x)
+    refer_conv = nn.Conv2d(4, 4, kernel_size=3, padding=1, groups=2)
+    refer_out = refer_conv(x)
+    assert group_sac_out.shape == refer_out.shape