code: import torch.nn as nn
  import torch.utils.checkpoint as cp
  from mmcv.cnn import constant_init, kaiming_init
  from mmcv.runner import load_checkpoint
  from torch.nn.modules.batchnorm import _BatchNorm
  
  from openselfsup.utils import get_root_logger
  from ..registry import BACKBONES
  from ..utils import build_conv_layer, build_norm_layer
  
  
  class BasicBlock(nn.Module):
      expansion = 1
  
      def __init__(self,
                   inplanes,
                   planes,
                   stride=1,
                   dilation=1,
                   downsample=None,
                   style='pytorch',
                   with_cp=False,
                   conv_cfg=None,
                   norm_cfg=dict(type='BN')):
          super(BasicBlock, self).__init__()
  
          self.norm1_name, norm1 = build_norm_layer(norm_cfg, planes, postfix=1)
          self.norm2_name, norm2 = build_norm_layer(norm_cfg, planes, postfix=2)
  
          self.conv1 = build_conv_layer(
              conv_cfg,
              inplanes,
              planes,
              3,
              stride=stride,
              padding=dilation,
              dilation=dilation,
              bias=False)
          self.add_module(self.norm1_name, norm1)
          self.conv2 = build_conv_layer(
              conv_cfg, planes, planes, 3, padding=1, bias=False)
          self.add_module(self.norm2_name, norm2)
  
          self.relu = nn.ReLU(inplace=True)
          self.downsample = downsample
          self.stride = stride
          self.dilation = dilation
          assert not with_cp
  
      @property
      def norm1(self):
          return getattr(self, self.norm1_name)
  
      @property
      def norm2(self):
          return getattr(self, self.norm2_name)
  
      def forward(self, x):
          identity = x
  
          out = self.conv1(x)
          out = self.norm1(out)
          out = self.relu(out)
  
          out = self.conv2(out)
          out = self.norm2(out)
  
          if self.downsample is not None:
              identity = self.downsample(x)
  
          out += identity
          out = self.relu(out)
  
          return out
  
  
  class Bottleneck(nn.Module):
      expansion = 4
  
      def __init__(self,
                   inplanes,
                   planes,
                   stride=1,
                   dilation=1,
                   downsample=None,
                   style='pytorch',
                   with_cp=False,
                   conv_cfg=None,
                   norm_cfg=dict(type='BN')):
          """Bottleneck block for ResNet.
          If style is "pytorch", the stride-two layer is the 3x3 conv layer,
          if it is "caffe", the stride-two layer is the first 1x1 conv layer.
          """
          super(Bottleneck, self).__init__()
          assert style in ['pytorch', 'caffe']
  
          self.inplanes = inplanes
          self.planes = planes
          self.stride = stride
          self.dilation = dilation
          self.style = style
          self.with_cp = with_cp
          self.conv_cfg = conv_cfg
          self.norm_cfg = norm_cfg
  
          if self.style == 'pytorch':
              self.conv1_stride = 1
              self.conv2_stride = stride
          else:
              self.conv1_stride = stride
              self.conv2_stride = 1
  
          self.norm1_name, norm1 = build_norm_layer(norm_cfg, planes, postfix=1)
          self.norm2_name, norm2 = build_norm_layer(norm_cfg, planes, postfix=2)
          self.norm3_name, norm3 = build_norm_layer(
              norm_cfg, planes * self.expansion, postfix=3)
  
          self.conv1 = build_conv_layer(
              conv_cfg,
              inplanes,
              planes,
              kernel_size=1,
              stride=self.conv1_stride,
              bias=False)
          self.add_module(self.norm1_name, norm1)
          self.conv2 = build_conv_layer(
              conv_cfg,
              planes,
              planes,
              kernel_size=3,
              stride=self.conv2_stride,
              padding=dilation,
              dilation=dilation,
              bias=False)
          self.add_module(self.norm2_name, norm2)
          self.conv3 = build_conv_layer(
              conv_cfg,
              planes,
              planes * self.expansion,
              kernel_size=1,
              bias=False)
          self.add_module(self.norm3_name, norm3)
  
          self.relu = nn.ReLU(inplace=True)
          self.downsample = downsample
  
      @property
      def norm1(self):
          return getattr(self, self.norm1_name)
  
      @property
      def norm2(self):
          return getattr(self, self.norm2_name)
  
      @property
      def norm3(self):
          return getattr(self, self.norm3_name)
  
      def forward(self, x):
  
          def _inner_forward(x):
              identity = x
  
              out = self.conv1(x)
              out = self.norm1(out)
              out = self.relu(out)
  
              out = self.conv2(out)
              out = self.norm2(out)
              out = self.relu(out)
  
              out = self.conv3(out)
              out = self.norm3(out)
  
              if self.downsample is not None:
                  identity = self.downsample(x)
  
              out += identity
  
              return out
  
          if self.with_cp and x.requires_grad:
              out = cp.checkpoint(_inner_forward, x)
          else:
              out = _inner_forward(x)
  
          out = self.relu(out)
  
          return out
  
  
  def make_res_layer(block,
                     inplanes,
                     planes,
                     blocks,
                     stride=1,
                     dilation=1,
                     style='pytorch',
                     with_cp=False,
                     conv_cfg=None,
                     norm_cfg=dict(type='BN')):
      downsample = None
      if stride != 1 or inplanes != planes * block.expansion:
          downsample = nn.Sequential(
              build_conv_layer(
                  conv_cfg,
                  inplanes,
                  planes * block.expansion,
                  kernel_size=1,
                  stride=stride,
                  bias=False),
              build_norm_layer(norm_cfg, planes * block.expansion)[1],
          )
  
      layers = []
      layers.append(
          block(
              inplanes=inplanes,
              planes=planes,
              stride=stride,
              dilation=dilation,
              downsample=downsample,
              style=style,
              with_cp=with_cp,
              conv_cfg=conv_cfg,
              norm_cfg=norm_cfg))
      inplanes = planes * block.expansion
      for i in range(1, blocks):
          layers.append(
              block(
                  inplanes=inplanes,
                  planes=planes,
                  stride=1,
                  dilation=dilation,
                  style=style,
                  with_cp=with_cp,
                  conv_cfg=conv_cfg,
                  norm_cfg=norm_cfg))
  
      return nn.Sequential(*layers)
  
  
  @BACKBONES.register_module
  class ResNet(nn.Module):
      """ResNet backbone.
  
      Args:
          depth (int): Depth of resnet, from {18, 34, 50, 101, 152}.
          in_channels (int): Number of input image channels. Normally 3.
          num_stages (int): Resnet stages, normally 4.
          strides (Sequence[int]): Strides of the first block of each stage.
          dilations (Sequence[int]): Dilation of each stage.
          out_indices (Sequence[int]): Output from which stages.
          style (str): `pytorch` or `caffe`. If set to "pytorch", the stride-two
              layer is the 3x3 conv layer, otherwise the stride-two layer is
              the first 1x1 conv layer.
          frozen_stages (int): Stages to be frozen (stop grad and set eval mode).
              -1 means not freezing any parameters.
          norm_cfg (dict): dictionary to construct and config norm layer.
          norm_eval (bool): Whether to set norm layers to eval mode, namely,
              freeze running stats (mean and var). Note: Effect on Batch Norm
              and its variants only.
          with_cp (bool): Use checkpoint or not. Using checkpoint will save some
              memory while slowing down the training speed.
          zero_init_residual (bool): whether to use zero init for last norm layer
              in resblocks to let them behave as identity.
  
      Example:
          >>> from openselfsup.models import ResNet
          >>> import torch
          >>> self = ResNet(depth=18)
          >>> self.eval()
          >>> inputs = torch.rand(1, 3, 32, 32)
          >>> level_outputs = self.forward(inputs)
          >>> for level_out in level_outputs:
          ...     print(tuple(level_out.shape))
          (1, 64, 8, 8)
          (1, 128, 4, 4)
          (1, 256, 2, 2)
          (1, 512, 1, 1)
      """
  
      arch_settings = {
          18: (BasicBlock, (2, 2, 2, 2)),
          34: (BasicBlock, (3, 4, 6, 3)),
          50: (Bottleneck, (3, 4, 6, 3)),
          101: (Bottleneck, (3, 4, 23, 3)),
          152: (Bottleneck, (3, 8, 36, 3))
      }
  
      def __init__(self,
                   depth,
                   in_channels=3,
                   num_stages=4,
                   strides=(1, 2, 2, 2),
                   dilations=(1, 1, 1, 1),
                   out_indices=(0, 1, 2, 3, 4),
                   style='pytorch',
                   frozen_stages=-1,
                   conv_cfg=None,
                   norm_cfg=dict(type='BN', requires_grad=True),
                   norm_eval=False,
                   with_cp=False,
                   zero_init_residual=False):
          super(ResNet, self).__init__()
          if depth not in self.arch_settings:
              raise KeyError('invalid depth {} for resnet'.format(depth))
          self.depth = depth
          self.num_stages = num_stages
          assert num_stages >= 1 and num_stages <= 4
          self.strides = strides
          self.dilations = dilations
          assert len(strides) == len(dilations) == num_stages
          self.out_indices = out_indices
          assert max(out_indices) < num_stages + 1
          self.style = style
          self.frozen_stages = frozen_stages
          self.conv_cfg = conv_cfg
          self.norm_cfg = norm_cfg
          self.with_cp = with_cp
          self.norm_eval = norm_eval
          self.zero_init_residual = zero_init_residual
          self.block, stage_blocks = self.arch_settings[depth]
          self.stage_blocks = stage_blocks[:num_stages]
          self.inplanes = 64
  
          self._make_stem_layer(in_channels)
  
          self.res_layers = []
          for i, num_blocks in enumerate(self.stage_blocks):
              stride = strides[i]
              dilation = dilations[i]
              planes = 64 * 2**i
              res_layer = make_res_layer(
                  self.block,
                  self.inplanes,
                  planes,
                  num_blocks,
                  stride=stride,
                  dilation=dilation,
                  style=self.style,
                  with_cp=with_cp,
                  conv_cfg=conv_cfg,
                  norm_cfg=norm_cfg)
              self.inplanes = planes * self.block.expansion
              layer_name = 'layer{}'.format(i + 1)
              self.add_module(layer_name, res_layer)
              self.res_layers.append(layer_name)
  
          self._freeze_stages()
  
          self.feat_dim = self.block.expansion * 64 * 2**(
              len(self.stage_blocks) - 1)
  
      @property
      def norm1(self):
          return getattr(self, self.norm1_name)
  
      def _make_stem_layer(self, in_channels):
          self.conv1 = build_conv_layer(
              self.conv_cfg,
              in_channels,
              64,
              kernel_size=7,
              stride=2,
              padding=3,
              bias=False)
          self.norm1_name, norm1 = build_norm_layer(self.norm_cfg, 64, postfix=1)
          self.add_module(self.norm1_name, norm1)
          self.relu = nn.ReLU(inplace=True)
          self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
  
      def _freeze_stages(self):
          if self.frozen_stages >= 0:
              self.norm1.eval()
              for m in [self.conv1, self.norm1]:
                  for param in m.parameters():
                      param.requires_grad = False
  
          for i in range(1, self.frozen_stages + 1):
              m = getattr(self, 'layer{}'.format(i))
              m.eval()
              for param in m.parameters():
                  param.requires_grad = False
  
      def init_weights(self, pretrained=None):
          if isinstance(pretrained, str):
              logger = get_root_logger()
              load_checkpoint(self, pretrained, strict=True, logger=logger)
          elif pretrained is None:
              for m in self.modules():
                  if isinstance(m, nn.Conv2d):
                      kaiming_init(m, mode='fan_in', nonlinearity='relu')
                  elif isinstance(m, (_BatchNorm, nn.GroupNorm)):
                      constant_init(m, 1)
  
              if self.zero_init_residual:
                  for m in self.modules():
                      if isinstance(m, Bottleneck):
                          constant_init(m.norm3, 0)
                      elif isinstance(m, BasicBlock):
                          constant_init(m.norm2, 0)
          else:
              raise TypeError('pretrained must be a str or None')
  
      def forward(self, x):
          outs = []
          x = self.conv1(x)
          x = self.norm1(x)
          x = self.relu(x)  # r50: 64x128x128
          if 0 in self.out_indices:
              outs.append(x)
          x = self.maxpool(x)  # r50: 64x56x56
          for i, layer_name in enumerate(self.res_layers):
              res_layer = getattr(self, layer_name)
              x = res_layer(x)
              if i + 1 in self.out_indices:
                  outs.append(x)
          # r50: 1-256x56x56; 2-512x28x28; 3-1024x14x14; 4-2048x7x7
          return tuple(outs)
  
      def train(self, mode=True):
          super(ResNet, self).train(mode)
          self._freeze_stages()
          if mode and self.norm_eval:
              for m in self.modules():
                  # trick: eval have effect on BatchNorm only
                  if isinstance(m, _BatchNorm):
                      m.eval()
  
apis: torch.nn.MaxPool2d torch.utils.checkpoint.checkpoint torch.nn.ReLU torch.nn.Sequential