captainspock lwanming commited on
Commit
a41d4a6
·
0 Parent(s):

Duplicate from lwanming/depth-anything-v2-small

Browse files

Co-authored-by: Wanming Lin <lwanming@users.noreply.huggingface.co>

.gitattributes ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
36
+ onnx/model_fp16.onnx_data filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ ---
4
+ The model (onnx/model_fp16.onnx) is sourced from onnx-community/depth-anything-v2-small. It is a Depth-Anything-V2 (with a DINOv2 backbone) ONNX model.
5
+
6
+ To resolve the issue where the original model constructs 5D tensors in its fused-QKV attention, we used convert_5d_to_4d.py to convert it into an equivalent model that maintains 4D attention tensors for better compatibility.
config.json ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_commit_hash": null,
3
+ "architectures": [
4
+ "DepthAnythingForDepthEstimation"
5
+ ],
6
+ "backbone": null,
7
+ "backbone_config": {
8
+ "architectures": [
9
+ "Dinov2Model"
10
+ ],
11
+ "hidden_size": 384,
12
+ "image_size": 518,
13
+ "model_type": "dinov2",
14
+ "num_attention_heads": 6,
15
+ "out_features": [
16
+ "stage3",
17
+ "stage6",
18
+ "stage9",
19
+ "stage12"
20
+ ],
21
+ "out_indices": [
22
+ 3,
23
+ 6,
24
+ 9,
25
+ 12
26
+ ],
27
+ "patch_size": 14,
28
+ "reshape_hidden_states": false,
29
+ "torch_dtype": "float32"
30
+ },
31
+ "fusion_hidden_size": 64,
32
+ "head_hidden_size": 32,
33
+ "head_in_index": -1,
34
+ "initializer_range": 0.02,
35
+ "model_type": "depth_anything",
36
+ "neck_hidden_sizes": [
37
+ 48,
38
+ 96,
39
+ 192,
40
+ 384
41
+ ],
42
+ "patch_size": 14,
43
+ "reassemble_factors": [
44
+ 4,
45
+ 2,
46
+ 1,
47
+ 0.5
48
+ ],
49
+ "reassemble_hidden_size": 384,
50
+ "torch_dtype": "float32",
51
+ "transformers_version": null,
52
+ "transformers.js_config": {
53
+ "use_external_data_format": true
54
+ },
55
+ "use_pretrained_backbone": false
56
+ }
convert_5d_to_4d.py ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Convert a Depth-Anything-V2 (DINOv2 backbone) ONNX model that builds 5D tensors
3
+ in its fused-QKV attention into an equivalent model whose attention stays 4D,
4
+ so it can fully offload to the WebNN execution provider.
5
+
6
+ Per transformer block the original (LiheYoung repo) attention does:
7
+
8
+ qkv Add [B, N, 3*C]
9
+ -> Reshape -> [B, N, 3, H, Dh] (5D)
10
+ -> Transpose -> [3, B, H, N, Dh] (5D), perm [2,0,3,1,4]
11
+ -> Gather idx 0/1/2 (axis 0) -> q,k,v [B, H, N, Dh]
12
+
13
+ We replace that 5D path with the HuggingFace-style 4D path that produces the
14
+ SAME q/k/v output tensor names the rest of the block already consumes:
15
+
16
+ qkv Add [B, N, 3*C]
17
+ -> Split(axis=2, 3) -> q_lin,k_lin,v_lin [B, N, C]
18
+ -> Reshape [0,0,H,Dh] -> [B, N, H, Dh]
19
+ -> Transpose [0,2,1,3] -> [B, H, N, Dh] (named as the old Gather outputs)
20
+
21
+ This is algebraically identical, preserves dynamic B/N (so
22
+ freeDimensionOverrides still apply), and keeps every other node untouched.
23
+ """
24
+
25
+ import os
26
+ import sys
27
+ import re
28
+ from collections import Counter, defaultdict
29
+
30
+ import onnx
31
+ from onnx import helper, TensorProto, shape_inference
32
+
33
+ HOME = os.path.expanduser("~")
34
+ SRC = os.path.join(HOME, "Downloads", "model_fp16-5d.onnx")
35
+ DST = os.path.join(HOME, "Downloads", "model_fp16-5d-to-4d.onnx")
36
+
37
+ HEADS = 6
38
+ HEAD_DIM = 64
39
+ # q, k, v are Gather idx 0, 1, 2 -> map to output-name suffix
40
+ GATHER_FOR = {0: "Gather_3", 1: "Gather_4", 2: "Gather_5"}
41
+
42
+
43
+ def tensor_rank(vi):
44
+ t = vi.type.tensor_type
45
+ if not t.HasField("shape"):
46
+ return None
47
+ return len(t.shape.dim)
48
+
49
+
50
+ def count_high_rank(model):
51
+ """Return number of value_info/input/output tensors with rank > 4.
52
+
53
+ Clears any pre-existing value_info first so stale shapes from deleted nodes
54
+ are not counted -- shape inference repopulates from the live graph.
55
+ """
56
+ m = onnx.ModelProto()
57
+ m.CopyFrom(model)
58
+ del m.graph.value_info[:]
59
+ m = shape_inference.infer_shapes(m, strict_mode=False, data_prop=True)
60
+ g = m.graph
61
+ n = 0
62
+ for coll in (g.value_info, g.input, g.output):
63
+ for vi in coll:
64
+ r = tensor_rank(vi)
65
+ if r is not None and r > 4:
66
+ n += 1
67
+ return n
68
+
69
+
70
+ def discover_blocks(graph):
71
+ """Find attention block indices that use the fused-qkv 5D reshape pattern."""
72
+ blocks = set()
73
+ pat = re.compile(r"^/blocks\.(\d+)/attn/Reshape$")
74
+ have_reshape = {}
75
+ for node in graph.node:
76
+ mo = pat.match(node.name or "")
77
+ if mo:
78
+ have_reshape[int(mo.group(1))] = True
79
+ # Only keep blocks that also have the 3 gather outputs we rewire onto.
80
+ node_names = {n.name for n in graph.node}
81
+ for i in have_reshape:
82
+ needed = [f"/blocks.{i}/attn/{g}" for g in GATHER_FOR.values()]
83
+ needed += [f"/blocks.{i}/attn/Transpose"]
84
+ if all(nm in node_names for nm in needed):
85
+ blocks.add(i)
86
+ return sorted(blocks)
87
+
88
+
89
+ def dead_code_eliminate(graph):
90
+ """Iteratively drop nodes whose outputs are consumed by nothing."""
91
+ graph_outputs = {o.name for o in graph.output}
92
+ removed_total = 0
93
+ while True:
94
+ consumed = set()
95
+ for n in graph.node:
96
+ for i in n.input:
97
+ consumed.add(i)
98
+ consumed |= graph_outputs
99
+ keep = []
100
+ removed = 0
101
+ for n in graph.node:
102
+ if any(o in consumed for o in n.output if o):
103
+ keep.append(n)
104
+ else:
105
+ removed += 1
106
+ if removed == 0:
107
+ break
108
+ del graph.node[:]
109
+ graph.node.extend(keep)
110
+ removed_total += removed
111
+ return removed_total
112
+
113
+
114
+ def topo_sort(graph, available):
115
+ """Stable topological sort of graph.node. `available` = names known before
116
+ any node runs (graph inputs + initializers)."""
117
+ ready = set(available)
118
+ pending = list(graph.node)
119
+ ordered = []
120
+ progressed = True
121
+ while pending and progressed:
122
+ progressed = False
123
+ still = []
124
+ for n in pending:
125
+ deps = [i for i in n.input if i]
126
+ if all(d in ready for d in deps):
127
+ ordered.append(n)
128
+ for o in n.output:
129
+ if o:
130
+ ready.add(o)
131
+ progressed = True
132
+ else:
133
+ still.append(n)
134
+ pending = still
135
+ if pending:
136
+ # Should not happen; keep leftovers to surface a checker error rather
137
+ # than silently dropping nodes.
138
+ ordered.extend(pending)
139
+ del graph.node[:]
140
+ graph.node.extend(ordered)
141
+
142
+
143
+ def main():
144
+ if not os.path.exists(SRC):
145
+ sys.exit(f"source model not found: {SRC}")
146
+
147
+ model = onnx.load(SRC, load_external_data=True)
148
+ graph = model.graph
149
+
150
+ before_hist = Counter(n.op_type for n in graph.node)
151
+ before_high = count_high_rank(model)
152
+ print(f"loaded {SRC}")
153
+ print(f" nodes={len(graph.node)} rank>4 tensors={before_high}")
154
+
155
+ blocks = discover_blocks(graph)
156
+ print(f" attention blocks to rewrite: {blocks}")
157
+ if not blocks:
158
+ sys.exit("no fused-qkv 5D attention blocks found; nothing to do")
159
+
160
+ # shared reshape target [0,0,H,Dh]
161
+ reshape_shape_name = "qkv_reshape_shape_0_0_H_Dh"
162
+ graph.initializer.append(
163
+ helper.make_tensor(
164
+ reshape_shape_name, TensorProto.INT64, [4], [0, 0, HEADS, HEAD_DIM]
165
+ )
166
+ )
167
+
168
+ remove_suffixes = {"Reshape", "Transpose", "Gather_3", "Gather_4", "Gather_5"}
169
+ remove_names = set()
170
+ for i in blocks:
171
+ for s in remove_suffixes:
172
+ remove_names.add(f"/blocks.{i}/attn/{s}")
173
+
174
+ # index nodes by name for reference / sanity
175
+ kept_nodes = [n for n in graph.node if n.name not in remove_names]
176
+ removed_count = len(graph.node) - len(kept_nodes)
177
+ del graph.node[:]
178
+ graph.node.extend(kept_nodes)
179
+
180
+ new_nodes = []
181
+ for i in blocks:
182
+ p = f"/blocks.{i}/attn"
183
+ qkv_add = f"{p}/qkv/Add_output_0"
184
+ q_lin, k_lin, v_lin = f"{p}/n_q_lin", f"{p}/n_k_lin", f"{p}/n_v_lin"
185
+ # Split [B,N,3C] -> 3 x [B,N,C] on axis 2
186
+ new_nodes.append(
187
+ helper.make_node(
188
+ "Split",
189
+ inputs=[qkv_add],
190
+ outputs=[q_lin, k_lin, v_lin],
191
+ name=f"{p}/n_Split",
192
+ axis=2,
193
+ )
194
+ )
195
+ for idx, lin in ((0, q_lin), (1, k_lin), (2, v_lin)):
196
+ rout = f"{p}/n_reshape_{idx}"
197
+ gather_out = f"{p}/{GATHER_FOR[idx]}_output_0"
198
+ new_nodes.append(
199
+ helper.make_node(
200
+ "Reshape",
201
+ inputs=[lin, reshape_shape_name],
202
+ outputs=[rout],
203
+ name=f"{p}/n_Reshape_{idx}",
204
+ allowzero=0,
205
+ )
206
+ )
207
+ new_nodes.append(
208
+ helper.make_node(
209
+ "Transpose",
210
+ inputs=[rout],
211
+ outputs=[gather_out], # feed the exact name downstream expects
212
+ name=f"{p}/n_Transpose_{idx}",
213
+ perm=[0, 2, 1, 3],
214
+ )
215
+ )
216
+ graph.node.extend(new_nodes)
217
+ print(f" removed {removed_count} nodes, added {len(new_nodes)} nodes")
218
+
219
+ # dead-code eliminate the now-orphan 5D shape builders (Concat, Unsqueeze_2, ...)
220
+ dce = dead_code_eliminate(graph)
221
+ print(f" dead-code eliminated {dce} orphan nodes")
222
+
223
+ # topo-sort so producers precede consumers
224
+ available = {i.name for i in graph.initializer} | {i.name for i in graph.input}
225
+ topo_sort(graph, available)
226
+
227
+ # drop stale value_info (deleted 5D tensors); ORT re-infers at load time
228
+ del graph.value_info[:]
229
+
230
+ onnx.checker.check_model(model, full_check=True)
231
+ after_high = count_high_rank(model)
232
+ after_hist = Counter(n.op_type for n in graph.node)
233
+ print(f" after: nodes={len(graph.node)} rank>4 tensors={after_high}")
234
+
235
+ # op histogram diff
236
+ diff = {}
237
+ for op in set(before_hist) | set(after_hist):
238
+ d = after_hist.get(op, 0) - before_hist.get(op, 0)
239
+ if d:
240
+ diff[op] = f"{before_hist.get(op,0)}->{after_hist.get(op,0)}"
241
+ print(f" op changes: {diff}")
242
+
243
+ assert after_high == 0, f"still have {after_high} rank>4 tensors after surgery"
244
+
245
+ onnx.save(model, DST, save_as_external_data=False)
246
+ print(f"saved {DST} ({os.path.getsize(DST)/1e6:.1f} MB)")
247
+
248
+
249
+ if __name__ == "__main__":
250
+ main()
onnx/model_fp16.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:09aba7b8af9535e11c0bf4b93da21ef5a2394e27487729ae624eae15473ef6ad
3
+ size 1768360
onnx/model_fp16.onnx_data ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9d60cae2c173c758fe9b8ece018de5c5dee55ee6c34a878e8701a918d1a38f02
3
+ size 48892416
preprocessor_config.json ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "do_normalize": true,
3
+ "do_pad": false,
4
+ "do_rescale": true,
5
+ "do_resize": true,
6
+ "ensure_multiple_of": 14,
7
+ "image_mean": [
8
+ 0.485,
9
+ 0.456,
10
+ 0.406
11
+ ],
12
+ "image_processor_type": "DPTImageProcessor",
13
+ "image_std": [
14
+ 0.229,
15
+ 0.224,
16
+ 0.225
17
+ ],
18
+ "keep_aspect_ratio": true,
19
+ "resample": 3,
20
+ "rescale_factor": 0.00392156862745098,
21
+ "size": {
22
+ "height": 518,
23
+ "width": 518
24
+ },
25
+ "size_divisor": null
26
+ }