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