Feature Extraction
Transformers
English
remote-sensing
earth-observation
self-supervised-learning
multispectral
sar
rgb
depth
decur
resnet
vit
segformer
Instructions to use BiliSakura/DECUR-transformers with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use BiliSakura/DECUR-transformers with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("feature-extraction", model="BiliSakura/DECUR-transformers")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("BiliSakura/DECUR-transformers", device_map="auto") - Notebooks
- Google Colab
- Kaggle
| # -------------------------------------------------------- | |
| # Swin Transformer | |
| # Copyright (c) 2021 Microsoft | |
| # Licensed under The MIT License [see LICENSE for details] | |
| # Written by Ze Liu | |
| # -------------------------------------------------------- | |
| # Vision Transformer with Deformable Attention | |
| # Modified by Zhuofan Xia | |
| # -------------------------------------------------------- | |
| import math | |
| import numpy as np | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| import einops | |
| from collections.abc import Sequence | |
| def to_2tuple(x: int | Sequence[int]) -> tuple[int, int]: | |
| if isinstance(x, Sequence) and not isinstance(x, (str, bytes)): | |
| if len(x) == 2: | |
| return int(x[0]), int(x[1]) | |
| if len(x) == 1: | |
| return int(x[0]), int(x[0]) | |
| return int(x), int(x) | |
| def trunc_normal_(tensor: torch.Tensor, mean: float = 0.0, std: float = 1.0) -> torch.Tensor: | |
| return nn.init.trunc_normal_(tensor, mean=mean, std=std) | |
| class LocalAttention(nn.Module): | |
| def __init__(self, dim, heads, window_size, attn_drop, proj_drop): | |
| super().__init__() | |
| window_size = to_2tuple(window_size) | |
| self.proj_qkv = nn.Linear(dim, 3 * dim) | |
| self.heads = heads | |
| assert dim % heads == 0 | |
| head_dim = dim // heads | |
| self.scale = head_dim ** -0.5 | |
| self.proj_out = nn.Linear(dim, dim) | |
| self.window_size = window_size | |
| self.proj_drop = nn.Dropout(proj_drop, inplace=True) | |
| self.attn_drop = nn.Dropout(attn_drop, inplace=True) | |
| Wh, Ww = self.window_size | |
| self.relative_position_bias_table = nn.Parameter( | |
| torch.zeros((2 * Wh - 1) * (2 * Ww - 1), heads) | |
| ) | |
| trunc_normal_(self.relative_position_bias_table, std=0.01) | |
| coords_h = torch.arange(self.window_size[0]) | |
| coords_w = torch.arange(self.window_size[1]) | |
| coords = torch.stack(torch.meshgrid([coords_h, coords_w], indexing='ij')) # 2, Wh, Ww | |
| coords_flatten = torch.flatten(coords, 1) # 2, Wh*Ww | |
| relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :] # 2, Wh*Ww, Wh*Ww | |
| relative_coords = relative_coords.permute(1, 2, 0).contiguous() # Wh*Ww, Wh*Ww, 2 | |
| relative_coords[:, :, 0] += self.window_size[0] - 1 # shift to start from 0 | |
| relative_coords[:, :, 1] += self.window_size[1] - 1 | |
| relative_coords[:, :, 0] *= 2 * self.window_size[1] - 1 | |
| relative_position_index = relative_coords.sum(-1) # Wh*Ww, Wh*Ww | |
| self.register_buffer("relative_position_index", relative_position_index) | |
| def forward(self, x, mask=None): | |
| B, C, H, W = x.size() | |
| r1, r2 = H // self.window_size[0], W // self.window_size[1] | |
| x_total = einops.rearrange(x, 'b c (r1 h1) (r2 w1) -> b (r1 r2) (h1 w1) c', h1=self.window_size[0], w1=self.window_size[1]) # B x Nr x Ws x C | |
| x_total = einops.rearrange(x_total, 'b m n c -> (b m) n c') | |
| qkv = self.proj_qkv(x_total) # B' x N x 3C | |
| q, k, v = torch.chunk(qkv, 3, dim=2) | |
| q = q * self.scale | |
| q, k, v = [einops.rearrange(t, 'b n (h c1) -> b h n c1', h=self.heads) for t in [q, k, v]] | |
| attn = torch.einsum('b h m c, b h n c -> b h m n', q, k) | |
| relative_position_bias = self.relative_position_bias_table[self.relative_position_index.view(-1)].view( | |
| self.window_size[0] * self.window_size[1], self.window_size[0] * self.window_size[1], -1) # Wh*Ww,Wh*Ww,nH | |
| relative_position_bias = relative_position_bias.permute(2, 0, 1).contiguous() # nH, Wh*Ww, Wh*Ww | |
| attn_bias = relative_position_bias | |
| attn = attn + attn_bias.unsqueeze(0) | |
| if mask is not None: | |
| # attn : (b * nW) h w w | |
| # mask : nW ww ww | |
| nW, ww, _ = mask.size() | |
| attn = einops.rearrange(attn, '(b n) h w1 w2 -> b n h w1 w2', n=nW, h=self.heads, w1=ww, w2=ww) + mask.reshape(1, nW, 1, ww, ww) | |
| attn = einops.rearrange(attn, 'b n h w1 w2 -> (b n) h w1 w2') | |
| attn = self.attn_drop(attn.softmax(dim=3)) | |
| x = torch.einsum('b h m n, b h n c -> b h m c', attn, v) | |
| x = einops.rearrange(x, 'b h n c1 -> b n (h c1)') | |
| x = self.proj_drop(self.proj_out(x)) # B' x N x C | |
| x = einops.rearrange(x, '(b r1 r2) (h1 w1) c -> b c (r1 h1) (r2 w1)', r1=r1, r2=r2, h1=self.window_size[0], w1=self.window_size[1]) # B x C x H x W | |
| return x, None, None | |
| class ShiftWindowAttention(LocalAttention): | |
| def __init__(self, dim, heads, window_size, attn_drop, proj_drop, shift_size, fmap_size): | |
| super().__init__(dim, heads, window_size, attn_drop, proj_drop) | |
| self.fmap_size = to_2tuple(fmap_size) | |
| self.shift_size = shift_size | |
| assert 0 < self.shift_size < min(self.window_size), "wrong shift size." | |
| img_mask = torch.zeros(*self.fmap_size) # H W | |
| h_slices = (slice(0, -self.window_size[0]), | |
| slice(-self.window_size[0], -self.shift_size), | |
| slice(-self.shift_size, None)) | |
| w_slices = (slice(0, -self.window_size[1]), | |
| slice(-self.window_size[1], -self.shift_size), | |
| slice(-self.shift_size, None)) | |
| cnt = 0 | |
| for h in h_slices: | |
| for w in w_slices: | |
| img_mask[h, w] = cnt | |
| cnt += 1 | |
| mask_windows = einops.rearrange(img_mask, '(r1 h1) (r2 w1) -> (r1 r2) (h1 w1)', h1=self.window_size[0],w1=self.window_size[1]) | |
| attn_mask = mask_windows.unsqueeze(1) - mask_windows.unsqueeze(2) # nW ww ww | |
| attn_mask = attn_mask.masked_fill(attn_mask != 0, float(-100.0)).masked_fill(attn_mask == 0, float(0.0)) | |
| self.register_buffer("attn_mask", attn_mask) | |
| def forward(self, x): | |
| shifted_x = torch.roll(x, shifts=(-self.shift_size, -self.shift_size), dims=(2, 3)) | |
| sw_x, _, _ = super().forward(shifted_x, self.attn_mask) | |
| x = torch.roll(sw_x, shifts=(self.shift_size, self.shift_size), dims=(2, 3)) | |
| return x, None, None | |
| class DAttentionBaseline(nn.Module): | |
| def __init__( | |
| self, q_size, kv_size, n_heads, n_head_channels, n_groups, | |
| attn_drop, proj_drop, stride, | |
| offset_range_factor, use_pe, dwc_pe, | |
| no_off, fixed_pe, ksize, log_cpb | |
| ): | |
| super().__init__() | |
| self.dwc_pe = dwc_pe | |
| self.n_head_channels = n_head_channels | |
| self.scale = self.n_head_channels ** -0.5 | |
| self.n_heads = n_heads | |
| self.q_h, self.q_w = q_size | |
| # self.kv_h, self.kv_w = kv_size | |
| self.kv_h, self.kv_w = self.q_h // stride, self.q_w // stride | |
| self.nc = n_head_channels * n_heads | |
| self.n_groups = n_groups | |
| self.n_group_channels = self.nc // self.n_groups | |
| self.n_group_heads = self.n_heads // self.n_groups | |
| self.use_pe = use_pe | |
| self.fixed_pe = fixed_pe | |
| self.no_off = no_off | |
| self.offset_range_factor = offset_range_factor | |
| self.ksize = ksize | |
| self.log_cpb = log_cpb | |
| self.stride = stride | |
| kk = self.ksize | |
| pad_size = kk // 2 if kk != stride else 0 | |
| self.conv_offset = nn.Sequential( | |
| nn.Conv2d(self.n_group_channels, self.n_group_channels, kk, stride, pad_size, groups=self.n_group_channels), | |
| LayerNormProxy(self.n_group_channels), | |
| nn.GELU(), | |
| nn.Conv2d(self.n_group_channels, 2, 1, 1, 0, bias=False) | |
| ) | |
| if self.no_off: | |
| for m in self.conv_offset.parameters(): | |
| m.requires_grad_(False) | |
| self.proj_q = nn.Conv2d( | |
| self.nc, self.nc, | |
| kernel_size=1, stride=1, padding=0 | |
| ) | |
| self.proj_k = nn.Conv2d( | |
| self.nc, self.nc, | |
| kernel_size=1, stride=1, padding=0 | |
| ) | |
| self.proj_v = nn.Conv2d( | |
| self.nc, self.nc, | |
| kernel_size=1, stride=1, padding=0 | |
| ) | |
| self.proj_out = nn.Conv2d( | |
| self.nc, self.nc, | |
| kernel_size=1, stride=1, padding=0 | |
| ) | |
| self.proj_drop = nn.Dropout(proj_drop, inplace=True) | |
| self.attn_drop = nn.Dropout(attn_drop, inplace=True) | |
| if self.use_pe and not self.no_off: | |
| if self.dwc_pe: | |
| self.rpe_table = nn.Conv2d( | |
| self.nc, self.nc, kernel_size=3, stride=1, padding=1, groups=self.nc) | |
| elif self.fixed_pe: | |
| self.rpe_table = nn.Parameter( | |
| torch.zeros(self.n_heads, self.q_h * self.q_w, self.kv_h * self.kv_w) | |
| ) | |
| trunc_normal_(self.rpe_table, std=0.01) | |
| elif self.log_cpb: | |
| # Borrowed from Swin-V2 | |
| self.rpe_table = nn.Sequential( | |
| nn.Linear(2, 32, bias=True), | |
| nn.ReLU(inplace=True), | |
| nn.Linear(32, self.n_group_heads, bias=False) | |
| ) | |
| else: | |
| self.rpe_table = nn.Parameter( | |
| torch.zeros(self.n_heads, self.q_h * 2 - 1, self.q_w * 2 - 1) | |
| ) | |
| trunc_normal_(self.rpe_table, std=0.01) | |
| else: | |
| self.rpe_table = None | |
| def _get_ref_points(self, H_key, W_key, B, dtype, device): | |
| ref_y, ref_x = torch.meshgrid( | |
| torch.linspace(0.5, H_key - 0.5, H_key, dtype=dtype, device=device), | |
| torch.linspace(0.5, W_key - 0.5, W_key, dtype=dtype, device=device), | |
| indexing='ij' | |
| ) | |
| ref = torch.stack((ref_y, ref_x), -1) | |
| ref[..., 1].div_(W_key - 1.0).mul_(2.0).sub_(1.0) | |
| ref[..., 0].div_(H_key - 1.0).mul_(2.0).sub_(1.0) | |
| ref = ref[None, ...].expand(B * self.n_groups, -1, -1, -1) # B * g H W 2 | |
| return ref | |
| def _get_q_grid(self, H, W, B, dtype, device): | |
| ref_y, ref_x = torch.meshgrid( | |
| torch.arange(0, H, dtype=dtype, device=device), | |
| torch.arange(0, W, dtype=dtype, device=device), | |
| indexing='ij' | |
| ) | |
| ref = torch.stack((ref_y, ref_x), -1) | |
| ref[..., 1].div_(W - 1.0).mul_(2.0).sub_(1.0) | |
| ref[..., 0].div_(H - 1.0).mul_(2.0).sub_(1.0) | |
| ref = ref[None, ...].expand(B * self.n_groups, -1, -1, -1) # B * g H W 2 | |
| return ref | |
| def forward(self, x): | |
| B, C, H, W = x.size() | |
| dtype, device = x.dtype, x.device | |
| q = self.proj_q(x) | |
| q_off = einops.rearrange(q, 'b (g c) h w -> (b g) c h w', g=self.n_groups, c=self.n_group_channels) | |
| offset = self.conv_offset(q_off).contiguous() # B * g 2 Hg Wg | |
| Hk, Wk = offset.size(2), offset.size(3) | |
| n_sample = Hk * Wk | |
| if self.offset_range_factor >= 0 and not self.no_off: | |
| offset_range = torch.tensor([1.0 / (Hk - 1.0), 1.0 / (Wk - 1.0)], device=device).reshape(1, 2, 1, 1) | |
| offset = offset.tanh().mul(offset_range).mul(self.offset_range_factor) | |
| offset = einops.rearrange(offset, 'b p h w -> b h w p') | |
| reference = self._get_ref_points(Hk, Wk, B, dtype, device) | |
| if self.no_off: | |
| offset = offset.fill_(0.0) | |
| if self.offset_range_factor >= 0: | |
| pos = offset + reference | |
| else: | |
| pos = (offset + reference).clamp(-1., +1.) | |
| if self.no_off: | |
| x_sampled = F.avg_pool2d(x, kernel_size=self.stride, stride=self.stride) | |
| assert x_sampled.size(2) == Hk and x_sampled.size(3) == Wk, f"Size is {x_sampled.size()}" | |
| else: | |
| x_sampled = F.grid_sample( | |
| input=x.reshape(B * self.n_groups, self.n_group_channels, H, W), | |
| grid=pos[..., (1, 0)], # y, x -> x, y | |
| mode='bilinear', align_corners=True) # B * g, Cg, Hg, Wg | |
| x_sampled = x_sampled.reshape(B, C, 1, n_sample) | |
| q = q.reshape(B * self.n_heads, self.n_head_channels, H * W) | |
| k = self.proj_k(x_sampled).reshape(B * self.n_heads, self.n_head_channels, n_sample) | |
| v = self.proj_v(x_sampled).reshape(B * self.n_heads, self.n_head_channels, n_sample) | |
| attn = torch.einsum('b c m, b c n -> b m n', q, k) # B * h, HW, Ns | |
| attn = attn.mul(self.scale) | |
| if self.use_pe and (not self.no_off): | |
| if self.dwc_pe: | |
| residual_lepe = self.rpe_table(q.reshape(B, C, H, W)).reshape(B * self.n_heads, self.n_head_channels, H * W) | |
| elif self.fixed_pe: | |
| rpe_table = self.rpe_table | |
| attn_bias = rpe_table[None, ...].expand(B, -1, -1, -1) | |
| attn = attn + attn_bias.reshape(B * self.n_heads, H * W, n_sample) | |
| elif self.log_cpb: | |
| q_grid = self._get_q_grid(H, W, B, dtype, device) | |
| displacement = (q_grid.reshape(B * self.n_groups, H * W, 2).unsqueeze(2) - pos.reshape(B * self.n_groups, n_sample, 2).unsqueeze(1)).mul(4.0) # d_y, d_x [-8, +8] | |
| displacement = torch.sign(displacement) * torch.log2(torch.abs(displacement) + 1.0) / np.log2(8.0) | |
| attn_bias = self.rpe_table(displacement) # B * g, H * W, n_sample, h_g | |
| attn = attn + einops.rearrange(attn_bias, 'b m n h -> (b h) m n', h=self.n_group_heads) | |
| else: | |
| rpe_table = self.rpe_table | |
| rpe_bias = rpe_table[None, ...].expand(B, -1, -1, -1) | |
| q_grid = self._get_q_grid(H, W, B, dtype, device) | |
| displacement = (q_grid.reshape(B * self.n_groups, H * W, 2).unsqueeze(2) - pos.reshape(B * self.n_groups, n_sample, 2).unsqueeze(1)).mul(0.5) | |
| attn_bias = F.grid_sample( | |
| input=einops.rearrange(rpe_bias, 'b (g c) h w -> (b g) c h w', c=self.n_group_heads, g=self.n_groups), | |
| grid=displacement[..., (1, 0)], | |
| mode='bilinear', align_corners=True) # B * g, h_g, HW, Ns | |
| attn_bias = attn_bias.reshape(B * self.n_heads, H * W, n_sample) | |
| attn = attn + attn_bias | |
| attn = F.softmax(attn, dim=2) | |
| attn = self.attn_drop(attn) | |
| out = torch.einsum('b m n, b c n -> b c m', attn, v) | |
| if self.use_pe and self.dwc_pe: | |
| out = out + residual_lepe | |
| out = out.reshape(B, C, H, W) | |
| y = self.proj_drop(self.proj_out(out)) | |
| return y, pos.reshape(B, self.n_groups, Hk, Wk, 2), reference.reshape(B, self.n_groups, Hk, Wk, 2) | |
| class DAttentionCross(nn.Module): | |
| def __init__( | |
| self, q_size, kv_size, n_heads, n_head_channels, n_groups, | |
| attn_drop, proj_drop, stride, | |
| offset_range_factor, use_pe, dwc_pe, | |
| no_off, fixed_pe, ksize, log_cpb | |
| ): | |
| super().__init__() | |
| self.dwc_pe = dwc_pe | |
| self.n_head_channels = n_head_channels | |
| self.scale = self.n_head_channels ** -0.5 | |
| self.n_heads = n_heads | |
| self.q_h, self.q_w = q_size | |
| # self.kv_h, self.kv_w = kv_size | |
| self.kv_h, self.kv_w = self.q_h // stride, self.q_w // stride | |
| self.nc = n_head_channels * n_heads | |
| self.n_groups = n_groups | |
| self.n_group_channels = self.nc // self.n_groups | |
| self.n_group_heads = self.n_heads // self.n_groups | |
| self.use_pe = use_pe | |
| self.fixed_pe = fixed_pe | |
| self.no_off = no_off | |
| self.offset_range_factor = offset_range_factor | |
| self.ksize = ksize | |
| self.log_cpb = log_cpb | |
| self.stride = stride | |
| kk = self.ksize | |
| pad_size = kk // 2 if kk != stride else 0 | |
| self.conv_offset = nn.Sequential( | |
| nn.Conv2d(self.n_group_channels, self.n_group_channels, kk, stride, pad_size, groups=self.n_group_channels), | |
| LayerNormProxy(self.n_group_channels), | |
| nn.GELU(), | |
| nn.Conv2d(self.n_group_channels, 2, 1, 1, 0, bias=False) | |
| ) | |
| if self.no_off: | |
| for m in self.conv_offset.parameters(): | |
| m.requires_grad_(False) | |
| self.proj_q = nn.Conv2d( | |
| self.nc, self.nc, | |
| kernel_size=1, stride=1, padding=0 | |
| ) | |
| self.proj_k = nn.Conv2d( | |
| self.nc, self.nc, | |
| kernel_size=1, stride=1, padding=0 | |
| ) | |
| self.proj_v = nn.Conv2d( | |
| self.nc, self.nc, | |
| kernel_size=1, stride=1, padding=0 | |
| ) | |
| self.proj_out = nn.Conv2d( | |
| self.nc, self.nc, | |
| kernel_size=1, stride=1, padding=0 | |
| ) | |
| self.proj_drop = nn.Dropout(proj_drop, inplace=True) | |
| self.attn_drop = nn.Dropout(attn_drop, inplace=True) | |
| if self.use_pe and not self.no_off: | |
| if self.dwc_pe: | |
| self.rpe_table = nn.Conv2d( | |
| self.nc, self.nc, kernel_size=3, stride=1, padding=1, groups=self.nc) | |
| elif self.fixed_pe: | |
| self.rpe_table = nn.Parameter( | |
| torch.zeros(self.n_heads, self.q_h * self.q_w, self.kv_h * self.kv_w) | |
| ) | |
| trunc_normal_(self.rpe_table, std=0.01) | |
| elif self.log_cpb: | |
| # Borrowed from Swin-V2 | |
| self.rpe_table = nn.Sequential( | |
| nn.Linear(2, 32, bias=True), | |
| nn.ReLU(inplace=True), | |
| nn.Linear(32, self.n_group_heads, bias=False) | |
| ) | |
| else: | |
| self.rpe_table = nn.Parameter( | |
| torch.zeros(self.n_heads, self.q_h * 2 - 1, self.q_w * 2 - 1) | |
| ) | |
| trunc_normal_(self.rpe_table, std=0.01) | |
| else: | |
| self.rpe_table = None | |
| def _get_ref_points(self, H_key, W_key, B, dtype, device): | |
| ref_y, ref_x = torch.meshgrid( | |
| torch.linspace(0.5, H_key - 0.5, H_key, dtype=dtype, device=device), | |
| torch.linspace(0.5, W_key - 0.5, W_key, dtype=dtype, device=device), | |
| indexing='ij' | |
| ) | |
| ref = torch.stack((ref_y, ref_x), -1) | |
| ref[..., 1].div_(W_key - 1.0).mul_(2.0).sub_(1.0) | |
| ref[..., 0].div_(H_key - 1.0).mul_(2.0).sub_(1.0) | |
| ref = ref[None, ...].expand(B * self.n_groups, -1, -1, -1) # B * g H W 2 | |
| return ref | |
| def _get_q_grid(self, H, W, B, dtype, device): | |
| ref_y, ref_x = torch.meshgrid( | |
| torch.arange(0, H, dtype=dtype, device=device), | |
| torch.arange(0, W, dtype=dtype, device=device), | |
| indexing='ij' | |
| ) | |
| ref = torch.stack((ref_y, ref_x), -1) | |
| ref[..., 1].div_(W - 1.0).mul_(2.0).sub_(1.0) | |
| ref[..., 0].div_(H - 1.0).mul_(2.0).sub_(1.0) | |
| ref = ref[None, ...].expand(B * self.n_groups, -1, -1, -1) # B * g H W 2 | |
| return ref | |
| def forward(self, x, x1): | |
| B, C, H, W = x.size() | |
| dtype, device = x.dtype, x.device | |
| #q = self.proj_q(x) | |
| q = self.proj_q(x1) | |
| q_off = einops.rearrange(q, 'b (g c) h w -> (b g) c h w', g=self.n_groups, c=self.n_group_channels) | |
| offset = self.conv_offset(q_off).contiguous() # B * g 2 Hg Wg | |
| Hk, Wk = offset.size(2), offset.size(3) | |
| n_sample = Hk * Wk | |
| if self.offset_range_factor >= 0 and not self.no_off: | |
| offset_range = torch.tensor([1.0 / (Hk - 1.0), 1.0 / (Wk - 1.0)], device=device).reshape(1, 2, 1, 1) | |
| offset = offset.tanh().mul(offset_range).mul(self.offset_range_factor) | |
| offset = einops.rearrange(offset, 'b p h w -> b h w p') | |
| reference = self._get_ref_points(Hk, Wk, B, dtype, device) | |
| if self.no_off: | |
| offset = offset.fill_(0.0) | |
| if self.offset_range_factor >= 0: | |
| pos = offset + reference | |
| else: | |
| pos = (offset + reference).clamp(-1., +1.) | |
| if self.no_off: | |
| x_sampled = F.avg_pool2d(x, kernel_size=self.stride, stride=self.stride) | |
| assert x_sampled.size(2) == Hk and x_sampled.size(3) == Wk, f"Size is {x_sampled.size()}" | |
| else: | |
| x_sampled = F.grid_sample( | |
| input=x.reshape(B * self.n_groups, self.n_group_channels, H, W), | |
| grid=pos[..., (1, 0)], # y, x -> x, y | |
| mode='bilinear', align_corners=True) # B * g, Cg, Hg, Wg | |
| x_sampled = x_sampled.reshape(B, C, 1, n_sample) | |
| q = q.reshape(B * self.n_heads, self.n_head_channels, H * W) | |
| k = self.proj_k(x_sampled).reshape(B * self.n_heads, self.n_head_channels, n_sample) | |
| v = self.proj_v(x_sampled).reshape(B * self.n_heads, self.n_head_channels, n_sample) | |
| attn = torch.einsum('b c m, b c n -> b m n', q, k) # B * h, HW, Ns | |
| attn = attn.mul(self.scale) | |
| if self.use_pe and (not self.no_off): | |
| if self.dwc_pe: | |
| residual_lepe = self.rpe_table(q.reshape(B, C, H, W)).reshape(B * self.n_heads, self.n_head_channels, H * W) | |
| elif self.fixed_pe: | |
| rpe_table = self.rpe_table | |
| attn_bias = rpe_table[None, ...].expand(B, -1, -1, -1) | |
| attn = attn + attn_bias.reshape(B * self.n_heads, H * W, n_sample) | |
| elif self.log_cpb: | |
| q_grid = self._get_q_grid(H, W, B, dtype, device) | |
| displacement = (q_grid.reshape(B * self.n_groups, H * W, 2).unsqueeze(2) - pos.reshape(B * self.n_groups, n_sample, 2).unsqueeze(1)).mul(4.0) # d_y, d_x [-8, +8] | |
| displacement = torch.sign(displacement) * torch.log2(torch.abs(displacement) + 1.0) / np.log2(8.0) | |
| attn_bias = self.rpe_table(displacement) # B * g, H * W, n_sample, h_g | |
| attn = attn + einops.rearrange(attn_bias, 'b m n h -> (b h) m n', h=self.n_group_heads) | |
| else: | |
| rpe_table = self.rpe_table | |
| rpe_bias = rpe_table[None, ...].expand(B, -1, -1, -1) | |
| q_grid = self._get_q_grid(H, W, B, dtype, device) | |
| displacement = (q_grid.reshape(B * self.n_groups, H * W, 2).unsqueeze(2) - pos.reshape(B * self.n_groups, n_sample, 2).unsqueeze(1)).mul(0.5) | |
| attn_bias = F.grid_sample( | |
| input=einops.rearrange(rpe_bias, 'b (g c) h w -> (b g) c h w', c=self.n_group_heads, g=self.n_groups), | |
| grid=displacement[..., (1, 0)], | |
| mode='bilinear', align_corners=True) # B * g, h_g, HW, Ns | |
| attn_bias = attn_bias.reshape(B * self.n_heads, H * W, n_sample) | |
| attn = attn + attn_bias | |
| attn = F.softmax(attn, dim=2) | |
| attn = self.attn_drop(attn) | |
| out = torch.einsum('b m n, b c n -> b c m', attn, v) | |
| if self.use_pe and self.dwc_pe: | |
| out = out + residual_lepe | |
| out = out.reshape(B, C, H, W) | |
| y = self.proj_drop(self.proj_out(out)) | |
| return y, pos.reshape(B, self.n_groups, Hk, Wk, 2), reference.reshape(B, self.n_groups, Hk, Wk, 2) | |
| class PyramidAttention(nn.Module): | |
| def __init__(self, dim, num_heads=8, attn_drop=0., proj_drop=0., sr_ratio=1): | |
| super().__init__() | |
| assert dim % num_heads == 0, f"dim {dim} should be divided by num_heads {num_heads}." | |
| self.dim = dim | |
| self.num_heads = num_heads | |
| self.head_dim = dim // num_heads | |
| self.scale = self.head_dim ** -0.5 | |
| self.q = nn.Conv2d(dim, dim, 1, 1, 0) | |
| self.kv = nn.Conv2d(dim, dim * 2, 1, 1, 0) | |
| self.attn_drop = nn.Dropout(attn_drop) | |
| self.proj = nn.Conv2d(dim, dim, 1, 1, 0) | |
| self.proj_drop = nn.Dropout(proj_drop) | |
| self.sr_ratio = sr_ratio | |
| if sr_ratio > 1: | |
| self.proj_ds = nn.Sequential( | |
| nn.Conv2d(dim, dim, kernel_size=sr_ratio, stride=sr_ratio), | |
| LayerNormProxy(dim) | |
| ) | |
| def forward(self, x): | |
| B, C, H, W = x.size() | |
| Nq = H * W | |
| q = self.q(x) | |
| if self.sr_ratio > 1: | |
| x_ds = self.proj_ds(x) | |
| kv = self.kv(x_ds) | |
| else: | |
| kv = self.kv(x) | |
| k, v = torch.chunk(kv, 2, dim=1) | |
| Nk = (H // self.sr_ratio) * (W // self.sr_ratio) | |
| q = q.reshape(B * self.num_heads, self.head_dim, Nq).mul(self.scale) | |
| k = k.reshape(B * self.num_heads, self.head_dim, Nk) | |
| v = v.reshape(B * self.num_heads, self.head_dim, Nk) | |
| attn = torch.einsum('b c m, b c n -> b m n', q, k) | |
| attn = F.softmax(attn, dim=2) | |
| attn = self.attn_drop(attn) | |
| x = torch.einsum('b m n, b c n -> b c m', attn, v) | |
| x = x.reshape(B, C, H, W) | |
| x = self.proj(x) | |
| x = self.proj_drop(x) | |
| return x, None, None | |
| class TransformerMLP(nn.Module): | |
| def __init__(self, channels, expansion, drop): | |
| super().__init__() | |
| self.dim1 = channels | |
| self.dim2 = channels * expansion | |
| self.chunk = nn.Sequential() | |
| self.chunk.add_module('linear1', nn.Linear(self.dim1, self.dim2)) | |
| self.chunk.add_module('act', nn.GELU()) | |
| self.chunk.add_module('drop1', nn.Dropout(drop, inplace=True)) | |
| self.chunk.add_module('linear2', nn.Linear(self.dim2, self.dim1)) | |
| self.chunk.add_module('drop2', nn.Dropout(drop, inplace=True)) | |
| def forward(self, x): | |
| _, _, H, W = x.size() | |
| x = einops.rearrange(x, 'b c h w -> b (h w) c') | |
| x = self.chunk(x) | |
| x = einops.rearrange(x, 'b (h w) c -> b c h w', h=H, w=W) | |
| return x | |
| class LayerNormProxy(nn.Module): | |
| def __init__(self, dim): | |
| super().__init__() | |
| self.norm = nn.LayerNorm(dim) | |
| def forward(self, x): | |
| x = einops.rearrange(x, 'b c h w -> b h w c') | |
| x = self.norm(x) | |
| return einops.rearrange(x, 'b h w c -> b c h w') | |
| class TransformerMLPWithConv(nn.Module): | |
| def __init__(self, channels, expansion, drop): | |
| super().__init__() | |
| self.dim1 = channels | |
| self.dim2 = channels * expansion | |
| self.linear1 = nn.Sequential( | |
| nn.Conv2d(self.dim1, self.dim2, 1, 1, 0), | |
| # nn.GELU(), | |
| # nn.BatchNorm2d(self.dim2, eps=1e-5) | |
| ) | |
| self.drop1 = nn.Dropout(drop, inplace=True) | |
| self.act = nn.GELU() | |
| # self.bn = nn.BatchNorm2d(self.dim2, eps=1e-5) | |
| self.linear2 = nn.Sequential( | |
| nn.Conv2d(self.dim2, self.dim1, 1, 1, 0), | |
| # nn.BatchNorm2d(self.dim1, eps=1e-5) | |
| ) | |
| self.drop2 = nn.Dropout(drop, inplace=True) | |
| self.dwc = nn.Conv2d(self.dim2, self.dim2, 3, 1, 1, groups=self.dim2) | |
| def forward(self, x): | |
| x = self.linear1(x) | |
| x = self.drop1(x) | |
| x = x + self.dwc(x) | |
| x = self.act(x) | |
| # x = self.bn(x) | |
| x = self.linear2(x) | |
| x = self.drop2(x) | |
| return x |