victor's picture
victor HF Staff
Cache examples and simplify frontend
e2ddf3f verified
Raw
History Blame Contribute Delete
9.87 kB
# 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
@dataclass
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,
)