Forward function. Args: x: Input feature, tensor size (B, H*W, C). H, W: Spatial resolution of the input feature. mask_matrix: Attention mask for cyclic shift.
(self, x, mask_matrix)
| 186 | self.W = None |
| 187 | |
| 188 | def forward(self, x, mask_matrix): |
| 189 | """ Forward function. |
| 190 | |
| 191 | Args: |
| 192 | x: Input feature, tensor size (B, H*W, C). |
| 193 | H, W: Spatial resolution of the input feature. |
| 194 | mask_matrix: Attention mask for cyclic shift. |
| 195 | """ |
| 196 | B, L, C = x.shape |
| 197 | H, W = self.H, self.W |
| 198 | assert L == H * W, "input feature has wrong size" |
| 199 | |
| 200 | shortcut = x |
| 201 | x = self.norm1(x) |
| 202 | x = x.view(B, H, W, C) |
| 203 | |
| 204 | # pad feature maps to multiples of window size |
| 205 | pad_l = pad_t = 0 |
| 206 | pad_r = (self.window_size - W % self.window_size) % self.window_size |
| 207 | pad_b = (self.window_size - H % self.window_size) % self.window_size |
| 208 | x = F.pad(x, (0, 0, pad_l, pad_r, pad_t, pad_b)) |
| 209 | _, Hp, Wp, _ = x.shape |
| 210 | |
| 211 | # cyclic shift |
| 212 | if self.shift_size > 0: |
| 213 | shifted_x = torch.roll(x, shifts=(-self.shift_size, -self.shift_size), dims=(1, 2)) |
| 214 | attn_mask = mask_matrix |
| 215 | else: |
| 216 | shifted_x = x |
| 217 | attn_mask = None |
| 218 | |
| 219 | # partition windows |
| 220 | x_windows = window_partition(shifted_x, self.window_size) # nW*B, window_size, window_size, C |
| 221 | x_windows = x_windows.view(-1, self.window_size * self.window_size, C) # nW*B, window_size*window_size, C |
| 222 | |
| 223 | # W-MSA/SW-MSA |
| 224 | attn_windows = self.attn(x_windows, mask=attn_mask) # nW*B, window_size*window_size, C |
| 225 | |
| 226 | # merge windows |
| 227 | attn_windows = attn_windows.view(-1, self.window_size, self.window_size, C) |
| 228 | shifted_x = window_reverse(attn_windows, self.window_size, Hp, Wp) # B H' W' C |
| 229 | |
| 230 | # reverse cyclic shift |
| 231 | if self.shift_size > 0: |
| 232 | x = torch.roll(shifted_x, shifts=(self.shift_size, self.shift_size), dims=(1, 2)) |
| 233 | else: |
| 234 | x = shifted_x |
| 235 | |
| 236 | if pad_r > 0 or pad_b > 0: |
| 237 | x = x[:, :H, :W, :].contiguous() |
| 238 | |
| 239 | x = x.view(B, H * W, C) |
| 240 | |
| 241 | # FFN feed-forward network |
| 242 | x = shortcut + self.drop_path(x) |
| 243 | x = x + self.drop_path(self.mlp(self.norm2(x))) |
| 244 | |
| 245 | return x |
nothing calls this directly
no test coverage detected