Image Classification
vision
transformer
mathmanu commited on
Commit
e89c268
·
verified ·
1 Parent(s): 17d4248

Add vit model files

Browse files
README.md ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: bsd-3-clause
3
+ tags:
4
+ - vision
5
+ - image-classification
6
+ - transformer
7
+ datasets:
8
+ - imagenet-1k
9
+ ---
10
+
11
+ <div align="center">
12
+
13
+ # ViT for TI EdgeAI
14
+
15
+ ### Pure Transformer for Image Classification at Scale
16
+
17
+ [![License](https://img.shields.io/badge/License-BSD--3--Clause-blue?style=for-the-badge)](https://opensource.org/licenses/BSD-3-Clause)
18
+ [![Framework](https://img.shields.io/badge/Framework-ONNX-orange?style=for-the-badge)](https://onnx.ai/)
19
+ [![Task](https://img.shields.io/badge/Task-Classification-green?style=for-the-badge)](https://github.com/TexasInstruments/edgeai)
20
+ [![Dataset](https://img.shields.io/badge/Dataset-ImageNet--1K-blueviolet?style=for-the-badge)](http://www.image-net.org/)
21
+
22
+ </div>
23
+
24
+ ---
25
+
26
+ ## Overview
27
+
28
+ **ViT** (Vision Transformer) applies the standard Transformer architecture directly to sequences of non-overlapping image patches — no convolutions. Introduced in [*An Image is Worth 16x16 Words*](https://arxiv.org/abs/2010.11929) (Dosovitskiy et al., ICLR 2021), ViT demonstrates that a pure transformer pre-trained on large data transfers strongly to standard image recognition benchmarks.
29
+
30
+ Pretrained weights are sourced from **torchvision** (BSD-3-Clause), trained on ImageNet-1K using a DeiT-style recipe. Each exported ONNX model is a single-input classification graph that outputs 1000-class ImageNet logits `[1, 1000]`.
31
+
32
+ ---
33
+
34
+ ## Model Variants
35
+
36
+ | Model | Architecture | Params | Top-1 Acc | Validated Devices | Config |
37
+ |-------|-------------|--------|-----------|--------------------|--------|
38
+ | `vit_b_16` | ViT-Base/16 | 86.6M | 81.1% | TDA4VH | [vit_b_16_config.yaml](vit_b_16_config.yaml) |
39
+ | `vit_b_32` | ViT-Base/32 | 88.2M | 75.9% | TDA4VH | [vit_b_32_config.yaml](vit_b_32_config.yaml) |
40
+ | `vit_l_16` | ViT-Large/16 | 304.3M | 79.7% | TDA4VH | [vit_l_16_config.yaml](vit_l_16_config.yaml) |
41
+ | `vit_l_32` | ViT-Large/32 | 306.5M | 77.0% | TDA4VH | [vit_l_32_config.yaml](vit_l_32_config.yaml) |
42
+
43
+ **Recommended for edge deployment:** `vit_b_16` (best accuracy/compute trade-off)
44
+
45
+ ---
46
+
47
+ ## Quick Start
48
+
49
+ ### Prerequisites
50
+
51
+ ```bash
52
+ pip install torch torchvision onnx>=1.22.0 onnxruntime>=1.23.2
53
+ # Optional but recommended for model optimization:
54
+ pip install onnx-simplifier
55
+ ```
56
+
57
+ ### Export the Model
58
+
59
+ ```bash
60
+ # Export the default model (vit_b_16)
61
+ python prepare_model.py
62
+
63
+ # Export a specific model variant
64
+ python prepare_model.py --model vit_b_32
65
+
66
+ # Export all supported models
67
+ python prepare_model.py --model all
68
+
69
+ # List all available variants
70
+ python prepare_model.py --list-models
71
+ ```
72
+
73
+ The script automatically:
74
+ - Downloads pretrained ImageNet-1K weights from torchvision (first run only)
75
+ - Exports the model to ONNX (opset 17) with static input shape `[1, 3, 224, 224]`
76
+ - Runs ONNX shape inference
77
+ - Optionally simplifies the graph with onnx-simplifier
78
+
79
+ ### Compile and Infer uing edgeai-tidlrunner
80
+
81
+ > **Note:** Run the commands below from inside the `tidlrunner` directory (the cloned [edgeai-tidlrunner](https://github.com/TexasInstruments/edgeai-tidlrunner) repository), with `--config_path` pointing to this model's config file.
82
+
83
+ **Compile using edgeai-tidlrunner - on PC**
84
+
85
+ ```bash
86
+ cd /path/to/edgeai-tidlrunner
87
+ tidlrunner-cli compile --target_device J784S4 \
88
+ --config_path /path/to/vit_b_16_config.yaml
89
+ ```
90
+
91
+ **Run Inference Benchmark - on device**
92
+
93
+ ```bash
94
+ cd /path/to/edgeai-tidlrunner
95
+ tidlrunner-cli infer --target_device J784S4 \
96
+ --config_path /path/to/vit_b_16_config.yaml
97
+ ```
98
+
99
+ ### Compile and Infer using edgeai-tidl-tools (Advanced):
100
+
101
+ Follow the instructions at https://github.com/TexasInstruments/edgeai-tidl-tools
102
+
103
+ ### Deploy using edgeai-tidl-tools:
104
+
105
+ Deplyment can be done using **[edgeai-tidl-tools](https://github.com/TexasInstruments/edgeai-tidl-tools)**. For ONNX models, onnxruntime-tidl with TIDL acceleration can be used. Consult the documentation of edgeai-tidl-tools for more details.
106
+
107
+ ---
108
+
109
+ ## Citation
110
+
111
+ ```bibtex
112
+ @inproceedings{dosovitskiy2021image,
113
+ title = {An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale},
114
+ author = {Dosovitskiy, Alexey and Beyer, Lucas and Kolesnikov, Alexander and
115
+ Weissenborn, Dirk and Zhai, Xiaohua and Unterthiner, Thomas and
116
+ Dehghani, Mostafa and Minderer, Matthias and Heigold, Georg and
117
+ Gelly, Sylvain and Uszkoreit, Jakob and Houlsby, Neil},
118
+ booktitle = {International Conference on Learning Representations (ICLR)},
119
+ year = {2021},
120
+ url = {https://arxiv.org/abs/2010.11929}
121
+ }
122
+ ```
123
+
124
+ ---
125
+
126
+ ## 🔗 Resources
127
+
128
+ | Resource | Link |
129
+ |----------|------|
130
+ | **Paper** | [arXiv:2010.11929](https://arxiv.org/abs/2010.11929) |
131
+ | **Source Code** | [pytorch/vision](https://github.com/pytorch/vision) |
132
+ | **Torchvision Docs** | [VisionTransformer](https://docs.pytorch.org/vision/main/models/vision_transformer.html) |
133
+ | **edgeai-tidl-tools** | [GitHub](https://github.com/TexasInstruments/edgeai-tidl-tools) |
134
+ | **edgeai-tidlrunner** | [GitHub](https://github.com/TexasInstruments/edgeai-tidlrunner) |
135
+ | **EdgeAI SDK** | [Documentation](https://github.com/TexasInstruments/edgeai/blob/main/edgeai-mpu/readme_sdk.md) |
136
+
137
+ ---
138
+
139
+ ## Related Models
140
+
141
+ <table>
142
+ <tr>
143
+ <td align="center">
144
+
145
+ **DINOv2**
146
+ Self-supervised ViT
147
+ Higher accuracy
148
+
149
+ </td>
150
+ <td align="center">
151
+
152
+ **DINO**
153
+ Self-supervised ViT
154
+ Linear classification head
155
+
156
+ </td>
157
+ <td align="center">
158
+
159
+ **ResNet**
160
+ CNN baseline
161
+ Lower compute
162
+
163
+ </td>
164
+ <td align="center">
165
+
166
+ **MobileNetV3**
167
+ Lightweight CNN
168
+ Built for edge
169
+
170
+ </td>
171
+ </tr>
172
+ </table>
173
+
174
+ ---
175
+
176
+ <div align="center">
177
+
178
+ **Maintained by:** Texas Instruments EdgeAI Team
179
+ **Last Updated:** August 2026
180
+
181
+ </div>
prepare_model.py ADDED
@@ -0,0 +1,525 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Export ViT (Vision Transformer) classification models from torchvision to ONNX
4
+ for TI EdgeAI hardware deployment.
5
+
6
+ Model variants (BSD-3-Clause, ImageNet-1K pretrained):
7
+ vit_b_16 – 224×224, 86.57M params, 17.56G FLOPs, top-1 81.072% [default, recommended]
8
+ vit_b_32 – 224×224, 88.22M params, 4.41G FLOPs, top-1 75.912%
9
+ vit_l_16 – 224×224, 304.33M params, 61.55G FLOPs, top-1 79.662%
10
+ vit_l_32 – 224×224, 306.54M params, 15.38G FLOPs, top-1 76.972%
11
+
12
+ Note: vit_h_14 (633M+ params, >1000 GFLOPS) is excluded as impractical for edge.
13
+
14
+ Reference paper: An Image is Worth 16x16 Words (Dosovitskiy et al., 2020)
15
+ https://arxiv.org/abs/2010.11929
16
+
17
+ Usage:
18
+ python prepare_model.py
19
+ python prepare_model.py --model vit_b_16
20
+ python prepare_model.py --model vit_b_16 vit_b_32
21
+ python prepare_model.py --model vit_b_16 --shape 224 224
22
+ python prepare_model.py --model all
23
+ python prepare_model.py --model vit_b_16 --weights /path/to/custom.pth
24
+ python prepare_model.py --list-models
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import argparse
30
+ import importlib
31
+ import os
32
+ import shutil
33
+ import subprocess
34
+ import sys
35
+ import tempfile
36
+
37
+
38
+ # ─────────────────────────────────────────────
39
+ # Model catalogue
40
+ # ─────────────────────────────────────────────
41
+
42
+ MODEL_CATALOG: dict[str, dict] = {
43
+ "vit_b_16": {
44
+ "tv_weights_cls": "ViT_B_16_Weights",
45
+ "backbone": "ViT-Base/16",
46
+ "shape": (224, 224),
47
+ "params_m": 86.57,
48
+ "flops_g": 17.56,
49
+ "top1_acc": 81.072,
50
+ "top5_acc": 95.318,
51
+ "license": "BSD-3-Clause",
52
+ },
53
+ "vit_b_32": {
54
+ "tv_weights_cls": "ViT_B_32_Weights",
55
+ "backbone": "ViT-Base/32",
56
+ "shape": (224, 224),
57
+ "params_m": 88.22,
58
+ "flops_g": 4.41,
59
+ "top1_acc": 75.912,
60
+ "top5_acc": 92.466,
61
+ "license": "BSD-3-Clause",
62
+ },
63
+ "vit_l_16": {
64
+ "tv_weights_cls": "ViT_L_16_Weights",
65
+ "backbone": "ViT-Large/16",
66
+ "shape": (224, 224),
67
+ "params_m": 304.33,
68
+ "flops_g": 61.55,
69
+ "top1_acc": 79.662,
70
+ "top5_acc": 94.638,
71
+ "license": "BSD-3-Clause",
72
+ },
73
+ "vit_l_32": {
74
+ "tv_weights_cls": "ViT_L_32_Weights",
75
+ "backbone": "ViT-Large/32",
76
+ "shape": (224, 224),
77
+ "params_m": 306.54,
78
+ "flops_g": 15.38,
79
+ "top1_acc": 76.972,
80
+ "top5_acc": 93.070,
81
+ "license": "BSD-3-Clause",
82
+ },
83
+ }
84
+
85
+ DEFAULT_MODEL = "vit_b_16"
86
+
87
+
88
+ # ─────────────────────────────────────────────
89
+ # Dependency installer
90
+ # ─────────────────────────────────────────────
91
+
92
+ def _pip_install(*packages: str) -> None:
93
+ """Install *packages* via pip, suppressing verbose output."""
94
+ print(f"[DEP] Installing: {', '.join(packages)} …")
95
+ result = subprocess.run(
96
+ [sys.executable, "-m", "pip", "install", *packages],
97
+ stdout=subprocess.DEVNULL,
98
+ stderr=subprocess.PIPE,
99
+ text=True,
100
+ )
101
+ if result.returncode != 0:
102
+ print(f"[DEP] ERROR: pip install failed (exit code {result.returncode}).")
103
+ if result.stderr:
104
+ print(result.stderr.strip())
105
+ print("[DEP] Please install manually and re-run:")
106
+ print(f" pip install {' '.join(packages)}")
107
+ sys.exit(1)
108
+ print("[DEP] Installation complete.\n")
109
+
110
+
111
+ def ensure_dependencies() -> None:
112
+ """Ensure all runtime dependencies are available."""
113
+ needed: list[str] = []
114
+ checks = {
115
+ "torch": "torch",
116
+ "torchvision": "torchvision",
117
+ "onnx": "onnx",
118
+ "onnxsim": "onnx-simplifier",
119
+ }
120
+ for mod, pkg in checks.items():
121
+ try:
122
+ importlib.import_module(mod)
123
+ print(f"[DEP] ✔ {mod} is already installed.")
124
+ except ImportError:
125
+ print(f"[DEP] ✘ {mod} not found – will install '{pkg}'.")
126
+ needed.append(pkg)
127
+ if needed:
128
+ _pip_install(*needed)
129
+ else:
130
+ print("[DEP] All dependencies satisfied.\n")
131
+
132
+
133
+ # ─────────────────────────────────────────────
134
+ # ONNX post-processing helpers
135
+ # ─────────────────────────────────────────────
136
+
137
+ def _run_shape_inference(onnx_path: str) -> None:
138
+ """Run ONNX shape inference in-place."""
139
+ try:
140
+ import onnx
141
+ import onnx.shape_inference
142
+ print("[POST] Running ONNX shape inference …")
143
+ model = onnx.load(onnx_path)
144
+ model = onnx.shape_inference.infer_shapes(model)
145
+ onnx.save(model, onnx_path)
146
+ print("[POST] Shape inference complete.\n")
147
+ except Exception as exc:
148
+ print(f"[POST] WARNING: shape inference failed ({exc}) – model unchanged.\n")
149
+
150
+
151
+ def _maybe_simplify(onnx_path: str) -> None:
152
+ """Simplify the ONNX model in-place using onnxsim."""
153
+ try:
154
+ import onnx
155
+ import onnxsim
156
+ except ImportError:
157
+ print("[POST] onnxsim not installed – skipping simplification.\n")
158
+ print("[POST] Install with: pip install onnx-simplifier\n")
159
+ return
160
+
161
+ print("[POST] Simplifying ONNX model with onnxsim …")
162
+ try:
163
+ model = onnx.load(onnx_path)
164
+ model_simp, ok = onnxsim.simplify(model)
165
+ if ok:
166
+ onnx.save(model_simp, onnx_path)
167
+ print("[POST] Simplification complete.\n")
168
+ else:
169
+ print("[POST] WARNING: onnxsim validation failed – using original.\n")
170
+ except Exception as exc:
171
+ print(f"[POST] WARNING: onnxsim failed ({exc}) – using original.\n")
172
+
173
+
174
+ # ─────────────────────────────────────────────
175
+ # Model catalogue helpers
176
+ # ─────────────────────────────────────────────
177
+
178
+ def print_model_table() -> None:
179
+ """Print a formatted table of all available models."""
180
+ col = 10
181
+ header = (
182
+ f" {'Variant':<12} {'Backbone':<16} {'Shape':<10} "
183
+ f"{'Params(M)':<10} {'FLOPs(G)':<9} {'Top-1 %':<9} Top-5 %"
184
+ )
185
+ sep = " " + "-" * (len(header) - 2)
186
+ print("\n" + "=" * len(header))
187
+ print(" Available ViT (Vision Transformer) model variants")
188
+ print("=" * len(header))
189
+ print(header)
190
+ print(sep)
191
+
192
+ for key, info in MODEL_CATALOG.items():
193
+ h, w = info["shape"]
194
+ print(
195
+ f" {key:<12} {info['backbone']:<16} {h}×{w:<5} "
196
+ f"{info['params_m']:<10.2f} {info['flops_g']:<9.2f} "
197
+ f"{info['top1_acc']:<9.3f} {info['top5_acc']:.3f}"
198
+ )
199
+ print("=" * len(header) + "\n")
200
+ print(" Accuracy evaluated on ImageNet-1K val (torchvision pretrained weights).")
201
+ print(" License: BSD-3-Clause (torchvision / PyTorch).\n")
202
+
203
+
204
+ # ─────────────────────────────────────────────
205
+ # Core export
206
+ # ─────────────────────────────────────────────
207
+
208
+ def export_model(
209
+ model_key: str,
210
+ output_dir: str,
211
+ shape: tuple[int, int] | None,
212
+ opset: int,
213
+ batch_size: int,
214
+ verbose: bool,
215
+ custom_weights: str | None,
216
+ force: bool,
217
+ simplify: bool = True,
218
+ ) -> str:
219
+ """
220
+ Load a ViT model from torchvision and export to ONNX.
221
+
222
+ The exported graph has a single image input (NCHW) and one output:
223
+ output [batch_size, 1000] – raw class logits (ImageNet-1K)
224
+
225
+ Shape inference and optional onnxsim simplification are applied.
226
+
227
+ Args:
228
+ model_key : Key from MODEL_CATALOG (e.g. "vit_b_16").
229
+ output_dir : Directory where the .onnx file will be saved.
230
+ shape : Custom (H, W) override, or None for model default.
231
+ opset : ONNX opset version (default 17).
232
+ batch_size : Batch size in the exported graph (default 1).
233
+ verbose : Print detailed loading messages.
234
+ custom_weights: Path to a local .pth checkpoint; None = torchvision pretrained.
235
+ force : Re-export even if the destination .onnx already exists.
236
+ simplify : Apply onnxsim after export (default: True).
237
+
238
+ Returns:
239
+ Absolute path of the saved .onnx file.
240
+ """
241
+ import torch
242
+ import torchvision.models as tvm
243
+
244
+ info = MODEL_CATALOG[model_key]
245
+ export_h, export_w = shape if shape is not None else info["shape"]
246
+
247
+ # ── Destination path ──────────────────────────────────────────────────────
248
+ os.makedirs(output_dir, exist_ok=True)
249
+ shape_tag = f"_{export_h}x{export_w}" if shape is not None else ""
250
+ dst_name = f"{model_key}{shape_tag}.onnx"
251
+ dst_path = os.path.join(output_dir, dst_name)
252
+
253
+ if not force and os.path.exists(dst_path):
254
+ print(f"[SKIP] {dst_name} already exists. Use --force to re-export.\n")
255
+ return dst_path
256
+
257
+ print(f"[INFO] Model variant : {model_key}")
258
+ print(f"[INFO] Backbone : {info['backbone']}")
259
+ print(f"[INFO] TV weights cls : {info['tv_weights_cls']}")
260
+ print(f"[INFO] Input shape : {export_h}×{export_w}")
261
+ print(f"[INFO] Batch size : {batch_size}")
262
+ print(f"[INFO] ONNX opset : {opset}")
263
+ print()
264
+
265
+ # ── Load model ───────────────────────────────────────────────────────────
266
+ model_fn = getattr(tvm, model_key)
267
+
268
+ if custom_weights:
269
+ print(f"[INFO] Loading architecture from torchvision, weights from: {custom_weights}")
270
+ model = model_fn(weights=None)
271
+ checkpoint = torch.load(custom_weights, map_location="cpu", weights_only=True)
272
+ state = checkpoint.get("model", checkpoint)
273
+ if isinstance(state, dict) and "module" in state:
274
+ state = state["module"]
275
+ model.load_state_dict(state)
276
+ else:
277
+ print(f"[INFO] Loading pretrained weights from torchvision …")
278
+ print(f"[INFO] (First run may download weights ~300 MB – 1.2 GB)")
279
+ weights_cls = getattr(tvm, info["tv_weights_cls"])
280
+ model = model_fn(weights=weights_cls.IMAGENET1K_V1)
281
+
282
+ model.eval()
283
+ print(f"[INFO] Model loaded.\n")
284
+
285
+ # ── Dry-run to confirm output shape ──────────────────────────────────────
286
+ dummy = torch.zeros(batch_size, 3, export_h, export_w)
287
+ with torch.no_grad():
288
+ out = model(dummy)
289
+ print(f"[INFO] Output shape : {list(out.shape)}")
290
+ print()
291
+
292
+ # ── Export to ONNX ────────────────────────────────────────────────────────
293
+ print(f"[INFO] Exporting to ONNX (opset {opset}) …")
294
+ with tempfile.TemporaryDirectory(prefix="vit_export_") as tmp_dir:
295
+ tmp_path = os.path.join(tmp_dir, dst_name)
296
+
297
+ torch.onnx.export(
298
+ model,
299
+ dummy,
300
+ tmp_path,
301
+ input_names=["input"],
302
+ output_names=["output"],
303
+ opset_version=opset,
304
+ do_constant_folding=True,
305
+ verbose=False,
306
+ )
307
+
308
+ shutil.move(tmp_path, dst_path)
309
+
310
+ print(f"[INFO] Raw ONNX written to: {dst_path}")
311
+
312
+ # ── Post-processing ───────────────────────────────────────────────────────
313
+ _run_shape_inference(dst_path)
314
+ if simplify:
315
+ _maybe_simplify(dst_path)
316
+
317
+ size_mb = os.path.getsize(dst_path) / (1024 * 1024)
318
+ print(f"\n[SUCCESS] ONNX model saved to: {dst_path} ({size_mb:.1f} MB)\n")
319
+ return dst_path
320
+
321
+
322
+ # ─────────────────────────────────────────────
323
+ # CLI
324
+ # ─────────────────────────────────────────────
325
+
326
+ def build_parser() -> argparse.ArgumentParser:
327
+ default_output = os.path.dirname(os.path.abspath(__file__))
328
+
329
+ parser = argparse.ArgumentParser(
330
+ description=(
331
+ "Export ViT (Vision Transformer) pretrained ONNX models.\n\n"
332
+ "Pretrained ImageNet-1K weights are downloaded automatically from\n"
333
+ "torchvision on first use. Run --list-models to see all variants."
334
+ ),
335
+ formatter_class=argparse.RawDescriptionHelpFormatter,
336
+ epilog=(
337
+ "Examples:\n"
338
+ " %(prog)s\n"
339
+ " %(prog)s --model vit_b_16\n"
340
+ " %(prog)s --model vit_b_16 vit_b_32\n"
341
+ " %(prog)s --model vit_b_16 --shape 224 224\n"
342
+ " %(prog)s --model all\n"
343
+ " %(prog)s --model vit_b_16 --weights /path/to/custom.pth\n"
344
+ " %(prog)s --list-models"
345
+ ),
346
+ )
347
+
348
+ # ── Model selection ───────────────────────────────────────────────────────
349
+ parser.add_argument(
350
+ "--model",
351
+ nargs="+",
352
+ default=[DEFAULT_MODEL],
353
+ choices=list(MODEL_CATALOG.keys()) + ["all"],
354
+ metavar="VARIANT",
355
+ help=(
356
+ f"Model variant(s) to export. Use 'all' for all variants. "
357
+ f"Default: {DEFAULT_MODEL}. Run --list-models to see all options."
358
+ ),
359
+ )
360
+
361
+ # ── Export parameters ─────────────────────────────────────────────────────
362
+ parser.add_argument(
363
+ "--shape",
364
+ nargs=2,
365
+ type=int,
366
+ default=None,
367
+ metavar=("H", "W"),
368
+ help=(
369
+ "Custom input resolution (height width). "
370
+ "Default: each model's native resolution (224×224)."
371
+ ),
372
+ )
373
+ parser.add_argument(
374
+ "--opset",
375
+ type=int,
376
+ default=17,
377
+ metavar="N",
378
+ help="ONNX opset version. Default: 17.",
379
+ )
380
+ parser.add_argument(
381
+ "--batch-size",
382
+ type=int,
383
+ default=1,
384
+ metavar="N",
385
+ help="Batch size embedded in the exported ONNX graph. Default: 1.",
386
+ )
387
+
388
+ # ── Weight source ─────────────────────────────────────────────────────────
389
+ parser.add_argument(
390
+ "--weights",
391
+ default=None,
392
+ metavar="PATH",
393
+ help=(
394
+ "Path to a local .pth checkpoint (optional). "
395
+ "When omitted the official ImageNet-1K pretrained weights are "
396
+ "downloaded automatically from torchvision."
397
+ ),
398
+ )
399
+
400
+ # ── Output ────────────────────────────────────────────────────────────────
401
+ parser.add_argument(
402
+ "--output-dir",
403
+ default=default_output,
404
+ metavar="DIR",
405
+ help=f"Directory where .onnx files will be saved. Default: {default_output}",
406
+ )
407
+ parser.add_argument(
408
+ "--force",
409
+ action="store_true",
410
+ default=False,
411
+ help="Re-export even if the destination .onnx file already exists.",
412
+ )
413
+
414
+ # ── Simplification ────────────────────────────────────────────────────────
415
+ parser.add_argument(
416
+ "--simplify",
417
+ action="store_true",
418
+ default=True,
419
+ help=(
420
+ "Apply onnx-simplifier after export (default: enabled). "
421
+ "Requires: pip install onnx-simplifier. Use --no-simplify to disable."
422
+ ),
423
+ )
424
+ parser.add_argument(
425
+ "--no-simplify",
426
+ dest="simplify",
427
+ action="store_false",
428
+ help="Disable onnx-simplifier after export.",
429
+ )
430
+
431
+ # ── Verbosity ─────────────────────────────────────────────────────────────
432
+ parser.add_argument(
433
+ "--quiet",
434
+ action="store_true",
435
+ default=False,
436
+ help="Suppress verbose output during model loading.",
437
+ )
438
+
439
+ # ── Utility ───────────────────────────────────────────────────────────────
440
+ parser.add_argument(
441
+ "--list-models",
442
+ action="store_true",
443
+ default=False,
444
+ help="Print the model catalogue table and exit.",
445
+ )
446
+
447
+ return parser
448
+
449
+
450
+ # ─────────────────────────────────────────────
451
+ # Entry point
452
+ # ─────────────────────────────────────────────
453
+
454
+ def main() -> None:
455
+ parser = build_parser()
456
+ args = parser.parse_args()
457
+
458
+ if args.list_models:
459
+ print_model_table()
460
+ return
461
+
462
+ # ── Expand "all" keyword ──────────────────────────────────────────────────
463
+ if "all" in args.model:
464
+ args.model = list(MODEL_CATALOG.keys())
465
+
466
+ # ── Warn when --weights is used with multiple models ──────────────────────
467
+ if args.weights and len(args.model) > 1:
468
+ print(
469
+ "[WARN] --weights applies the same checkpoint to every model in "
470
+ "--model.\n This is unusual; pass a single --model variant "
471
+ "when using custom weights.\n"
472
+ )
473
+
474
+ # ── Install dependencies ──────────────────────────────────────────────────
475
+ ensure_dependencies()
476
+
477
+ # ── Export each model ─────────────────────────────────────────────────────
478
+ shape = (args.shape[0], args.shape[1]) if args.shape else None
479
+ output_dir = os.path.abspath(args.output_dir)
480
+
481
+ exported: list[str] = []
482
+ failed: list[str] = []
483
+
484
+ for model_key in args.model:
485
+ print(f"\n{'='*60}")
486
+ print(f" Exporting: {model_key}")
487
+ print(f"{'='*60}\n")
488
+
489
+ try:
490
+ out_path = export_model(
491
+ model_key = model_key,
492
+ output_dir = output_dir,
493
+ shape = shape,
494
+ opset = args.opset,
495
+ batch_size = args.batch_size,
496
+ verbose = not args.quiet,
497
+ custom_weights = args.weights,
498
+ force = args.force,
499
+ simplify = args.simplify,
500
+ )
501
+ exported.append(out_path)
502
+ except SystemExit:
503
+ raise
504
+ except Exception as exc:
505
+ print(f"[ERROR] Export failed for '{model_key}': {exc}")
506
+ failed.append(model_key)
507
+
508
+ # ── Summary ───────────────────────────────────────────────────────────────
509
+ print("\n" + "=" * 60)
510
+ print(" Export Summary")
511
+ print("=" * 60)
512
+ for path in exported:
513
+ size_mb = os.path.getsize(path) / (1024 * 1024)
514
+ print(f" ✔ {os.path.basename(path)} ({size_mb:.1f} MB)")
515
+ print(f" {path}")
516
+ if failed:
517
+ for key in failed:
518
+ print(f" ✘ {key}")
519
+ print(f"\n {len(exported)}/{len(args.model)} model(s) exported successfully.")
520
+ if failed:
521
+ sys.exit(1)
522
+
523
+
524
+ if __name__ == "__main__":
525
+ main()
vit_b_16_config.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task_type: classification
2
+ #dataset_category: imagenet
3
+ #calibration_dataset: imagenet
4
+ #input_dataset: imagenet
5
+ dataloader:
6
+ name: image_classification_dataloader
7
+ path: ./data/datasets/imagenetv2c/val
8
+ postprocess: {}
9
+ preprocess:
10
+ resize: 256
11
+ crop: 224
12
+ data_layout: NCHW
13
+ reverse_channels: false
14
+ backend: pil
15
+ interpolation: null
16
+ resize_with_pad: false
17
+ pad_color: 0
18
+ session:
19
+ session_name: onnxrt
20
+ target_device: null
21
+ input_optimization: false
22
+ input_data_layout: NCHW
23
+ input_mean: [123.675, 116.28, 103.53]
24
+ input_scale: [0.017125, 0.017507, 0.017429]
25
+ model_path: vit_b_16.onnx
26
+ model_id: cl-mh6030
27
+ input_details: null
28
+ output_details: null
29
+ num_inputs: 1
30
+ model_info:
31
+ metric_reference:
32
+ accuracy_top1%: 81.072
33
+ model_shortlist: 10
34
+ compact_name: vit-b-16-224x224
35
+ shortlisted: true
36
+ recommended: true
vit_b_32_config.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task_type: classification
2
+ #dataset_category: imagenet
3
+ #calibration_dataset: imagenet
4
+ #input_dataset: imagenet
5
+ dataloader:
6
+ name: image_classification_dataloader
7
+ path: ./data/datasets/imagenetv2c/val
8
+ postprocess: {}
9
+ preprocess:
10
+ resize: 256
11
+ crop: 224
12
+ data_layout: NCHW
13
+ reverse_channels: false
14
+ backend: pil
15
+ interpolation: null
16
+ resize_with_pad: false
17
+ pad_color: 0
18
+ session:
19
+ session_name: onnxrt
20
+ target_device: null
21
+ input_optimization: false
22
+ input_data_layout: NCHW
23
+ input_mean: [123.675, 116.28, 103.53]
24
+ input_scale: [0.017125, 0.017507, 0.017429]
25
+ model_path: vit_b_32.onnx
26
+ model_id: cl-mh6031
27
+ input_details: null
28
+ output_details: null
29
+ num_inputs: 1
30
+ model_info:
31
+ metric_reference:
32
+ accuracy_top1%: 75.912
33
+ model_shortlist: 10
34
+ compact_name: vit-b-32-224x224
35
+ shortlisted: true
36
+ recommended: false
vit_l_16_config.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task_type: classification
2
+ #dataset_category: imagenet
3
+ #calibration_dataset: imagenet
4
+ #input_dataset: imagenet
5
+ dataloader:
6
+ name: image_classification_dataloader
7
+ path: ./data/datasets/imagenetv2c/val
8
+ postprocess: {}
9
+ preprocess:
10
+ resize: 242
11
+ crop: 224
12
+ data_layout: NCHW
13
+ reverse_channels: false
14
+ backend: pil
15
+ interpolation: null
16
+ resize_with_pad: false
17
+ pad_color: 0
18
+ session:
19
+ session_name: onnxrt
20
+ target_device: null
21
+ input_optimization: false
22
+ input_data_layout: NCHW
23
+ input_mean: [123.675, 116.28, 103.53]
24
+ input_scale: [0.017125, 0.017507, 0.017429]
25
+ model_path: vit_l_16.onnx
26
+ model_id: cl-mh6032
27
+ input_details: null
28
+ output_details: null
29
+ num_inputs: 1
30
+ model_info:
31
+ metric_reference:
32
+ accuracy_top1%: 79.662
33
+ model_shortlist: 10
34
+ compact_name: vit-l-16-224x224
35
+ shortlisted: true
36
+ recommended: false
vit_l_32_config.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task_type: classification
2
+ #dataset_category: imagenet
3
+ #calibration_dataset: imagenet
4
+ #input_dataset: imagenet
5
+ dataloader:
6
+ name: image_classification_dataloader
7
+ path: ./data/datasets/imagenetv2c/val
8
+ postprocess: {}
9
+ preprocess:
10
+ resize: 256
11
+ crop: 224
12
+ data_layout: NCHW
13
+ reverse_channels: false
14
+ backend: pil
15
+ interpolation: null
16
+ resize_with_pad: false
17
+ pad_color: 0
18
+ session:
19
+ session_name: onnxrt
20
+ target_device: null
21
+ input_optimization: false
22
+ input_data_layout: NCHW
23
+ input_mean: [123.675, 116.28, 103.53]
24
+ input_scale: [0.017125, 0.017507, 0.017429]
25
+ model_path: vit_l_32.onnx
26
+ model_id: cl-mh6033
27
+ input_details: null
28
+ output_details: null
29
+ num_inputs: 1
30
+ model_info:
31
+ metric_reference:
32
+ accuracy_top1%: 76.972
33
+ model_shortlist: 10
34
+ compact_name: vit-l-32-224x224
35
+ shortlisted: true
36
+ recommended: false