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)
| 233 | self.W = None |
| 234 | |
| 235 | def forward(self, x, mask_matrix): |
| 236 | """Forward function. |
| 237 | Args: |
| 238 | x: Input feature, tensor size (B, H*W, C). |
| 239 | H, W: Spatial resolution of the input feature. |
| 240 | mask_matrix: Attention mask for cyclic shift. |
| 241 | """ |
| 242 | B, L, C = x.shape |
| 243 | H, W = self.H, self.W |
| 244 | assert L == H * W, "input feature has wrong size" |
| 245 | |
| 246 | shortcut = x |
| 247 | x = self.norm1(x) |
| 248 | x = x.view(B, H, W, C) |
| 249 | |
| 250 | # pad feature maps to multiples of window size |
| 251 | pad_l = pad_t = 0 |
| 252 | pad_r = (self.window_size - W % self.window_size) % self.window_size |
| 253 | pad_b = (self.window_size - H % self.window_size) % self.window_size |
| 254 | x = F.pad(x, (0, 0, pad_l, pad_r, pad_t, pad_b)) |
| 255 | _, Hp, Wp, _ = x.shape |
| 256 | |
| 257 | # cyclic shift |
| 258 | if self.shift_size > 0: |
| 259 | shifted_x = torch.roll(x, shifts=(-self.shift_size, -self.shift_size), dims=(1, 2)) |
| 260 | attn_mask = mask_matrix |
| 261 | else: |
| 262 | shifted_x = x |
| 263 | attn_mask = None |
| 264 | |
| 265 | # partition windows |
| 266 | x_windows = window_partition( |
| 267 | shifted_x, self.window_size |
| 268 | ) # nW*B, window_size, window_size, C |
| 269 | x_windows = x_windows.view( |
| 270 | -1, self.window_size * self.window_size, C |
| 271 | ) # nW*B, window_size*window_size, C |
| 272 | |
| 273 | # W-MSA/SW-MSA |
| 274 | attn_windows = self.attn(x_windows, mask=attn_mask) # nW*B, window_size*window_size, C |
| 275 | |
| 276 | # merge windows |
| 277 | attn_windows = attn_windows.view(-1, self.window_size, self.window_size, C) |
| 278 | shifted_x = window_reverse(attn_windows, self.window_size, Hp, Wp) # B H' W' C |
| 279 | |
| 280 | # reverse cyclic shift |
| 281 | if self.shift_size > 0: |
| 282 | x = torch.roll(shifted_x, shifts=(self.shift_size, self.shift_size), dims=(1, 2)) |
| 283 | else: |
| 284 | x = shifted_x |
| 285 | |
| 286 | if pad_r > 0 or pad_b > 0: |
| 287 | x = x[:, :H, :W, :].contiguous() |
| 288 | |
| 289 | x = x.view(B, H * W, C) |
| 290 | |
| 291 | # FFN |
| 292 | x = shortcut + self.drop_path(x) |
nothing calls this directly
no test coverage detected