Spaces:
Running on Zero
Running on Zero
| # Scale-RAE ViT-MAE decoder (ported from | |
| # https://github.com/nyu-visionx/Scale-RAE — scale_rae/model/multimodal_decoder/decoder.py:805-1015). | |
| # | |
| # Mirrors the upstream `GeneralDecoder` 1:1 so the published Scale-RAE | |
| # checkpoints (e.g. siglip2_sop14_i224_web73M_ganw3_decXL.pt) load cleanly with | |
| # strict=True. Differences vs the sibling `rae_decoder.py` (DINOv2-RAE): | |
| # * `forward` returns `ViTMAEDecoderOutput` (has `.logits` attribute). | |
| # * `interpolate_pos_encoding` is provided for variable token grids. | |
| # * `set_trainable_cls_token(tensor=None)` setter for parity with upstream. | |
| # * `forward(.., drop_cls_token=False)` raises NotImplementedError, matching | |
| # the upstream `else` branch — Scale-RAE's published decoders are always | |
| # called with `drop_cls_token=True`. | |
| # * `forward(.., skip_interpolate_latent=True)` lets a caller feed an | |
| # arbitrary token grid (e.g. 32×32 = 1024 tokens) instead of the | |
| # pretrained 16×16; without this flag, `interpolate_latent` always | |
| # down/up-samples back to `num_patches`. Pair with | |
| # `interpolate_pos_encoding=True` so the sin-cos pos embed is bicubic | |
| # resized to match the input grid. | |
| from copy import deepcopy | |
| from dataclasses import dataclass | |
| from typing import Optional, Tuple | |
| import numpy as np | |
| import torch | |
| import torch.nn as nn | |
| from transformers.modeling_outputs import ModelOutput | |
| from transformers.models.vit_mae.configuration_vit_mae import ViTMAEConfig | |
| from transformers.models.vit_mae.modeling_vit_mae import ViTMAELayer | |
| def _get_1d_sincos_pos_embed_from_grid(embed_dim: int, pos: np.ndarray) -> np.ndarray: | |
| assert embed_dim % 2 == 0 | |
| omega = np.arange(embed_dim // 2, dtype=float) | |
| omega /= embed_dim / 2.0 | |
| omega = 1.0 / 10000**omega | |
| pos = pos.reshape(-1) | |
| out = np.einsum("m,d->md", pos, omega) | |
| return np.concatenate([np.sin(out), np.cos(out)], axis=1) | |
| def _get_2d_sincos_pos_embed_from_grid(embed_dim: int, grid: np.ndarray) -> np.ndarray: | |
| assert embed_dim % 2 == 0 | |
| emb_h = _get_1d_sincos_pos_embed_from_grid(embed_dim // 2, grid[0]) | |
| emb_w = _get_1d_sincos_pos_embed_from_grid(embed_dim // 2, grid[1]) | |
| return np.concatenate([emb_h, emb_w], axis=1) | |
| def get_2d_sincos_pos_embed(embed_dim: int, grid_size: int, add_cls_token: bool = False) -> np.ndarray: | |
| grid_h = np.arange(grid_size, dtype=np.float32) | |
| grid_w = np.arange(grid_size, dtype=np.float32) | |
| grid = np.meshgrid(grid_w, grid_h) # w goes first | |
| grid = np.stack(grid, axis=0).reshape([2, 1, grid_size, grid_size]) | |
| pos_embed = _get_2d_sincos_pos_embed_from_grid(embed_dim, grid) | |
| if add_cls_token: | |
| pos_embed = np.concatenate([np.zeros([1, embed_dim]), pos_embed], axis=0) | |
| return pos_embed | |
| class ViTMAEDecoderOutput(ModelOutput): | |
| logits: Optional[torch.FloatTensor] = None | |
| hidden_states: Optional[Tuple[torch.FloatTensor, ...]] = None | |
| attentions: Optional[Tuple[torch.FloatTensor, ...]] = None | |
| class GeneralDecoder(nn.Module): | |
| """Scale-RAE ViT-MAE decoder. | |
| Input convention: `(B, num_patches+1, hidden_size)` — first token is a | |
| placeholder CLS that is stripped (`drop_cls_token=True`) and replaced by | |
| a learned `trainable_cls_token`. Patch tokens are bilinearly rescaled to | |
| the decoder's training grid (`interpolate_latent`) when needed. | |
| Output: `ViTMAEDecoderOutput(logits=(B, num_patches, patch_size**2 * num_channels))`. | |
| """ | |
| def __init__(self, config: ViTMAEConfig, num_patches: int): | |
| super().__init__() | |
| self.decoder_embed = nn.Linear(config.hidden_size, config.decoder_hidden_size, bias=True) | |
| self.decoder_pos_embed = nn.Parameter( | |
| torch.zeros(1, num_patches + 1, config.decoder_hidden_size), requires_grad=False | |
| ) | |
| decoder_config = deepcopy(config) | |
| decoder_config.hidden_size = config.decoder_hidden_size | |
| decoder_config.num_hidden_layers = config.decoder_num_hidden_layers | |
| decoder_config.num_attention_heads = config.decoder_num_attention_heads | |
| decoder_config.intermediate_size = config.decoder_intermediate_size | |
| decoder_config._attn_implementation = getattr(config, "_attn_implementation", "sdpa") or "sdpa" | |
| self.decoder_layers = nn.ModuleList( | |
| [ViTMAELayer(decoder_config) for _ in range(config.decoder_num_hidden_layers)] | |
| ) | |
| self.decoder_norm = nn.LayerNorm(config.decoder_hidden_size, eps=config.layer_norm_eps) | |
| self.decoder_pred = nn.Linear(config.decoder_hidden_size, config.patch_size**2 * config.num_channels, bias=True) | |
| self.gradient_checkpointing = False | |
| self.config = config | |
| self.num_patches = num_patches | |
| self.decoder_config = decoder_config | |
| # Init fixed sin-cos decoder pos embed (CLS slot stays zero). | |
| pos = get_2d_sincos_pos_embed(self.decoder_pos_embed.shape[-1], int(num_patches**0.5), add_cls_token=True) | |
| self.decoder_pos_embed.data.copy_(torch.from_numpy(pos).float().unsqueeze(0)) | |
| self.set_trainable_cls_token() | |
| def set_trainable_cls_token(self, tensor: Optional[torch.Tensor] = None): | |
| tensor = torch.zeros(1, 1, self.decoder_config.hidden_size) if tensor is None else tensor | |
| self.trainable_cls_token = nn.Parameter(tensor) | |
| def interpolate_pos_encoding(self, embeddings: torch.Tensor) -> torch.Tensor: | |
| """Bicubic-resize the patch portion of decoder_pos_embed to the input grid size.""" | |
| embeddings_positions = embeddings.shape[1] - 1 | |
| num_positions = self.decoder_pos_embed.shape[1] - 1 | |
| class_pos_embed = self.decoder_pos_embed[:, 0, :] | |
| patch_pos_embed = self.decoder_pos_embed[:, 1:, :] | |
| dim = self.decoder_pos_embed.shape[-1] | |
| patch_pos_embed = patch_pos_embed.reshape(1, 1, -1, dim).permute(0, 3, 1, 2) | |
| patch_pos_embed = nn.functional.interpolate( | |
| patch_pos_embed, | |
| scale_factor=(1, embeddings_positions / num_positions), | |
| mode="bicubic", | |
| align_corners=False, | |
| ) | |
| patch_pos_embed = patch_pos_embed.permute(0, 2, 3, 1).view(1, -1, dim) | |
| return torch.cat((class_pos_embed.unsqueeze(0), patch_pos_embed), dim=1) | |
| def interpolate_latent(self, x: torch.Tensor) -> torch.Tensor: | |
| """(B, L, C) → (B, num_patches, C), bilinear on the 2D grid.""" | |
| b, l, c = x.shape | |
| if l == self.num_patches: | |
| return x | |
| h = w = int(l**0.5) | |
| assert h * w == l, f"cannot reshape length {l} to a square grid" | |
| x = x.reshape(b, h, w, c).permute(0, 3, 1, 2) | |
| target = int(self.num_patches**0.5) | |
| x = nn.functional.interpolate(x, size=(target, target), mode="bilinear", align_corners=False) | |
| return x.permute(0, 2, 3, 1).contiguous().view(b, self.num_patches, c) | |
| def unpatchify( | |
| self, | |
| patchified_pixel_values: torch.Tensor, | |
| original_image_size: Optional[Tuple[int, int]] = None, | |
| ) -> torch.Tensor: | |
| patch_size, num_channels = self.config.patch_size, self.config.num_channels | |
| H, W = ( | |
| original_image_size if original_image_size is not None else (self.config.image_size, self.config.image_size) | |
| ) | |
| nph, npw = H // patch_size, W // patch_size | |
| if nph * npw != patchified_pixel_values.shape[1]: | |
| raise ValueError(f"patch count {patchified_pixel_values.shape[1]} does not match grid {nph}*{npw}") | |
| B = patchified_pixel_values.shape[0] | |
| patches = patchified_pixel_values.reshape(B, nph, npw, patch_size, patch_size, num_channels) | |
| patches = torch.einsum("nhwpqc->nchpwq", patches) | |
| return patches.reshape(B, num_channels, nph * patch_size, npw * patch_size) | |
| def forward( | |
| self, | |
| hidden_states: torch.Tensor, | |
| output_attentions: bool = False, | |
| output_hidden_states: bool = False, | |
| return_dict: bool = True, | |
| interpolate_pos_encoding: bool = False, | |
| drop_cls_token: bool = False, | |
| skip_interpolate_latent: bool = False, | |
| ): | |
| x = self.decoder_embed(hidden_states) | |
| x_ = x[:, 1:, :] # input first token is a placeholder CLS, stripped here | |
| if drop_cls_token: | |
| cls_token = self.trainable_cls_token.expand(x_.shape[0], -1, -1) | |
| if not skip_interpolate_latent: | |
| x_ = self.interpolate_latent(x_) | |
| x = torch.cat([cls_token, x_], dim=1) | |
| else: | |
| raise NotImplementedError("drop_cls_token=False is not implemented for Scale-RAE decoder") | |
| if interpolate_pos_encoding: | |
| decoder_pos_embed = self.interpolate_pos_encoding(x) | |
| else: | |
| decoder_pos_embed = self.decoder_pos_embed | |
| hidden_states = x + decoder_pos_embed | |
| # Note: in transformers 4.57+ `ViTMAELayer.forward` no longer accepts | |
| # `head_mask` / `output_attentions` and returns the hidden tensor | |
| # directly (not a tuple). We therefore drop the optional outputs and | |
| # call each layer with just the hidden states — matching the sibling | |
| # `rae_decoder.py` convention. | |
| del output_attentions, output_hidden_states # unused on this transformers version | |
| all_hidden_states = None | |
| all_self_attentions = None | |
| for layer_module in self.decoder_layers: | |
| out = layer_module(hidden_states) | |
| hidden_states = out[0] if isinstance(out, tuple) else out | |
| hidden_states = self.decoder_norm(hidden_states) | |
| logits = self.decoder_pred(hidden_states) | |
| logits = logits[:, 1:, :] # strip CLS slot | |
| if not return_dict: | |
| return tuple(v for v in [logits, all_hidden_states, all_self_attentions] if v is not None) | |
| return ViTMAEDecoderOutput( | |
| logits=logits, | |
| hidden_states=all_hidden_states, | |
| attentions=all_self_attentions, | |
| ) | |