HanzoHuang commited on
Commit
5e59746
·
verified ·
1 Parent(s): 2975365

Add source

Browse files
source/convert-official.py ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Download the ONNX listed by Rockchip and invoke its unmodified converters."""
3
+ import argparse
4
+ import concurrent.futures
5
+ import hashlib
6
+ from importlib.metadata import version
7
+ import json
8
+ from pathlib import Path
9
+ import re
10
+ import shutil
11
+ import subprocess
12
+ import sys
13
+ import tempfile
14
+ import yaml
15
+
16
+ DETECTORS = ("yolov5", "yolov6", "yolov7", "yolov8", "yolov10", "yolo11",
17
+ "yolo26", "yolox", "ppyoloe", "yolo_world")
18
+ TASKS = ("yolov5_seg", "yolov8_seg", "yolov8_pose", "yolov8_obb")
19
+ SUPPLIED_ONNX = {
20
+ "yolo26n": "https://meta.zbox.filez.com/v/link/view/dddfdaa76107404a8a358673fa31a041",
21
+ "yolo26m": "https://meta.zbox.filez.com/v/link/view/198e90ee6bc94c71ad2002d5f9897ac4",
22
+ }
23
+
24
+
25
+ def inventory(zoo):
26
+ for family in (*DETECTORS, *TASKS):
27
+ readme = zoo / "examples" / family / "README.md"
28
+ urls = re.findall(r"\((https://[^)]+\.onnx)\)", readme.read_text())
29
+ assets = {Path(url).stem: url for url in urls}
30
+ if family in ("yolov8_pose", "yolov8_obb"):
31
+ assets = {name: url for name, url in assets.items() if "v5n-" in name or "v8n-" in name}
32
+ if family == "yolo26":
33
+ assets.update({"yolo26n": None, "yolo26m": None})
34
+ for name, url in assets.items():
35
+ yield family, name, url
36
+
37
+
38
+ def download(root, zoo, family, name, url):
39
+ destination = root / "onnx" / family / f"{name}.onnx"
40
+ destination.parent.mkdir(parents=True, exist_ok=True)
41
+ if not destination.is_file():
42
+ local = zoo / "examples" / family / "model" / destination.name
43
+ if not url and local.is_file():
44
+ shutil.copy2(local, destination)
45
+ elif url:
46
+ partial = destination.with_suffix(".part")
47
+ subprocess.run(["curl", "-fLsS", "--retry", "2", "--connect-timeout", "12",
48
+ "--max-time", "180", "-o", partial, url], check=True)
49
+ partial.replace(destination)
50
+ else:
51
+ raise FileNotFoundError(
52
+ f"Download {SUPPLIED_ONNX[name]} and save its ONNX as {destination}")
53
+ import onnx
54
+ onnx.load(str(destination), load_external_data=False)
55
+ return destination
56
+
57
+
58
+ def digest(path):
59
+ checksum = hashlib.sha256()
60
+ with path.open("rb") as stream:
61
+ for block in iter(lambda: stream.read(1024 * 1024), b""):
62
+ checksum.update(block)
63
+ return checksum.hexdigest()
64
+
65
+
66
+ def write_metadata(zoo, family, model, destination, chip):
67
+ if family == "yolo_world":
68
+ return
69
+ import onnx
70
+ inputs = onnx.load(str(model), load_external_data=False).graph.input
71
+ shape = [dim.dim_value for dim in inputs[0].type.tensor_type.shape.dim]
72
+ if len(shape) != 4 or shape[:2] != [1, 3] or min(shape[2:]) <= 0:
73
+ raise RuntimeError(f"Expected static NCHW RGB model, got {shape}")
74
+ assets = zoo / "examples" / family / "model"
75
+ labels = next(assets.glob("*labels_list.txt"))
76
+ tasks = {"yolov5_seg": "segment", "yolov8_seg": "segment",
77
+ "yolov8_pose": "pose", "yolov8_obb": "obb"}
78
+ task = tasks.get(family, "detect")
79
+ info = {
80
+ "task": task, "batch": 1, "channels": 3, "imgsz": shape[2:],
81
+ "names": [line.strip() for line in labels.read_text().splitlines() if line.strip()],
82
+ "target_platform": chip,
83
+ "coordinates": "pixels",
84
+ }
85
+ if family in ("yolov5", "yolov5_seg", "yolov7"):
86
+ values = [float(value) for value in next(assets.glob("anchors_*.txt")).read_text().split()]
87
+ info.update(head="anchored", anchors=[values[i:i + 6] for i in range(0, len(values), 6)])
88
+ if family == "yolox":
89
+ info["head"] = "yolox"
90
+ if family in ("yolov10", "yolo26"):
91
+ info["end2end"] = True
92
+ if task == "pose":
93
+ info["kpt_shape"] = [17, 3]
94
+ (destination / "metadata.yaml").write_text(yaml.safe_dump(info, sort_keys=False))
95
+
96
+
97
+ def convert(root, zoo, asset, chip, precision, refresh_metadata=False):
98
+ family, name, model, source = asset
99
+ destination = root / "rknn" / chip / family / name / precision
100
+ destination.mkdir(parents=True, exist_ok=True)
101
+ output = destination / "model.rknn"
102
+ receipt = destination / "conversion.json"
103
+ if not refresh_metadata and output.is_file() and receipt.is_file() and (
104
+ family == "yolo_world" or (destination / "metadata.yaml").is_file()):
105
+ return f"cached {family}/{name} {chip} {precision}"
106
+ work_root = root / "scratch"
107
+ work_root.mkdir(exist_ok=True)
108
+ with tempfile.TemporaryDirectory(dir=work_root, prefix=f"{name}-{chip}-{precision}-") as scratch:
109
+ # Keep the relative dataset and model paths expected by the official scripts.
110
+ tree = Path(scratch)
111
+ (tree / "datasets").symlink_to(zoo / "datasets")
112
+ example = tree / "examples" / family
113
+ example.mkdir(parents=True)
114
+ (example / "model").symlink_to(zoo / "examples" / family / "model")
115
+ working = example / "python"
116
+ shutil.copytree(zoo / "examples" / family / "python", working)
117
+ staged = destination / "model.partial.rknn"
118
+ commands = []
119
+ if family == "yolo_world":
120
+ subdir = "clip_text" if name == "clip_text" else "yolo_world"
121
+ script = f"{subdir}/convert.py"
122
+ commands.append([script, str(model), chip, precision, str(staged)])
123
+ elif family == "yolov8_pose":
124
+ if precision == "i8":
125
+ commands.append(["convert.py", str(model), chip, "i8", "1"])
126
+ commands.append(["convert.py", str(model), chip, "i8", "2", str(staged)])
127
+ else:
128
+ commands.append(["convert.py", str(model), chip, "fp", "1", str(staged)])
129
+ else:
130
+ commands.append(["convert.py", str(model), chip, precision, str(staged)])
131
+ if not output.is_file():
132
+ with (destination / "convert.log").open("w") as log:
133
+ for command in commands:
134
+ print(subprocess.list2cmdline(command), file=log, flush=True)
135
+ subprocess.run([sys.executable, *command], cwd=working,
136
+ stdout=log, stderr=subprocess.STDOUT, check=True)
137
+ if not staged.is_file() or not staged.stat().st_size:
138
+ raise RuntimeError("Converter did not produce an RKNN file")
139
+ staged.replace(output)
140
+ write_metadata(zoo, family, model, destination, chip)
141
+ receipt.write_text(json.dumps({
142
+ "source": source, "onnx_sha256": digest(model), "rknn_sha256": digest(output),
143
+ "commands": commands, "toolkit_python": sys.executable,
144
+ "toolkit_version": version("rknn-toolkit2"),
145
+ "zoo_commit": subprocess.check_output(
146
+ ["git", "-C", str(zoo), "rev-parse", "HEAD"], text=True).strip(),
147
+ }, indent=2) + "\n")
148
+ return f"ok {family}/{name} {chip} {precision}"
149
+
150
+
151
+ def main():
152
+ parser = argparse.ArgumentParser(description=__doc__)
153
+ root = Path(__file__).resolve().parent
154
+ parser.add_argument("--zoo", type=Path, default=root.parent / "rknn_model_zoo",
155
+ help="Model Zoo checkout (default: ../rknn_model_zoo)")
156
+ parser.add_argument("--jobs", type=int, default=4)
157
+ parser.add_argument("--model", action="append", help="Limit the run to named variants")
158
+ parser.add_argument("--chip", choices=("rk3576", "rk3588"), action="append")
159
+ parser.add_argument("--precision", choices=("i8", "fp"), action="append")
160
+ parser.add_argument("--refresh-metadata", action="store_true")
161
+ args = parser.parse_args()
162
+ zoo = args.zoo.resolve()
163
+ inventory_rows = [item for item in inventory(zoo) if not args.model or item[1] in args.model]
164
+ failures = 0
165
+ with concurrent.futures.ThreadPoolExecutor(max_workers=6) as downloads, \
166
+ concurrent.futures.ThreadPoolExecutor(max_workers=args.jobs) as workers:
167
+ pending = {downloads.submit(download, root, zoo, *item): item for item in inventory_rows}
168
+ builds = {}
169
+ for future in concurrent.futures.as_completed(pending):
170
+ family, name, source = pending[future]
171
+ try:
172
+ model = future.result()
173
+ asset = family, name, model, source or SUPPLIED_ONNX.get(name) or str(model)
174
+ for chip in args.chip or ("rk3576", "rk3588"):
175
+ for precision in args.precision or ("i8", "fp"):
176
+ if name == "clip_text" and precision == "i8":
177
+ continue
178
+ job = workers.submit(convert, root, zoo, asset, chip, precision,
179
+ args.refresh_metadata)
180
+ builds[job] = family, name, chip, precision
181
+ except Exception as error:
182
+ print(f"asset failed {family}/{name}: {error}", flush=True)
183
+ failures += 1
184
+ for future in concurrent.futures.as_completed(builds):
185
+ try:
186
+ print(future.result(), flush=True)
187
+ except Exception as error:
188
+ print(f"build failed {' '.join(builds[future])}: {error}", flush=True)
189
+ failures += 1
190
+ return bool(failures)
191
+
192
+
193
+ if __name__ == "__main__":
194
+ raise SystemExit(main())
source/onnx/yolo26m.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:890c8b5241232f21a683e86708d98badb4d579e1998a4f05483819d0a945120c
3
+ size 81963156
source/onnx/yolo26n.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9c6e79ecfaa699806e71acdafd06455086280428ad8424a6ec3eeada5689020a
3
+ size 9941956
source/onnx/yolo26s.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:88dbcad6f8e1e70e3c32dd3f86d37ab41ec52e5a65bc638407d44c6bee73bb6c
3
+ size 38291128