Handle images with non-square aspect ratio. All images in the same batch have the same aspect ratio. true_shape = [(height, width) ...] indicates the actual shape of each image.
| 30 | |
| 31 | |
| 32 | class ManyAR_PatchEmbed (PatchEmbed): |
| 33 | """ Handle images with non-square aspect ratio. |
| 34 | All images in the same batch have the same aspect ratio. |
| 35 | true_shape = [(height, width) ...] indicates the actual shape of each image. |
| 36 | """ |
| 37 | |
| 38 | def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768, norm_layer=None, flatten=True): |
| 39 | self.embed_dim = embed_dim |
| 40 | super().__init__(img_size, patch_size, in_chans, embed_dim, norm_layer, flatten) |
| 41 | |
| 42 | def forward(self, img, true_shape): |
| 43 | B, C, H, W = img.shape |
| 44 | assert W >= H, f'img should be in landscape mode, but got {W=} {H=}' |
| 45 | assert H % self.patch_size[0] == 0, f"Input image height ({H}) is not a multiple of patch size ({self.patch_size[0]})." |
| 46 | assert W % self.patch_size[1] == 0, f"Input image width ({W}) is not a multiple of patch size ({self.patch_size[1]})." |
| 47 | assert true_shape.shape == (B, 2), f"true_shape has the wrong shape={true_shape.shape}" |
| 48 | |
| 49 | # size expressed in tokens |
| 50 | W //= self.patch_size[0] |
| 51 | H //= self.patch_size[1] |
| 52 | n_tokens = H * W |
| 53 | |
| 54 | height, width = true_shape.T |
| 55 | is_landscape = (width >= height) |
| 56 | is_portrait = ~is_landscape |
| 57 | |
| 58 | # allocate result |
| 59 | x = img.new_zeros((B, n_tokens, self.embed_dim)) |
| 60 | pos = img.new_zeros((B, n_tokens, 2), dtype=torch.int64) |
| 61 | |
| 62 | # linear projection, transposed if necessary |
| 63 | x[is_landscape] = self.proj(img[is_landscape]).permute(0, 2, 3, 1).flatten(1, 2).float() |
| 64 | x[is_portrait] = self.proj(img[is_portrait].swapaxes(-1, -2)).permute(0, 2, 3, 1).flatten(1, 2).float() |
| 65 | |
| 66 | pos[is_landscape] = self.position_getter(1, H, W, pos.device) |
| 67 | pos[is_portrait] = self.position_getter(1, W, H, pos.device) |
| 68 | |
| 69 | x = self.norm(x) |
| 70 | return x, pos |
nothing calls this directly
no outgoing calls
no test coverage detected