r"""ConvNeXt Block. There are two equivalent implementations: (1) DwConv -> LayerNorm (channels_first) -> 1x1 Conv -> GELU -> 1x1 Conv; all in (N, C, H, W) (2) DwConv -> Permute to (N, H, W, C); LayerNorm (channels_last) -> Linear -> GELU -> Linear; Permute back We use (2) as we find it
| 60 | |
| 61 | # Lightly adapted from ConvNext (https://github.com/facebookresearch/ConvNeXt) |
| 62 | class CXBlock(nn.Module): |
| 63 | r"""ConvNeXt Block. There are two equivalent implementations: |
| 64 | (1) DwConv -> LayerNorm (channels_first) -> 1x1 Conv -> GELU -> 1x1 Conv; all in (N, C, H, W) |
| 65 | (2) DwConv -> Permute to (N, H, W, C); LayerNorm (channels_last) -> Linear -> GELU -> Linear; Permute back |
| 66 | We use (2) as we find it slightly faster in PyTorch |
| 67 | |
| 68 | Args: |
| 69 | dim (int): Number of input channels. |
| 70 | drop_path (float): Stochastic depth rate. Default: 0.0 |
| 71 | layer_scale_init_value (float): Init value for Layer Scale. Default: 1e-6. |
| 72 | """ |
| 73 | |
| 74 | def __init__( |
| 75 | self, |
| 76 | dim, |
| 77 | kernel_size=7, |
| 78 | padding=3, |
| 79 | drop_path=0.0, |
| 80 | layer_scale_init_value=1e-6, |
| 81 | use_dwconv=True, |
| 82 | ): |
| 83 | super().__init__() |
| 84 | self.dwconv = nn.Conv2d( |
| 85 | dim, |
| 86 | dim, |
| 87 | kernel_size=kernel_size, |
| 88 | padding=padding, |
| 89 | groups=dim if use_dwconv else 1, |
| 90 | ) # depthwise conv |
| 91 | self.norm = LayerNorm2d(dim, eps=1e-6) |
| 92 | self.pwconv1 = nn.Linear( |
| 93 | dim, 4 * dim |
| 94 | ) # pointwise/1x1 convs, implemented with linear layers |
| 95 | self.act = nn.GELU() |
| 96 | self.pwconv2 = nn.Linear(4 * dim, dim) |
| 97 | self.gamma = ( |
| 98 | nn.Parameter(layer_scale_init_value * torch.ones((dim)), requires_grad=True) |
| 99 | if layer_scale_init_value > 0 |
| 100 | else None |
| 101 | ) |
| 102 | self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() |
| 103 | |
| 104 | def forward(self, x): |
| 105 | input = x |
| 106 | x = self.dwconv(x) |
| 107 | x = self.norm(x) |
| 108 | x = x.permute(0, 2, 3, 1) # (N, C, H, W) -> (N, H, W, C) |
| 109 | x = self.pwconv1(x) |
| 110 | x = self.act(x) |
| 111 | x = self.pwconv2(x) |
| 112 | if self.gamma is not None: |
| 113 | x = self.gamma * x |
| 114 | x = x.permute(0, 3, 1, 2) # (N, H, W, C) -> (N, C, H, W) |
| 115 | |
| 116 | x = input + self.drop_path(x) |
| 117 | return x |
| 118 | |
| 119 |
nothing calls this directly
no outgoing calls
no test coverage detected