Progressively downsample a mask by total_stride, each time by stride. Note that LayerNorm is applied per *token*, like in ViT. With each downsample (by a factor stride**2), channel capacity increases by the same factor. In the end, we linearly project to embed_dim channels.
| 15 | |
| 16 | |
| 17 | class MaskDownSampler(nn.Module): |
| 18 | """ |
| 19 | Progressively downsample a mask by total_stride, each time by stride. |
| 20 | Note that LayerNorm is applied per *token*, like in ViT. |
| 21 | |
| 22 | With each downsample (by a factor stride**2), channel capacity increases by the same factor. |
| 23 | In the end, we linearly project to embed_dim channels. |
| 24 | """ |
| 25 | |
| 26 | def __init__( |
| 27 | self, |
| 28 | embed_dim=256, |
| 29 | kernel_size=4, |
| 30 | stride=4, |
| 31 | padding=0, |
| 32 | total_stride=16, |
| 33 | activation=nn.GELU, |
| 34 | ): |
| 35 | super().__init__() |
| 36 | num_layers = int(math.log2(total_stride) // math.log2(stride)) |
| 37 | assert stride**num_layers == total_stride |
| 38 | self.encoder = nn.Sequential() |
| 39 | mask_in_chans, mask_out_chans = 1, 1 |
| 40 | for _ in range(num_layers): |
| 41 | mask_out_chans = mask_in_chans * (stride**2) |
| 42 | self.encoder.append( |
| 43 | nn.Conv2d( |
| 44 | mask_in_chans, |
| 45 | mask_out_chans, |
| 46 | kernel_size=kernel_size, |
| 47 | stride=stride, |
| 48 | padding=padding, |
| 49 | ) |
| 50 | ) |
| 51 | self.encoder.append(LayerNorm2d(mask_out_chans)) |
| 52 | self.encoder.append(activation()) |
| 53 | mask_in_chans = mask_out_chans |
| 54 | |
| 55 | self.encoder.append(nn.Conv2d(mask_out_chans, embed_dim, kernel_size=1)) |
| 56 | |
| 57 | def forward(self, x): |
| 58 | return self.encoder(x) |
| 59 | |
| 60 | |
| 61 | # Lightly adapted from ConvNext (https://github.com/facebookresearch/ConvNeXt) |
nothing calls this directly
no outgoing calls
no test coverage detected