| | |
| | from typing import Optional |
| |
|
| | from mmcv.cnn import build_conv_layer, build_norm_layer |
| | from mmengine.model import BaseModule, Sequential |
| | from torch import Tensor |
| | from torch import nn as nn |
| |
|
| | from mmdet.utils import ConfigType, OptConfigType, OptMultiConfig |
| |
|
| |
|
| | class ResLayer(Sequential): |
| | """ResLayer to build ResNet style backbone. |
| | |
| | Args: |
| | block (nn.Module): block used to build ResLayer. |
| | inplanes (int): inplanes of block. |
| | planes (int): planes of block. |
| | num_blocks (int): number of blocks. |
| | stride (int): stride of the first block. Defaults to 1 |
| | avg_down (bool): Use AvgPool instead of stride conv when |
| | downsampling in the bottleneck. Defaults to False |
| | conv_cfg (dict): dictionary to construct and config conv layer. |
| | Defaults to None |
| | norm_cfg (dict): dictionary to construct and config norm layer. |
| | Defaults to dict(type='BN') |
| | downsample_first (bool): Downsample at the first block or last block. |
| | False for Hourglass, True for ResNet. Defaults to True |
| | """ |
| |
|
| | def __init__(self, |
| | block: BaseModule, |
| | inplanes: int, |
| | planes: int, |
| | num_blocks: int, |
| | stride: int = 1, |
| | avg_down: bool = False, |
| | conv_cfg: OptConfigType = None, |
| | norm_cfg: ConfigType = dict(type='BN'), |
| | downsample_first: bool = True, |
| | **kwargs) -> None: |
| | self.block = block |
| |
|
| | downsample = None |
| | if stride != 1 or inplanes != planes * block.expansion: |
| | downsample = [] |
| | conv_stride = stride |
| | if avg_down: |
| | conv_stride = 1 |
| | downsample.append( |
| | nn.AvgPool2d( |
| | kernel_size=stride, |
| | stride=stride, |
| | ceil_mode=True, |
| | count_include_pad=False)) |
| | downsample.extend([ |
| | build_conv_layer( |
| | conv_cfg, |
| | inplanes, |
| | planes * block.expansion, |
| | kernel_size=1, |
| | stride=conv_stride, |
| | bias=False), |
| | build_norm_layer(norm_cfg, planes * block.expansion)[1] |
| | ]) |
| | downsample = nn.Sequential(*downsample) |
| |
|
| | layers = [] |
| | if downsample_first: |
| | layers.append( |
| | block( |
| | inplanes=inplanes, |
| | planes=planes, |
| | stride=stride, |
| | downsample=downsample, |
| | conv_cfg=conv_cfg, |
| | norm_cfg=norm_cfg, |
| | **kwargs)) |
| | inplanes = planes * block.expansion |
| | for _ in range(1, num_blocks): |
| | layers.append( |
| | block( |
| | inplanes=inplanes, |
| | planes=planes, |
| | stride=1, |
| | conv_cfg=conv_cfg, |
| | norm_cfg=norm_cfg, |
| | **kwargs)) |
| |
|
| | else: |
| | for _ in range(num_blocks - 1): |
| | layers.append( |
| | block( |
| | inplanes=inplanes, |
| | planes=inplanes, |
| | stride=1, |
| | conv_cfg=conv_cfg, |
| | norm_cfg=norm_cfg, |
| | **kwargs)) |
| | layers.append( |
| | block( |
| | inplanes=inplanes, |
| | planes=planes, |
| | stride=stride, |
| | downsample=downsample, |
| | conv_cfg=conv_cfg, |
| | norm_cfg=norm_cfg, |
| | **kwargs)) |
| | super().__init__(*layers) |
| |
|
| |
|
| | class SimplifiedBasicBlock(BaseModule): |
| | """Simplified version of original basic residual block. This is used in |
| | `SCNet <https://arxiv.org/abs/2012.10150>`_. |
| | |
| | - Norm layer is now optional |
| | - Last ReLU in forward function is removed |
| | """ |
| | expansion = 1 |
| |
|
| | def __init__(self, |
| | inplanes: int, |
| | planes: int, |
| | stride: int = 1, |
| | dilation: int = 1, |
| | downsample: Optional[Sequential] = None, |
| | style: ConfigType = 'pytorch', |
| | with_cp: bool = False, |
| | conv_cfg: OptConfigType = None, |
| | norm_cfg: ConfigType = dict(type='BN'), |
| | dcn: OptConfigType = None, |
| | plugins: OptConfigType = None, |
| | init_cfg: OptMultiConfig = None) -> None: |
| | super().__init__(init_cfg=init_cfg) |
| | assert dcn is None, 'Not implemented yet.' |
| | assert plugins is None, 'Not implemented yet.' |
| | assert not with_cp, 'Not implemented yet.' |
| | self.with_norm = norm_cfg is not None |
| | with_bias = True if norm_cfg is None else False |
| | self.conv1 = build_conv_layer( |
| | conv_cfg, |
| | inplanes, |
| | planes, |
| | 3, |
| | stride=stride, |
| | padding=dilation, |
| | dilation=dilation, |
| | bias=with_bias) |
| | if self.with_norm: |
| | self.norm1_name, norm1 = build_norm_layer( |
| | norm_cfg, planes, postfix=1) |
| | self.add_module(self.norm1_name, norm1) |
| | self.conv2 = build_conv_layer( |
| | conv_cfg, planes, planes, 3, padding=1, bias=with_bias) |
| | if self.with_norm: |
| | self.norm2_name, norm2 = build_norm_layer( |
| | norm_cfg, planes, postfix=2) |
| | self.add_module(self.norm2_name, norm2) |
| |
|
| | self.relu = nn.ReLU(inplace=True) |
| | self.downsample = downsample |
| | self.stride = stride |
| | self.dilation = dilation |
| | self.with_cp = with_cp |
| |
|
| | @property |
| | def norm1(self) -> Optional[BaseModule]: |
| | """nn.Module: normalization layer after the first convolution layer""" |
| | return getattr(self, self.norm1_name) if self.with_norm else None |
| |
|
| | @property |
| | def norm2(self) -> Optional[BaseModule]: |
| | """nn.Module: normalization layer after the second convolution layer""" |
| | return getattr(self, self.norm2_name) if self.with_norm else None |
| |
|
| | def forward(self, x: Tensor) -> Tensor: |
| | """Forward function for SimplifiedBasicBlock.""" |
| |
|
| | identity = x |
| |
|
| | out = self.conv1(x) |
| | if self.with_norm: |
| | out = self.norm1(out) |
| | out = self.relu(out) |
| |
|
| | out = self.conv2(out) |
| | if self.with_norm: |
| | out = self.norm2(out) |
| |
|
| | if self.downsample is not None: |
| | identity = self.downsample(x) |
| |
|
| | out += identity |
| |
|
| | return out |
| |
|