CoolFace
Modelpublic

google/tipsv1-s14

sourceHugging Faceapache-2.0updated 1mo agoView on Hugging Face
2likes367downloads
image_encoder.py1003 linesDownload Raw Back to root
1# Copyright 2025 Google LLC2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7#    http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14# ==============================================================================15 16"""Vision encoder implementation in PyTorch."""17 18import functools19import math20import os21from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union22import warnings23import torch24from torch import nn25import torch.nn.functional as F26import torch.utils.checkpoint27 28 29class Mlp(nn.Module):30  """Transformer MLP, following DINOv2 implementation."""31 32  def __init__(33      self,34      in_features: int,35      hidden_features: Optional[int] = None,36      out_features: Optional[int] = None,37      act_layer: Callable[..., nn.Module] = nn.GELU,38      drop: float = 0.0,39      bias: bool = True,40  ) -> None:41    super().__init__()42    out_features = out_features or in_features43    hidden_features = hidden_features or in_features44    self.fc1 = nn.Linear(in_features, hidden_features, bias=bias)45    self.act = act_layer()46    self.fc2 = nn.Linear(hidden_features, out_features, bias=bias)47    self.drop = nn.Dropout(drop)48 49  def forward(self, x: torch.Tensor) -> torch.Tensor:50    x = self.fc1(x)51    x = self.act(x)52    x = self.drop(x)53    x = self.fc2(x)54    x = self.drop(x)55    return x56 57 58def make_2tuple(x):59  if isinstance(x, tuple):60    assert len(x) == 261    return x62 63  assert isinstance(x, int)64  return (x, x)65 66 67class PatchEmbed(nn.Module):68  """2D image to patch embedding: (B,C,H,W) -> (B,N,D)."""69 70  def __init__(71      self,72      img_size: Union[int, Tuple[int, int]] = 224,73      patch_size: Union[int, Tuple[int, int]] = 16,74      in_chans: int = 3,75      embed_dim: int = 768,76      norm_layer: Optional[Callable] = None,  # pylint: disable=g-bare-generic77      flatten_embedding: bool = True,78  ) -> None:79    super().__init__()80 81    image_hw = make_2tuple(img_size)82    patch_hw = make_2tuple(patch_size)83    patch_grid_size = (84        image_hw[0] // patch_hw[0],85        image_hw[1] // patch_hw[1],86    )87 88    self.img_size = image_hw89    self.patch_size = patch_hw90    self.patches_resolution = patch_grid_size91    self.num_patches = patch_grid_size[0] * patch_grid_size[1]92 93    self.in_chans = in_chans94    self.embed_dim = embed_dim95 96    self.flatten_embedding = flatten_embedding97 98    self.proj = nn.Conv2d(99        in_chans, embed_dim, kernel_size=patch_hw, stride=patch_hw100    )101    self.norm = norm_layer(embed_dim) if norm_layer else nn.Identity()102 103  def forward(self, x: torch.Tensor) -> torch.Tensor:104    _, _, h, w = x.shape105    patch_h, patch_w = self.patch_size106 107    assert (108        h % patch_h == 0109    ), f"Input image height {h} is not a multiple of patch height {patch_h}"110    assert (111        w % patch_w == 0112    ), f"Input image width {w} is not a multiple of patch width: {patch_w}"113 114    x = self.proj(x)  # B C H W115    h, w = x.size(2), x.size(3)116    x = x.flatten(2).transpose(1, 2)  # B HW C117    x = self.norm(x)118    if not self.flatten_embedding:119      x = x.reshape(-1, h, w, self.embed_dim)  # B H W C120    return x121 122  def flops(self) -> float:123    ho, wo = self.patches_resolution124    flops = (125        ho126        * wo127        * self.embed_dim128        * self.in_chans129        * (self.patch_size[0] * self.patch_size[1])130    )131    if self.norm is not None:132      flops += ho * wo * self.embed_dim133    return flops134 135 136class SwiGLUFFN(nn.Module):137  """SwiGLU FFN layer, following DINOv2 implementation."""138 139  def __init__(140      self,141      in_features: int,142      hidden_features: Optional[int] = None,143      out_features: Optional[int] = None,144      act_layer: Callable[..., nn.Module] = None,145      drop: float = 0.0,146      bias: bool = True,147  ) -> None:148    super().__init__()149    out_features = out_features or in_features150    hidden_features = hidden_features or in_features151    self.w12 = nn.Linear(in_features, 2 * hidden_features, bias=bias)152    self.w3 = nn.Linear(hidden_features, out_features, bias=bias)153 154  def forward(self, x: torch.Tensor) -> torch.Tensor:155    x12 = self.w12(x)156    x1, x2 = x12.chunk(2, dim=-1)157    hidden = F.silu(x1) * x2158    return self.w3(hidden)159 160 161XFORMERS_ENABLED = os.environ.get("XFORMERS_DISABLED") is None162try:163  if XFORMERS_ENABLED:164    from xformers.ops import SwiGLU, memory_efficient_attention, unbind, fmha, scaled_index_add, index_select_cat  # pylint: disable=g-multiple-import, g-import-not-at-top165 166    XFORMERS_AVAILABLE = True167    warnings.warn("xFormers is available (SwiGLU)")168  else:169    warnings.warn("xFormers is disabled (SwiGLU)")170    raise ImportError171except ImportError:172  SwiGLU = SwiGLUFFN173  XFORMERS_AVAILABLE = False174 175  warnings.warn("xFormers is not available (SwiGLU)")176 177 178class SwiGLUFFNFused(SwiGLU):179  """SwiGLU FFN layer, following DINOv2 implementation."""180 181  def __init__(182      self,183      in_features: int,184      hidden_features: Optional[int] = None,185      out_features: Optional[int] = None,186      act_layer: Callable[..., nn.Module] = None,  # pylint: disable=unused-argument187      drop: float = 0.0,  # pylint: disable=unused-argument188      bias: bool = True,189  ) -> None:190    out_features = out_features or in_features191    hidden_features = hidden_features or in_features192    hidden_features = (int(hidden_features * 2 / 3) + 7) // 8 * 8193    super().__init__(194        in_features=in_features,195        hidden_features=hidden_features,196        out_features=out_features,197        bias=bias,198    )199 200 201class Attention(nn.Module):202  """Attention layer, following DINOv2 implementation."""203 204  def __init__(205      self,206      dim: int,207      num_heads: int = 8,208      qkv_bias: bool = False,209      proj_bias: bool = True,210      attn_drop: float = 0.0,211      proj_drop: float = 0.0,212  ) -> None:213    super().__init__()214    self.num_heads = num_heads215    head_dim = dim // num_heads216    self.scale = head_dim**-0.5217 218    self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)219    self.attn_drop = nn.Dropout(attn_drop)220    self.proj = nn.Linear(dim, dim, bias=proj_bias)221    self.proj_drop = nn.Dropout(proj_drop)222 223  def forward(self, x: torch.Tensor) -> torch.Tensor:224    b_dim, n_dim, c_dim = x.shape225    qkv = (226        self.qkv(x)227        .reshape(b_dim, n_dim, 3, self.num_heads, c_dim // self.num_heads)228        .permute(2, 0, 3, 1, 4)229    )230 231    q, k, v = qkv[0] * self.scale, qkv[1], qkv[2]232    attn = q @ k.transpose(-2, -1)233 234    attn = attn.softmax(dim=-1)235    attn = self.attn_drop(attn)236 237    x = (attn @ v).transpose(1, 2).reshape(b_dim, n_dim, c_dim)238    x = self.proj(x)239    x = self.proj_drop(x)240    return x241 242 243class MemEffAttention(Attention):244  """Memory Efficient Attention layer, following DINOv2 implementation."""245 246  def forward(self, x: torch.Tensor, attn_bias=None) -> torch.Tensor:247    if not XFORMERS_AVAILABLE:248      if attn_bias is not None:249        raise AssertionError("xFormers is required for using nested tensors")250      return super().forward(x)251 252    b_dim, n_dim, c_dim = x.shape253    qkv = self.qkv(x).reshape(254        b_dim, n_dim, 3, self.num_heads, c_dim // self.num_heads255    )256 257    q, k, v = unbind(qkv, 2)258 259    x = memory_efficient_attention(q, k, v, attn_bias=attn_bias)260    x = x.reshape([b_dim, n_dim, c_dim])261 262    x = self.proj(x)263    x = self.proj_drop(x)264    return x265 266 267class LayerScale(nn.Module):268  """Layer scale, following DINOv2 implementation."""269 270  def __init__(271      self,272      dim: int,273      init_values: Union[float, torch.Tensor] = 1e-5,274      inplace: bool = False,275  ) -> None:276    super().__init__()277    self.inplace = inplace278    self.gamma = nn.Parameter(init_values * torch.ones(dim))279 280  def forward(self, x: torch.Tensor) -> torch.Tensor:281    return x.mul_(self.gamma) if self.inplace else x * self.gamma282 283 284def drop_path_impl(x, drop_prob: float = 0.0, training: bool = False):285  if drop_prob == 0.0 or not training:286    return x287  keep_prob = 1 - drop_prob288  shape = (x.shape[0],) + (1,) * (289      x.ndim - 1290  )  # work with diff dim tensors, not just 2D ConvNets291  random_tensor = x.new_empty(shape).bernoulli_(keep_prob)292  if keep_prob > 0.0:293    random_tensor.div_(keep_prob)294  output = x * random_tensor295  return output296 297 298class DropPath(nn.Module):299  """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks)."""300 301  def __init__(self, drop_prob=None):302    super(DropPath, self).__init__()303    self.drop_prob = drop_prob304 305  def forward(self, x):306    return drop_path_impl(x, self.drop_prob, self.training)307 308 309class Block(nn.Module):310  """Transformer Block Implementation, following DINOv2 implementation."""311 312  def __init__(313      self,314      dim: int,315      num_heads: int,316      mlp_ratio: float = 4.0,317      qkv_bias: bool = False,318      proj_bias: bool = True,319      ffn_bias: bool = True,320      drop: float = 0.0,321      attn_drop: float = 0.0,322      init_values=None,323      drop_path: float = 0.0,324      act_layer: Callable[..., nn.Module] = nn.GELU,325      norm_layer: Callable[..., nn.Module] = nn.LayerNorm,326      attn_class: Callable[..., nn.Module] = Attention,327      ffn_layer: Callable[..., nn.Module] = Mlp,328  ) -> None:329    super().__init__()330    self.norm1 = norm_layer(dim)331    self.attn = attn_class(332        dim,333        num_heads=num_heads,334        qkv_bias=qkv_bias,335        proj_bias=proj_bias,336        attn_drop=attn_drop,337        proj_drop=drop,338    )339    self.ls1 = (340        LayerScale(dim, init_values=init_values)341        if init_values342        else nn.Identity()343    )344    self.drop_path1 = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()345 346    self.norm2 = norm_layer(dim)347    mlp_hidden_dim = int(dim * mlp_ratio)348    self.mlp = ffn_layer(349        in_features=dim,350        hidden_features=mlp_hidden_dim,351        act_layer=act_layer,352        drop=drop,353        bias=ffn_bias,354    )355    self.ls2 = (356        LayerScale(dim, init_values=init_values)357        if init_values358        else nn.Identity()359    )360    self.drop_path2 = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()361 362    self.sample_drop_ratio = drop_path363 364  def forward(self, x: torch.Tensor) -> torch.Tensor:365    def attn_residual_func(x: torch.Tensor) -> torch.Tensor:366      return self.ls1(self.attn(self.norm1(x)))367 368    def ffn_residual_func(x: torch.Tensor) -> torch.Tensor:369      return self.ls2(self.mlp(self.norm2(x)))370 371    if self.training and self.sample_drop_ratio > 0.1:372      # the overhead is compensated only for a drop path rate larger than 0.1373      x = drop_add_residual_stochastic_depth(374          x,375          residual_func=attn_residual_func,376          sample_drop_ratio=self.sample_drop_ratio,377      )378      x = drop_add_residual_stochastic_depth(379          x,380          residual_func=ffn_residual_func,381          sample_drop_ratio=self.sample_drop_ratio,382      )383    elif self.training and self.sample_drop_ratio > 0.0:384      x = x + self.drop_path1(attn_residual_func(x))385      x = x + self.drop_path1(ffn_residual_func(x))386    else:387      x = x + attn_residual_func(x)388      x = x + ffn_residual_func(x)389    return x390 391 392def drop_add_residual_stochastic_depth(393    x: torch.Tensor,394    residual_func: Callable[[torch.Tensor], torch.Tensor],395    sample_drop_ratio: float = 0.0,396) -> torch.Tensor:397  """This function is taken from the original implementation in DINOv2 to implement stochastic depth in the image encoder."""398  # 1) extract subset using permutation399  b, _, _ = x.shape400  sample_subset_size = max(int(b * (1 - sample_drop_ratio)), 1)401  brange = (torch.randperm(b, device=x.device))[:sample_subset_size]402  x_subset = x[brange]403 404  # 2) apply residual_func to get residual405  residual = residual_func(x_subset)406 407  x_flat = x.flatten(1)408  residual = residual.flatten(1)409 410  residual_scale_factor = b / sample_subset_size411 412  # 3) add the residual413  x_plus_residual = torch.index_add(414      x_flat, 0, brange, residual.to(dtype=x.dtype), alpha=residual_scale_factor415  )416  return x_plus_residual.view_as(x)417 418 419def get_branges_scales(x, sample_drop_ratio=0.0):420  b, _, _ = x.shape421  sample_subset_size = max(int(b * (1 - sample_drop_ratio)), 1)422  brange = (torch.randperm(b, device=x.device))[:sample_subset_size]423  residual_scale_factor = b / sample_subset_size424  return brange, residual_scale_factor425 426 427def add_residual(428    x, brange, residual, residual_scale_factor, scaling_vector=None429):430  """Implement residual addition in the image encoder."""431  if scaling_vector is None:432    x_flat = x.flatten(1)433    residual = residual.flatten(1)434    x_plus_residual = torch.index_add(435        x_flat,436        0,437        brange,438        residual.to(dtype=x.dtype),439        alpha=residual_scale_factor,440    )441  else:442    x_plus_residual = scaled_index_add(443        x,444        brange,445        residual.to(dtype=x.dtype),446        scaling=scaling_vector,447        alpha=residual_scale_factor,448    )449  return x_plus_residual450 451 452attn_bias_cache: Dict[Tuple, Any] = {}  # pylint: disable=g-bare-generic453 454 455def get_attn_bias_and_cat(x_list, branges=None):456  """this will perform the index select, cat the tensors, and provide the attn_bias from cache."""457  batch_sizes = (458      [b.shape[0] for b in branges]459      if branges is not None460      else [x.shape[0] for x in x_list]461  )462  all_shapes = tuple((b, x.shape[1]) for b, x in zip(batch_sizes, x_list))463  if all_shapes not in attn_bias_cache.keys():464    seqlens = []465    for b, x in zip(batch_sizes, x_list):466      for _ in range(b):467        seqlens.append(x.shape[1])468    attn_bias = fmha.BlockDiagonalMask.from_seqlens(seqlens)469    attn_bias._batch_sizes = batch_sizes  # pylint: disable=protected-access470    attn_bias_cache[all_shapes] = attn_bias471 472  if branges is not None:473    cat_tensors = index_select_cat(474        [x.flatten(1) for x in x_list], branges475    ).view(1, -1, x_list[0].shape[-1])476  else:477    tensors_bs1 = tuple(x.reshape([1, -1, *x.shape[2:]]) for x in x_list)478    cat_tensors = torch.cat(tensors_bs1, dim=1)479 480  return attn_bias_cache[all_shapes], cat_tensors481 482 483def drop_add_residual_stochastic_depth_list(484    x_list: List[torch.Tensor],485    residual_func: Callable[[torch.Tensor, Any], torch.Tensor],486    sample_drop_ratio: float = 0.0,487    scaling_vector=None,488) -> torch.Tensor:489  """Add residual to a list of tensors."""490  # 1) generate random set of indices for dropping samples in the batch.491  branges_scales = [492      get_branges_scales(x, sample_drop_ratio=sample_drop_ratio) for x in x_list493  ]494  branges = [s[0] for s in branges_scales]495  residual_scale_factors = [s[1] for s in branges_scales]496 497  # 2) get attention bias and index+concat the tensors.498  attn_bias, x_cat = get_attn_bias_and_cat(x_list, branges)499 500  # 3) apply residual_func to get residual, and split the result.501  residual_list = attn_bias.split(residual_func(x_cat, attn_bias=attn_bias))  # type: ignore502 503  outputs = []504  for x, brange, residual, residual_scale_factor in zip(505      x_list, branges, residual_list, residual_scale_factors506  ):507    outputs.append(508        add_residual(509            x, brange, residual, residual_scale_factor, scaling_vector510        ).view_as(x)511    )512  return outputs513 514 515class NestedTensorBlock(Block):516  """Nested tensor block implementation."""517 518  def forward_nested(self, x_list: List[torch.Tensor]) -> List[torch.Tensor]:519    """x_list contains a list of tensors to nest together and run."""520    assert isinstance(self.attn, MemEffAttention)521 522    if self.training and self.sample_drop_ratio > 0.0:523 524      def attn_residual_func(x: torch.Tensor, attn_bias=None) -> torch.Tensor:525        return self.attn(self.norm1(x), attn_bias=attn_bias)526 527      def ffn_residual_func(x: torch.Tensor, attn_bias=None) -> torch.Tensor:528        del attn_bias529        return self.mlp(self.norm2(x))530 531      x_list = drop_add_residual_stochastic_depth_list(532          x_list,533          residual_func=attn_residual_func,534          sample_drop_ratio=self.sample_drop_ratio,535          scaling_vector=self.ls1.gamma536          if isinstance(self.ls1, LayerScale)537          else None,538      )539      x_list = drop_add_residual_stochastic_depth_list(540          x_list,541          residual_func=ffn_residual_func,542          sample_drop_ratio=self.sample_drop_ratio,543          scaling_vector=self.ls2.gamma544          if isinstance(self.ls1, LayerScale)545          else None,546      )547      return x_list548    else:549 550      def attn_residual_func(x: torch.Tensor, attn_bias=None) -> torch.Tensor:551        return self.ls1(self.attn(self.norm1(x), attn_bias=attn_bias))552 553      def ffn_residual_func(x: torch.Tensor, attn_bias=None) -> torch.Tensor:554        del attn_bias555        return self.ls2(self.mlp(self.norm2(x)))556 557      attn_bias, x = get_attn_bias_and_cat(x_list)558      x = x + attn_residual_func(x, attn_bias=attn_bias)559      x = x + ffn_residual_func(x)560      return attn_bias.split(x)561 562  def forward(self, x):563    if isinstance(x, torch.Tensor):564      return super().forward(x)565    elif isinstance(x, list):566      if not XFORMERS_AVAILABLE:567        raise AssertionError("xFormers is required for using nested tensors")568      return self.forward_nested(x)569    else:570      raise AssertionError571 572 573def named_apply(574    fn: Callable,  # pylint: disable=g-bare-generic575    module: nn.Module,576    name="",577    depth_first=True,578    include_root=False,579) -> nn.Module:580  """Apply a function to a module and its children."""581  if not depth_first and include_root:582    fn(module=module, name=name)583  for child_name, child_module in module.named_children():584    child_name = ".".join((name, child_name)) if name else child_name585    named_apply(586        fn=fn,587        module=child_module,588        name=child_name,589        depth_first=depth_first,590        include_root=True,591    )592  if depth_first and include_root:593    fn(module=module, name=name)594  return module595 596 597class BlockChunk(nn.ModuleList):598 599  def forward(self, x):600    for b in self:601      x = b(x)602    return x603 604 605class VisionTransformer(nn.Module):606  """Vision Transformer implementation."""607 608  def __init__(609      self,610      img_size=224,611      patch_size=16,612      in_chans=3,613      embed_dim=768,614      depth=12,615      num_heads=12,616      mlp_ratio=4.0,617      qkv_bias=True,618      ffn_bias=True,619      proj_bias=True,620      drop_path_rate=0.0,621      drop_path_uniform=False,622      init_values=None,  # for layerscale: None or 0 => no layerscale623      embed_layer=PatchEmbed,624      act_layer=nn.GELU,625      block_fn=Block,626      ffn_layer="mlp",627      block_chunks=1,628      num_register_tokens=0,629      interpolate_antialias=False,630      interpolate_offset=0.1,631  ):632    """Defines the Vision Transformer model.633 634    Args:635      img_size (int, tuple): input image size636      patch_size (int, tuple): patch size637      in_chans (int): number of input channels638      embed_dim (int): embedding dimension639      depth (int): depth of transformer640      num_heads (int): number of attention heads641      mlp_ratio (int): ratio of mlp hidden dim to embedding dim642      qkv_bias (bool): enable bias for qkv if True643      ffn_bias (bool): enable bias for ffn if True644      proj_bias (bool): enable bias for proj in attn if True645      drop_path_rate (float): stochastic depth rate646      drop_path_uniform (bool): apply uniform drop rate across blocks647      init_values (float): layer-scale init values648      embed_layer (nn.Module): patch embedding layer649      act_layer (nn.Module): MLP activation layer650      block_fn (nn.Module): transformer block class651      ffn_layer (str): "mlp", "swiglu", "swiglufused" or "identity"652      block_chunks: (int) split block sequence into block_chunks units for FSDP653        wrap654      num_register_tokens: (int) number of extra cls tokens (so-called655        "registers")656      interpolate_antialias: (str) flag to apply anti-aliasing when657        interpolating positional embeddings658      interpolate_offset: (float) work-around offset to apply when interpolating659        positional embeddings660    """661    super().__init__()662    norm_layer = functools.partial(nn.LayerNorm, eps=1e-6)663 664    self.num_features = self.embed_dim = (665        embed_dim  # num_features for consistency with other models666    )667    self.num_tokens = 1668    self.n_blocks = depth669    self.num_heads = num_heads670    self.patch_size = patch_size671    self.num_register_tokens = num_register_tokens672    self.interpolate_antialias = interpolate_antialias673    self.interpolate_offset = interpolate_offset674 675    self.patch_embed = embed_layer(676        img_size=img_size,677        patch_size=patch_size,678        in_chans=in_chans,679        embed_dim=embed_dim,680    )681    num_patches = self.patch_embed.num_patches682 683    self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))684    self.pos_embed = nn.Parameter(685        torch.zeros(1, num_patches + self.num_tokens, embed_dim)686    )687    assert num_register_tokens >= 0688    self.register_tokens = (689        nn.Parameter(torch.zeros(1, num_register_tokens, embed_dim))690        if num_register_tokens691        else None692    )693 694    if drop_path_uniform:695      dpr = [drop_path_rate] * depth696    else:697      dpr = [698          drop_path_rate * i / max(depth - 1, 1) for i in range(depth)699      ]  # stochastic depth decay rule700 701    if ffn_layer == "mlp":702      ffn_layer = Mlp703    elif ffn_layer == "swiglufused" or ffn_layer == "swiglu":704      ffn_layer = SwiGLUFFNFused705    else:706      raise NotImplementedError707 708    blocks_list = [709        block_fn(710            dim=embed_dim,711            num_heads=num_heads,712            mlp_ratio=mlp_ratio,713            qkv_bias=qkv_bias,714            proj_bias=proj_bias,715            ffn_bias=ffn_bias,716            drop_path=dpr[i],717            norm_layer=norm_layer,718            act_layer=act_layer,719            ffn_layer=ffn_layer,720            init_values=init_values,721        )722        for i in range(depth)723    ]724    if block_chunks > 0:725      self.chunked_blocks = True726      chunked_blocks = []727      chunksize = depth // block_chunks728      for i in range(0, depth, chunksize):729        # this is to keep the block index consistent if we chunk the block list730        chunked_blocks.append(731            [nn.Identity()] * i + blocks_list[i : i + chunksize]732        )733      self.blocks = nn.ModuleList([BlockChunk(p) for p in chunked_blocks])734    else:735      self.chunked_blocks = False736      self.blocks = nn.ModuleList(blocks_list)737 738    self.norm = norm_layer(embed_dim)739    self.head = nn.Identity()740 741    self.mask_token = nn.Parameter(torch.zeros(1, embed_dim))742 743    self.init_weights()744 745  def init_weights(self):746    nn.init.trunc_normal_(self.pos_embed, std=0.02)747    nn.init.normal_(self.cls_token, std=1e-6)748    if self.register_tokens is not None:749      nn.init.normal_(self.register_tokens, std=1e-6)750    named_apply(init_weights_vit_timm, self)751 752  def interpolate_pos_encoding(self, x, w, h):753    previous_dtype = x.dtype754    npatch = x.shape[1] - 1755    num_patches = self.pos_embed.shape[1] - 1756    if npatch == num_patches and w == h:757      return self.pos_embed758    pos_embed = self.pos_embed.float()759    class_pos_embed = pos_embed[:, 0]760    patch_pos_embed = pos_embed[:, 1:]761    dim = x.shape[-1]762    w0 = w // self.patch_size763    h0 = h // self.patch_size764    num_patches_dim = int(765        math.sqrt(num_patches)766    )  # Recover the number of patches in each dimension767    assert num_patches == num_patches_dim * num_patches_dim768    kwargs = {}769    if self.interpolate_offset:770      sx = float(w0 + self.interpolate_offset) / num_patches_dim771      sy = float(h0 + self.interpolate_offset) / num_patches_dim772      kwargs["scale_factor"] = (sx, sy)773    else:774      # Simply specify an output size instead of a scale factor775      kwargs["size"] = (w0, h0)776    patch_pos_embed = nn.functional.interpolate(777        patch_pos_embed.reshape(778            1, num_patches_dim, num_patches_dim, dim779        ).permute(0, 3, 1, 2),780        mode="bilinear",781        antialias=self.interpolate_antialias,782        **kwargs,783    )784    assert (w0, h0) == patch_pos_embed.shape[-2:]785    patch_pos_embed = patch_pos_embed.permute(0, 2, 3, 1).view(1, -1, dim)786    return torch.cat((class_pos_embed.unsqueeze(0), patch_pos_embed), dim=1).to(787        previous_dtype788    )789 790  def prepare_tokens_with_masks(self, x, masks=None):791    _, _, w, h = x.shape792    x = self.patch_embed(x)793    if masks is not None:794      x = torch.where(795          masks.unsqueeze(-1), self.mask_token.to(x.dtype).unsqueeze(0), x796      )797 798    x = torch.cat((self.cls_token.expand(x.shape[0], -1, -1), x), dim=1)799    x = x + self.interpolate_pos_encoding(x, w, h)800 801    if self.register_tokens is not None:802      x = torch.cat(803          (804              x[:, :1],805              self.register_tokens.expand(x.shape[0], -1, -1),806              x[:, 1:],807          ),808          dim=1,809      )810 811    return x812 813  def forward_features_list(self, x_list, masks_list):814    x = [815        self.prepare_tokens_with_masks(x, masks)816        for x, masks in zip(x_list, masks_list)817    ]818    for blk in self.blocks:819      x = blk(x)820 821    all_x = x822    output = []823    for x, masks in zip(all_x, masks_list):824      x_norm = self.norm(x)825      output.append({826          "x_norm_1st_clstoken": x_norm[:, :1],827          "x_norm_2nd_clstoken": x_norm[:, 1 : self.num_register_tokens + 1],828          "x_norm_patchtokens": x_norm[:, self.num_register_tokens + 1 :],829          "x_prenorm": x,830          "masks": masks,831      })832    return output833 834  def forward_features(self, x, masks=None):835    if isinstance(x, list):836      return self.forward_features_list(x, masks)837 838    x = self.prepare_tokens_with_masks(x, masks)839 840    for blk in self.blocks:841      x = blk(x)842 843    x_norm = self.norm(x)844    return {845        "x_norm_1st_clstoken": x_norm[:, :1],846        "x_norm_2nd_clstoken": x_norm[:, 1 : self.num_register_tokens + 1],847        "x_norm_patchtokens": x_norm[:, self.num_register_tokens + 1 :],848        "x_prenorm": x,849        "masks": masks,850    }851 852  def _get_intermediate_layers_not_chunked(self, x, n=1):853    x = self.prepare_tokens_with_masks(x)854    # If n is an int, take the n last blocks. If it's a list, take them855    output, total_block_len = [], len(self.blocks)856    blocks_to_take = (857        range(total_block_len - n, total_block_len) if isinstance(n, int) else n858    )859    for i, blk in enumerate(self.blocks):860      x = blk(x)861      if i in blocks_to_take:862        output.append(x)863    assert len(output) == len(864        blocks_to_take865    ), f"only {len(output)} / {len(blocks_to_take)} blocks found"866    return output867 868  def _get_intermediate_layers_chunked(self, x, n=1):869    x = self.prepare_tokens_with_masks(x)870    output, i, total_block_len = [], 0, len(self.blocks[-1])871    # If n is an int, take the n last blocks. If it's a list, take them872    blocks_to_take = (873        range(total_block_len - n, total_block_len) if isinstance(n, int) else n874    )875    for block_chunk in self.blocks:876      for blk in block_chunk[i:]:  # Passing the nn.Identity()877        x = blk(x)878        if i in blocks_to_take:879          output.append(x)880        i += 1881    assert len(output) == len(882        blocks_to_take883    ), f"only {len(output)} / {len(blocks_to_take)} blocks found"884    return output885 886  def get_intermediate_layers(887      self,888      x: torch.torch.Tensor,889      n: Union[int, Sequence] = 1,  # Layers or n last layers to take  # pylint: disable=g-bare-generic890      reshape: bool = False,891      return_class_token: bool = False,892      norm=True,893  ) -> Tuple[Union[torch.torch.Tensor, Tuple[torch.torch.Tensor]]]:  # pylint: disable=g-one-element-tuple894    if self.chunked_blocks:895      outputs = self._get_intermediate_layers_chunked(x, n)896    else:897      outputs = self._get_intermediate_layers_not_chunked(x, n)898    if norm:899      outputs = [self.norm(out) for out in outputs]900    class_tokens = [out[:, 0] for out in outputs]901    outputs = [out[:, 1 + self.num_register_tokens :] for out in outputs]902    if reshape:903      batch_size, _, w, h = x.shape904      outputs = [905          out.reshape(906              batch_size, w // self.patch_size, h // self.patch_size, -1907          )908          .permute(0, 3, 1, 2)909          .contiguous()910          for out in outputs911      ]912    if return_class_token:913      return tuple(zip(outputs, class_tokens))914    return tuple(outputs)915 916  def forward(self, *args, is_training=False, **kwargs):917    ret = self.forward_features(*args, **kwargs)918    if is_training:919      return ret920    else:921      return self.head(ret["x_norm_1st_clstoken"]), self.head(922          ret["x_norm_2nd_clstoken"]923      ), ret["x_norm_patchtokens"]924 925 926def init_weights_vit_timm(module: nn.Module, name: str = ""):  # pylint: disable=unused-argument927  """ViT weight initialization, original timm impl (for reproducibility)."""928  if isinstance(module, nn.Linear):929    nn.init.trunc_normal_(module.weight, std=0.02)930    if module.bias is not None:931      nn.init.zeros_(module.bias)932 933 934def vit_small(patch_size=14, **kwargs):935  model = VisionTransformer(936      patch_size=patch_size,937      embed_dim=384,938      depth=12,939      num_heads=6,940      mlp_ratio=4,941      block_fn=functools.partial(Block, attn_class=MemEffAttention),942      num_register_tokens=1,943      **kwargs,944  )945  return model946 947 948def vit_base(patch_size=14, **kwargs):949  model = VisionTransformer(950      patch_size=patch_size,951      embed_dim=768,952      depth=12,953      num_heads=12,954      mlp_ratio=4,955      block_fn=functools.partial(Block, attn_class=MemEffAttention),956      num_register_tokens=1,957      **kwargs,958  )959  return model960 961 962def vit_large(patch_size=14, **kwargs):963  model = VisionTransformer(964      patch_size=patch_size,965      embed_dim=1024,966      depth=24,967      num_heads=16,968      mlp_ratio=4,969      block_fn=functools.partial(Block, attn_class=MemEffAttention),970      num_register_tokens=1,971      **kwargs,972  )973  return model974 975 976def vit_so400m(patch_size=14, **kwargs):977  """SoViT 400M model (https://arxiv.org/abs/2305.13035)."""978  model = VisionTransformer(979      patch_size=patch_size,980      embed_dim=1152,981      depth=27,982      num_heads=16,983      mlp_ratio=4304 / 1152,984      block_fn=functools.partial(Block, attn_class=MemEffAttention),985      num_register_tokens=1,986      **kwargs,987  )988  return model989 990 991def vit_giant2(patch_size=14, **kwargs):992  model = VisionTransformer(993      patch_size=patch_size,994      embed_dim=1536,995      depth=40,996      num_heads=24,997      mlp_ratio=4,998      block_fn=functools.partial(Block, attn_class=MemEffAttention),999      num_register_tokens=1,1000      **kwargs,1001  )1002  return model1003