import math from collections import OrderedDict from functools import partial from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union import torch import torch.nn.functional as F from einops import rearrange, repeat from torch import broadcast_tensors, einsum, nn from torch.nn.parameter import Parameter from torch.utils.checkpoint import checkpoint from .utils_d2 import ( add_decomposed_rel_pos, PatchEmbed, window_partition, window_unpartition, ) def get_abs_pos(abs_pos, has_cls_token, hw, tile=False): h, w = hw if has_cls_token: abs_pos = abs_pos[:, 1:] xy_num = abs_pos.shape[1] size = int(math.sqrt(xy_num)) assert size * size == xy_num if size != h or size != w: if tile == True: new_abs_pos = abs_pos.reshape(1, size, size, -1).tile( [1, h // size + 1, w // size + 1, 1] )[:, :h, :w, :] return new_abs_pos else: new_abs_pos = F.interpolate( abs_pos.reshape(1, size, size, -1).permute(0, 3, 1, 2), size=(h, w), mode="bicubic", align_corners=False, ) return new_abs_pos.permute(0, 2, 3, 1) else: return abs_pos.reshape(1, h, w, -1) # broadcat, as tortoise-tts was using it def broadcat(tensors, dim=-1): broadcasted_tensors = broadcast_tensors(*tensors) return torch.cat(broadcasted_tensors, dim=dim) # rotary embedding helper functions def rotate_half(x): x = rearrange(x, "... (d r) -> ... d r", r=2) x1, x2 = x.unbind(dim=-1) x = torch.stack((-x2, x1), dim=-1) return rearrange(x, "... d r -> ... (d r)") class VisionRotaryEmbeddingFast(nn.Module): def __init__( self, dim, pt_seq_len=16, ft_seq_len=None, custom_freqs=None, freqs_for="lang", theta=10000, max_freq=10, num_freqs=1, ): super().__init__() if custom_freqs: freqs = custom_freqs elif freqs_for == "lang": freqs = 1.0 / ( theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim) ) elif freqs_for == "pixel": freqs = torch.linspace(1.0, max_freq / 2, dim // 2) * pi elif freqs_for == "constant": freqs = torch.ones(num_freqs).float() else: raise ValueError(f"unknown modality {freqs_for}") if ft_seq_len is None: ft_seq_len = pt_seq_len t = ( torch.arange(ft_seq_len) / ft_seq_len * pt_seq_len + 1 ) # + 1 is hacking vev0 pt code freqs = torch.einsum("..., f -> ... f", t, freqs) freqs = repeat(freqs, "... n -> ... (n r)", r=2) # freqs = broadcat((freqs[:, None, :], freqs[None, :, :]), dim = -1) freqs = broadcat( (freqs[None, :, :], freqs[:, None, :]), dim=-1 ) # follow vev0 pt code freqs_cos = freqs.cos().view(-1, freqs.shape[-1]) freqs_sin = freqs.sin().view(-1, freqs.shape[-1]) self.register_buffer("freqs_cos", freqs_cos) self.register_buffer("freqs_sin", freqs_sin) print("======== shape of rope freq", self.freqs_cos.shape, "========") def forward(self, tt): return tt * self.freqs_cos + rotate_half(tt) * self.freqs_sin class LayerNorm(nn.LayerNorm): """Subclass torch's LayerNorm to handle fp16.""" def forward(self, x: torch.Tensor): orig_type = x.dtype # ret = super().forward(x.type(torch.float32)) ret = F.layer_norm( x.type(torch.float32), self.normalized_shape, self.weight.type(torch.float32), self.bias.type(torch.float32), self.eps, ) return ret.type(orig_type) class QuickGELU(nn.Module): def forward(self, x: torch.Tensor): return x * torch.sigmoid(1.702 * x) def drop_path( x, drop_prob: float = 0.0, training: bool = False, scale_by_keep: bool = True ): """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks). This is the same as the DropConnect impl I created for EfficientNet, etc networks, however, the original name is misleading as 'Drop Connect' is a different form of dropout in a separate paper... See discussion: https://github.com/tensorflow/tpu/issues/494#issuecomment-532968956 ... I've opted for changing the layer and argument names to 'drop path' rather than mix DropConnect as a layer name and use 'survival rate' as the argument. """ if drop_prob == 0.0 or not training: return x keep_prob = 1 - drop_prob shape = (x.shape[0],) + (1,) * ( x.ndim - 1 ) # work with diff dim tensors, not just 2D ConvNets random_tensor = x.new_empty(shape).bernoulli_(keep_prob) if keep_prob > 0.0 and scale_by_keep: random_tensor.div_(keep_prob) return x * random_tensor class DropPath(nn.Module): """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).""" def __init__(self, drop_prob: float = 0.0, scale_by_keep: bool = True): super(DropPath, self).__init__() self.drop_prob = drop_prob self.scale_by_keep = scale_by_keep def forward(self, x): return drop_path(x, self.drop_prob, self.training, self.scale_by_keep) def extra_repr(self): return f"drop_prob={round(self.drop_prob,3):0.3f}" class Attention(nn.Module): r""" Implements attention based on Rope """ def __init__( self, embed_dim: int, num_heads: int, dropout: float = 0.0, bias: bool = True, add_bias_kv: bool = False, kdim: Optional[bool] = None, vdim: Optional[bool] = None, rope=None, ): super(Attention, self).__init__() self.embed_dim = embed_dim self.kdim = kdim if kdim is not None else embed_dim self.vdim = vdim if vdim is not None else embed_dim self._qkv_same_embed_dim = self.kdim == embed_dim and self.vdim == embed_dim self.num_heads = num_heads self.dropout = dropout self.head_dim = embed_dim // num_heads assert ( self.head_dim * num_heads == self.embed_dim ), "embed_dim must be divisible by num_heads" if self._qkv_same_embed_dim is False: self.q_proj_weight = Parameter(torch.Tensor(embed_dim, embed_dim)) self.k_proj_weight = Parameter(torch.Tensor(embed_dim, self.kdim)) self.v_proj_weight = Parameter(torch.Tensor(embed_dim, self.vdim)) else: self.in_proj_weight = Parameter(torch.empty(3 * embed_dim, embed_dim)) if bias: self.in_proj_bias = Parameter(torch.empty(3 * embed_dim)) else: self.register_parameter("in_proj_bias", None) self.out_proj = nn.Linear(embed_dim, embed_dim, bias=bias) if add_bias_kv: self.bias_k = Parameter(torch.empty(1, 1, embed_dim)) self.bias_v = Parameter(torch.empty(1, 1, embed_dim)) else: self.bias_k = self.bias_v = None self.rope = rope self.scale = self.head_dim ** (-0.5) def forward(self, query, attn_mask: Optional[torch.Tensor] = None): batch, seq, embed_dim = query.shape proj = torch._C._nn.linear(query, self.in_proj_weight, self.in_proj_bias) # reshape to 3, E and not E, 3 is deliberate for better memory coalescing and keeping same order as chunk() proj = ( proj.unflatten(-1, (3, embed_dim)) .unsqueeze(0) .transpose(0, -2) .squeeze(-2) .contiguous() ) q_, k_, v_ = proj[0], proj[1], proj[2] # Use "q_" so that we don't accidentally quit in pdb :) q_ = rearrange(q_, "b s (h d) -> b h s d", h=self.num_heads) k_ = rearrange(k_, "b s (h d) -> b h s d", h=self.num_heads) v_ = rearrange(v_, "b s (h d) -> b h s d", h=self.num_heads) ## rope q_ = self.rope(q_).type_as(v_) k_ = self.rope(k_).type_as(v_) attn = (q_ * self.scale) @ k_.transpose(-2, -1) attn = attn.softmax(dim=-1) x_ = attn @ v_ x_ = rearrange(x_, "b h s d -> b s (h d)") return torch._C._nn.linear(x_, self.out_proj.weight, self.out_proj.bias) class LayerScale(nn.Module): def __init__( self, dim: int, init_values: float = 1e-5, inplace: bool = False, ) -> None: super().__init__() self.inplace = inplace self.gamma = nn.Parameter(init_values * torch.ones(dim)) def forward(self, x: torch.Tensor) -> torch.Tensor: return x.mul_(self.gamma) if self.inplace else x * self.gamma class ResidualAttentionBlock(nn.Module): def __init__( self, d_model: int, n_head: int, mlp_ratio=4.0, act_layer=nn.GELU, norm_layer=LayerNorm, drop_path=0.0, use_rel_pos=False, rel_pos_zero_init=True, window_size=0, rope=None, input_size=None, attn_mask=None, init_values=0.0, ): super().__init__() self.attn = Attention(embed_dim=d_model, num_heads=n_head, rope=rope) self.ls_1 = ( LayerScale(d_model, init_values=init_values) if init_values > 0.0 else nn.Identity() ) self.ln_1 = LayerNorm(d_model) self.mlp = nn.Sequential( OrderedDict( [ ("c_fc", nn.Linear(d_model, int(d_model * mlp_ratio))), ("gelu", act_layer()), ("c_proj", nn.Linear(int(d_model * mlp_ratio), d_model)), ] ) ) self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() self.ln_2 = LayerNorm(d_model) self.attn_mask = attn_mask self.ls_2 = ( LayerScale(d_model, init_values=init_values) if init_values > 0.0 else nn.Identity() ) self.window_size = window_size def attention_nhwc(self, x: torch.Tensor): self.attn_mask = ( self.attn_mask.to(dtype=x.dtype, device=x.device) if self.attn_mask is not None else None ) B, H, W, _ = x.shape x = x.reshape(B, H * W, -1) x = self.attn(x, attn_mask=self.attn_mask) x = x.reshape(B, H, W, -1) return x def forward(self, x: torch.Tensor): shortcut = x x = self.ln_1(x) # Window partition if self.window_size > 0: H, W = x.shape[1], x.shape[2] x, pad_hw = window_partition(x, self.window_size) x = self.attention_nhwc(x) # Reverse window partition if self.window_size > 0: x = window_unpartition(x, self.window_size, pad_hw, (H, W)) x = shortcut + self.drop_path(self.ls_1(x)) x = x + self.drop_path(self.ls_2(self.mlp(self.ln_2(x)))) return x class Transformer(nn.Module): def __init__( self, embed_dim: int, depth: int, num_heads: int, mlp_ratio=4.0, act_layer=nn.GELU, norm_layer=LayerNorm, drop_path_rate=0.0, use_rel_pos=False, rel_pos_zero_init=True, window_size=0, window_block_indexes=(), img_size=1024, patch_size=16, rope_win=None, rope_glb=None, use_act_checkpoint=False, act_checkpoint_ratio=1.0, attn_mask=None, init_values=0.0, return_layer=[-1], ): super().__init__() self.use_act_checkpoint = use_act_checkpoint self.act_checkpoint_ratio = act_checkpoint_ratio # stochastic depth decay rule dpr = [x.item() for x in torch.linspace(0, drop_path_rate, depth)] self.resblocks = nn.ModuleList() for i in range(depth): block = ResidualAttentionBlock( embed_dim, num_heads, attn_mask=attn_mask, drop_path=dpr[i], mlp_ratio=mlp_ratio, act_layer=act_layer, norm_layer=norm_layer, use_rel_pos=use_rel_pos, rel_pos_zero_init=rel_pos_zero_init, window_size=window_size if i in window_block_indexes else 0, rope=rope_win if i in window_block_indexes else rope_glb, input_size=(img_size // patch_size, img_size // patch_size), init_values=init_values, ) self.resblocks.append(block) self.return_layer = return_layer def forward(self, x: torch.Tensor): x_list = [] for idx, blk in enumerate(self.resblocks): if ( self.use_act_checkpoint and (idx / len(self.resblocks)) <= self.act_checkpoint_ratio ): x = checkpoint(blk, x) else: x = blk(x) if idx in self.return_layer or idx == len(self.resblocks) - 1: x_list.append(x) return x, x_list class PEv1_simpleFPN(nn.Module): def __init__( self, img_size=1024, patch_size=16, in_chans=3, embed_dim=768, depth=12, num_heads=12, mlp_ratio=4.0, qkv_bias=True, drop_path_rate=0.0, norm_layer=nn.LayerNorm, act_layer=nn.GELU, use_abs_pos=True, use_rel_pos=False, rel_pos_zero_init=True, rope=True, pt_hw_seq_len=16, intp_freq=True, window_size=0, window_block_indexes=(), residual_block_indexes=(), use_act_checkpoint=False, act_checkpoint_ratio=1.0, pretrain_img_size=336, pretrain_use_cls_token=True, out_feature="last_feat", tile_posemb=False, init_values=0.0, tta_rope=False, return_layer=[-1], ): super().__init__() self.pretrain_use_cls_token = pretrain_use_cls_token self.conv1 = nn.Conv2d( in_channels=in_chans, out_channels=embed_dim, kernel_size=patch_size, stride=patch_size, bias=False, ) if use_abs_pos: # Initialize absolute positional embedding with pretrain image size. num_patches = (pretrain_img_size // patch_size) * ( pretrain_img_size // patch_size ) num_positions = (num_patches + 1) if pretrain_use_cls_token else num_patches self.positional_embedding = nn.Parameter( torch.zeros(1, num_positions, embed_dim) ) print("positional_embedding:", self.positional_embedding.shape) print("positional_embedding:", self.positional_embedding.shape) print("positional_embedding:", self.positional_embedding.shape) else: self.positional_embedding = None self.tile_posemb = tile_posemb self.ln_pre = LayerNorm(embed_dim) half_head_dim = embed_dim // num_heads // 2 hw_seq_len = img_size // patch_size self.rope_win = VisionRotaryEmbeddingFast( dim=half_head_dim, pt_seq_len=pt_hw_seq_len, ft_seq_len=window_size if intp_freq else None, ) self.rope_glb = VisionRotaryEmbeddingFast( dim=half_head_dim, pt_seq_len=pt_hw_seq_len, ft_seq_len=hw_seq_len if intp_freq else None, ) self.transformer = Transformer( embed_dim=embed_dim, depth=depth, num_heads=num_heads, mlp_ratio=mlp_ratio, act_layer=act_layer, norm_layer=norm_layer, drop_path_rate=drop_path_rate, use_rel_pos=use_rel_pos, rel_pos_zero_init=rel_pos_zero_init, window_size=window_size, window_block_indexes=window_block_indexes, rope_win=self.rope_win, rope_glb=self.rope_glb, img_size=img_size, patch_size=patch_size, use_act_checkpoint=use_act_checkpoint, act_checkpoint_ratio=act_checkpoint_ratio, init_values=init_values, return_layer=return_layer, ) self._out_feature_channels = {out_feature: embed_dim} self._out_feature_strides = {out_feature: patch_size} self._out_features = [out_feature] if self.positional_embedding is not None: nn.init.trunc_normal_(self.positional_embedding, std=0.02) self.return_layer = return_layer # In our method, we don't use backbone feature with stride 4 self.fpn1 = nn.Sequential( nn.ConvTranspose2d(embed_dim, embed_dim // 2, kernel_size=2, stride=2), ) self.fpn2 = nn.Identity() self.fpn3 = nn.MaxPool2d(kernel_size=2, stride=2) self.apply(self._init_weights) strides = [patch_size // 2, patch_size, patch_size * 2] self._out_features = ["p{}".format(int(math.log2(s))) for s in strides] self._out_feature_strides = { "p3": 8, "p4": 16, "p5": 32, } self._out_feature_channels = { "p3": embed_dim // 2, "p4": embed_dim, "p5": embed_dim, } self._size_divisibility = strides[-1] self._square_pad = img_size def _init_weights(self, m): if isinstance(m, nn.Linear): nn.init.trunc_normal_(m.weight, std=0.02) if isinstance(m, nn.Linear) and m.bias is not None: nn.init.constant_(m.bias, 0) elif isinstance(m, nn.LayerNorm): nn.init.constant_(m.bias, 0) nn.init.constant_(m.weight, 1.0) def forward(self, x): x = self.conv1(x) x = x.permute(0, 2, 3, 1) if self.positional_embedding is not None: x = x + get_abs_pos( self.positional_embedding, self.pretrain_use_cls_token, (x.shape[1], x.shape[2]), self.tile_posemb, ) x = self.ln_pre(x) x, x_list = self.transformer(x) xp = x.permute(0, 3, 1, 2) # (b, h, w, c) --> (b, c, h, w) features = [] ops = [self.fpn1, self.fpn2, self.fpn3] for i in range(len(ops)): features.append(ops[i](xp)) rets = {"p{}".format(u + 3): v for (u, v) in enumerate(features)} return rets def get_pev1_and_fpn_backbone(args): if args.lsj_img_size_max > 0: img_size = args.lsj_img_size_max else: img_size = args.lsj_img_size use_act_checkpoint = args.backbone_use_act_checkpoint act_checkpoint_ratio = args.backbone_act_checkpoint_ratio init_values = args.backbone_init_values tile_posemb = args.backbone_tile_posemb tta_rope = args.backbone_tta_rope multi_layer = args.backbone_multi_layer backbone_dp = args.backbone_dp if args.backbone_size == "G": embed_dim, depth, num_heads, mlp_ratio, dp = 1536, 50, 16, 8960 / 1536, 0.5 pretrain_img_size, patch_size, window_size = 224, 16, 14 window_block_indexes = ( list(range(0, 12)) + list(range(13, 24)) + list(range(25, 36)) + list(range(37, 49)) ) pretrain_use_cls_token = False if multi_layer: return_layer = [12, 24, 36, 49] else: return_layer = [-1] elif args.backbone_size == "Gwin384": embed_dim, depth, num_heads, mlp_ratio, dp = 1536, 50, 16, 8960 / 1536, 0.5 pretrain_img_size, patch_size, window_size = 384, 16, 24 window_block_indexes = ( list(range(0, 12)) + list(range(13, 24)) + list(range(25, 36)) + list(range(37, 49)) ) pretrain_use_cls_token = False if multi_layer: return_layer = [12, 24, 36, 49] else: return_layer = [-1] elif args.backbone_size == "Gwin512": embed_dim, depth, num_heads, mlp_ratio, dp = 1536, 50, 16, 8960 / 1536, 0.5 pretrain_img_size, patch_size, window_size = 512, 16, 32 window_block_indexes = ( list(range(0, 12)) + list(range(13, 24)) + list(range(25, 36)) + list(range(37, 49)) ) pretrain_use_cls_token = False if multi_layer: return_layer = [12, 24, 36, 49] else: return_layer = [-1] else: raise ValueError("Unsupported backbone size") if backbone_dp >= 0: dp = backbone_dp assert ( depth == args.backbone_layers ), f"backbone depth {depth} and layers {args.backbone_layers}(from config) must be the same" model = PEv1_simpleFPN( use_act_checkpoint=use_act_checkpoint, act_checkpoint_ratio=act_checkpoint_ratio, pretrain_img_size=pretrain_img_size, pretrain_use_cls_token=pretrain_use_cls_token, img_size=img_size, patch_size=patch_size, embed_dim=embed_dim, depth=depth, num_heads=num_heads, drop_path_rate=dp, window_size=window_size, pt_hw_seq_len=16, # Maybe a bug ? mlp_ratio=mlp_ratio, qkv_bias=True, norm_layer=partial(nn.LayerNorm, eps=1e-6), window_block_indexes=window_block_indexes, residual_block_indexes=[], use_rel_pos=True, out_feature="last_feat", tile_posemb=tile_posemb, init_values=init_values, tta_rope=tta_rope, return_layer=return_layer, ) pretrained_backbone_path = args.backbone_path if pretrained_backbone_path: state_dict = torch.load(pretrained_backbone_path, map_location="cpu") load_info = model.load_state_dict(state_dict["model"], strict=False) print("Missing keys", load_info.missing_keys) print("Unexpected keys", load_info.unexpected_keys) else: print("Skip pretrained backbone loading") return model