| 47 | |
| 48 | class BottleneckBlock(nn.Module): |
| 49 | def __init__(self, in_channels, out_channels, stride=1, expansion=4): |
| 50 | super().__init__() |
| 51 | mid_channels = out_channels // expansion |
| 52 | |
| 53 | self.conv1 = ConvBlock(in_channels, mid_channels, kernel_size=1, padding=0) |
| 54 | self.conv2 = ConvBlock(mid_channels, mid_channels, kernel_size=3, stride=stride, padding=1) |
| 55 | self.conv3 = ConvBlock(mid_channels, out_channels, kernel_size=1, padding=0, activation='none') |
| 56 | |
| 57 | self.shortcut = nn.Sequential() |
| 58 | if stride != 1 or in_channels != out_channels: |
| 59 | self.shortcut = nn.Sequential( |
| 60 | nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False), |
| 61 | nn.BatchNorm2d(out_channels) |
| 62 | ) |
| 63 | |
| 64 | self.activation = nn.ReLU(inplace=True) |
| 65 | |
| 66 | def forward(self, x): |
| 67 | residual = self.shortcut(x) |