| 44 | |
| 45 | |
| 46 | class GhostModule(nn.Module): |
| 47 | def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True): |
| 48 | super(GhostModule, self).__init__() |
| 49 | self.oup = oup |
| 50 | init_channels = math.ceil(oup / ratio) |
| 51 | new_channels = init_channels * (ratio - 1) |
| 52 | |
| 53 | self.primary_conv = nn.Sequential( |
| 54 | nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False), |
| 55 | nn.BatchNorm2d(init_channels), |
| 56 | nn.ReLU(inplace=True) if relu else nn.Sequential(), |
| 57 | ) |
| 58 | |
| 59 | self.cheap_operation = nn.Sequential( |
| 60 | nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False), |
| 61 | nn.BatchNorm2d(new_channels), |
| 62 | nn.ReLU(inplace=True) if relu else nn.Sequential(), |
| 63 | ) |
| 64 | |
| 65 | def forward(self, x): |
| 66 | x1 = self.primary_conv(x) |
| 67 | x2 = self.cheap_operation(x1) |
| 68 | out = torch.cat([x1, x2], dim=1) |
| 69 | return out[:, :self.oup, :, :] |
| 70 | |
| 71 | |
| 72 | class GhostBottleneck(nn.Module): |