CoolFace
Apppublic

tennant/MUG_caption

sourceHugging Facemitupdated 3y agoView on Hugging Face
4likes
model.py841 linesDownload Raw Back to root
1# --------------------------------------------------------2# References:3# timm: https://github.com/rwightman/pytorch-image-models/tree/master/timm4# DeiT: https://github.com/facebookresearch/deit5# --------------------------------------------------------6 7from functools import partial8 9import torch10from torch._C import Value11import torch.nn as nn12import numpy as np13 14from timm.models.vision_transformer import PatchEmbed, Block15from transformers import EncoderDecoderModel, BertTokenizer, AutoTokenizer16 17 18from torch import einsum, nn19import torch.nn.functional as F20from einops import rearrange, repeat21 22import torch23import torch.nn as nn24import torch.nn.functional as F25 26class FocalLoss(nn.CrossEntropyLoss):27    ''' Focal loss for classification tasks on imbalanced datasets '''28 29    def __init__(self, gamma=1.0, alpha=None, ignore_index=-100, reduction='none'):30        super().__init__(weight=alpha, ignore_index=ignore_index, reduction='none')31        self.reduction = reduction32        self.gamma = gamma33 34    def forward(self, input_, target):35        cross_entropy = super().forward(input_, target)36        # Temporarily mask out ignore index to '0' for valid gather-indices input.37        # This won't contribute final loss as the cross_entropy contribution38        # for these would be zero.39        target = target * (target != self.ignore_index).long()40        input_prob = torch.gather(F.softmax(input_, 1), 1, target.unsqueeze(1)).squeeze(1)41        loss = torch.pow(1 - input_prob, self.gamma) * cross_entropy42        return torch.mean(loss) if self.reduction == 'mean' \43               else torch.sum(loss) if self.reduction == 'sum' \44               else loss45 46 47# helper functions48 49import math50from functools import reduce51 52def prob_mask_like(t, prob):53    return torch.zeros_like(t).float().uniform_(0, 1) < prob54 55def mask_with_tokens(t, token_ids):56    init_no_mask = torch.full_like(t, False, dtype=torch.bool)57    mask = reduce(lambda acc, el: acc | (t == el), token_ids, init_no_mask)58    return mask59 60def get_mask_subset_with_prob(mask, prob):61    batch, seq_len, device = *mask.shape, mask.device62    max_masked = math.ceil(prob * seq_len)63 64    num_tokens = mask.sum(dim=-1, keepdim=True)65    mask_excess = (mask.cumsum(dim=-1) > (num_tokens * prob).ceil())66    mask_excess = mask_excess[:, :max_masked]67 68    rand = torch.rand((batch, seq_len), device=device).masked_fill(~mask, -1e9)69    _, sampled_indices = rand.topk(max_masked, dim=-1)70    sampled_indices = (sampled_indices + 1).masked_fill_(mask_excess, 0)71 72    new_mask = torch.zeros((batch, seq_len + 1), device=device)73    new_mask.scatter_(-1, sampled_indices, 1)74    return new_mask[:, 1:].bool()75 76 77def exists(val):78    return val is not None79 80def default(val, d):81    return val if exists(val) else d82 83# normalization84# they use layernorm without bias, something that pytorch does not offer85 86 87class LayerNorm(nn.Module):88    def __init__(self, dim):89        super().__init__()90        self.gamma = nn.Parameter(torch.ones(dim))91        self.register_buffer("beta", torch.zeros(dim))92 93    def forward(self, x):94        return F.layer_norm(x, x.shape[-1:], self.gamma, self.beta)95 96# residual97class Residual(nn.Module):98    def __init__(self, fn):99        super().__init__()100        self.fn = fn101 102    def forward(self, x, *args, **kwargs):103        return self.fn(x, *args, **kwargs) + x104 105# rotary positional embedding106# https://arxiv.org/abs/2104.09864107class RotaryEmbedding(nn.Module):108    def __init__(self, dim):109        super().__init__()110        inv_freq = 1.0 / (10000 ** (torch.arange(0, dim, 2).float() / dim))111        self.register_buffer("inv_freq", inv_freq)112 113    def forward(self, max_seq_len, *, device):114        seq = torch.arange(max_seq_len, device=device, dtype=self.inv_freq.dtype)115        freqs = einsum("i , j -> i j", seq, self.inv_freq)116        return torch.cat((freqs, freqs), dim=-1)117 118 119def rotate_half(x):120    x = rearrange(x, "... (j d) -> ... j d", j=2)121    x1, x2 = x.unbind(dim=-2)122    return torch.cat((-x2, x1), dim=-1)123 124 125def apply_rotary_pos_emb(pos, t):126    return (t * pos.cos()) + (rotate_half(t) * pos.sin())127 128 129# classic Noam Shazeer paper, except here they use SwiGLU instead of the more popular GELU for gating the feedforward130# https://arxiv.org/abs/2002.05202131class SwiGLU(nn.Module):132    def forward(self, x):133        x, gate = x.chunk(2, dim=-1)134        return F.silu(gate) * x135 136 137# parallel attention and feedforward with residual138# discovered by Wang et al + EleutherAI from GPT-J fame139class ParallelTransformerBlock(nn.Module):140    def __init__(self, dim, dim_head=64, heads=8, ff_mult=4, attn_drop_rate=0.0):141        super().__init__()142        self.norm = LayerNorm(dim)143 144        attn_inner_dim = dim_head * heads145        ff_inner_dim = dim * ff_mult146        self.fused_dims = (attn_inner_dim, dim_head, dim_head, (ff_inner_dim * 2))147 148        self.heads = heads149        self.scale = dim_head**-0.5150        self.rotary_emb = RotaryEmbedding(dim_head)151 152        self.fused_attn_ff_proj = nn.Linear(dim, sum(self.fused_dims), bias=False)153        self.attn_out = nn.Linear(attn_inner_dim, dim, bias=False)154 155        self.ff_out = nn.Sequential(156            SwiGLU(),157            nn.Linear(ff_inner_dim, dim, bias=False)158        )159 160        self.attn_drop_rate = attn_drop_rate161 162        # for caching causal mask and rotary embeddings163 164        self.register_buffer("mask", None, persistent=False)165        self.register_buffer("pos_emb", None, persistent=False)166 167    def get_mask(self, n, device):168        if self.mask is not None and self.mask.shape[-1] >= n:169            return self.mask[:n, :n]170 171        mask = torch.ones((n, n), device=device, dtype=torch.bool).triu(1)172        self.register_buffer("mask", mask, persistent=False)173        return mask174 175    def get_rotary_embedding(self, n, device):176        if self.pos_emb is not None and self.pos_emb.shape[-2] >= n:177            return self.pos_emb[:n]178 179        pos_emb = self.rotary_emb(n, device=device)180        self.register_buffer("pos_emb", pos_emb, persistent=False)181        return pos_emb182 183    def forward(self, x, attn_mask=None):184        """185        Performs self attention and feedforward186        einstein notation187        b - batch188        h - heads189        n, i, j - sequence length (base sequence length, source, target)190        d - feature dimension191        """192 193        n, device, h = x.shape[1], x.device, self.heads194        # pre layernorm195        x = self.norm(x)196        # attention queries, keys, values, and feedforward inner197        q, k, v, ff = self.fused_attn_ff_proj(x).split(self.fused_dims, dim=-1)198 199        # split heads200        # they use multi-query single-key-value attention, yet another Noam Shazeer paper201        # they found no performance loss past a certain scale, and more efficient decoding obviously202        # https://arxiv.org/abs/1911.02150203        q = rearrange(q, "b n (h d) -> b h n d", h=h)204        # rotary embeddings205        positions = self.get_rotary_embedding(n, device)206        q, k = map(lambda t: apply_rotary_pos_emb(positions, t), (q, k))207        # scale208        q = q * self.scale209        # similarity210        sim = einsum("b h i d, b j d -> b h i j", q, k)211        # causal mask212        causal_mask = self.get_mask(n, device)213        sim = sim.masked_fill(causal_mask, -torch.finfo(sim.dtype).max)214 215        # extra attention mask - for masking out attention from text CLS token to padding216        if exists(attn_mask):217            attn_mask = rearrange(attn_mask, 'b i j -> b 1 i j')218            sim = sim.masked_fill(~attn_mask, -torch.finfo(sim.dtype).max)219 220            if self.attn_drop_rate != 0.:221                # import ipdb; ipdb.set_trace()222                drop_ind = sim != -torch.finfo(sim.dtype).max223                dropout_mask = torch.cuda.FloatTensor(*sim[drop_ind].shape).uniform_() > self.attn_drop_rate224                sim[drop_ind] = sim[drop_ind].masked_fill(~dropout_mask, -torch.finfo(sim.dtype).max)225 226        # attention227        sim = sim - sim.amax(dim=-1, keepdim=True).detach()228        attn = sim.softmax(dim=-1)229        # aggregate values230        out = einsum("b h i j, b j d -> b h i d", attn, v)231        # merge heads232        out = rearrange(out, "b h n d -> b n (h d)")233        return self.attn_out(out) + self.ff_out(ff)234 235# cross attention - using multi-query + one-headed key / values as in PaLM w/ optional parallel feedforward236class CrossAttention(nn.Module):237    def __init__(238        self,239        dim,240        *,241        context_dim=None,242        dim_head=64,243        heads=8,244        parallel_ff=False,245        ff_mult=4,246        norm_context=False,247        dropout=0.0,248    ):249        super().__init__()250        self.heads = heads251        self.scale = dim_head ** -0.5252        inner_dim = heads * dim_head253        context_dim = default(context_dim, dim)254 255        self.norm = LayerNorm(dim)256        self.context_norm = LayerNorm(context_dim) if norm_context else nn.Identity()257 258        self.to_q = nn.Linear(dim, inner_dim, bias=False)259        self.to_kv = nn.Linear(context_dim, dim_head * 2, bias=False)260        self.to_out = nn.Linear(inner_dim, dim, bias=False)261 262        self.dropout = dropout263 264        # whether to have parallel feedforward265        ff_inner_dim = ff_mult * dim266 267        self.ff = nn.Sequential(268            nn.Linear(dim, ff_inner_dim * 2, bias=False),269            SwiGLU(),270            nn.Linear(ff_inner_dim, dim, bias=False)271        ) if parallel_ff else None272 273    def forward(self, x, context):274        """275        Use text and query, and image as kv276        einstein notation277        b - batch278        h - heads279        n, i, j - sequence length (base sequence length, source, target)280        d - feature dimension281        """282 283        # pre-layernorm, for queries and context284        x = self.norm(x)285        context = self.context_norm(context)286        # get queries287        q = self.to_q(x)288        q = rearrange(q, 'b n (h d) -> b h n d', h = self.heads)289        # scale290        q = q * self.scale291        # get key / values292        k, v = self.to_kv(context).chunk(2, dim=-1)293        # query / key similarity294        sim = einsum('b h i d, b j d -> b h i j', q, k)295        296        # dropout297        if self.training:298            dropout_mask = torch.cuda.FloatTensor(*sim.shape).uniform_() > self.dropout299            sim = sim.masked_fill(~dropout_mask, -torch.finfo(sim.dtype).max)300 301        # attention302        sim = sim - sim.amax(dim=-1, keepdim=True)303        attn = sim.softmax(dim=-1)304        # aggregate305        out = einsum('b h i j, b j d -> b h i d', attn, v)306        # merge and combine heads307        out = rearrange(out, 'b h n d -> b n (h d)')308        out = self.to_out(out)309        # add parallel feedforward (for multimodal layers)310        if exists(self.ff):311            out = out + self.ff(x)312        return out313 314 315 316def get_2d_sincos_pos_embed(embed_dim, grid_size, cls_token=False):317    """318    grid_size: int of the grid height and width319    return:320    pos_embed: [grid_size*grid_size, embed_dim] or [1+grid_size*grid_size, embed_dim] (w/ or w/o cls_token)321    """322    grid_h = np.arange(grid_size, dtype=np.float32)323    grid_w = np.arange(grid_size, dtype=np.float32)324    grid = np.meshgrid(grid_w, grid_h)  # here w goes first325    grid = np.stack(grid, axis=0)326 327    grid = grid.reshape([2, 1, grid_size, grid_size])328    pos_embed = get_2d_sincos_pos_embed_from_grid(embed_dim, grid)329    if cls_token:330        pos_embed = np.concatenate([np.zeros([1, embed_dim]), pos_embed], axis=0)331    return pos_embed332 333def get_2d_sincos_pos_embed_from_grid(embed_dim, grid):334    assert embed_dim % 2 == 0335 336    # use half of dimensions to encode grid_h337    emb_h = get_1d_sincos_pos_embed_from_grid(embed_dim // 2, grid[0])  # (H*W, D/2)338    emb_w = get_1d_sincos_pos_embed_from_grid(embed_dim // 2, grid[1])  # (H*W, D/2)339 340    emb = np.concatenate([emb_h, emb_w], axis=1) # (H*W, D)341    return emb342 343def get_1d_sincos_pos_embed_from_grid(embed_dim, pos):344    """345    embed_dim: output dimension for each position346    pos: a list of positions to be encoded: size (M,)347    out: (M, D)348    """349    assert embed_dim % 2 == 0350    omega = np.arange(embed_dim // 2, dtype=np.float32)351    omega /= embed_dim / 2.352    omega = 1. / 10000**omega  # (D/2,)353 354    pos = pos.reshape(-1)  # (M,)355    out = np.einsum('m,d->md', pos, omega)  # (M, D/2), outer product356 357    emb_sin = np.sin(out) # (M, D/2)358    emb_cos = np.cos(out) # (M, D/2)359 360    emb = np.concatenate([emb_sin, emb_cos], axis=1)  # (M, D)361    return emb362 363class MaskedAutoencoderViT(nn.Module):364    """ Masked Autoencoder with VisionTransformer backbone365    """366    def __init__(self, img_size=224, patch_size=16, in_chans=3,367                 embed_dim=1024, depth=24, num_heads=16,368                 decoder_embed_dim=512, decoder_depth=8, decoder_num_heads=16,369                 mlp_ratio=4., norm_layer=nn.LayerNorm, norm_pix_loss=True,370                 unimodal_depth=2, multimodal_depth=8, dim_head=64,heads=8,371                 ff_mult=4, extract_multi_level=False, use_focal_loss=False, focal_gamma=1.0,372                 less_u=False, use_weak_negative=False, use_label_smooth=False, ls_coef=0.1,373                 use_maximum_entropy=False, ce_additional=False, use_word_weights=False, use_token_pos=False,374                 use_expect_k=False, use_top_k=False, mae_decoder_caption=False, decoder_slot_depth=2, disable_decoder_vis_token_grad=False,375                 cross_attn_dropout=0.0, predict_next_k_words=False, next_k=3, masked_text=False, masked_text_ratio=0.25, text_length=70,376                 projector_layer=0, uni_dim=1024, uni_dim_head=64, uni_heads=8, uni_ff_mult=4, text_drop_attn=0.):377        super().__init__()378 379        # --------------------------------------------------------------------------380        # MAE encoder specifics381        self.patch_embed = PatchEmbed(img_size, patch_size, in_chans, embed_dim)382        num_patches = self.patch_embed.num_patches383 384        self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))385        self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, embed_dim), requires_grad=False)  # fixed sin-cos embedding386 387        self.blocks = nn.ModuleList([388            Block(embed_dim, num_heads, mlp_ratio, qkv_bias=True, norm_layer=norm_layer)389            for i in range(depth)])390        self.norm = norm_layer(embed_dim)391        # --------------------------------------------------------------------------392 393        # --------------------------------------------------------------------------394        # MAE decoder specifics395        self.decoder_embed = nn.Linear(embed_dim, decoder_embed_dim, bias=True)396 397        self.mask_token = nn.Parameter(torch.zeros(1, 1, decoder_embed_dim))398 399        self.decoder_pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, decoder_embed_dim), requires_grad=False)  # fixed sin-cos embedding400 401        self.mae_decoder_depth = decoder_depth402        self.mae_decoder_caption = mae_decoder_caption403        self.decoder_blocks = nn.ModuleList([404            Block(decoder_embed_dim, decoder_num_heads, mlp_ratio, qkv_bias=True, norm_layer=norm_layer)405            for i in range(decoder_depth)])406 407        if self.mae_decoder_caption:408 409            self.decoder_slot_layers = nn.ModuleList([])410            for _ in range(decoder_slot_depth):411                self.decoder_slot_layers.append(412                    Residual(CrossAttention(dim=decoder_embed_dim, dim_head=dim_head, heads=heads, parallel_ff=True, ff_mult=ff_mult,)),413                    # Residual(CrossAttention(dim=decoder_embed_dim, dim_head=dim_head, heads=heads, parallel_ff=True, ff_mult=ff_mult,))414                )415            self.decoder_caption_proj = nn.Linear(decoder_embed_dim, embed_dim)416            self.disable_decoder_vis_token_grad = disable_decoder_vis_token_grad417 418        self.decoder_norm = norm_layer(decoder_embed_dim)419        self.decoder_pred = nn.Linear(decoder_embed_dim, patch_size**2 * in_chans, bias=True) # encoder to decoder420        # --------------------------------------------------------------------------421 422        self.norm_pix_loss = norm_pix_loss423 424        # --------------------------------------------------------------------------425        # captioner specifics426        # unimodal layer is for text tokens.427        # multimodal layer is for text to query from image.        428        self.tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased", )429        430        # token embeddings431        # NOTE: +1 for mask token used by MLM objective432        # self.token_emb = nn.Embedding(len(self.tokenizer.vocab) + 1, uni_dim)433 434        self.token_emb = nn.Embedding(len(self.tokenizer.vocab), uni_dim)435        self.text_cls_token = nn.Parameter(torch.randn(uni_dim))436 437        self.embed_dim = embed_dim438        self.uni_dim = uni_dim439        440        #import ipdb; ipdb.set_trace()441        # unimodal layers442        # TODO: search on the four parameters443        # uni_dim=1024, uni_dim_head=64, uni_heads=8, uni_ff_mult=4444        self.text_drop_attn = text_drop_attn445        self.unimodal_layers = nn.ModuleList([])446        for _ in range(unimodal_depth):447            self.unimodal_layers.append(448                Residual(ParallelTransformerBlock(dim=uni_dim, dim_head=uni_dim_head, 449                        heads=uni_heads, ff_mult=uni_ff_mult, attn_drop_rate=self.text_drop_attn)),450            )451 452        self.need_uni_2_mul_proj = False453        if uni_dim != embed_dim:454            self.need_uni_2_mul_proj = True455            self.uni_2_mul_proj = nn.Linear(uni_dim, embed_dim)456        457        # multimodal layers458        self.multimodal_layers = nn.ModuleList([])459        self.less_u = less_u460        if less_u:461            for _ in range(multimodal_depth):462                self.multimodal_layers.append(nn.ModuleList([463                    Residual(CrossAttention(dim=embed_dim, dim_head=dim_head, heads=heads, parallel_ff=True, ff_mult=ff_mult, dropout=cross_attn_dropout)),464                    Residual(CrossAttention(dim=embed_dim, dim_head=dim_head, heads=heads, parallel_ff=True, ff_mult=ff_mult, dropout=cross_attn_dropout))465                ]))466        else:467            for _ in range(multimodal_depth):468                self.multimodal_layers.append(nn.ModuleList([469                    Residual(ParallelTransformerBlock(dim=embed_dim, dim_head=dim_head, heads=heads, ff_mult=ff_mult)),470                    Residual(CrossAttention(dim=embed_dim, dim_head=dim_head, heads=heads, parallel_ff=True, ff_mult=ff_mult, dropout=cross_attn_dropout))471                ]))472 473        # to logits: for softmax caption loss474        self.to_logits = nn.Sequential(475            LayerNorm(embed_dim),476            nn.Linear(embed_dim, len(self.tokenizer.vocab), bias=False)477        )478 479        self.ce_additional = ce_additional480        if ce_additional:481            # to logits: for other losses482            self.to_logits_1 = nn.Sequential(483                LayerNorm(embed_dim),484                nn.Linear(embed_dim, len(self.tokenizer.vocab), bias=False)485            )486        487        nn.init.normal_(self.token_emb.weight, std=0.02)488 489        self.pad_id = 0490        self.cls_id = 101491        self.sep_id = 102492 493        self.logsoftmax = nn.LogSoftmax(dim=1)494 495        self.extract_multi_level = extract_multi_level496        if self.extract_multi_level:497            self.projectors = nn.ModuleList([nn.Sequential(498                nn.Linear(embed_dim, embed_dim // 2),499                nn.GELU(),500                nn.Linear(embed_dim // 2, embed_dim),501                norm_layer(embed_dim)502            ) for _ in [2, 5, 8,]])503        # --------------------------------------------------------------------------504        505        self.use_focal_loss = use_focal_loss506        507        self.use_weak_negative = use_weak_negative508        self.use_label_smooth = use_label_smooth509        self.ls_coef = ls_coef510        self.use_entropy = use_maximum_entropy511        self.use_word_weights = use_word_weights512        self.use_token_pos = use_token_pos513 514        self.predict_next_k_words = predict_next_k_words515        self.next_k = next_k516        self.pad = torch.nn.ReplicationPad1d((0, self.next_k-1))517 518        self.use_expect_k = use_expect_k519        self.use_top_k = use_top_k520 521        if self.use_word_weights or self.use_token_pos:522            self.focal_loss = FocalLoss(ignore_index=self.pad_id, gamma=focal_gamma, reduction='none')523        else:524            self.focal_loss = FocalLoss(ignore_index=self.pad_id, gamma=focal_gamma, reduction='mean')525 526        self.masked_text = masked_text527        self.masked_text_ratio = masked_text_ratio528        # self.text_mask_token = nn.Parameter(torch.randn(embed_dim))529        self.mask_token_id = len(self.tokenizer.vocab)530 531        # self.text_position_embed = nn.Parameter(torch.zeros(1, text_length, embed_dim), requires_grad=False)532        self.text_length = text_length533 534        self.latent_projector_layer = projector_layer535        if self.latent_projector_layer != 0:536            self.latent_projector = [537                nn.Linear(embed_dim, embed_dim),538                nn.ReLU()539            ] * (self.latent_projector_layer - 1)540            self.latent_projector.append(nn.Linear(embed_dim, embed_dim))541 542            self.latent_projector = nn.Sequential(*self.latent_projector)543 544 545        self.initialize_weights()546 547 548    def initialize_weights(self):549        # initialization550        # initialize (and freeze) pos_embed by sin-cos embedding551        pos_embed = get_2d_sincos_pos_embed(self.pos_embed.shape[-1], int(self.patch_embed.num_patches**.5), cls_token=True)552        self.pos_embed.data.copy_(torch.from_numpy(pos_embed).float().unsqueeze(0))553 554        decoder_pos_embed = get_2d_sincos_pos_embed(self.decoder_pos_embed.shape[-1], int(self.patch_embed.num_patches**.5), cls_token=True)555        self.decoder_pos_embed.data.copy_(torch.from_numpy(decoder_pos_embed).float().unsqueeze(0))556 557        # text_pos_embed = get_1d_sincos_pos_embed_from_grid(self.embed_dim, )558        # torch.nn.init.xavier_normal_(self.text_position_embed) # learnable text position embedding559 560        # initialize patch_embed like nn.Linear (instead of nn.Conv2d)561        w = self.patch_embed.proj.weight.data562        torch.nn.init.xavier_uniform_(w.view([w.shape[0], -1]))563 564        # timm's trunc_normal_(std=.02) is effectively normal_(std=0.02) as cutoff is too big (2.)565        torch.nn.init.normal_(self.cls_token, std=.02)566        torch.nn.init.normal_(self.mask_token, std=.02)567        # torch.nn.init.normal_(self.text_mask_token, std=.02)568 569        # initialize nn.Linear and nn.LayerNorm570        self.apply(self._init_weights)571 572    def _init_weights(self, m):573        if isinstance(m, nn.Linear):574            # we use xavier_uniform following official JAX ViT:575            torch.nn.init.xavier_uniform_(m.weight)576            if isinstance(m, nn.Linear) and m.bias is not None:577                nn.init.constant_(m.bias, 0)578        elif isinstance(m, nn.LayerNorm):579            nn.init.constant_(m.bias, 0)580            nn.init.constant_(m.weight, 1.0)581 582    def patchify(self, imgs):583        """584        imgs: (N, 3, H, W)585        x: (N, L, patch_size**2 *3)586        """587        p = self.patch_embed.patch_size[0]588        assert imgs.shape[2] == imgs.shape[3] and imgs.shape[2] % p == 0589 590        h = w = imgs.shape[2] // p591        x = imgs.reshape(shape=(imgs.shape[0], 3, h, p, w, p))592        x = torch.einsum('nchpwq->nhwpqc', x)593        x = x.reshape(shape=(imgs.shape[0], h * w, p**2 * 3))594        return x595 596    def unpatchify(self, x):597        """598        x: (N, L, patch_size**2 *3)599        imgs: (N, 3, H, W)600        """601        p = self.patch_embed.patch_size[0]602        h = w = int(x.shape[1]**.5)603        assert h * w == x.shape[1]604        605        x = x.reshape(shape=(x.shape[0], h, w, p, p, 3))606        x = torch.einsum('nhwpqc->nchpwq', x)607        imgs = x.reshape(shape=(x.shape[0], 3, h * p, h * p))608        return imgs609 610    def random_masking(self, x, mask_ratio):611        """612        Perform per-sample random masking by per-sample shuffling.613        Per-sample shuffling is done by argsort random noise.614        x: [N, L, D], sequence615        """616        N, L, D = x.shape  # batch, length, dim617        len_keep = int(L * (1 - mask_ratio))618        619        noise = torch.rand(N, L, device=x.device)  # noise in [0, 1]620        621        # sort noise for each sample622        ids_shuffle = torch.argsort(noise, dim=1)  # ascend: small is keep, large is remove623        ids_restore = torch.argsort(ids_shuffle, dim=1)624 625        # keep the first subset626        ids_keep = ids_shuffle[:, :len_keep]627        x_masked = torch.gather(x, dim=1, index=ids_keep.unsqueeze(-1).repeat(1, 1, D))628 629        # generate the binary mask: 0 is keep, 1 is remove630        mask = torch.ones([N, L], device=x.device)631        mask[:, :len_keep] = 0632        # unshuffle to get the binary mask633        mask = torch.gather(mask, dim=1, index=ids_restore)634 635        return x_masked, mask, ids_restore, ids_keep636 637    def forward_encoder(self, x, mask_ratio):638        # embed patches639        x = self.patch_embed(x)640 641        # add pos embed w/o cls token642        x = x + self.pos_embed[:, 1:, :]643 644        # masking: length -> length * mask_ratio645        x, mask, ids_restore, ids_keep = self.random_masking(x, mask_ratio)646 647        # append cls token648        cls_token = self.cls_token + self.pos_embed[:, :1, :]649        cls_tokens = cls_token.expand(x.shape[0], -1, -1)650        x = torch.cat((cls_tokens, x), dim=1)651 652        if self.extract_multi_level:653            multi_level_feats = []654            # apply Transformer blocks655            for blk_idx, blk in enumerate(self.blocks):656                x = blk(x)657                if blk_idx in [2, 5, 8]:658                    multi_level_feats.append(self.projectors[[2,5,8].index(blk_idx)](x))659            x = self.norm(x)660            multi_level_feats.append(x)661 662            return multi_level_feats, mask, ids_restore663 664 665        # apply Transformer blocks666        for blk_idx, blk in enumerate(self.blocks):667            x = blk(x)668        x = self.norm(x)669        670        return x, mask, ids_restore, ids_keep671 672    def forward_decoder(self, x, ids_restore):673        # embed tokens674        x = self.decoder_embed(x)675        # non_mask_token = x676 677        # append mask tokens to sequence678        mask_tokens = self.mask_token.repeat(x.shape[0], ids_restore.shape[1] + 1 - x.shape[1], 1)679        x_ = torch.cat([x[:, 1:, :], mask_tokens], dim=1)  # no cls token680        x_ = torch.gather(x_, dim=1, index=ids_restore.unsqueeze(-1).repeat(1, 1, x.shape[2]))  # unshuffle681        x = torch.cat([x[:, :1, :], x_], dim=1)  # append cls token682 683        # add pos embed684        x = x + self.decoder_pos_embed685 686        # apply Transformer blocks687        decoder_feat = []688        for idx, blk in enumerate(self.decoder_blocks):689            x = blk(x)690            if idx == self.mae_decoder_depth // 2:691                decoder_feat.append(x)692 693        x = self.decoder_norm(x)694 695        # use the output from decoder to do captioning696 697        # predictor projection698        x = self.decoder_pred(x)699 700        # remove cls token701        x = x[:, 1:, :]702 703        return x, decoder_feat704 705    def forward_loss(self, imgs, pred, mask):706        """707        imgs: [N, 3, H, W]708        pred: [N, L, p*p*3]709        mask: [N, L], 0 is keep, 1 is remove, 710        """711        target = self.patchify(imgs)712        if self.norm_pix_loss:713            mean = target.mean(dim=-1, keepdim=True)714            var = target.var(dim=-1, keepdim=True)715            target = (target - mean) / (var + 1.e-6)**.5716 717        loss = (pred - target) ** 2718        loss = loss.mean(dim=-1)  # [N, L], mean loss per patch719 720        loss = (loss * mask).sum() / mask.sum()  # mean loss on removed patches721        return loss722 723    def embed_text(self, text):724        batch, device = text.shape[0], text.device725 726        seq = text.shape[1]727 728        text_tokens = self.token_emb(text)729 730        # append text cls tokens731        text_cls_tokens = repeat(self.text_cls_token, 'd -> b 1 d', b=batch)732        text_tokens = torch.cat((text_tokens, text_cls_tokens), dim=-2)733 734        # create specific mask for text cls token at the end735        # to prevent it from attending to padding736        cls_mask = rearrange(text != self.pad_id, 'b j -> b 1 j')737        attn_mask = F.pad(cls_mask, (0, 1, seq, 0), value=True)738 739        # go through unimodal layers740        for attn_ff in self.unimodal_layers:741            text_tokens = attn_ff(text_tokens, attn_mask=attn_mask)742 743        if self.need_uni_2_mul_proj:744            text_tokens = self.uni_2_mul_proj(text_tokens)745 746        # get text cls token747        text_tokens, text_cls_tokens = text_tokens[:, :-1], text_tokens[:, -1]748        return text_tokens749 750        751    752    def forward(self, imgs, caption_ids=None, attention_mask=None, mask_ratio=0.75, 753                    freeze_bert=False, teacher_forcing=False, caption_only=False,754                    encoder_only=False, word_weights=None, syn_count=None):755        latent, mask, ids_restore, ids_keep = self.forward_encoder(imgs, mask_ratio)756 757        if not caption_only:758            pred, decoder_feat = self.forward_decoder(latent, ids_restore)  # [N, L, p*p*3]759            mae_loss = self.forward_loss(imgs, pred, mask)760        else:761            mae_loss = 0.762 763        if self.latent_projector_layer != 0:764            latent = self.latent_projector(latent)765 766        # latent: visual info: N, L, C767        # caption_ids: N, Len768        text, labels = caption_ids[:, :-1], caption_ids[:, 1:]769 770        seq = text.shape[1]771        text_tokens = self.embed_text(text) # N, Len, C772 773        # create specific mask for text cls token at the end774        # to prevent it from attending to padding775        cls_mask = rearrange(text != self.pad_id, 'b j -> b 1 j')776        attn_mask = F.pad(cls_mask, (0, 1, seq, 0), value=True)777        unimodal_text_tokens = text_tokens778        if not self.less_u:779            for attn_ff, cross_attn in self.multimodal_layers:780                text_tokens = attn_ff(text_tokens, attn_mask=attn_mask[:, :-1, :-1])781                text_tokens = cross_attn(text_tokens, latent)782        else:783            # dim, num_head, 784            for cross_attn1, cross_attn2 in self.multimodal_layers:785                text_tokens = cross_attn1(text_tokens, latent)786                text_tokens = cross_attn2(text_tokens, latent)787 788        logits = self.to_logits(text_tokens) # N, Len, NVocab789        logits = logits.reshape(-1, len(self.tokenizer.vocab))790        labels = labels.reshape(-1)791 792        caption_loss = F.cross_entropy(logits, labels, ignore_index=self.pad_id,)793 794 795        return mae_loss, caption_loss, None796 797 798 799def mae_vit_small_patch16_dec512d8b(**kwargs):800    model = MaskedAutoencoderViT(801        patch_size=16, embed_dim=384, depth=12, num_heads=6,802        decoder_embed_dim=512, decoder_depth=8, decoder_num_heads=16,803        mlp_ratio=4, norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)804    return model805 806 807 808def mae_vit_base_patch16_dec512d8b(**kwargs):809    model = MaskedAutoencoderViT(810        patch_size=16, embed_dim=768, depth=12, num_heads=12,811        decoder_embed_dim=512, decoder_depth=8, decoder_num_heads=16,812        mlp_ratio=4, norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)813    return model814 815def mae_vit_large_patch16_dec512d8b(**kwargs):816    model = MaskedAutoencoderViT(817        patch_size=16, embed_dim=1024, depth=24, num_heads=16,818        decoder_embed_dim=512, decoder_depth=8, decoder_num_heads=16,819        mlp_ratio=4, norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)820    return model821 822 823def mae_vit_huge_patch14_dec512d8b(**kwargs):824    model = MaskedAutoencoderViT(825        patch_size=14, embed_dim=1280, depth=32, num_heads=16,826        decoder_embed_dim=512, decoder_depth=8, decoder_num_heads=16,827        mlp_ratio=4, norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)828    return model829 830 831# set recommended archs832mae_vit_small_patch16 = mae_vit_small_patch16_dec512d8b833mae_vit_base_patch16 = mae_vit_base_patch16_dec512d8b  # decoder: 512 dim, 8 blocks834mae_vit_large_patch16 = mae_vit_large_patch16_dec512d8b  # decoder: 512 dim, 8 blocks835mae_vit_huge_patch14 = mae_vit_huge_patch14_dec512d8b  # decoder: 512 dim, 8 blocks836 837 838 839 840 841