CollectionStudio gberton commited on
Commit
6f989b9
·
0 Parent(s):

Duplicate from google/tipsv2-l14-dpt

Browse files

Co-authored-by: Gabriele Berton <gberton@users.noreply.huggingface.co>

Files changed (8) hide show
  1. .gitattributes +35 -0
  2. README.md +80 -0
  3. config.json +397 -0
  4. configuration_dpt.py +44 -0
  5. dpt_head.py +702 -0
  6. model.safetensors +3 -0
  7. modeling_dpt.py +115 -0
  8. preprocessor_config.json +13 -0
.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,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - vision
5
+ - depth-estimation
6
+ - surface-normals
7
+ - semantic-segmentation
8
+ - dense-prediction
9
+ - arxiv:2604.12012
10
+ library_name: transformers
11
+ pipeline_tag: depth-estimation
12
+ ---
13
+
14
+ # TIPSv2 — L/14 DPT Heads
15
+
16
+ DPT (Dense Prediction Transformer) heads for depth estimation, surface normal prediction, and semantic segmentation on top of the frozen [TIPSv2 L/14](https://huggingface.co/google/tipsv2-l14) backbone. The backbone is loaded automatically. The depth and normals heads are trained on the NYU Depth V2 dataset and segmentation is trained on the ADE20K dataset (150 classes).
17
+
18
+ | Variant | Vision params | Text params | Embed dim | DPT Heads |
19
+ |---------|--------------|-------------|-----------|-----------|
20
+ | [B/14](https://huggingface.co/google/tipsv2-b14) | 86M | 110M | 768 | [B/14-dpt](https://huggingface.co/google/tipsv2-b14-dpt) |
21
+ | [L/14](https://huggingface.co/google/tipsv2-l14) | 303M | 184M | 1024 | [L/14-dpt](https://huggingface.co/google/tipsv2-l14-dpt) |
22
+ | [SO400m/14](https://huggingface.co/google/tipsv2-so400m14) | 412M | 448M | 1152 | [SO400m/14-dpt](https://huggingface.co/google/tipsv2-so400m14-dpt) |
23
+ | [g/14](https://huggingface.co/google/tipsv2-g14) | 1.1B | 389M | 1536 | [g/14-dpt](https://huggingface.co/google/tipsv2-g14-dpt) |
24
+
25
+ ## Usage
26
+
27
+ ```bash
28
+ pip install transformers torch torchvision sentencepiece
29
+ ```
30
+
31
+ ```python
32
+ from transformers import AutoModel
33
+ from torchvision import transforms
34
+ from PIL import Image
35
+ import requests
36
+
37
+ model = AutoModel.from_pretrained("google/tipsv2-l14-dpt", trust_remote_code=True)
38
+ model.eval().cuda()
39
+
40
+ url = "https://huggingface.co/spaces/google/tipsv2/resolve/main/examples/depth/ade20k_00014.png"
41
+ image = Image.open(requests.get(url, stream=True).raw)
42
+ transform = transforms.Compose([transforms.Resize((448, 448)), transforms.ToTensor()])
43
+ pixel_values = transform(image).unsqueeze(0).cuda()
44
+
45
+ # All tasks at once
46
+ outputs = model(pixel_values)
47
+ print(outputs.depth.shape) # (1, 1, 448, 448) — depth map
48
+ print(outputs.normals.shape) # (1, 3, 448, 448) — surface normals
49
+ print(outputs.segmentation.shape) # (1, 150, 448, 448) — segmentation logits
50
+
51
+ # Or individual tasks (only runs the requested head)
52
+ depth = model.predict_depth(pixel_values)
53
+ normals = model.predict_normals(pixel_values)
54
+ seg = model.predict_segmentation(pixel_values)
55
+ print(seg.argmax(dim=1).shape) # (1, 448, 448) — per-pixel class prediction
56
+ ```
57
+
58
+ ## Model details
59
+
60
+ - **Backbone**: [TIPSv2 L/14](https://huggingface.co/google/tipsv2-l14) (loaded automatically)
61
+ - **Heads**: ~102M total params (depth + normals + segmentation)
62
+ - **Depth & normals**: NYU Depth V2
63
+ - **Segmentation**: ADE20K, 150 classes
64
+ - **Input**: images in `[0, 1]` range, any resolution (multiples of 14 recommended)
65
+
66
+ ## License
67
+
68
+ Apache 2.0
69
+
70
+ ## Citation
71
+
72
+ ```bibtex
73
+ @inproceedings{cao2026tipsv2,
74
+ title = {{TIPSv2: Advancing Vision-Language Pretraining with Enhanced Patch-Text Alignment}},
75
+ author = {Cao, Bingyi and Chen, Koert and Maninis, Kevis-Kokitsi and Chen, Kaifeng and Karpur, Arjun and Xia, Ye and Dua, Sahil and Dabral, Tanmaya and Han, Guangxing and Han, Bohyung and Ainslie, Joshua and Bewley, Alex and Jacob, Mithun and Wagner, Rene and Ramos, Washington and Choromanski, Krzysztof and Seyedhosseini, Mojtaba and Zhou, Howard and Araujo, Andre},
76
+ booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)},
77
+ year = {2026},
78
+ url = {https://arxiv.org/abs/2604.12012}
79
+ }
80
+ ```
config.json ADDED
@@ -0,0 +1,397 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "TIPSv2DPTModel"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_dpt.TIPSv2DPTConfig",
7
+ "AutoModel": "modeling_dpt.TIPSv2DPTModel"
8
+ },
9
+ "backbone_config": {
10
+ "apply_layernorm": true,
11
+ "attention_probs_dropout_prob": 0.0,
12
+ "drop_path_rate": 0.0,
13
+ "hidden_act": "gelu",
14
+ "hidden_dropout_prob": 0.0,
15
+ "hidden_size": 1024,
16
+ "image_size": 448,
17
+ "initializer_range": 0.02,
18
+ "interpolate_antialias": true,
19
+ "interpolate_offset": 0.0,
20
+ "layer_norm_eps": 1e-06,
21
+ "layerscale_value": 1.0,
22
+ "mlp_ratio": 4,
23
+ "model_type": "tipsv2_vision_model",
24
+ "num_attention_heads": 16,
25
+ "num_channels": 3,
26
+ "num_hidden_layers": 24,
27
+ "num_register_tokens": 1,
28
+ "out_features": [
29
+ "stage6",
30
+ "stage12",
31
+ "stage18",
32
+ "stage24"
33
+ ],
34
+ "out_indices": [
35
+ 6,
36
+ 12,
37
+ 18,
38
+ 24
39
+ ],
40
+ "patch_size": 14,
41
+ "qkv_bias": true,
42
+ "reshape_hidden_states": false,
43
+ "stage_names": [
44
+ "stem",
45
+ "stage1",
46
+ "stage2",
47
+ "stage3",
48
+ "stage4",
49
+ "stage5",
50
+ "stage6",
51
+ "stage7",
52
+ "stage8",
53
+ "stage9",
54
+ "stage10",
55
+ "stage11",
56
+ "stage12",
57
+ "stage13",
58
+ "stage14",
59
+ "stage15",
60
+ "stage16",
61
+ "stage17",
62
+ "stage18",
63
+ "stage19",
64
+ "stage20",
65
+ "stage21",
66
+ "stage22",
67
+ "stage23",
68
+ "stage24"
69
+ ],
70
+ "use_swiglu_ffn": false
71
+ },
72
+ "depth_decoder_activation": "relu",
73
+ "fusion_hidden_size": 256,
74
+ "id2label": {
75
+ "0": "wall",
76
+ "1": "building",
77
+ "10": "cabinet",
78
+ "100": "poster",
79
+ "101": "stage",
80
+ "102": "van",
81
+ "103": "ship",
82
+ "104": "fountain",
83
+ "105": "conveyer belt",
84
+ "106": "canopy",
85
+ "107": "washer",
86
+ "108": "plaything",
87
+ "109": "swimming pool",
88
+ "11": "sidewalk",
89
+ "110": "stool",
90
+ "111": "barrel",
91
+ "112": "basket",
92
+ "113": "waterfall",
93
+ "114": "tent",
94
+ "115": "bag",
95
+ "116": "minibike",
96
+ "117": "cradle",
97
+ "118": "oven",
98
+ "119": "ball",
99
+ "12": "person",
100
+ "120": "food",
101
+ "121": "step",
102
+ "122": "tank",
103
+ "123": "trade name",
104
+ "124": "microwave",
105
+ "125": "pot",
106
+ "126": "animal",
107
+ "127": "bicycle",
108
+ "128": "lake",
109
+ "129": "dishwasher",
110
+ "13": "earth",
111
+ "130": "screen",
112
+ "131": "blanket",
113
+ "132": "sculpture",
114
+ "133": "hood",
115
+ "134": "sconce",
116
+ "135": "vase",
117
+ "136": "traffic light",
118
+ "137": "tray",
119
+ "138": "ashcan",
120
+ "139": "fan",
121
+ "14": "door",
122
+ "140": "pier",
123
+ "141": "crt screen",
124
+ "142": "plate",
125
+ "143": "monitor",
126
+ "144": "bulletin board",
127
+ "145": "shower",
128
+ "146": "radiator",
129
+ "147": "glass",
130
+ "148": "clock",
131
+ "149": "flag",
132
+ "15": "table",
133
+ "16": "mountain",
134
+ "17": "plant",
135
+ "18": "curtain",
136
+ "19": "chair",
137
+ "2": "sky",
138
+ "20": "car",
139
+ "21": "water",
140
+ "22": "painting",
141
+ "23": "sofa",
142
+ "24": "shelf",
143
+ "25": "house",
144
+ "26": "sea",
145
+ "27": "mirror",
146
+ "28": "rug",
147
+ "29": "field",
148
+ "3": "floor",
149
+ "30": "armchair",
150
+ "31": "seat",
151
+ "32": "fence",
152
+ "33": "desk",
153
+ "34": "rock",
154
+ "35": "wardrobe",
155
+ "36": "lamp",
156
+ "37": "bathtub",
157
+ "38": "railing",
158
+ "39": "cushion",
159
+ "4": "tree",
160
+ "40": "base",
161
+ "41": "box",
162
+ "42": "column",
163
+ "43": "signboard",
164
+ "44": "chest of drawers",
165
+ "45": "counter",
166
+ "46": "sand",
167
+ "47": "sink",
168
+ "48": "skyscraper",
169
+ "49": "fireplace",
170
+ "5": "ceiling",
171
+ "50": "refrigerator",
172
+ "51": "grandstand",
173
+ "52": "path",
174
+ "53": "stairs",
175
+ "54": "runway",
176
+ "55": "case",
177
+ "56": "pool table",
178
+ "57": "pillow",
179
+ "58": "screen door",
180
+ "59": "stairway",
181
+ "6": "road",
182
+ "60": "river",
183
+ "61": "bridge",
184
+ "62": "bookcase",
185
+ "63": "blind",
186
+ "64": "coffee table",
187
+ "65": "toilet",
188
+ "66": "flower",
189
+ "67": "book",
190
+ "68": "hill",
191
+ "69": "bench",
192
+ "7": "bed ",
193
+ "70": "countertop",
194
+ "71": "stove",
195
+ "72": "palm",
196
+ "73": "kitchen island",
197
+ "74": "computer",
198
+ "75": "swivel chair",
199
+ "76": "boat",
200
+ "77": "bar",
201
+ "78": "arcade machine",
202
+ "79": "hovel",
203
+ "8": "windowpane",
204
+ "80": "bus",
205
+ "81": "towel",
206
+ "82": "light",
207
+ "83": "truck",
208
+ "84": "tower",
209
+ "85": "chandelier",
210
+ "86": "awning",
211
+ "87": "streetlight",
212
+ "88": "booth",
213
+ "89": "television receiver",
214
+ "9": "grass",
215
+ "90": "airplane",
216
+ "91": "dirt track",
217
+ "92": "apparel",
218
+ "93": "pole",
219
+ "94": "land",
220
+ "95": "bannister",
221
+ "96": "escalator",
222
+ "97": "ottoman",
223
+ "98": "bottle",
224
+ "99": "buffet"
225
+ },
226
+ "label2id": {
227
+ "airplane": 90,
228
+ "animal": 126,
229
+ "apparel": 92,
230
+ "arcade machine": 78,
231
+ "armchair": 30,
232
+ "ashcan": 138,
233
+ "awning": 86,
234
+ "bag": 115,
235
+ "ball": 119,
236
+ "bannister": 95,
237
+ "bar": 77,
238
+ "barrel": 111,
239
+ "base": 40,
240
+ "basket": 112,
241
+ "bathtub": 37,
242
+ "bed ": 7,
243
+ "bench": 69,
244
+ "bicycle": 127,
245
+ "blanket": 131,
246
+ "blind": 63,
247
+ "boat": 76,
248
+ "book": 67,
249
+ "bookcase": 62,
250
+ "booth": 88,
251
+ "bottle": 98,
252
+ "box": 41,
253
+ "bridge": 61,
254
+ "buffet": 99,
255
+ "building": 1,
256
+ "bulletin board": 144,
257
+ "bus": 80,
258
+ "cabinet": 10,
259
+ "canopy": 106,
260
+ "car": 20,
261
+ "case": 55,
262
+ "ceiling": 5,
263
+ "chair": 19,
264
+ "chandelier": 85,
265
+ "chest of drawers": 44,
266
+ "clock": 148,
267
+ "coffee table": 64,
268
+ "column": 42,
269
+ "computer": 74,
270
+ "conveyer belt": 105,
271
+ "counter": 45,
272
+ "countertop": 70,
273
+ "cradle": 117,
274
+ "crt screen": 141,
275
+ "curtain": 18,
276
+ "cushion": 39,
277
+ "desk": 33,
278
+ "dirt track": 91,
279
+ "dishwasher": 129,
280
+ "door": 14,
281
+ "earth": 13,
282
+ "escalator": 96,
283
+ "fan": 139,
284
+ "fence": 32,
285
+ "field": 29,
286
+ "fireplace": 49,
287
+ "flag": 149,
288
+ "floor": 3,
289
+ "flower": 66,
290
+ "food": 120,
291
+ "fountain": 104,
292
+ "glass": 147,
293
+ "grandstand": 51,
294
+ "grass": 9,
295
+ "hill": 68,
296
+ "hood": 133,
297
+ "house": 25,
298
+ "hovel": 79,
299
+ "kitchen island": 73,
300
+ "lake": 128,
301
+ "lamp": 36,
302
+ "land": 94,
303
+ "light": 82,
304
+ "microwave": 124,
305
+ "minibike": 116,
306
+ "mirror": 27,
307
+ "monitor": 143,
308
+ "mountain": 16,
309
+ "ottoman": 97,
310
+ "oven": 118,
311
+ "painting": 22,
312
+ "palm": 72,
313
+ "path": 52,
314
+ "person": 12,
315
+ "pier": 140,
316
+ "pillow": 57,
317
+ "plant": 17,
318
+ "plate": 142,
319
+ "plaything": 108,
320
+ "pole": 93,
321
+ "pool table": 56,
322
+ "poster": 100,
323
+ "pot": 125,
324
+ "radiator": 146,
325
+ "railing": 38,
326
+ "refrigerator": 50,
327
+ "river": 60,
328
+ "road": 6,
329
+ "rock": 34,
330
+ "rug": 28,
331
+ "runway": 54,
332
+ "sand": 46,
333
+ "sconce": 134,
334
+ "screen": 130,
335
+ "screen door": 58,
336
+ "sculpture": 132,
337
+ "sea": 26,
338
+ "seat": 31,
339
+ "shelf": 24,
340
+ "ship": 103,
341
+ "shower": 145,
342
+ "sidewalk": 11,
343
+ "signboard": 43,
344
+ "sink": 47,
345
+ "sky": 2,
346
+ "skyscraper": 48,
347
+ "sofa": 23,
348
+ "stage": 101,
349
+ "stairs": 53,
350
+ "stairway": 59,
351
+ "step": 121,
352
+ "stool": 110,
353
+ "stove": 71,
354
+ "streetlight": 87,
355
+ "swimming pool": 109,
356
+ "swivel chair": 75,
357
+ "table": 15,
358
+ "tank": 122,
359
+ "television receiver": 89,
360
+ "tent": 114,
361
+ "toilet": 65,
362
+ "towel": 81,
363
+ "tower": 84,
364
+ "trade name": 123,
365
+ "traffic light": 136,
366
+ "tray": 137,
367
+ "tree": 4,
368
+ "truck": 83,
369
+ "van": 102,
370
+ "vase": 135,
371
+ "wall": 0,
372
+ "wardrobe": 35,
373
+ "washer": 107,
374
+ "water": 21,
375
+ "waterfall": 113,
376
+ "windowpane": 8
377
+ },
378
+ "max_depth": 10.0,
379
+ "min_depth": 0.001,
380
+ "model_type": "tipsv2_dpt",
381
+ "neck_hidden_sizes": [
382
+ 128,
383
+ 256,
384
+ 512,
385
+ 1024
386
+ ],
387
+ "num_depth_bins": 256,
388
+ "readout_act": "gelu_pytorch_tanh",
389
+ "reassemble_factors": [
390
+ 4,
391
+ 2,
392
+ 1,
393
+ 0.5
394
+ ],
395
+ "semantic_loss_ignore_index": 255,
396
+ "transformers_version": "5.10.0.dev0"
397
+ }
configuration_dpt.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """TIPSv2 DPT head configuration."""
2
+
3
+ from transformers import PretrainedConfig
4
+
5
+
6
+ _BACKBONE_REPO_BY_HIDDEN_SIZE = {
7
+ 768: "google/tipsv2-b14",
8
+ 1024: "google/tipsv2-l14",
9
+ 1152: "google/tipsv2-so400m14",
10
+ 1536: "google/tipsv2-g14",
11
+ }
12
+
13
+
14
+ class TIPSv2DPTConfig(PretrainedConfig):
15
+ """Configuration for TIPSv2 DPT dense prediction heads."""
16
+
17
+ model_type = "tipsv2_dpt"
18
+
19
+ def __init__(
20
+ self,
21
+ backbone_config=None,
22
+ neck_hidden_sizes=(96, 192, 384, 768),
23
+ fusion_hidden_size=256,
24
+ reassemble_factors=(4, 2, 1, 0.5),
25
+ readout_type="project",
26
+ num_depth_bins=256,
27
+ min_depth=1e-3,
28
+ max_depth=10.0,
29
+ **kwargs,
30
+ ):
31
+ super().__init__(**kwargs)
32
+ backbone_config = backbone_config or {}
33
+ hidden_size = backbone_config.get("hidden_size", 768)
34
+ out_indices = backbone_config.get("out_indices", (3, 6, 9, 12))
35
+ self.backbone_repo = _BACKBONE_REPO_BY_HIDDEN_SIZE[hidden_size]
36
+ self.embed_dim = hidden_size
37
+ self.channels = fusion_hidden_size
38
+ self.post_process_channels = list(neck_hidden_sizes)
39
+ self.block_indices = [out_index - 1 for out_index in out_indices]
40
+ self.readout_type = readout_type
41
+ self.num_depth_bins = num_depth_bins
42
+ self.min_depth = min_depth
43
+ self.max_depth = max_depth
44
+ self.num_seg_classes = self.num_labels
dpt_head.py ADDED
@@ -0,0 +1,702 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """DPT (Dense Prediction Transformer) depth head in PyTorch.
17
+
18
+ Ported from the Scenic/Flax implementation at:
19
+ research/vision/scene_understanding/imsight/modules/dpt.py
20
+ scenic/projects/dense_features/models/decoders.py
21
+
22
+ Architecture:
23
+ ReassembleBlocks → 4×Conv3x3 → 4×FeatureFusionBlock → project → DepthHead
24
+ """
25
+
26
+ import io
27
+ import os
28
+ import urllib.request
29
+ import zipfile
30
+
31
+ import numpy as np
32
+ import torch
33
+ from torch import nn
34
+ import torch.nn.functional as F
35
+
36
+
37
+ # ── Building blocks ─────────────────────────────────────────────────────────
38
+
39
+
40
+ class PreActResidualConvUnit(nn.Module):
41
+ """Pre-activation residual convolution unit."""
42
+
43
+ def __init__(self, features: int):
44
+ super().__init__()
45
+ self.conv1 = nn.Conv2d(features, features, 3, padding=1, bias=False)
46
+ self.conv2 = nn.Conv2d(features, features, 3, padding=1, bias=False)
47
+
48
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
49
+ residual = x
50
+ x = F.relu(x)
51
+ x = self.conv1(x)
52
+ x = F.relu(x)
53
+ x = self.conv2(x)
54
+ return x + residual
55
+
56
+
57
+ class FeatureFusionBlock(nn.Module):
58
+ """Fuses features with optional residual input, then upsamples 2×."""
59
+
60
+ def __init__(self, features: int, has_residual: bool = False,
61
+ expand: bool = False):
62
+ super().__init__()
63
+ self.has_residual = has_residual
64
+ if has_residual:
65
+ self.residual_unit = PreActResidualConvUnit(features)
66
+ self.main_unit = PreActResidualConvUnit(features)
67
+ out_features = features // 2 if expand else features
68
+ self.out_conv = nn.Conv2d(features, out_features, 1, bias=True)
69
+
70
+ def forward(self, x: torch.Tensor,
71
+ residual: torch.Tensor = None) -> torch.Tensor:
72
+ if self.has_residual and residual is not None:
73
+ if residual.shape != x.shape:
74
+ residual = F.interpolate(
75
+ residual, size=x.shape[2:], mode="bilinear",
76
+ align_corners=False)
77
+ residual = self.residual_unit(residual)
78
+ x = x + residual
79
+ x = self.main_unit(x)
80
+ # Upsample 2× with align_corners=True (matches Scenic reference)
81
+ x = F.interpolate(x, scale_factor=2, mode="bilinear",
82
+ align_corners=True)
83
+ x = self.out_conv(x)
84
+ return x
85
+
86
+
87
+ class ReassembleBlocks(nn.Module):
88
+ """Projects and resizes intermediate ViT features to different scales."""
89
+
90
+ def __init__(self, input_embed_dim: int = 1024,
91
+ out_channels: tuple = (128, 256, 512, 1024),
92
+ readout_type: str = "project"):
93
+ super().__init__()
94
+ self.readout_type = readout_type
95
+
96
+ # 1×1 conv to project to per-level channels
97
+ self.out_projections = nn.ModuleList([
98
+ nn.Conv2d(input_embed_dim, ch, 1) for ch in out_channels
99
+ ])
100
+
101
+ # Spatial resize layers: 4× up, 2× up, identity, 2× down
102
+ self.resize_layers = nn.ModuleList([
103
+ nn.ConvTranspose2d(out_channels[0], out_channels[0],
104
+ kernel_size=4, stride=4, padding=0),
105
+ nn.ConvTranspose2d(out_channels[1], out_channels[1],
106
+ kernel_size=2, stride=2, padding=0),
107
+ nn.Identity(),
108
+ nn.Conv2d(out_channels[3], out_channels[3], 3, stride=2,
109
+ padding=1),
110
+ ])
111
+
112
+ # Readout projection (concatenate cls_token with patch features)
113
+ if readout_type == "project":
114
+ self.readout_projects = nn.ModuleList([
115
+ nn.Linear(2 * input_embed_dim, input_embed_dim)
116
+ for _ in out_channels
117
+ ])
118
+
119
+ def forward(self, features):
120
+ """Process list of (cls_token, spatial_features) tuples.
121
+
122
+ Args:
123
+ features: list of (cls_token [B,D], patch_feats [B,D,H,W])
124
+
125
+ Returns:
126
+ list of tensors at different scales.
127
+ """
128
+ out = []
129
+ for i, (cls_token, x) in enumerate(features):
130
+ B, D, H, W = x.shape
131
+
132
+ if self.readout_type == "project":
133
+ # Flatten spatial → (B, HW, D)
134
+ x_flat = x.flatten(2).transpose(1, 2)
135
+ # Expand cls_token → (B, HW, D)
136
+ readout = cls_token.unsqueeze(1).expand(-1, x_flat.shape[1], -1)
137
+ # Concat + project + GELU
138
+ x_cat = torch.cat([x_flat, readout], dim=-1)
139
+ x_proj = F.gelu(self.readout_projects[i](x_cat))
140
+ # Reshape back to spatial
141
+ x = x_proj.transpose(1, 2).reshape(B, D, H, W)
142
+
143
+ # 1×1 projection
144
+ x = self.out_projections[i](x)
145
+ # Spatial resize
146
+ x = self.resize_layers[i](x)
147
+ out.append(x)
148
+ return out
149
+
150
+
151
+ class DPTDepthHead(nn.Module):
152
+ """Full DPT head + depth classification decoder.
153
+
154
+ Takes 4 intermediate ViT features and produces a depth map.
155
+ """
156
+
157
+ def __init__(self, input_embed_dim: int = 1024,
158
+ channels: int = 256,
159
+ post_process_channels: tuple = (128, 256, 512, 1024),
160
+ readout_type: str = "project",
161
+ num_depth_bins: int = 256,
162
+ min_depth: float = 1e-3,
163
+ max_depth: float = 10.0):
164
+ super().__init__()
165
+ self.num_depth_bins = num_depth_bins
166
+ self.min_depth = min_depth
167
+ self.max_depth = max_depth
168
+
169
+ # Reassemble: project + resize
170
+ self.reassemble = ReassembleBlocks(
171
+ input_embed_dim=input_embed_dim,
172
+ out_channels=post_process_channels,
173
+ readout_type=readout_type,
174
+ )
175
+
176
+ # 3×3 convs to map each level to `channels`
177
+ self.convs = nn.ModuleList([
178
+ nn.Conv2d(ch, channels, 3, padding=1, bias=False)
179
+ for ch in post_process_channels
180
+ ])
181
+
182
+ # Fusion blocks: first has no residual, rest have residual
183
+ self.fusion_blocks = nn.ModuleList([
184
+ FeatureFusionBlock(channels, has_residual=False),
185
+ FeatureFusionBlock(channels, has_residual=True),
186
+ FeatureFusionBlock(channels, has_residual=True),
187
+ FeatureFusionBlock(channels, has_residual=True),
188
+ ])
189
+
190
+ # Final projection
191
+ self.project = nn.Conv2d(channels, channels, 3, padding=1, bias=True)
192
+
193
+ # Depth classification head (Dense layer)
194
+ self.depth_head = nn.Linear(channels, num_depth_bins)
195
+
196
+ def forward(self, intermediate_features, image_size=None):
197
+ """Run DPT depth prediction.
198
+
199
+ Args:
200
+ intermediate_features: list of 4 (cls_token, patch_feats) tuples
201
+ image_size: (H, W) to resize output to, or None
202
+
203
+ Returns:
204
+ depth map tensor (B, 1, H, W)
205
+ """
206
+ # Reassemble
207
+ x = self.reassemble(intermediate_features)
208
+ # 3×3 conv per level
209
+ x = [self.convs[i](feat) for i, feat in enumerate(x)]
210
+
211
+ # Fuse bottom-up: start from deepest (x[-1])
212
+ out = self.fusion_blocks[0](x[-1])
213
+ for i in range(1, 4):
214
+ out = self.fusion_blocks[i](out, residual=x[-(i + 1)])
215
+
216
+ # Project
217
+ out = self.project(out)
218
+ out = F.relu(out)
219
+
220
+ # Depth classification
221
+ # out: (B, C, H, W) → (B, H, W, C)
222
+ out = out.permute(0, 2, 3, 1)
223
+ out = self.depth_head(out) # (B, H, W, num_bins)
224
+
225
+ # Classification-based depth prediction
226
+ bin_centers = torch.linspace(
227
+ self.min_depth, self.max_depth, self.num_depth_bins,
228
+ device=out.device)
229
+ out = F.relu(out) + self.min_depth
230
+ out_norm = out / out.sum(dim=-1, keepdim=True)
231
+ depth = torch.einsum("bhwn,n->bhw", out_norm, bin_centers)
232
+ depth = depth.unsqueeze(1) # (B, 1, H, W)
233
+
234
+ # Resize to original image size
235
+ if image_size is not None:
236
+ depth = F.interpolate(depth, size=image_size, mode="bilinear",
237
+ align_corners=False)
238
+
239
+ return depth
240
+
241
+
242
+ class DPTNormalsHead(nn.Module):
243
+ """Full DPT head + surface normals decoder.
244
+
245
+ Takes 4 intermediate ViT features and produces a normal map.
246
+ """
247
+
248
+ def __init__(self, input_embed_dim: int = 1024,
249
+ channels: int = 256,
250
+ post_process_channels: tuple = (128, 256, 512, 1024),
251
+ readout_type: str = "project"):
252
+ super().__init__()
253
+
254
+ # Reassemble: project + resize
255
+ self.reassemble = ReassembleBlocks(
256
+ input_embed_dim=input_embed_dim,
257
+ out_channels=post_process_channels,
258
+ readout_type=readout_type,
259
+ )
260
+
261
+ # 3×3 convs to map each level to `channels`
262
+ self.convs = nn.ModuleList([
263
+ nn.Conv2d(ch, channels, 3, padding=1, bias=False)
264
+ for ch in post_process_channels
265
+ ])
266
+
267
+ # Fusion blocks: first has no residual, rest have residual
268
+ self.fusion_blocks = nn.ModuleList([
269
+ FeatureFusionBlock(channels, has_residual=False),
270
+ FeatureFusionBlock(channels, has_residual=True),
271
+ FeatureFusionBlock(channels, has_residual=True),
272
+ FeatureFusionBlock(channels, has_residual=True),
273
+ ])
274
+
275
+ # Final projection
276
+ self.project = nn.Conv2d(channels, channels, 3, padding=1, bias=True)
277
+
278
+ # Normals head (Dense layer)
279
+ self.normals_head = nn.Linear(channels, 3)
280
+
281
+ def forward(self, intermediate_features, image_size=None):
282
+ """Run DPT normals prediction.
283
+
284
+ Args:
285
+ intermediate_features: list of 4 (cls_token, patch_feats) tuples
286
+ image_size: (H, W) to resize output to, or None
287
+
288
+ Returns:
289
+ normal map tensor (B, 3, H, W)
290
+ """
291
+ # Reassemble
292
+ x = self.reassemble(intermediate_features)
293
+ # 3×3 conv per level
294
+ x = [self.convs[i](feat) for i, feat in enumerate(x)]
295
+
296
+ # Fuse bottom-up: start from deepest (x[-1])
297
+ out = self.fusion_blocks[0](x[-1])
298
+ for i in range(1, 4):
299
+ out = self.fusion_blocks[i](out, residual=x[-(i + 1)])
300
+
301
+ # Project
302
+ out = self.project(out)
303
+
304
+ # Normals head
305
+ # out: (B, C, H, W) → (B, H, W, C)
306
+ out = out.permute(0, 2, 3, 1)
307
+ out = self.normals_head(out) # (B, H, W, 3)
308
+
309
+ # Normalize to unit length
310
+ out = F.normalize(out, p=2, dim=-1)
311
+
312
+ # Resize to original image size
313
+ if image_size is not None:
314
+ # PyTorch interpolate expects (B, C, H, W)
315
+ out = out.permute(0, 3, 1, 2)
316
+ out = F.interpolate(out, size=image_size, mode="bilinear",
317
+ align_corners=False)
318
+ else:
319
+ out = out.permute(0, 3, 1, 2)
320
+
321
+ return out
322
+
323
+
324
+ class DPTSegmentationHead(nn.Module):
325
+ """Full DPT head + segmentation decoder.
326
+
327
+ Takes 4 intermediate ViT features and produces a segmentation map.
328
+ """
329
+
330
+ def __init__(self, input_embed_dim: int = 1024,
331
+ channels: int = 256,
332
+ post_process_channels: tuple = (128, 256, 512, 1024),
333
+ readout_type: str = "project",
334
+ num_classes: int = 150):
335
+ super().__init__()
336
+
337
+ # Reassemble: project + resize
338
+ self.reassemble = ReassembleBlocks(
339
+ input_embed_dim=input_embed_dim,
340
+ out_channels=post_process_channels,
341
+ readout_type=readout_type,
342
+ )
343
+
344
+ # 3×3 convs to map each level to `channels`
345
+ self.convs = nn.ModuleList([
346
+ nn.Conv2d(ch, channels, 3, padding=1, bias=False)
347
+ for ch in post_process_channels
348
+ ])
349
+
350
+ # Fusion blocks: first has no residual, rest have residual
351
+ self.fusion_blocks = nn.ModuleList([
352
+ FeatureFusionBlock(channels, has_residual=False),
353
+ FeatureFusionBlock(channels, has_residual=True),
354
+ FeatureFusionBlock(channels, has_residual=True),
355
+ FeatureFusionBlock(channels, has_residual=True),
356
+ ])
357
+
358
+ # Final projection
359
+ self.project = nn.Conv2d(channels, channels, 3, padding=1, bias=True)
360
+
361
+ # Segmentation head (Dense layer)
362
+ self.segmentation_head = nn.Linear(channels, num_classes)
363
+
364
+ def forward(self, intermediate_features, image_size=None):
365
+ """Run DPT segmentation prediction.
366
+
367
+ Args:
368
+ intermediate_features: list of 4 (cls_token, patch_feats) tuples
369
+ image_size: (H, W) to resize output to, or None
370
+
371
+ Returns:
372
+ segmentation map tensor (B, num_classes, H, W)
373
+ """
374
+ # Reassemble
375
+ x = self.reassemble(intermediate_features)
376
+ # 3×3 conv per level
377
+ x = [self.convs[i](feat) for i, feat in enumerate(x)]
378
+
379
+ # Fuse bottom-up: start from deepest (x[-1])
380
+ out = self.fusion_blocks[0](x[-1])
381
+ for i in range(1, 4):
382
+ out = self.fusion_blocks[i](out, residual=x[-(i + 1)])
383
+
384
+ # Project
385
+ out = self.project(out)
386
+
387
+ # Segmentation head
388
+ # out: (B, C, H, W) → (B, H, W, C)
389
+ out = out.permute(0, 2, 3, 1)
390
+ out = self.segmentation_head(out) # (B, H, W, num_classes)
391
+
392
+ # Resize to original image size
393
+ if image_size is not None:
394
+ # PyTorch interpolate expects (B, C, H, W)
395
+ out = out.permute(0, 3, 1, 2)
396
+ out = F.interpolate(out, size=image_size, mode="bilinear",
397
+ align_corners=False)
398
+ else:
399
+ out = out.permute(0, 3, 1, 2)
400
+
401
+ return out
402
+
403
+
404
+ # ── Weight loading from Scenic/Flax checkpoint ─────────────────────────────
405
+
406
+
407
+ def _load_npy_from_zip(zf, name):
408
+ """Load a single .npy array from a zipfile."""
409
+ with zf.open(name) as f:
410
+ return np.load(io.BytesIO(f.read()))
411
+
412
+
413
+ def _conv_kernel_flax_to_torch(w):
414
+ """Convert Flax conv kernel (H,W,Cin,Cout) → PyTorch (Cout,Cin,H,W)."""
415
+ return torch.from_numpy(w.transpose(3, 2, 0, 1).copy())
416
+
417
+
418
+ def _conv_transpose_kernel_flax_to_torch(w):
419
+ """Convert Flax ConvTranspose kernel (H,W,Cin,Cout) → PyTorch (Cin,Cout,H,W)."""
420
+ return torch.from_numpy(w.transpose(2, 3, 0, 1).copy())
421
+
422
+
423
+ def _linear_kernel_flax_to_torch(w):
424
+ """Convert Flax Dense kernel (in,out) → PyTorch Linear (out,in)."""
425
+ return torch.from_numpy(w.T.copy())
426
+
427
+
428
+ def _bias(w):
429
+ return torch.from_numpy(w.copy())
430
+
431
+
432
+ def load_dpt_weights(model: DPTDepthHead, zip_path: str):
433
+ """Load Scenic/Flax DPT weights from a zip/npz file into PyTorch model."""
434
+ zf = zipfile.ZipFile(zip_path, "r")
435
+ npy = lambda name: _load_npy_from_zip(zf, name)
436
+ sd = {}
437
+ prefix = "decoder/dpt/"
438
+
439
+ # --- ReassembleBlocks ---
440
+ for i in range(4):
441
+ # out_projections (Conv2d 1×1)
442
+ sd[f"reassemble.out_projections.{i}.weight"] = _conv_kernel_flax_to_torch(
443
+ npy(f"{prefix}reassemble_blocks/out_projection_{i}/kernel.npy"))
444
+ sd[f"reassemble.out_projections.{i}.bias"] = _bias(
445
+ npy(f"{prefix}reassemble_blocks/out_projection_{i}/bias.npy"))
446
+
447
+ # readout_projects (Linear)
448
+ sd[f"reassemble.readout_projects.{i}.weight"] = _linear_kernel_flax_to_torch(
449
+ npy(f"{prefix}reassemble_blocks/readout_projects_{i}/kernel.npy"))
450
+ sd[f"reassemble.readout_projects.{i}.bias"] = _bias(
451
+ npy(f"{prefix}reassemble_blocks/readout_projects_{i}/bias.npy"))
452
+
453
+ # resize_layers: 0=ConvTranspose, 1=ConvTranspose, 2=Identity, 3=Conv
454
+ sd["reassemble.resize_layers.0.weight"] = _conv_transpose_kernel_flax_to_torch(
455
+ npy(f"{prefix}reassemble_blocks/resize_layers_0/kernel.npy"))
456
+ sd["reassemble.resize_layers.0.bias"] = _bias(
457
+ npy(f"{prefix}reassemble_blocks/resize_layers_0/bias.npy"))
458
+ sd["reassemble.resize_layers.1.weight"] = _conv_transpose_kernel_flax_to_torch(
459
+ npy(f"{prefix}reassemble_blocks/resize_layers_1/kernel.npy"))
460
+ sd["reassemble.resize_layers.1.bias"] = _bias(
461
+ npy(f"{prefix}reassemble_blocks/resize_layers_1/bias.npy"))
462
+ # resize_layers_2 = Identity (no weights)
463
+ sd["reassemble.resize_layers.3.weight"] = _conv_kernel_flax_to_torch(
464
+ npy(f"{prefix}reassemble_blocks/resize_layers_3/kernel.npy"))
465
+ sd["reassemble.resize_layers.3.bias"] = _bias(
466
+ npy(f"{prefix}reassemble_blocks/resize_layers_3/bias.npy"))
467
+
468
+ # --- Convs (3×3, no bias) ---
469
+ for i in range(4):
470
+ sd[f"convs.{i}.weight"] = _conv_kernel_flax_to_torch(
471
+ npy(f"{prefix}convs_{i}/kernel.npy"))
472
+
473
+ # --- Fusion blocks ---
474
+ for i in range(4):
475
+ fb = f"{prefix}fusion_blocks_{i}/"
476
+ if i == 0:
477
+ # No residual unit, only 1 PreActResidualConvUnit
478
+ sd[f"fusion_blocks.{i}.main_unit.conv1.weight"] = _conv_kernel_flax_to_torch(
479
+ npy(f"{fb}PreActResidualConvUnit_0/conv1/kernel.npy"))
480
+ sd[f"fusion_blocks.{i}.main_unit.conv2.weight"] = _conv_kernel_flax_to_torch(
481
+ npy(f"{fb}PreActResidualConvUnit_0/conv2/kernel.npy"))
482
+ else:
483
+ # Residual unit (index 0) + main unit (index 1)
484
+ sd[f"fusion_blocks.{i}.residual_unit.conv1.weight"] = _conv_kernel_flax_to_torch(
485
+ npy(f"{fb}PreActResidualConvUnit_0/conv1/kernel.npy"))
486
+ sd[f"fusion_blocks.{i}.residual_unit.conv2.weight"] = _conv_kernel_flax_to_torch(
487
+ npy(f"{fb}PreActResidualConvUnit_0/conv2/kernel.npy"))
488
+ sd[f"fusion_blocks.{i}.main_unit.conv1.weight"] = _conv_kernel_flax_to_torch(
489
+ npy(f"{fb}PreActResidualConvUnit_1/conv1/kernel.npy"))
490
+ sd[f"fusion_blocks.{i}.main_unit.conv2.weight"] = _conv_kernel_flax_to_torch(
491
+ npy(f"{fb}PreActResidualConvUnit_1/conv2/kernel.npy"))
492
+
493
+ # out_conv (Conv2d 1×1)
494
+ sd[f"fusion_blocks.{i}.out_conv.weight"] = _conv_kernel_flax_to_torch(
495
+ npy(f"{fb}Conv_0/kernel.npy"))
496
+ sd[f"fusion_blocks.{i}.out_conv.bias"] = _bias(
497
+ npy(f"{fb}Conv_0/bias.npy"))
498
+
499
+ # --- Project ---
500
+ sd["project.weight"] = _conv_kernel_flax_to_torch(
501
+ npy(f"{prefix}project/kernel.npy"))
502
+ sd["project.bias"] = _bias(
503
+ npy(f"{prefix}project/bias.npy"))
504
+
505
+ # --- Depth classification head ---
506
+ sd["depth_head.weight"] = _linear_kernel_flax_to_torch(
507
+ npy("decoder/pixel_depth_classif/kernel.npy"))
508
+ sd["depth_head.bias"] = _bias(
509
+ npy("decoder/pixel_depth_classif/bias.npy"))
510
+
511
+ zf.close()
512
+
513
+ # Load into model
514
+ missing, unexpected = model.load_state_dict(sd, strict=True)
515
+ if missing:
516
+ print(f"WARNING: Missing keys: {missing}")
517
+ if unexpected:
518
+ print(f"WARNING: Unexpected keys: {unexpected}")
519
+ print(f"Loaded DPT depth head weights ({len(sd)} tensors)")
520
+ return model
521
+
522
+
523
+ def load_normals_weights(model: DPTNormalsHead, zip_path: str):
524
+ """Load Scenic/Flax DPT weights from a zip/npz file into PyTorch model."""
525
+ zf = zipfile.ZipFile(zip_path, "r")
526
+ npy = lambda name: _load_npy_from_zip(zf, name)
527
+ sd = {}
528
+ prefix = "decoder/dpt/"
529
+
530
+ # --- ReassembleBlocks ---
531
+ for i in range(4):
532
+ # out_projections (Conv2d 1×1)
533
+ sd[f"reassemble.out_projections.{i}.weight"] = _conv_kernel_flax_to_torch(
534
+ npy(f"{prefix}reassemble_blocks/out_projection_{i}/kernel.npy"))
535
+ sd[f"reassemble.out_projections.{i}.bias"] = _bias(
536
+ npy(f"{prefix}reassemble_blocks/out_projection_{i}/bias.npy"))
537
+
538
+ # readout_projects (Linear)
539
+ sd[f"reassemble.readout_projects.{i}.weight"] = _linear_kernel_flax_to_torch(
540
+ npy(f"{prefix}reassemble_blocks/readout_projects_{i}/kernel.npy"))
541
+ sd[f"reassemble.readout_projects.{i}.bias"] = _bias(
542
+ npy(f"{prefix}reassemble_blocks/readout_projects_{i}/bias.npy"))
543
+
544
+ # resize_layers: 0=ConvTranspose, 1=ConvTranspose, 2=Identity, 3=Conv
545
+ sd["reassemble.resize_layers.0.weight"] = _conv_transpose_kernel_flax_to_torch(
546
+ npy(f"{prefix}reassemble_blocks/resize_layers_0/kernel.npy"))
547
+ sd["reassemble.resize_layers.0.bias"] = _bias(
548
+ npy(f"{prefix}reassemble_blocks/resize_layers_0/bias.npy"))
549
+ sd["reassemble.resize_layers.1.weight"] = _conv_transpose_kernel_flax_to_torch(
550
+ npy(f"{prefix}reassemble_blocks/resize_layers_1/kernel.npy"))
551
+ sd["reassemble.resize_layers.1.bias"] = _bias(
552
+ npy(f"{prefix}reassemble_blocks/resize_layers_1/bias.npy"))
553
+ # resize_layers_2 = Identity (no weights)
554
+ sd["reassemble.resize_layers.3.weight"] = _conv_kernel_flax_to_torch(
555
+ npy(f"{prefix}reassemble_blocks/resize_layers_3/kernel.npy"))
556
+ sd["reassemble.resize_layers.3.bias"] = _bias(
557
+ npy(f"{prefix}reassemble_blocks/resize_layers_3/bias.npy"))
558
+
559
+ # --- Convs (3×3, no bias) ---
560
+ for i in range(4):
561
+ sd[f"convs.{i}.weight"] = _conv_kernel_flax_to_torch(
562
+ npy(f"{prefix}convs_{i}/kernel.npy"))
563
+
564
+ # --- Fusion blocks ---
565
+ for i in range(4):
566
+ fb = f"{prefix}fusion_blocks_{i}/"
567
+ if i == 0:
568
+ # No residual unit, only 1 PreActResidualConvUnit
569
+ sd[f"fusion_blocks.{i}.main_unit.conv1.weight"] = _conv_kernel_flax_to_torch(
570
+ npy(f"{fb}PreActResidualConvUnit_0/conv1/kernel.npy"))
571
+ sd[f"fusion_blocks.{i}.main_unit.conv2.weight"] = _conv_kernel_flax_to_torch(
572
+ npy(f"{fb}PreActResidualConvUnit_0/conv2/kernel.npy"))
573
+ else:
574
+ # Residual unit (index 0) + main unit (index 1)
575
+ sd[f"fusion_blocks.{i}.residual_unit.conv1.weight"] = _conv_kernel_flax_to_torch(
576
+ npy(f"{fb}PreActResidualConvUnit_0/conv1/kernel.npy"))
577
+ sd[f"fusion_blocks.{i}.residual_unit.conv2.weight"] = _conv_kernel_flax_to_torch(
578
+ npy(f"{fb}PreActResidualConvUnit_0/conv2/kernel.npy"))
579
+ sd[f"fusion_blocks.{i}.main_unit.conv1.weight"] = _conv_kernel_flax_to_torch(
580
+ npy(f"{fb}PreActResidualConvUnit_1/conv1/kernel.npy"))
581
+ sd[f"fusion_blocks.{i}.main_unit.conv2.weight"] = _conv_kernel_flax_to_torch(
582
+ npy(f"{fb}PreActResidualConvUnit_1/conv2/kernel.npy"))
583
+
584
+ # out_conv (Conv2d 1×1)
585
+ sd[f"fusion_blocks.{i}.out_conv.weight"] = _conv_kernel_flax_to_torch(
586
+ npy(f"{fb}Conv_0/kernel.npy"))
587
+ sd[f"fusion_blocks.{i}.out_conv.bias"] = _bias(
588
+ npy(f"{fb}Conv_0/bias.npy"))
589
+
590
+ # --- Project ---
591
+ sd["project.weight"] = _conv_kernel_flax_to_torch(
592
+ npy(f"{prefix}project/kernel.npy"))
593
+ sd["project.bias"] = _bias(
594
+ npy(f"{prefix}project/bias.npy"))
595
+
596
+ # --- Normals head ---
597
+ sd["normals_head.weight"] = _linear_kernel_flax_to_torch(
598
+ npy("decoder/pixel_normals/kernel.npy"))
599
+ sd["normals_head.bias"] = _bias(
600
+ npy("decoder/pixel_normals/bias.npy"))
601
+
602
+ zf.close()
603
+
604
+ # Load into model
605
+ missing, unexpected = model.load_state_dict(sd, strict=True)
606
+ if missing:
607
+ print(f"WARNING: Missing keys: {missing}")
608
+ if unexpected:
609
+ print(f"WARNING: Unexpected keys: {unexpected}")
610
+ print(f"Loaded DPT normals head weights ({len(sd)} tensors)")
611
+ return model
612
+
613
+
614
+ def load_segmentation_weights(model: DPTSegmentationHead, zip_path: str):
615
+ """Load Scenic/Flax DPT weights from a zip/npz file into PyTorch model."""
616
+ zf = zipfile.ZipFile(zip_path, "r")
617
+ npy = lambda name: _load_npy_from_zip(zf, name)
618
+ sd = {}
619
+ prefix = "decoder/dpt/"
620
+
621
+ # --- ReassembleBlocks ---
622
+ for i in range(4):
623
+ # out_projections (Conv2d 1×1)
624
+ sd[f"reassemble.out_projections.{i}.weight"] = _conv_kernel_flax_to_torch(
625
+ npy(f"{prefix}reassemble_blocks/out_projection_{i}/kernel.npy"))
626
+ sd[f"reassemble.out_projections.{i}.bias"] = _bias(
627
+ npy(f"{prefix}reassemble_blocks/out_projection_{i}/bias.npy"))
628
+
629
+ # readout_projects (Linear)
630
+ sd[f"reassemble.readout_projects.{i}.weight"] = _linear_kernel_flax_to_torch(
631
+ npy(f"{prefix}reassemble_blocks/readout_projects_{i}/kernel.npy"))
632
+ sd[f"reassemble.readout_projects.{i}.bias"] = _bias(
633
+ npy(f"{prefix}reassemble_blocks/readout_projects_{i}/bias.npy"))
634
+
635
+ # resize_layers: 0=ConvTranspose, 1=ConvTranspose, 2=Identity, 3=Conv
636
+ sd["reassemble.resize_layers.0.weight"] = _conv_transpose_kernel_flax_to_torch(
637
+ npy(f"{prefix}reassemble_blocks/resize_layers_0/kernel.npy"))
638
+ sd["reassemble.resize_layers.0.bias"] = _bias(
639
+ npy(f"{prefix}reassemble_blocks/resize_layers_0/bias.npy"))
640
+ sd["reassemble.resize_layers.1.weight"] = _conv_transpose_kernel_flax_to_torch(
641
+ npy(f"{prefix}reassemble_blocks/resize_layers_1/kernel.npy"))
642
+ sd["reassemble.resize_layers.1.bias"] = _bias(
643
+ npy(f"{prefix}reassemble_blocks/resize_layers_1/bias.npy"))
644
+ # resize_layers_2 = Identity (no weights)
645
+ sd["reassemble.resize_layers.3.weight"] = _conv_kernel_flax_to_torch(
646
+ npy(f"{prefix}reassemble_blocks/resize_layers_3/kernel.npy"))
647
+ sd["reassemble.resize_layers.3.bias"] = _bias(
648
+ npy(f"{prefix}reassemble_blocks/resize_layers_3/bias.npy"))
649
+
650
+ # --- Convs (3×3, no bias) ---
651
+ for i in range(4):
652
+ sd[f"convs.{i}.weight"] = _conv_kernel_flax_to_torch(
653
+ npy(f"{prefix}convs_{i}/kernel.npy"))
654
+
655
+ # --- Fusion blocks ---
656
+ for i in range(4):
657
+ fb = f"{prefix}fusion_blocks_{i}/"
658
+ if i == 0:
659
+ # No residual unit, only 1 PreActResidualConvUnit
660
+ sd[f"fusion_blocks.{i}.main_unit.conv1.weight"] = _conv_kernel_flax_to_torch(
661
+ npy(f"{fb}PreActResidualConvUnit_0/conv1/kernel.npy"))
662
+ sd[f"fusion_blocks.{i}.main_unit.conv2.weight"] = _conv_kernel_flax_to_torch(
663
+ npy(f"{fb}PreActResidualConvUnit_0/conv2/kernel.npy"))
664
+ else:
665
+ # Residual unit (index 0) + main unit (index 1)
666
+ sd[f"fusion_blocks.{i}.residual_unit.conv1.weight"] = _conv_kernel_flax_to_torch(
667
+ npy(f"{fb}PreActResidualConvUnit_0/conv1/kernel.npy"))
668
+ sd[f"fusion_blocks.{i}.residual_unit.conv2.weight"] = _conv_kernel_flax_to_torch(
669
+ npy(f"{fb}PreActResidualConvUnit_0/conv2/kernel.npy"))
670
+ sd[f"fusion_blocks.{i}.main_unit.conv1.weight"] = _conv_kernel_flax_to_torch(
671
+ npy(f"{fb}PreActResidualConvUnit_1/conv1/kernel.npy"))
672
+ sd[f"fusion_blocks.{i}.main_unit.conv2.weight"] = _conv_kernel_flax_to_torch(
673
+ npy(f"{fb}PreActResidualConvUnit_1/conv2/kernel.npy"))
674
+
675
+ # out_conv (Conv2d 1×1)
676
+ sd[f"fusion_blocks.{i}.out_conv.weight"] = _conv_kernel_flax_to_torch(
677
+ npy(f"{fb}Conv_0/kernel.npy"))
678
+ sd[f"fusion_blocks.{i}.out_conv.bias"] = _bias(
679
+ npy(f"{fb}Conv_0/bias.npy"))
680
+
681
+ # --- Project ---
682
+ sd["project.weight"] = _conv_kernel_flax_to_torch(
683
+ npy(f"{prefix}project/kernel.npy"))
684
+ sd["project.bias"] = _bias(
685
+ npy(f"{prefix}project/bias.npy"))
686
+
687
+ # --- Segmentation head ---
688
+ sd["segmentation_head.weight"] = _linear_kernel_flax_to_torch(
689
+ npy("decoder/pixel_segmentation/kernel.npy"))
690
+ sd["segmentation_head.bias"] = _bias(
691
+ npy("decoder/pixel_segmentation/bias.npy"))
692
+
693
+ zf.close()
694
+
695
+ # Load into model
696
+ missing, unexpected = model.load_state_dict(sd, strict=True)
697
+ if missing:
698
+ print(f"WARNING: Missing keys: {missing}")
699
+ if unexpected:
700
+ print(f"WARNING: Unexpected keys: {unexpected}")
701
+ print(f"Loaded DPT segmentation head weights ({len(sd)} tensors)")
702
+ return model
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:38362aae91092ca0a6f2fe7f7ed29ec2e7042e3b920b7217d9317ad4c13abdfa
3
+ size 1622839292
modeling_dpt.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """TIPSv2 DPT dense prediction model for HuggingFace."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Optional
5
+
6
+ import torch
7
+ from transformers import AutoConfig, AutoModel, PreTrainedModel
8
+
9
+ from .configuration_dpt import TIPSv2DPTConfig
10
+ from .dpt_head import DPTDepthHead, DPTNormalsHead, DPTSegmentationHead
11
+
12
+
13
+ @dataclass
14
+ class TIPSv2DPTOutput:
15
+ depth: Optional[torch.Tensor] = None
16
+ normals: Optional[torch.Tensor] = None
17
+ segmentation: Optional[torch.Tensor] = None
18
+
19
+
20
+ class TIPSv2DPTModel(PreTrainedModel):
21
+ """TIPSv2 DPT dense prediction model (depth, normals, segmentation).
22
+
23
+ The backbone is loaded automatically from the base TIPSv2 model repo.
24
+
25
+ Usage::
26
+
27
+ model = AutoModel.from_pretrained("google/tipsv2-l14-dpt", trust_remote_code=True)
28
+ model.eval().cuda()
29
+
30
+ outputs = model(pixel_values)
31
+ outputs.depth # (B, 1, H, W)
32
+ outputs.normals # (B, 3, H, W)
33
+ outputs.segmentation # (B, 150, H, W)
34
+
35
+ # Individual tasks
36
+ depth = model.predict_depth(pixel_values)
37
+ normals = model.predict_normals(pixel_values)
38
+ seg = model.predict_segmentation(pixel_values)
39
+ """
40
+
41
+ config_class = TIPSv2DPTConfig
42
+ _no_split_modules = []
43
+ _supports_cache_class = False
44
+ _tied_weights_keys = []
45
+
46
+ @property
47
+ def all_tied_weights_keys(self):
48
+ return {}
49
+
50
+ def __init__(self, config: TIPSv2DPTConfig):
51
+ super().__init__(config)
52
+
53
+ ppc = tuple(config.post_process_channels)
54
+
55
+ backbone_config = AutoConfig.from_pretrained(config.backbone_repo, trust_remote_code=True)
56
+ backbone = AutoModel.from_config(backbone_config, trust_remote_code=True)
57
+ self.vision_encoder = backbone.vision_encoder
58
+
59
+ self.depth_head = DPTDepthHead(
60
+ input_embed_dim=config.embed_dim, channels=config.channels,
61
+ post_process_channels=ppc, readout_type=config.readout_type,
62
+ num_depth_bins=config.num_depth_bins,
63
+ min_depth=config.min_depth, max_depth=config.max_depth,
64
+ )
65
+ self.normals_head = DPTNormalsHead(
66
+ input_embed_dim=config.embed_dim, channels=config.channels,
67
+ post_process_channels=ppc, readout_type=config.readout_type,
68
+ )
69
+ self.segmentation_head = DPTSegmentationHead(
70
+ input_embed_dim=config.embed_dim, channels=config.channels,
71
+ post_process_channels=ppc, readout_type=config.readout_type,
72
+ num_classes=config.num_seg_classes,
73
+ )
74
+
75
+ def _extract_intermediate(self, pixel_values):
76
+ intermediate = self.vision_encoder.get_intermediate_layers(
77
+ pixel_values, n=self.config.block_indices,
78
+ reshape=True, return_class_token=True, norm=True,
79
+ )
80
+ return [(cls_tok, patch_feat) for patch_feat, cls_tok in intermediate]
81
+
82
+ @torch.no_grad()
83
+ def predict_depth(self, pixel_values: torch.Tensor) -> torch.Tensor:
84
+ """Predict depth map. Returns (B, 1, H, W)."""
85
+ pixel_values = pixel_values.to(self.device)
86
+ h, w = pixel_values.shape[2:]
87
+ dpt_inputs = self._extract_intermediate(pixel_values)
88
+ return self.depth_head(dpt_inputs, image_size=(h, w))
89
+
90
+ @torch.no_grad()
91
+ def predict_normals(self, pixel_values: torch.Tensor) -> torch.Tensor:
92
+ """Predict surface normals. Returns (B, 3, H, W)."""
93
+ pixel_values = pixel_values.to(self.device)
94
+ h, w = pixel_values.shape[2:]
95
+ dpt_inputs = self._extract_intermediate(pixel_values)
96
+ return self.normals_head(dpt_inputs, image_size=(h, w))
97
+
98
+ @torch.no_grad()
99
+ def predict_segmentation(self, pixel_values: torch.Tensor) -> torch.Tensor:
100
+ """Predict semantic segmentation (ADE20K). Returns (B, 150, H, W)."""
101
+ pixel_values = pixel_values.to(self.device)
102
+ h, w = pixel_values.shape[2:]
103
+ dpt_inputs = self._extract_intermediate(pixel_values)
104
+ return self.segmentation_head(dpt_inputs, image_size=(h, w))
105
+
106
+ def forward(self, pixel_values: torch.Tensor) -> TIPSv2DPTOutput:
107
+ """Run all three tasks. Returns TIPSv2DPTOutput."""
108
+ pixel_values = pixel_values.to(self.device)
109
+ h, w = pixel_values.shape[2:]
110
+ dpt_inputs = self._extract_intermediate(pixel_values)
111
+ return TIPSv2DPTOutput(
112
+ depth=self.depth_head(dpt_inputs, image_size=(h, w)),
113
+ normals=self.normals_head(dpt_inputs, image_size=(h, w)),
114
+ segmentation=self.segmentation_head(dpt_inputs, image_size=(h, w)),
115
+ )
preprocessor_config.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "do_convert_rgb": true,
3
+ "do_normalize": false,
4
+ "do_rescale": true,
5
+ "do_resize": true,
6
+ "image_processor_type": "Tipsv2DptImageProcessor",
7
+ "resample": 2,
8
+ "rescale_factor": 0.00392156862745098,
9
+ "size": {
10
+ "height": 448,
11
+ "width": 448
12
+ }
13
+ }