code: def test_resnet_bottleneck():
      with pytest.raises(AssertionError):
          # Style must be in ['pytorch', 'caffe']
          Bottleneck(64, 64, style="tensorflow")
  
      with pytest.raises(AssertionError):
          # Allowed positions are 'after_conv1', 'after_conv2', 'after_conv3'
          plugins = [
              dict(
                  cfg=dict(type="ContextBlock", ratio=1.0 / 16),
                  position="after_conv4",
              )
          ]
          Bottleneck(64, 16, plugins=plugins)
  
      with pytest.raises(AssertionError):
          # Need to specify different postfix to avoid duplicate plugin name
          plugins = [
              dict(
                  cfg=dict(type="ContextBlock", ratio=1.0 / 16),
                  position="after_conv3",
              ),
              dict(
                  cfg=dict(type="ContextBlock", ratio=1.0 / 16),
                  position="after_conv3",
              ),
          ]
          Bottleneck(64, 16, plugins=plugins)
  
      with pytest.raises(KeyError):
          # Plugin type is not supported
          plugins = [
              dict(cfg=dict(type="WrongPlugin"), position="after_conv3")
          ]
          Bottleneck(64, 16, plugins=plugins)
  
      # Test Bottleneck with checkpoint forward
      block = Bottleneck(64, 16, with_cp=True)
      assert block.with_cp
      x = torch.randn(1, 64, 56, 56)
      x_out = block(x)
      assert x_out.shape == torch.Size([1, 64, 56, 56])
  
      # Test Bottleneck style
      block = Bottleneck(64, 64, stride=2, style="pytorch")
      assert block.conv1.stride == (1, 1)
      assert block.conv2.stride == (2, 2)
      block = Bottleneck(64, 64, stride=2, style="caffe")
      assert block.conv1.stride == (2, 2)
      assert block.conv2.stride == (1, 1)
  
      # Test Bottleneck DCN
      dcn = dict(type="DCN", deform_groups=1, fallback_on_stride=False)
      with pytest.raises(AssertionError):
          Bottleneck(64, 64, dcn=dcn, conv_cfg=dict(type="Conv"))
      block = Bottleneck(64, 64, dcn=dcn)
      assert isinstance(block.conv2, DeformConv2dPack)
  
      # Test Bottleneck forward
      block = Bottleneck(64, 16)
      x = torch.randn(1, 64, 56, 56)
      x_out = block(x)
      assert x_out.shape == torch.Size([1, 64, 56, 56])
  
      # Test Bottleneck with 1 ContextBlock after conv3
      plugins = [
          dict(
              cfg=dict(type="ContextBlock", ratio=1.0 / 16),
              position="after_conv3",
          )
      ]
      block = Bottleneck(64, 16, plugins=plugins)
      assert block.context_block.in_channels == 64
      x = torch.randn(1, 64, 56, 56)
      x_out = block(x)
      assert x_out.shape == torch.Size([1, 64, 56, 56])
  
      # Test Bottleneck with 1 GeneralizedAttention after conv2
      plugins = [
          dict(
              cfg=dict(
                  type="GeneralizedAttention",
                  spatial_range=-1,
                  num_heads=8,
                  attention_type="0010",
                  kv_stride=2,
              ),
              position="after_conv2",
          )
      ]
      block = Bottleneck(64, 16, plugins=plugins)
      assert block.gen_attention_block.in_channels == 16
      x = torch.randn(1, 64, 56, 56)
      x_out = block(x)
      assert x_out.shape == torch.Size([1, 64, 56, 56])
  
      # Test Bottleneck with 1 GeneralizedAttention after conv2, 1 NonLocal2D
      # after conv2, 1 ContextBlock after conv3
      plugins = [
          dict(
              cfg=dict(
                  type="GeneralizedAttention",
                  spatial_range=-1,
                  num_heads=8,
                  attention_type="0010",
                  kv_stride=2,
              ),
              position="after_conv2",
          ),
          dict(cfg=dict(type="NonLocal2d"), position="after_conv2"),
          dict(
              cfg=dict(type="ContextBlock", ratio=1.0 / 16),
              position="after_conv3",
          ),
      ]
      block = Bottleneck(64, 16, plugins=plugins)
      assert block.gen_attention_block.in_channels == 16
      assert block.nonlocal_block.in_channels == 16
      assert block.context_block.in_channels == 64
      x = torch.randn(1, 64, 56, 56)
      x_out = block(x)
      assert x_out.shape == torch.Size([1, 64, 56, 56])
  
      # Test Bottleneck with 1 ContextBlock after conv2, 2 ContextBlock after
      # conv3
      plugins = [
          dict(
              cfg=dict(type="ContextBlock", ratio=1.0 / 16, postfix=1),
              position="after_conv2",
          ),
          dict(
              cfg=dict(type="ContextBlock", ratio=1.0 / 16, postfix=2),
              position="after_conv3",
          ),
          dict(
              cfg=dict(type="ContextBlock", ratio=1.0 / 16, postfix=3),
              position="after_conv3",
          ),
      ]
      block = Bottleneck(64, 16, plugins=plugins)
      assert block.context_block1.in_channels == 16
      assert block.context_block2.in_channels == 64
      assert block.context_block3.in_channels == 64
      x = torch.randn(1, 64, 56, 56)
      x_out = block(x)
      assert x_out.shape == torch.Size([1, 64, 56, 56])
  
file_path: mmdetection/tests/test_models/test_backbones/test_resnet.py
imports: import pytest
  import torch
  from mmcv.ops import DeformConv2dPack
  from torch.nn.modules import AvgPool2d, GroupNorm
  from torch.nn.modules.batchnorm import _BatchNorm
  from mmdet.models.backbones import ResNet, ResNetV1d
  from mmdet.models.backbones.resnet import BasicBlock, Bottleneck
  from mmdet.models.layers import ResLayer, SimplifiedBasicBlock
  from .utils import check_norm_state, is_block, is_norm
label_desc: Use image node_id 3 for calling a global function with example usage: test_resnet_bottleneck() without return types