| 91 | |
| 92 | |
| 93 | class ShiftWindowAttention(LocalAttention): |
| 94 | |
| 95 | def __init__(self, dim, heads, window_size, attn_drop, proj_drop, shift_size, fmap_size): |
| 96 | |
| 97 | super().__init__(dim, heads, window_size, attn_drop, proj_drop) |
| 98 | |
| 99 | self.fmap_size = to_2tuple(fmap_size) |
| 100 | self.shift_size = shift_size |
| 101 | |
| 102 | assert 0 < self.shift_size < min(self.window_size), "wrong shift size." |
| 103 | |
| 104 | img_mask = torch.zeros(*self.fmap_size) # H W |
| 105 | h_slices = (slice(0, -self.window_size[0]), |
| 106 | slice(-self.window_size[0], -self.shift_size), |
| 107 | slice(-self.shift_size, None)) |
| 108 | w_slices = (slice(0, -self.window_size[1]), |
| 109 | slice(-self.window_size[1], -self.shift_size), |
| 110 | slice(-self.shift_size, None)) |
| 111 | cnt = 0 |
| 112 | for h in h_slices: |
| 113 | for w in w_slices: |
| 114 | img_mask[h, w] = cnt |
| 115 | cnt += 1 |
| 116 | mask_windows = einops.rearrange(img_mask, '(r1 h1) (r2 w1) -> (r1 r2) (h1 w1)', h1=self.window_size[0],w1=self.window_size[1]) |
| 117 | attn_mask = mask_windows.unsqueeze(1) - mask_windows.unsqueeze(2) # nW ww ww |
| 118 | attn_mask = attn_mask.masked_fill(attn_mask != 0, float(-100.0)).masked_fill(attn_mask == 0, float(0.0)) |
| 119 | self.register_buffer("attn_mask", attn_mask) |
| 120 | |
| 121 | def forward(self, x): |
| 122 | |
| 123 | shifted_x = torch.roll(x, shifts=(-self.shift_size, -self.shift_size), dims=(2, 3)) |
| 124 | sw_x, _, _ = super().forward(shifted_x, self.attn_mask) |
| 125 | x = torch.roll(sw_x, shifts=(self.shift_size, self.shift_size), dims=(2, 3)) |
| 126 | |
| 127 | return x, None, None |
| 128 | |
| 129 | |
| 130 | class DAttentionBaseline(nn.Module): |