import torch import torch.nn as nn import torch.nn.functional as F from timm.models.vision_transformer import DropPath from torch.nn.utils import spectral_norm class Attention(nn.Module): def __init__( self, dim, num_heads=8, qkv_bias=False, attn_drop=0.0, proj_drop=0.0, spectral=False, ): super().__init__() assert dim % num_heads == 0, "dim should be divisible by num_heads" self.num_heads = num_heads head_dim = dim // num_heads self.scale = head_dim**-0.5 if spectral: self.qkv = spectral_norm(nn.Linear(dim, dim * 3, bias=qkv_bias)) self.proj = spectral_norm(nn.Linear(dim, dim)) else: self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias) self.proj = nn.Linear(dim, dim) self.attn_drop = nn.Dropout(attn_drop) self.proj_drop = nn.Dropout(proj_drop) def forward(self, x): B, N, C = x.shape qkv = ( self.qkv(x) .reshape(B, N, 3, self.num_heads, C // self.num_heads) .permute(2, 0, 3, 1, 4) ) q, k, v = qkv.unbind(0) # make torchscript happy (cannot use tensor as tuple) attn = (q @ k.transpose(-2, -1)) * self.scale attn = attn.softmax(dim=-1) attn = self.attn_drop(attn) x = (attn @ v).transpose(1, 2).reshape(B, N, C) x = self.proj(x) x = self.proj_drop(x) return x class CrossAttention(nn.Module): def __init__( self, que_dim, key_dim, num_heads=4, qkv_bias=False, qk_scale=None, attn_drop=0.0, proj_drop=0.0, ): super().__init__() self.que_dim = que_dim self.key_dim = key_dim self.num_heads = num_heads head_dim = que_dim // num_heads # NOTE scale factor was wrong in my original version, can set manually to be compat with prev weights self.scale = qk_scale or head_dim**-0.5 # self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias) self.q_transform = nn.Linear(que_dim, que_dim, bias=qkv_bias) self.k_transform = nn.Linear(key_dim, que_dim, bias=qkv_bias) self.v_transform = nn.Linear(key_dim, que_dim, bias=qkv_bias) self.attn_drop = nn.Dropout(attn_drop) self.proj = nn.Linear(que_dim, que_dim) self.proj_drop = nn.Dropout(proj_drop) self.noise_strength_1 = torch.nn.Parameter(torch.zeros([])) def forward(self, x, embedding): B, N, C = x.shape B, E_N, E_C = embedding.shape # transform q = self.q_transform(x) k = self.k_transform(embedding) v = self.v_transform(embedding) # reshape q = q.reshape(B, N, self.num_heads, self.que_dim // self.num_heads).permute( 0, 2, 1, 3 ) # (B, H, N, C) k = k.reshape(B, E_N, self.num_heads, self.que_dim // self.num_heads).permute( 0, 2, 1, 3 ) # (B, H, N, C) v = v.reshape(B, E_N, self.num_heads, self.que_dim // self.num_heads).permute( 0, 2, 1, 3 ) # (B, H, N, C) attn = (q @ k.transpose(-2, -1)) * self.scale attn = attn.softmax(dim=-1) attn = self.attn_drop(attn) assert attn.size(-1) == v.size( -2 ), f"attn.size: {attn.size()}, v.size:{v.size()}" output = (attn @ v).transpose(1, 2).reshape(B, N, self.que_dim) output = self.proj(output) output = self.proj_drop(output) return x + output class LayerScale(nn.Module): def __init__(self, dim, init_values=1e-5, inplace=False): super().__init__() self.inplace = inplace self.gamma = nn.Parameter(init_values * torch.ones(dim)) def forward(self, x): return x.mul_(self.gamma) if self.inplace else x * self.gamma class Mlp(nn.Module): def __init__( self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.0, spectral=False, ): super().__init__() out_features = out_features or in_features hidden_features = hidden_features or in_features self.act = act_layer() if spectral: self.fc1 = spectral_norm(nn.Linear(in_features, hidden_features)) self.fc2 = spectral_norm(nn.Linear(hidden_features, out_features)) else: self.fc1 = nn.Linear(in_features, hidden_features) self.fc2 = nn.Linear(hidden_features, out_features) self.drop = nn.Dropout(drop) def forward(self, x): x = self.fc1(x) x = self.act(x) x = self.drop(x) x = self.fc2(x) x = self.drop(x) return x class Block(nn.Module): def __init__( self, dim, num_heads, mlp_ratio=4.0, qkv_bias=False, drop=0.0, attn_drop=0.0, init_values=None, drop_path=0.0, act_layer=nn.GELU, norm_layer=nn.LayerNorm, spectral=False, ): super().__init__() self.norm1 = norm_layer(dim, elementwise_affine=True) self.attn = Attention( dim, num_heads=num_heads, qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=drop, spectral=spectral, ) self.ls1 = ( LayerScale(dim, init_values=init_values) if init_values else nn.Identity() ) # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here self.drop_path1 = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() self.norm2 = norm_layer(dim, elementwise_affine=True) self.mlp = Mlp( in_features=dim, hidden_features=int(dim * mlp_ratio), act_layer=act_layer, drop=drop, spectral=spectral, ) self.ls2 = ( LayerScale(dim, init_values=init_values) if init_values else nn.Identity() ) self.drop_path2 = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() def forward(self, x): x = x + self.drop_path1(self.ls1(self.attn(self.norm1(x)))) x = x + self.drop_path2(self.ls2(self.mlp(self.norm2(x)))) return x class CrossBlock(nn.Module): def __init__( self, dim, num_heads, mlp_ratio=4.0, qkv_bias=False, drop=0.0, attn_drop=0.0, init_values=None, drop_path=0.0, act_layer=nn.GELU, norm_layer=nn.LayerNorm, ): super().__init__() self.norm1 = norm_layer(dim, elementwise_affine=True) self.norm3 = norm_layer(dim, elementwise_affine=True) self.norm2 = norm_layer(dim, elementwise_affine=True) # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here self.mlp = Mlp( in_features=dim, hidden_features=int(dim * mlp_ratio), act_layer=act_layer, drop=drop, ) self.attn = Attention( dim, num_heads=num_heads, qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=drop, ) self.cross_attention = CrossAttention( dim, dim, num_heads=num_heads, qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=drop, ) self.ls1 = ( LayerScale(dim, init_values=init_values) if init_values else nn.Identity() ) self.ls2 = ( LayerScale(dim, init_values=init_values) if init_values else nn.Identity() ) self.ls3 = ( LayerScale(dim, init_values=init_values) if init_values else nn.Identity() ) self.drop_path1 = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() self.drop_path2 = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() self.drop_path3 = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() def forward(self, src, tgt): src = src + self.drop_path1(self.ls1(self.attn(self.norm1(src)))) src = self.norm2(src) src = src + self.drop_path2(self.ls2(self.cross_attention(src, tgt))) src = src + self.drop_path3(self.ls3(self.mlp(self.norm3(src)))) return src