(self, x)
| 238 | self.register_buffer("attn_mask", attn_mask) |
| 239 | |
| 240 | def forward(self, x): |
| 241 | H, W = self.input_resolution |
| 242 | B, L, C = x.shape |
| 243 | assert L == H * W, "input feature has wrong size" |
| 244 | |
| 245 | shortcut = x |
| 246 | x = self.norm1(x) |
| 247 | x = x.view(B, H, W, C) |
| 248 | |
| 249 | # cyclic shift |
| 250 | if self.shift_size > 0: |
| 251 | shifted_x = torch.roll(x, shifts=(-self.shift_size, -self.shift_size), dims=(1, 2)) |
| 252 | else: |
| 253 | shifted_x = x |
| 254 | |
| 255 | # partition windows |
| 256 | x_windows = window_partition(shifted_x, self.window_size) # nW*B, window_size, window_size, C |
| 257 | x_windows = x_windows.view(-1, self.window_size * self.window_size, C) # nW*B, window_size*window_size, C |
| 258 | |
| 259 | # W-MSA/SW-MSA |
| 260 | attn_windows = self.attn(x_windows, mask=self.attn_mask) # nW*B, window_size*window_size, C |
| 261 | |
| 262 | # merge windows |
| 263 | attn_windows = attn_windows.view(-1, self.window_size, self.window_size, C) |
| 264 | shifted_x = window_reverse(attn_windows, self.window_size, H, W) # B H' W' C |
| 265 | |
| 266 | # reverse cyclic shift |
| 267 | if self.shift_size > 0: |
| 268 | x = torch.roll(shifted_x, shifts=(self.shift_size, self.shift_size), dims=(1, 2)) |
| 269 | else: |
| 270 | x = shifted_x |
| 271 | x = x.view(B, H * W, C) |
| 272 | |
| 273 | # FFN |
| 274 | x = shortcut + self.drop_path(x) |
| 275 | x = x + self.drop_path(self.mlp(self.norm2(x))) |
| 276 | |
| 277 | return x |
| 278 | |
| 279 | def extra_repr(self) -> str: |
| 280 | return f"dim={self.dim}, input_resolution={self.input_resolution}, num_heads={self.num_heads}, " \ |
nothing calls this directly
no test coverage detected