gberton commited on
Commit
05c1dd4
·
0 Parent(s):

tips v1 l14

Browse files
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - vision
5
+ - image-text
6
+ - contrastive-learning
7
+ - zero-shot
8
+ - feature-extraction
9
+ - arxiv:2410.16512
10
+ library_name: transformers
11
+ pipeline_tag: zero-shot-image-classification
12
+ ---
13
+
14
+ # TIPS — L/14 (v1)
15
+
16
+ TIPS (Text-Image Pre-training with Spatial awareness, ICLR 2025) is a family of contrastive vision-language models that produce spatially rich image features aligned with text embeddings. This is the original (v1) L/14 release with 304M vision params and 184M text params, converted from the [official checkpoints](https://github.com/google-deepmind/tips).
17
+
18
+ | Variant | Vision params | Text params | Embed dim | Resolution |
19
+ |---------|---------------|-------------|-----------|------------|
20
+ | [S/14](https://huggingface.co/google/tipsv1-s14) | 22M | 34M | 384 | 448 |
21
+ | [B/14](https://huggingface.co/google/tipsv1-b14) | 86M | 110M | 768 | 448 |
22
+ | [L/14](https://huggingface.co/google/tipsv1-l14) | 304M | 184M | 1024 | 448 |
23
+ | [So400m/14](https://huggingface.co/google/tipsv1-so400m14) | 413M | 448M | 1152 | 448 |
24
+ | [g/14](https://huggingface.co/google/tipsv1-g14) | 1.1B | 389M | 1536 | 448 |
25
+ | [g/14 low-res](https://huggingface.co/google/tipsv1-g14-lowres) | 1.1B | 389M | 1536 | 224 |
26
+
27
+ ## Usage
28
+
29
+ ```bash
30
+ pip install transformers torch torchvision sentencepiece scikit-learn requests
31
+ ```
32
+
33
+ ### Load the model
34
+
35
+ ```python
36
+ from transformers import AutoModel
37
+
38
+ model = AutoModel.from_pretrained("google/tipsv1-l14", trust_remote_code=True)
39
+ model.eval()
40
+ ```
41
+
42
+ ### Encode images
43
+
44
+ Images should be tensors in `[0, 1]` range (just `ToTensor()`, no ImageNet normalization).
45
+
46
+ ```python
47
+ import requests
48
+ from PIL import Image
49
+ from torchvision import transforms
50
+
51
+ url = "https://huggingface.co/spaces/google/TIPSv2/resolve/main/examples/zeroseg/pascal_context_00049_image.png"
52
+ image = Image.open(requests.get(url, stream=True).raw).convert("RGB")
53
+ transform = transforms.Compose([transforms.Resize((448, 448)), transforms.ToTensor()])
54
+ pixel_values = transform(image).unsqueeze(0)
55
+
56
+ out = model.encode_image(pixel_values)
57
+ print(out.cls_token.shape) # (1, 1, 1024) — global image embedding
58
+ print(out.patch_tokens.shape) # (1, 1024, 1024) — per-patch spatial features
59
+ ```
60
+
61
+ The second CLS token (`out.register_tokens`) was trained on synthetic captions; the first (`out.cls_token`) on web alt-text, and is the one aligned with the text tower.
62
+
63
+ ### Encode text
64
+
65
+ ```python
66
+ text_emb = model.encode_text(["a photo of a bus", "a photo of a dog"])
67
+ print(text_emb.shape) # (2, 1024) — one embedding per query
68
+ ```
69
+
70
+ ### Zero-shot classification
71
+
72
+ ```python
73
+ import torch.nn.functional as F
74
+
75
+ classes = ["bus", "car", "dog", "cat"]
76
+ cls = F.normalize(out.cls_token[:, 0, :], dim=-1)
77
+ text_emb = F.normalize(model.encode_text(classes), dim=-1)
78
+ similarity = cls @ text_emb.T
79
+ print(classes[similarity.argmax()]) # predicted class
80
+ ```
81
+
82
+ ### Visualize spatial features
83
+
84
+ ```python
85
+ import numpy as np
86
+ from sklearn.decomposition import PCA
87
+
88
+ feat = out.patch_tokens[0].detach().cpu().numpy()
89
+ rgb = PCA(n_components=3, whiten=True).fit_transform(feat).reshape(32, 32, 3)
90
+ rgb = 1 / (1 + np.exp(-2.0 * rgb)) # sigmoid for [0, 1] range with good contrast
91
+ ```
92
+
93
+ ## Model details
94
+
95
+ - ViT-L/14 vision encoder (24 layers, patch size 14, two CLS tokens) + 12-layer transformer text encoder
96
+ - Native resolution 448; other patch-multiple resolutions work via positional-embedding interpolation
97
+ - Preprocessing: images to `[0, 1]`, no normalization; SentencePiece tokenizer, lowercased, max 64 tokens
98
+
99
+ ## License
100
+
101
+ Apache 2.0
102
+
103
+ ## Citation
104
+
105
+ ```bibtex
106
+ @inproceedings{maninis2025tips,
107
+ title = {{TIPS: Text-Image Pretraining with Spatial Awareness}},
108
+ author = {Maninis, Kevis-Kokitsi and Chen, Kaifeng and Ghosh, Soham and Karpur, Arjun and Chen, Koert and Xia, Ye and Cao, Bingyi and Salz, Daniel and Han, Guangxing and Dlabal, Jan and Gnanapragasam, Dan and Seyedhosseini, Mojtaba and Zhou, Howard and Araujo, Andre},
109
+ booktitle = {International Conference on Learning Representations (ICLR)},
110
+ year = {2025},
111
+ url = {https://arxiv.org/abs/2410.16512}
112
+ }
113
+ ```
config.json ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "TIPSv2Model"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_tips.TIPSv2Config",
7
+ "AutoModel": "modeling_tips.TIPSv2Model"
8
+ },
9
+ "model_type": "tipsv2",
10
+ "temperature_init_value": 0.004205586854368448,
11
+ "text_config": {
12
+ "attention_dropout": 0.0,
13
+ "bos_token_id": null,
14
+ "eos_token_id": null,
15
+ "hidden_act": "relu",
16
+ "hidden_size": 1024,
17
+ "initializer_range": 0.02,
18
+ "intermediate_size": 4096,
19
+ "layer_norm_eps": 1e-05,
20
+ "max_position_embeddings": 64,
21
+ "model_type": "tipsv2_text_model",
22
+ "num_attention_heads": 16,
23
+ "num_hidden_layers": 12,
24
+ "pad_token_id": 0,
25
+ "pooling_epsilon": 1e-08,
26
+ "scale_sqrt_depth": true,
27
+ "vocab_size": 32000
28
+ },
29
+ "transformers_version": "5.14.1",
30
+ "vision_config": {
31
+ "apply_layernorm": true,
32
+ "attention_probs_dropout_prob": 0.0,
33
+ "drop_path_rate": 0.0,
34
+ "hidden_act": "gelu",
35
+ "hidden_dropout_prob": 0.0,
36
+ "hidden_size": 1024,
37
+ "image_size": 448,
38
+ "initializer_range": 0.02,
39
+ "layer_norm_eps": 1e-06,
40
+ "layerscale_value": 1.0,
41
+ "mlp_ratio": 4,
42
+ "model_type": "tipsv2_vision_model",
43
+ "num_attention_heads": 16,
44
+ "num_channels": 3,
45
+ "num_hidden_layers": 24,
46
+ "num_register_tokens": 1,
47
+ "out_features": [
48
+ "stage24"
49
+ ],
50
+ "out_indices": [
51
+ 24
52
+ ],
53
+ "patch_size": 14,
54
+ "qkv_bias": true,
55
+ "reshape_hidden_states": true,
56
+ "stage_names": [
57
+ "stem",
58
+ "stage1",
59
+ "stage2",
60
+ "stage3",
61
+ "stage4",
62
+ "stage5",
63
+ "stage6",
64
+ "stage7",
65
+ "stage8",
66
+ "stage9",
67
+ "stage10",
68
+ "stage11",
69
+ "stage12",
70
+ "stage13",
71
+ "stage14",
72
+ "stage15",
73
+ "stage16",
74
+ "stage17",
75
+ "stage18",
76
+ "stage19",
77
+ "stage20",
78
+ "stage21",
79
+ "stage22",
80
+ "stage23",
81
+ "stage24"
82
+ ],
83
+ "use_swiglu_ffn": false
84
+ }
85
+ }
configuration_tips.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """TIPSv2 model configuration."""
2
+
3
+ from transformers import PretrainedConfig
4
+
5
+
6
+ _VISION_FN_BY_GEOMETRY = {
7
+ (384, 12): "vit_small",
8
+ (768, 12): "vit_base",
9
+ (1024, 24): "vit_large",
10
+ (1152, 27): "vit_so400m",
11
+ (1536, 40): "vit_giant2",
12
+ }
13
+
14
+
15
+ class TIPSv2Config(PretrainedConfig):
16
+ """Configuration for TIPSv2 vision-language model."""
17
+
18
+ model_type = "tipsv2"
19
+
20
+ def __init__(
21
+ self,
22
+ vision_config=None,
23
+ text_config=None,
24
+ temperature_init_value=0.01,
25
+ **kwargs,
26
+ ):
27
+ super().__init__(**kwargs)
28
+ vision_config = vision_config or {}
29
+ text_config = text_config or {}
30
+ hidden_size = vision_config.get("hidden_size", 768)
31
+ num_hidden_layers = vision_config.get("num_hidden_layers", 12)
32
+ self.vision_fn = _VISION_FN_BY_GEOMETRY[(hidden_size, num_hidden_layers)]
33
+ self.embed_dim = hidden_size
34
+ self.patch_size = vision_config.get("patch_size", 14)
35
+ self.img_size = vision_config.get("image_size", 448)
36
+ self.ffn_layer = "swiglu" if vision_config.get("use_swiglu_ffn", False) else "mlp"
37
+ self.init_values = vision_config.get("layerscale_value", 1.0)
38
+ self.num_register_tokens = vision_config.get("num_register_tokens", 1)
39
+ self.text_hidden_size = text_config.get("hidden_size", 768)
40
+ self.text_mlp_dim = text_config.get("intermediate_size", 3072)
41
+ self.text_num_heads = text_config.get("num_attention_heads", 12)
42
+ self.text_num_layers = text_config.get("num_hidden_layers", 12)
43
+ self.vocab_size = text_config.get("vocab_size", 32000)
44
+ self.max_len = text_config.get("max_position_embeddings", 64)
45
+ self.temperature = temperature_init_value
image_encoder.py ADDED
@@ -0,0 +1,1002 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2025 Google LLC
2
+ #
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 at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # 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 and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+
16
+ """Vision encoder implementation in PyTorch."""
17
+
18
+ import functools
19
+ import math
20
+ import os
21
+ from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union
22
+ import warnings
23
+ import torch
24
+ from torch import nn
25
+ import torch.nn.functional as F
26
+ import torch.utils.checkpoint
27
+
28
+
29
+ class 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_features
43
+ hidden_features = hidden_features or in_features
44
+ 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 x
56
+
57
+
58
+ def make_2tuple(x):
59
+ if isinstance(x, tuple):
60
+ assert len(x) == 2
61
+ return x
62
+
63
+ assert isinstance(x, int)
64
+ return (x, x)
65
+
66
+
67
+ class 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-generic
77
+ 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_hw
89
+ self.patch_size = patch_hw
90
+ self.patches_resolution = patch_grid_size
91
+ self.num_patches = patch_grid_size[0] * patch_grid_size[1]
92
+
93
+ self.in_chans = in_chans
94
+ self.embed_dim = embed_dim
95
+
96
+ self.flatten_embedding = flatten_embedding
97
+
98
+ self.proj = nn.Conv2d(
99
+ in_chans, embed_dim, kernel_size=patch_hw, stride=patch_hw
100
+ )
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.shape
105
+ patch_h, patch_w = self.patch_size
106
+
107
+ assert (
108
+ h % patch_h == 0
109
+ ), f"Input image height {h} is not a multiple of patch height {patch_h}"
110
+ assert (
111
+ w % patch_w == 0
112
+ ), f"Input image width {w} is not a multiple of patch width: {patch_w}"
113
+
114
+ x = self.proj(x) # B C H W
115
+ h, w = x.size(2), x.size(3)
116
+ x = x.flatten(2).transpose(1, 2) # B HW C
117
+ x = self.norm(x)
118
+ if not self.flatten_embedding:
119
+ x = x.reshape(-1, h, w, self.embed_dim) # B H W C
120
+ return x
121
+
122
+ def flops(self) -> float:
123
+ ho, wo = self.patches_resolution
124
+ flops = (
125
+ ho
126
+ * wo
127
+ * self.embed_dim
128
+ * self.in_chans
129
+ * (self.patch_size[0] * self.patch_size[1])
130
+ )
131
+ if self.norm is not None:
132
+ flops += ho * wo * self.embed_dim
133
+ return flops
134
+
135
+
136
+ class 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_features
150
+ hidden_features = hidden_features or in_features
151
+ 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) * x2
158
+ return self.w3(hidden)
159
+
160
+
161
+ XFORMERS_ENABLED = os.environ.get("XFORMERS_DISABLED") is None
162
+ try:
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-top
165
+
166
+ XFORMERS_AVAILABLE = True
167
+ warnings.warn("xFormers is available (SwiGLU)")
168
+ else:
169
+ warnings.warn("xFormers is disabled (SwiGLU)")
170
+ raise ImportError
171
+ except ImportError:
172
+ SwiGLU = SwiGLUFFN
173
+ XFORMERS_AVAILABLE = False
174
+
175
+ warnings.warn("xFormers is not available (SwiGLU)")
176
+
177
+
178
+ class 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-argument
187
+ drop: float = 0.0, # pylint: disable=unused-argument
188
+ bias: bool = True,
189
+ ) -> None:
190
+ out_features = out_features or in_features
191
+ hidden_features = hidden_features or in_features
192
+ hidden_features = (int(hidden_features * 2 / 3) + 7) // 8 * 8
193
+ super().__init__(
194
+ in_features=in_features,
195
+ hidden_features=hidden_features,
196
+ out_features=out_features,
197
+ bias=bias,
198
+ )
199
+
200
+
201
+ class 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_heads
215
+ head_dim = dim // num_heads
216
+ self.scale = head_dim**-0.5
217
+
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.shape
225
+ 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 x
241
+
242
+
243
+ class 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.shape
253
+ qkv = self.qkv(x).reshape(
254
+ b_dim, n_dim, 3, self.num_heads, c_dim // self.num_heads
255
+ )
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 x
265
+
266
+
267
+ class 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 = inplace
278
+ 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.gamma
282
+
283
+
284
+ def drop_path_impl(x, drop_prob: float = 0.0, training: bool = False):
285
+ if drop_prob == 0.0 or not training:
286
+ return x
287
+ keep_prob = 1 - drop_prob
288
+ shape = (x.shape[0],) + (1,) * (
289
+ x.ndim - 1
290
+ ) # work with diff dim tensors, not just 2D ConvNets
291
+ 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_tensor
295
+ return output
296
+
297
+
298
+ class 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_prob
304
+
305
+ def forward(self, x):
306
+ return drop_path_impl(x, self.drop_prob, self.training)
307
+
308
+
309
+ class 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_values
342
+ 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_values
358
+ 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_path
363
+
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.1
373
+ 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 x
390
+
391
+
392
+ def 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 permutation
399
+ b, _, _ = x.shape
400
+ 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 residual
405
+ 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_size
411
+
412
+ # 3) add the residual
413
+ x_plus_residual = torch.index_add(
414
+ x_flat, 0, brange, residual.to(dtype=x.dtype), alpha=residual_scale_factor
415
+ )
416
+ return x_plus_residual.view_as(x)
417
+
418
+
419
+ def get_branges_scales(x, sample_drop_ratio=0.0):
420
+ b, _, _ = x.shape
421
+ 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_size
424
+ return brange, residual_scale_factor
425
+
426
+
427
+ def add_residual(
428
+ x, brange, residual, residual_scale_factor, scaling_vector=None
429
+ ):
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_residual
450
+
451
+
452
+ attn_bias_cache: Dict[Tuple, Any] = {} # pylint: disable=g-bare-generic
453
+
454
+
455
+ def 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 None
460
+ 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-access
470
+ attn_bias_cache[all_shapes] = attn_bias
471
+
472
+ if branges is not None:
473
+ cat_tensors = index_select_cat(
474
+ [x.flatten(1) for x in x_list], branges
475
+ ).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_tensors
481
+
482
+
483
+ def 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_list
493
+ ]
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: ignore
502
+
503
+ outputs = []
504
+ for x, brange, residual, residual_scale_factor in zip(
505
+ x_list, branges, residual_list, residual_scale_factors
506
+ ):
507
+ outputs.append(
508
+ add_residual(
509
+ x, brange, residual, residual_scale_factor, scaling_vector
510
+ ).view_as(x)
511
+ )
512
+ return outputs
513
+
514
+
515
+ class 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_bias
529
+ 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.gamma
536
+ 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.gamma
544
+ if isinstance(self.ls1, LayerScale)
545
+ else None,
546
+ )
547
+ return x_list
548
+ 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_bias
555
+ 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 AssertionError
571
+
572
+
573
+ def named_apply(
574
+ fn: Callable, # pylint: disable=g-bare-generic
575
+ 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_name
585
+ 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 module
595
+
596
+
597
+ class BlockChunk(nn.ModuleList):
598
+
599
+ def forward(self, x):
600
+ for b in self:
601
+ x = b(x)
602
+ return x
603
+
604
+
605
+ class 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 layerscale
623
+ 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 size
636
+ patch_size (int, tuple): patch size
637
+ in_chans (int): number of input channels
638
+ embed_dim (int): embedding dimension
639
+ depth (int): depth of transformer
640
+ num_heads (int): number of attention heads
641
+ mlp_ratio (int): ratio of mlp hidden dim to embedding dim
642
+ qkv_bias (bool): enable bias for qkv if True
643
+ ffn_bias (bool): enable bias for ffn if True
644
+ proj_bias (bool): enable bias for proj in attn if True
645
+ drop_path_rate (float): stochastic depth rate
646
+ drop_path_uniform (bool): apply uniform drop rate across blocks
647
+ init_values (float): layer-scale init values
648
+ embed_layer (nn.Module): patch embedding layer
649
+ act_layer (nn.Module): MLP activation layer
650
+ block_fn (nn.Module): transformer block class
651
+ ffn_layer (str): "mlp", "swiglu", "swiglufused" or "identity"
652
+ block_chunks: (int) split block sequence into block_chunks units for FSDP
653
+ wrap
654
+ num_register_tokens: (int) number of extra cls tokens (so-called
655
+ "registers")
656
+ interpolate_antialias: (str) flag to apply anti-aliasing when
657
+ interpolating positional embeddings
658
+ interpolate_offset: (float) work-around offset to apply when interpolating
659
+ positional embeddings
660
+ """
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 models
666
+ )
667
+ self.num_tokens = 1
668
+ self.n_blocks = depth
669
+ self.num_heads = num_heads
670
+ self.patch_size = patch_size
671
+ self.num_register_tokens = num_register_tokens
672
+ self.interpolate_antialias = interpolate_antialias
673
+ self.interpolate_offset = interpolate_offset
674
+
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_patches
682
+
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 >= 0
688
+ self.register_tokens = (
689
+ nn.Parameter(torch.zeros(1, num_register_tokens, embed_dim))
690
+ if num_register_tokens
691
+ else None
692
+ )
693
+
694
+ if drop_path_uniform:
695
+ dpr = [drop_path_rate] * depth
696
+ else:
697
+ dpr = [
698
+ drop_path_rate * i / max(depth - 1, 1) for i in range(depth)
699
+ ] # stochastic depth decay rule
700
+
701
+ if ffn_layer == "mlp":
702
+ ffn_layer = Mlp
703
+ elif ffn_layer == "swiglufused" or ffn_layer == "swiglu":
704
+ ffn_layer = SwiGLUFFNFused
705
+ else:
706
+ raise NotImplementedError
707
+
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 = True
726
+ chunked_blocks = []
727
+ chunksize = depth // block_chunks
728
+ for i in range(0, depth, chunksize):
729
+ # this is to keep the block index consistent if we chunk the block list
730
+ 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 = False
736
+ 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.dtype
754
+ npatch = x.shape[1] - 1
755
+ num_patches = self.pos_embed.shape[1] - 1
756
+ if npatch == num_patches and w == h:
757
+ return self.pos_embed
758
+ 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_size
763
+ h0 = h // self.patch_size
764
+ num_patches_dim = int(
765
+ math.sqrt(num_patches)
766
+ ) # Recover the number of patches in each dimension
767
+ assert num_patches == num_patches_dim * num_patches_dim
768
+ kwargs = {}
769
+ if self.interpolate_offset:
770
+ sx = float(w0 + self.interpolate_offset) / num_patches_dim
771
+ sy = float(h0 + self.interpolate_offset) / num_patches_dim
772
+ kwargs["scale_factor"] = (sx, sy)
773
+ else:
774
+ # Simply specify an output size instead of a scale factor
775
+ kwargs["size"] = (w0, h0)
776
+ patch_pos_embed = nn.functional.interpolate(
777
+ patch_pos_embed.reshape(
778
+ 1, num_patches_dim, num_patches_dim, dim
779
+ ).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_dtype
788
+ )
789
+
790
+ def prepare_tokens_with_masks(self, x, masks=None):
791
+ _, _, w, h = x.shape
792
+ 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), x
796
+ )
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 x
812
+
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 = x
822
+ 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 output
833
+
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 them
855
+ 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 n
858
+ )
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_take
865
+ ), f"only {len(output)} / {len(blocks_to_take)} blocks found"
866
+ return output
867
+
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 them
872
+ blocks_to_take = (
873
+ range(total_block_len - n, total_block_len) if isinstance(n, int) else n
874
+ )
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 += 1
881
+ assert len(output) == len(
882
+ blocks_to_take
883
+ ), f"only {len(output)} / {len(blocks_to_take)} blocks found"
884
+ return output
885
+
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-generic
890
+ 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-tuple
894
+ 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.shape
904
+ outputs = [
905
+ out.reshape(
906
+ batch_size, w // self.patch_size, h // self.patch_size, -1
907
+ )
908
+ .permute(0, 3, 1, 2)
909
+ .contiguous()
910
+ for out in outputs
911
+ ]
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 ret
920
+ 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
+
926
+ def init_weights_vit_timm(module: nn.Module, name: str = ""): # pylint: disable=unused-argument
927
+ """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
+
934
+ def 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 model
946
+
947
+
948
+ def 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 model
960
+
961
+
962
+ def 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 model
974
+
975
+
976
+ def 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 model
989
+
990
+
991
+ def 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 model
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4e69fd95fb0ce676f793355d1a7a53fb90145608098a2a64e2af2a324e6c20bc
3
+ size 1951820792
modeling_tips.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """TIPSv2 model for HuggingFace — wraps vision and text encoders."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List, Optional, Union
5
+
6
+ import torch
7
+ from transformers import PreTrainedModel
8
+ from transformers.utils import cached_file
9
+
10
+ from .configuration_tips import TIPSv2Config
11
+ from .image_encoder import vit_base, vit_giant2, vit_large, vit_small, vit_so400m
12
+ from .text_encoder import TextEncoder, Tokenizer
13
+
14
+ _VISION_FACTORIES = {
15
+ "vit_small": vit_small,
16
+ "vit_base": vit_base,
17
+ "vit_large": vit_large,
18
+ "vit_so400m": vit_so400m,
19
+ "vit_giant2": vit_giant2,
20
+ }
21
+
22
+
23
+ @dataclass
24
+ class TIPSv2ImageOutput:
25
+ """Output from the vision encoder."""
26
+ cls_token: torch.Tensor # (B, 1, D)
27
+ register_tokens: torch.Tensor # (B, R, D)
28
+ patch_tokens: torch.Tensor # (B, N, D)
29
+
30
+
31
+ @dataclass
32
+ class TIPSv2Output:
33
+ """Output from the full model."""
34
+ image_features: Optional[TIPSv2ImageOutput] = None
35
+ text_embeds: Optional[torch.Tensor] = None
36
+ temperature: Optional[float] = None
37
+
38
+
39
+ class TIPSv2Model(PreTrainedModel):
40
+ """TIPSv2 vision-language model.
41
+
42
+ Usage::
43
+
44
+ model = AutoModel.from_pretrained("google/tipsv2-b14", trust_remote_code=True)
45
+
46
+ # Image features
47
+ out = model.encode_image(pixel_values) # pixel_values in [0, 1]
48
+ cls = out.cls_token # (B, 1, D)
49
+ spatial = out.patch_tokens # (B, N, D)
50
+
51
+ # Text features
52
+ text_emb = model.encode_text(["a photo of a cat"]) # (B, D)
53
+ """
54
+
55
+ config_class = TIPSv2Config
56
+ _no_split_modules = []
57
+ _supports_cache_class = False
58
+ _tied_weights_keys = []
59
+
60
+ @property
61
+ def all_tied_weights_keys(self):
62
+ return {}
63
+
64
+ def __init__(self, config: TIPSv2Config):
65
+ super().__init__(config)
66
+
67
+ self.vision_encoder = _VISION_FACTORIES[config.vision_fn](
68
+ img_size=config.img_size,
69
+ patch_size=config.patch_size,
70
+ ffn_layer=config.ffn_layer,
71
+ block_chunks=0,
72
+ init_values=config.init_values,
73
+ interpolate_antialias=True,
74
+ interpolate_offset=0.0,
75
+ )
76
+
77
+ self.text_encoder = TextEncoder(
78
+ config={
79
+ "hidden_size": config.text_hidden_size,
80
+ "mlp_dim": config.text_mlp_dim,
81
+ "num_heads": config.text_num_heads,
82
+ "num_layers": config.text_num_layers,
83
+ },
84
+ vocab_size=config.vocab_size,
85
+ )
86
+
87
+ self._tokenizer = None
88
+
89
+ def _load_tokenizer(self):
90
+ """Load the SentencePiece tokenizer shipped with the checkpoint."""
91
+ return Tokenizer(cached_file(self.name_or_path, "tokenizer.model"))
92
+
93
+ @torch.no_grad()
94
+ def encode_image(self, pixel_values: torch.Tensor) -> TIPSv2ImageOutput:
95
+ """Encode images. pixel_values: (B, 3, H, W) in [0, 1]."""
96
+ pixel_values = pixel_values.to(self.device)
97
+ cls_token, register_tokens, patch_tokens = self.vision_encoder(pixel_values)
98
+ return TIPSv2ImageOutput(
99
+ cls_token=cls_token,
100
+ register_tokens=register_tokens,
101
+ patch_tokens=patch_tokens,
102
+ )
103
+
104
+ @torch.no_grad()
105
+ def encode_text(
106
+ self,
107
+ texts: Union[str, List[str], torch.Tensor],
108
+ padding_mask: Optional[torch.Tensor] = None,
109
+ ) -> torch.Tensor:
110
+ """Encode text. Pass strings (auto-tokenized) or pre-tokenized tensors."""
111
+ if isinstance(texts, (str, list)):
112
+ if isinstance(texts, str):
113
+ texts = [texts]
114
+ if self._tokenizer is None:
115
+ self._tokenizer = self._load_tokenizer()
116
+ ids, paddings = self._tokenizer.tokenize(texts, max_len=self.config.max_len)
117
+ ids = torch.from_numpy(ids).to(self.device)
118
+ padding_mask = torch.from_numpy(paddings).to(self.device)
119
+ else:
120
+ ids = texts.to(self.device)
121
+ padding_mask = padding_mask.to(self.device)
122
+ return self.text_encoder(ids, padding_mask)
123
+
124
+ def forward(
125
+ self,
126
+ pixel_values: Optional[torch.Tensor] = None,
127
+ input_ids: Optional[torch.Tensor] = None,
128
+ padding_mask: Optional[torch.Tensor] = None,
129
+ ) -> TIPSv2Output:
130
+ """Forward pass for both or either modality."""
131
+ image_features = None
132
+ text_embeds = None
133
+ if pixel_values is not None:
134
+ image_features = self.encode_image(pixel_values)
135
+ if input_ids is not None:
136
+ text_embeds = self.encode_text(input_ids, padding_mask)
137
+ return TIPSv2Output(
138
+ image_features=image_features,
139
+ text_embeds=text_embeds,
140
+ temperature=self.config.temperature,
141
+ )
processor_config.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "image_processor": {
3
+ "do_convert_rgb": true,
4
+ "do_normalize": false,
5
+ "do_rescale": true,
6
+ "do_resize": true,
7
+ "image_processor_type": "Tipsv2ImageProcessor",
8
+ "resample": 2,
9
+ "rescale_factor": 0.00392156862745098,
10
+ "size": {
11
+ "height": 448,
12
+ "width": 448
13
+ }
14
+ },
15
+ "processor_class": "Tipsv2Processor"
16
+ }
text_encoder.py ADDED
@@ -0,0 +1,342 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2025 Google LLC
2
+ #
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 at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # 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 and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+
16
+ """Text encoder implementation in PyTorch."""
17
+
18
+ import typing as t
19
+
20
+ import numpy as np
21
+ import sentencepiece as spm
22
+ import torch
23
+ from torch import nn
24
+ import torch.nn.functional as F
25
+
26
+
27
+ class Tokenizer(object):
28
+ """A simple tokenizer using SentencePiece."""
29
+
30
+ def __init__(self, tokenizer_path: str):
31
+ self.sp = spm.SentencePieceProcessor(model_file=tokenizer_path)
32
+ # Explicitly disable BOS/EOS to match the reference Colab implementation.
33
+ self._add_bos = False
34
+ self._add_eos = False
35
+
36
+ def tokenize(self, input_texts, max_len=64):
37
+ if isinstance(input_texts, str):
38
+ input_texts = [input_texts]
39
+ batch_ids = [
40
+ self.sp.encode(t.lower(), add_bos=self._add_bos, add_eos=self._add_eos)
41
+ for t in input_texts
42
+ ]
43
+ tokens = np.zeros((len(batch_ids), max_len), dtype=np.int64)
44
+ for i, ids in enumerate(batch_ids):
45
+ length = min(len(ids), max_len)
46
+ tokens[i, :length] = ids[:length]
47
+ is_padding = (tokens == 0).astype(np.int32)
48
+ return tokens, is_padding
49
+
50
+
51
+ class PositionalEmbedding(nn.Module):
52
+ """Generates position embedding for a given 1-d sequence.
53
+
54
+ Attributes:
55
+ min_timescale: Start of the geometric index. Determines the periodicity of
56
+ the added signal.
57
+ max_timescale: End of the geometric index. Determines the frequency of the
58
+ added signal.
59
+ embedding_dim: Dimension of the embedding to be generated.
60
+ """
61
+
62
+ min_timescale: int = 1
63
+ max_timescale: int = 10_000
64
+ embedding_dim: int = 0
65
+
66
+ def __init__(self, embedding_dim: int):
67
+ super().__init__()
68
+ self.embedding_dim = embedding_dim
69
+
70
+ def __call__(self, seq_length: int = None, position: torch.tensor = None):
71
+ """Generates a torch.tensor of sinusoids with different frequencies.
72
+
73
+ Args:
74
+ seq_length: an optional Python int defining the output sequence length.
75
+ if the `position` argument is specified.
76
+ position: [B, seq_length], optional position for each token in the
77
+ sequence, only required when the sequence is packed.
78
+
79
+ Returns:
80
+ [B, seqlen, D] if `position` is specified, else [1, seqlen, D]
81
+ """
82
+ if position is None:
83
+ assert seq_length is not None
84
+ # [1, seqlen]
85
+ position = torch.arange(seq_length, dtype=torch.float32)[None, :]
86
+ else:
87
+ assert position.ndim == 2, position.shape
88
+
89
+ num_timescales = self.embedding_dim // 2
90
+ log_timescale_increment = torch.log(
91
+ torch.tensor(float(self.max_timescale) / float(self.min_timescale))
92
+ ) / torch.maximum(
93
+ torch.tensor(num_timescales, dtype=torch.float32) - 1, torch.tensor(1)
94
+ )
95
+ inv_timescales = self.min_timescale * torch.exp(
96
+ torch.arange(num_timescales, dtype=torch.float32)
97
+ * -log_timescale_increment
98
+ )
99
+ scaled_time = position[:, :, None] * inv_timescales[None, None, :]
100
+ signal = torch.cat((torch.sin(scaled_time), torch.cos(scaled_time)), dim=2)
101
+ # Force usage of `np` rather than `jnp` to compute static values at trace
102
+ # time.
103
+ signal = F.pad(signal, (0, self.embedding_dim % 2, 0, 0, 0, 0))
104
+ return signal
105
+
106
+
107
+ class MlpBlockWithMask(nn.Module):
108
+ """Transformer MLP / feed-forward block that supports masking."""
109
+
110
+ def __init__(
111
+ self,
112
+ mlp_dim: int,
113
+ d_model: int,
114
+ use_bias: bool = True,
115
+ dtype: torch.dtype = torch.float32,
116
+ activation_fn: nn.Module = nn.GELU,
117
+ ):
118
+ super().__init__()
119
+
120
+ self.mlp_dim = mlp_dim
121
+ self.d_model = d_model
122
+ self.use_bias = use_bias
123
+ self.dtype = dtype
124
+ self.activation_fn = activation_fn
125
+
126
+ self.c_fc = nn.Linear(
127
+ in_features=self.d_model,
128
+ out_features=self.mlp_dim,
129
+ dtype=self.dtype,
130
+ bias=self.use_bias,
131
+ )
132
+ self.c_proj = nn.Linear(
133
+ in_features=self.mlp_dim,
134
+ out_features=self.d_model,
135
+ dtype=self.dtype,
136
+ bias=self.use_bias,
137
+ )
138
+
139
+ def __call__(
140
+ self, inputs: torch.Tensor, mlp_mask: torch.Tensor
141
+ ) -> torch.Tensor:
142
+ """Applies Transformer MlpBlock with mask module."""
143
+ x = self.c_fc(inputs)
144
+ x = self.activation_fn()(x)
145
+ x = x * mlp_mask[..., None] # First masking.
146
+ x = self.c_proj(x)
147
+ x = x * mlp_mask[..., None] # Second masking.
148
+ return x
149
+
150
+
151
+ class ResidualAttentionBlock(nn.Module):
152
+ """Transformer residual attention block."""
153
+
154
+ def __init__(
155
+ self,
156
+ d_model: int,
157
+ n_head: int,
158
+ mlp_dim: int,
159
+ dtype: torch.dtype = torch.float32,
160
+ ):
161
+ super().__init__()
162
+ self.d_model = d_model
163
+ self.n_head = n_head
164
+ self.mlp_dim = mlp_dim
165
+ self.dtype = dtype
166
+
167
+ self.attn = nn.MultiheadAttention(d_model, n_head, dtype=self.dtype)
168
+ self.ln_1 = nn.LayerNorm(d_model, dtype=self.dtype)
169
+ self.mlp = MlpBlockWithMask(
170
+ self.mlp_dim,
171
+ d_model,
172
+ use_bias=True,
173
+ dtype=self.dtype,
174
+ activation_fn=nn.ReLU,
175
+ )
176
+ self.ln_2 = nn.LayerNorm(d_model, dtype=self.dtype)
177
+
178
+ def attention(self, x: torch.Tensor, mask: torch.Tensor):
179
+ attn_mask = (
180
+ mask[:, None, None, :]
181
+ .repeat(1, self.n_head, x.shape[0], 1)
182
+ .flatten(0, 1)
183
+ )
184
+ attn_mask[attn_mask == 0] = float('-inf')
185
+ attn_mask[attn_mask == 1] = 0
186
+ return self.attn(x, x, x, need_weights=False, attn_mask=attn_mask)[0]
187
+
188
+ def forward(self, x: torch.Tensor, mask: torch.Tensor):
189
+ x = x + self.attention(self.ln_1(x), mask.permute(1, 0))
190
+ x = x + self.mlp(self.ln_2(x), mask)
191
+ return x, mask
192
+
193
+
194
+ class SequentialMultiInput(nn.Sequential):
195
+ """Sequential module that can take multiple inputs."""
196
+
197
+ def forward(self, *inputs):
198
+ for module in self._modules.values():
199
+ if isinstance(inputs, tuple):
200
+ inputs = module(*inputs)
201
+ else:
202
+ inputs = module(inputs)
203
+ return inputs
204
+
205
+
206
+ class Transformer(nn.Module):
207
+ """Transformer implementation."""
208
+
209
+ def __init__(
210
+ self,
211
+ width: int,
212
+ layers: int,
213
+ heads: int,
214
+ mlp_dim: int,
215
+ dtype: torch.dtype = torch.float32,
216
+ ):
217
+ super().__init__()
218
+ self.width = width
219
+ self.layers = layers
220
+ self.heads = heads
221
+ self.mlp_dim = mlp_dim
222
+ self.dtype = dtype
223
+
224
+ self.resblocks = SequentialMultiInput(*[
225
+ ResidualAttentionBlock(self.width, self.heads, self.mlp_dim, self.dtype)
226
+ for _ in range(self.layers)
227
+ ])
228
+
229
+ def forward(self, x: torch.Tensor, mask: torch.Tensor):
230
+ return self.resblocks(x, mask)[0]
231
+
232
+
233
+ class GlobalAvgPooling(nn.Module):
234
+ """Performs a simple global pooling over the input with optional paddings.
235
+
236
+ Attributes:
237
+ pooling_dims: A list of dims to perform pooling over.
238
+ keepdims: If True, keep dimension of inputs after pooling.
239
+ """
240
+
241
+ pooling_dims: t.Sequence[int]
242
+ epsilon: float = 1e-8
243
+
244
+ def __init__(
245
+ self, pooling_dims: t.Sequence[int], epsilon: float = 1e-8
246
+ ):
247
+ super().__init__()
248
+ self.pooling_dims = pooling_dims
249
+ self.epsilon = epsilon
250
+
251
+ if not all([p_dims >= 0 for p_dims in self.pooling_dims]):
252
+ raise ValueError('pooling_dims must be non-negative integers.')
253
+
254
+ def __call__(
255
+ self,
256
+ inputs: torch.tensor,
257
+ compatible_paddings: torch.tensor,
258
+ ):
259
+ """Applies global average spatial pooling to inputs.
260
+
261
+ Args:
262
+ inputs: An input tensor.
263
+ compatible_paddings: paddings of inputs with shapes compatible with
264
+ inputs, e.g. compatible_paddings with shape [B, 1] for inputs with shape
265
+ [B, D].
266
+
267
+ Returns:
268
+ Output tensor with global pooling applied.
269
+ """
270
+ padded_value = torch.zeros_like(inputs)
271
+ padded_value = torch.ones_like(inputs) * padded_value
272
+ inputs = torch.where(compatible_paddings > 0, padded_value, inputs)
273
+ valid_inputs = (
274
+ torch.sum(
275
+ 1.0 - compatible_paddings,
276
+ self.pooling_dims,
277
+ keepdims=True,
278
+ dtype=inputs.dtype,
279
+ )
280
+ + self.epsilon
281
+ )
282
+ inputs_sum = torch.sum(inputs, self.pooling_dims, keepdims=True)
283
+ outputs = torch.divide(inputs_sum, valid_inputs).type(inputs.dtype)
284
+ outputs = torch.squeeze(outputs, axis=self.pooling_dims)
285
+ return outputs
286
+
287
+
288
+ class TextEncoder(nn.Module):
289
+ """Text encoder implementation."""
290
+
291
+ def __init__(
292
+ self,
293
+ config: t.Dict[str, int],
294
+ vocab_size: int,
295
+ dtype: torch.dtype = torch.float32,
296
+ scale_sqrt_depth: bool = True,
297
+ ):
298
+ super().__init__()
299
+ self.vocab_size = vocab_size
300
+ self.dtype = dtype
301
+ self.scale_sqrt_depth = scale_sqrt_depth
302
+
303
+ # The text tower layers are fixed independent of vision tower size.
304
+ self.transformer_layers = config['num_layers']
305
+ self.embedding_dim = config['hidden_size']
306
+ self.transformer_width = config['hidden_size']
307
+ self.mlp_dim = config['mlp_dim']
308
+ self.transformer_heads = config['num_heads']
309
+
310
+ self.token_embedding = nn.Embedding(
311
+ self.vocab_size, self.embedding_dim, dtype=self.dtype
312
+ )
313
+ self.pos_embedder = PositionalEmbedding(embedding_dim=self.embedding_dim)
314
+ self.transformer = Transformer(
315
+ width=self.transformer_width,
316
+ layers=self.transformer_layers,
317
+ heads=self.transformer_heads,
318
+ mlp_dim=self.mlp_dim,
319
+ dtype=self.dtype,
320
+ )
321
+ self.pooling = GlobalAvgPooling(pooling_dims=[1])
322
+ self.ln_final = nn.LayerNorm(self.transformer_width, dtype=self.dtype)
323
+
324
+ def __call__(
325
+ self,
326
+ ids: torch.tensor,
327
+ paddings: torch.tensor,
328
+ ):
329
+ """Applies TextEncoder module."""
330
+ _, seq_length = ids.shape
331
+ mask = (paddings == 0).type(torch.float32)
332
+ mask = mask.permute(1, 0) # NL -> LN
333
+ x = self.token_embedding(ids)
334
+ if self.scale_sqrt_depth:
335
+ x = x * (self.embedding_dim**0.5)
336
+ x = x + self.pos_embedder(seq_length=seq_length).to(x.device)
337
+ x = x.permute(1, 0, 2) # NLD -> LND
338
+ x = self.transformer(x, mask)
339
+ x = x.permute(1, 0, 2) # LND -> NLD
340
+ x = self.ln_final(x)
341
+ x = self.pooling(x, compatible_paddings=paddings[:, :, None])
342
+ return x
tokenizer.model ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4c40e7723348d5d9a3d3c2bdcec5120d97fb29edfe1bf118b4494bce02fc7624
3
+ size 731655
tokenizer_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "bos_token": null,
4
+ "do_lower_case": true,
5
+ "eos_token": null,
6
+ "model_max_length": 64,
7
+ "pad_token": "<pad>",
8
+ "processor_class": "Tipsv2Processor",
9
+ "token_type_ids_pattern": "all_zeros",
10
+ "tokenizer_class": "Tipsv2Tokenizer",
11
+ "unk_token": "<unk>"
12
+ }