Image Classification
vision
mathmanu commited on
Commit
4dbaa85
·
verified ·
1 Parent(s): c5d78bd

Add resnet model files

Browse files
README.md ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - vision
5
+ - image-classification
6
+ datasets:
7
+ - imagenet-1k
8
+ ---
9
+
10
+ <div align="center">
11
+
12
+ # ResNet for TI EdgeAI
13
+
14
+ ### Deep Residual Network for Image Classification
15
+
16
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue?style=for-the-badge)](https://opensource.org/licenses/Apache-2.0)
17
+ [![Framework](https://img.shields.io/badge/Framework-ONNX-orange?style=for-the-badge)](https://onnx.ai/)
18
+ [![Task](https://img.shields.io/badge/Task-Classification-green?style=for-the-badge)](https://github.com/TexasInstruments/edgeai)
19
+ [![Dataset](https://img.shields.io/badge/Dataset-ImageNet--1K-blueviolet?style=for-the-badge)](http://www.image-net.org/)
20
+
21
+ </div>
22
+
23
+ ---
24
+
25
+ ## Overview
26
+
27
+ **ResNet-50** is a 50-layer deep convolutional neural network optimized for **Texas Instruments MPU devices**. This folder provides two production-ready ONNX variants that deliver industry-leading accuracy on ImageNet classification while maintaining efficient computation suitable for edge deployment.
28
+
29
+ This folder contains two distinct architectural generations of ResNet-50:
30
+
31
+ - **resNet50** — ResNet-50 **v1.5**, the modern de-facto standard. Used by PyTorch (`torchvision`), TensorFlow, and most current frameworks. The stride-2 downsampling in each bottleneck block is applied in the **3×3 convolution** rather than the 1×1, which improves accuracy with no added parameters. This is the version most practitioners encounter today.
32
+
33
+ - **resnet50-v1** — ResNet-50 **v1**, the original architecture from He et al. (2016) as published in the ONNX Model Zoo (opset 7). Stride-2 is applied in the **1×1 convolution**. Useful when strict reproducibility with the original paper or ONNX Model Zoo benchmarks is required.
34
+
35
+ The two variants differ only in where the stride-2 downsampling is placed inside each bottleneck block: moving the stride to the 3×3 conv (v1.5) preserves more spatial information before downsampling, which accounts for the ~1.2% accuracy gain over v1 at zero extra cost in parameters or FLOPs.
36
+
37
+ > **Which should I use?** For new projects, prefer **resNet50 (v1.5)** — it is more accurate and is the implementation underlying most pre-trained weights available today. Use **resnet50-v1** when you need exact compatibility with the original ONNX Model Zoo model or are comparing against v1 benchmarks.
38
+
39
+ ---
40
+
41
+ ## Model Variants
42
+
43
+ | Model | Architecture | Params | Top-1 Accuracy | Validated Devices | Config |
44
+ |-------|--------------|--------|-----------------|--------------------|--------|
45
+ | `resNet50` | ResNet-50 v1.5 (stride-2 in 3×3 conv) | ~25.6M | 76.15% | TDA4VH, TDA4VL, TDA4AEN | [resnet50_config.yaml](resnet50_config.yaml) |
46
+ | `resnet50-v1` | ResNet-50 v1, original (stride-2 in 1×1 conv) | ~25.6M | 74.93% | TDA4VH, TDA4VL, TDA4AEN | [resnet50-v1_config.yaml](resnet50-v1_config.yaml) |
47
+
48
+ **Recommended for edge deployment:** `resNet50` (v1.5) — highest accuracy with the same compute cost (4.1 GigaMACs) as the original v1.
49
+
50
+ ---
51
+
52
+ ## Quick Start
53
+
54
+ ### Prerequisites
55
+
56
+ ```bash
57
+ pip install onnx>=1.22.0 onnxruntime>=1.23.2
58
+ ```
59
+
60
+ ### Export the Model
61
+
62
+ ```bash
63
+ # Download and prepare the default model (resNet50, v1.5)
64
+ python prepare_model.py
65
+
66
+ # Download and prepare a specific variant via its .link file
67
+ python prepare_model.py --link-file resnet50-v1.onnx.link
68
+
69
+ # Skip download and only fix shapes on an already-downloaded model
70
+ python prepare_model.py --link-file resnet50.onnx.link --skip-download
71
+
72
+ # Use a custom input resolution
73
+ python prepare_model.py --link-file resnet50.onnx.link --height 256 --width 256
74
+ ```
75
+
76
+ The script automatically:
77
+ - Parses the `.link` file to get the download URL and output filename
78
+ - Downloads the ONNX model from HuggingFace (unless `--skip-download` is set)
79
+ - Fixes dynamic input shapes to a static shape (default `[1, 3, 224, 224]`)
80
+ - Runs ONNX shape inference and optional `onnx-simplifier` optimization
81
+ - Validates the resulting model and confirms all shapes are fixed
82
+
83
+ ### Compile and Infer uing edgeai-tidlrunner
84
+
85
+ > **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.
86
+
87
+ **Compile using edgeai-tidlrunner - on PC**
88
+
89
+ ```bash
90
+ cd /path/to/edgeai-tidlrunner
91
+ tidlrunner-cli compile --target_device J784S4 \
92
+ --config_path /path/to/resnet50_config.yaml
93
+ ```
94
+
95
+ **Run Inference Benchmark - on device**
96
+
97
+ ```bash
98
+ cd /path/to/edgeai-tidlrunner
99
+ tidlrunner-cli infer --target_device J784S4 \
100
+ --config_path /path/to/resnet50_config.yaml
101
+ ```
102
+
103
+ ### Compile and Infer using edgeai-tidl-tools (Advanced):
104
+
105
+ Follow the instructions at https://github.com/TexasInstruments/edgeai-tidl-tools
106
+
107
+ ### Deploy using edgeai-tidl-tools:
108
+
109
+ 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.
110
+
111
+ ---
112
+
113
+ ## Citation
114
+
115
+ If you use this model, please cite:
116
+
117
+ ```bibtex
118
+ @inproceedings{he2016deep,
119
+ title={Deep residual learning for image recognition},
120
+ author={He, Kaiming and Zhang, Xiangyu and Ren, Shaoqing and Sun, Jian},
121
+ booktitle={Proceedings of the IEEE conference on computer vision
122
+ and pattern recognition},
123
+ pages={770--778},
124
+ year={2016}
125
+ }
126
+ ```
127
+
128
+ ---
129
+
130
+ ## 🔗 Resources
131
+
132
+ | Resource | Link |
133
+ |----------|------|
134
+ | **Paper** | [arXiv:1512.03385](https://arxiv.org/abs/1512.03385) |
135
+ | **Source (resNet50)** | [onnx-community/resnet-50-ONNX](https://huggingface.co/onnx-community/resnet-50-ONNX) |
136
+ | **Source (resnet50-v1)** | [onnxmodelzoo/resnet50-v1-7](https://huggingface.co/onnxmodelzoo/resnet50-v1-7) |
137
+ | **edgeai-tidl-tools** | [GitHub](https://github.com/TexasInstruments/edgeai-tidl-tools) |
138
+ | **edgeai-tidlrunner** | [GitHub](https://github.com/TexasInstruments/edgeai-tidlrunner) |
139
+ | **EdgeAI SDK** | [Documentation](https://github.com/TexasInstruments/edgeai/blob/main/edgeai-mpu/readme_sdk.md) |
140
+
141
+ ---
142
+
143
+ ## Related Models
144
+
145
+ <table>
146
+ <tr>
147
+ <td align="center">
148
+
149
+ **MobileNetV3**
150
+ Mobile-optimized CNN
151
+ Lighter alternative
152
+
153
+ </td>
154
+ <td align="center">
155
+
156
+ **ConvNeXt**
157
+ Modern CNN successor
158
+ Higher accuracy
159
+
160
+ </td>
161
+ <td align="center">
162
+
163
+ **DINO (ResNet-50)**
164
+ Self-supervised ResNet
165
+ No-label pre-training
166
+
167
+ </td>
168
+ <td align="center">
169
+
170
+ **ViT**
171
+ Vision Transformer
172
+ Attention-based backbone
173
+
174
+ </td>
175
+ </tr>
176
+ </table>
177
+
178
+ ---
179
+
180
+ <div align="center">
181
+
182
+ **Maintained by:** Texas Instruments EdgeAI Team
183
+ **Last Updated:** August 2026
184
+
185
+ </div>
prepare_model.py ADDED
@@ -0,0 +1,425 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Unified script to download ONNX models and fix their shapes for hardware deployment.
4
+
5
+ Reads .link files containing download URLs and automatically:
6
+ 1. Downloads the model if not present
7
+ 2. Fixes dynamic shapes to static shapes
8
+ 3. Validates the result
9
+
10
+ Link file format:
11
+ <download_url> -o <output_filename>
12
+
13
+ Example:
14
+ https://huggingface.co/.../model.onnx -o resnet50.onnx
15
+ """
16
+
17
+ import sys
18
+ import subprocess
19
+ from pathlib import Path
20
+
21
+
22
+ def _ensure_dependencies():
23
+ required = {"onnx": "onnx", "onnxsim": "onnx-simplifier"}
24
+ for module, package in required.items():
25
+ try:
26
+ __import__(module)
27
+ except ImportError:
28
+ print(f"Installing missing dependency: {package}")
29
+ subprocess.check_call([sys.executable, "-m", "pip", "install", package])
30
+
31
+
32
+ _ensure_dependencies()
33
+
34
+ import onnx
35
+ from onnx import shape_inference
36
+ import argparse
37
+
38
+
39
+ def parse_link_file(link_file_path):
40
+ """
41
+ Parse .link file to extract download URL and output filename.
42
+
43
+ Expected format: <URL> -o <filename>
44
+
45
+ Returns:
46
+ tuple: (download_url, output_filename) or (None, None) if parsing fails
47
+ """
48
+ try:
49
+ with open(link_file_path, 'r') as f:
50
+ content = f.read().strip()
51
+
52
+ # Find the line with the URL and -o flag
53
+ for line in content.split('\n'):
54
+ line = line.strip()
55
+ if not line or line.startswith('#'):
56
+ continue
57
+
58
+ # Look for pattern: URL -o filename
59
+ if '-o' in line:
60
+ parts = line.split('-o')
61
+ if len(parts) == 2:
62
+ url = parts[0].strip()
63
+ filename = parts[1].strip()
64
+
65
+ # Convert HuggingFace blob URLs to resolve URLs for direct download
66
+ if 'huggingface.co' in url and '/blob/' in url:
67
+ url = url.replace('/blob/', '/resolve/')
68
+
69
+ return url, filename
70
+
71
+ print(f"Error: Could not parse link file format. Expected: <URL> -o <filename>")
72
+ return None, None
73
+
74
+ except Exception as e:
75
+ print(f"Error reading link file: {e}")
76
+ return None, None
77
+
78
+
79
+ def download_model(url, output_path, force=False):
80
+ """
81
+ Download model from URL using curl.
82
+
83
+ Args:
84
+ url: Download URL
85
+ output_path: Path to save downloaded model
86
+ force: Force re-download even if file exists
87
+
88
+ Returns:
89
+ bool: True if successful, False otherwise
90
+ """
91
+ if output_path.exists() and not force:
92
+ print(f"Model already exists: {output_path}")
93
+ file_size = output_path.stat().st_size
94
+ print(f"File size: {file_size:,} bytes ({file_size / 1024 / 1024:.2f} MB)")
95
+ return True
96
+
97
+ print(f"\n📥 Downloading Model:")
98
+ print("-" * 80)
99
+ print(f"URL: {url}")
100
+ print(f"Output: {output_path}")
101
+ print()
102
+
103
+ try:
104
+ # Use curl to download with progress bar
105
+ result = subprocess.run(
106
+ ['curl', '-L', url, '-o', str(output_path), '--progress-bar'],
107
+ check=True,
108
+ capture_output=False
109
+ )
110
+
111
+ if output_path.exists():
112
+ file_size = output_path.stat().st_size
113
+ print(f"\n✓ Download completed successfully!")
114
+ print(f"✓ File size: {file_size:,} bytes ({file_size / 1024 / 1024:.2f} MB)")
115
+ return True
116
+ else:
117
+ print(f"\n✗ Download failed: output file not created")
118
+ return False
119
+
120
+ except subprocess.CalledProcessError as e:
121
+ print(f"\n✗ Download failed: {e}")
122
+ return False
123
+ except FileNotFoundError:
124
+ print(f"\n✗ curl not found. Please install curl.")
125
+ return False
126
+
127
+
128
+ def fix_model_shape(model_path, output_path, batch_size=1, channels=3, height=224, width=224, use_simplifier=True):
129
+ """
130
+ Convert dynamic ONNX model input shape to fixed shape in all layers.
131
+
132
+ Uses ONNX shape inference to propagate fixed shapes through all intermediate layers.
133
+ Optionally uses onnxsim for additional simplification and optimization.
134
+ """
135
+ print(f"\n🔧 Fixing Model Shapes:")
136
+ print("=" * 80)
137
+ print(f"Input model: {model_path}")
138
+ print(f"Output model: {output_path}")
139
+
140
+ # Load model
141
+ print(f"\nLoading model...")
142
+ model = onnx.load(str(model_path))
143
+
144
+ # Get the first input (skip initializers)
145
+ graph = model.graph
146
+ input_tensor = None
147
+ for inp in graph.input:
148
+ if any(init.name == inp.name for init in graph.initializer):
149
+ continue
150
+ input_tensor = inp
151
+ break
152
+
153
+ if input_tensor is None:
154
+ print("✗ Error: No input tensor found!")
155
+ return False
156
+
157
+ # Print original shape
158
+ print(f"\n📋 Original Shape:")
159
+ print("-" * 80)
160
+ print(f"Input name: {input_tensor.name}")
161
+ original_shape = []
162
+ for dim in input_tensor.type.tensor_type.shape.dim:
163
+ if dim.dim_value:
164
+ original_shape.append(str(dim.dim_value))
165
+ elif dim.dim_param:
166
+ original_shape.append(f"'{dim.dim_param}'")
167
+ else:
168
+ original_shape.append("?")
169
+ print(f"Shape: [{', '.join(original_shape)}]")
170
+
171
+ # Modify input shape to fixed dimensions
172
+ print(f"\n🔧 Setting Fixed Shape:")
173
+ print("-" * 80)
174
+ new_shape = [batch_size, channels, height, width]
175
+ print(f"New shape: {new_shape}")
176
+ print(f"Format: [batch_size, channels, height, width]")
177
+
178
+ # Clear existing dimensions and add new fixed dimensions
179
+ input_tensor.type.tensor_type.shape.ClearField('dim')
180
+ for dim_value in new_shape:
181
+ dim = input_tensor.type.tensor_type.shape.dim.add()
182
+ dim.dim_value = dim_value
183
+
184
+ # Run shape inference
185
+ print(f"\n🔄 Running Shape Inference:")
186
+ print("-" * 80)
187
+ try:
188
+ model = shape_inference.infer_shapes(model)
189
+ value_info_count = len(model.graph.value_info)
190
+ print(f"✓ Propagated shapes through {value_info_count} intermediate tensors")
191
+ except Exception as e:
192
+ print(f"⚠ Warning: Shape inference issue: {e}")
193
+ print(" Continuing with partial inference...")
194
+
195
+ # Validate model
196
+ print(f"\n✅ Validating Model:")
197
+ print("-" * 80)
198
+ try:
199
+ onnx.checker.check_model(model)
200
+ print("✓ Model validation passed")
201
+ except Exception as e:
202
+ print(f"✗ Model validation failed: {e}")
203
+ return False
204
+
205
+ # Optional: Use onnx-simplifier
206
+ if use_simplifier:
207
+ print(f"\n🚀 Running ONNX Simplifier:")
208
+ print("-" * 80)
209
+ try:
210
+ import onnxsim
211
+ model_simplified, check = onnxsim.simplify(
212
+ model,
213
+ check_n=3,
214
+ perform_optimization=True,
215
+ skip_fuse_bn=False,
216
+ overwrite_input_shapes={input_tensor.name: new_shape}
217
+ )
218
+
219
+ if check:
220
+ print("✓ Model simplified and optimized")
221
+ model = model_simplified
222
+
223
+ # Report node reduction if any
224
+ original_nodes = len(graph.node)
225
+ simplified_nodes = len(model.graph.node)
226
+ if simplified_nodes < original_nodes:
227
+ print(f"✓ Reduced nodes: {original_nodes} → {simplified_nodes}")
228
+ else:
229
+ print("⚠ Simplification validation failed, using non-simplified version")
230
+
231
+ except ImportError:
232
+ print("⚠ onnx-simplifier not installed, skipping")
233
+ print(" Install with: pip install onnx-simplifier")
234
+ except Exception as e:
235
+ print(f"⚠ Simplification failed: {e}")
236
+ print(" Continuing with non-simplified model")
237
+
238
+ # Save the modified model
239
+ print(f"\n💾 Saving Fixed Model:")
240
+ print("-" * 80)
241
+ onnx.save(model, str(output_path))
242
+ output_size = output_path.stat().st_size
243
+ print(f"✓ Saved to: {output_path}")
244
+ print(f"✓ File size: {output_size:,} bytes ({output_size / 1024 / 1024:.2f} MB)")
245
+
246
+ # Final verification
247
+ print(f"\n🔍 Final Verification:")
248
+ print("-" * 80)
249
+ try:
250
+ verified_model = onnx.load(str(output_path))
251
+ onnx.checker.check_model(verified_model)
252
+
253
+ # Check input shape
254
+ verified_graph = verified_model.graph
255
+ for inp in verified_graph.input:
256
+ if any(init.name == inp.name for init in verified_graph.initializer):
257
+ continue
258
+ shape = [dim.dim_value for dim in inp.type.tensor_type.shape.dim]
259
+ all_fixed = all(isinstance(s, int) and s > 0 for s in shape)
260
+ if all_fixed:
261
+ print(f"✓ Input '{inp.name}': {shape}")
262
+ else:
263
+ print(f"⚠ Input '{inp.name}' has dynamic dimensions")
264
+
265
+ # Check intermediate tensors
266
+ if verified_graph.value_info:
267
+ fixed_count = sum(
268
+ 1 for vi in verified_graph.value_info
269
+ if all(dim.dim_value > 0 for dim in vi.type.tensor_type.shape.dim)
270
+ )
271
+ total_count = len(verified_graph.value_info)
272
+ print(f"✓ Fixed shapes: {fixed_count}/{total_count} intermediate tensors")
273
+
274
+ print(f"\n✨ Success! Fixed model ready for deployment")
275
+ return True
276
+
277
+ except Exception as e:
278
+ print(f"✗ Final verification failed: {e}")
279
+ return False
280
+
281
+
282
+ def main():
283
+ parser = argparse.ArgumentParser(
284
+ description='Download ONNX model and fix shapes for hardware deployment',
285
+ formatter_class=argparse.RawDescriptionHelpFormatter,
286
+ epilog="""
287
+ Examples:
288
+ # Use default .link file and settings
289
+ %(prog)s
290
+
291
+ # Specify custom .link file
292
+ %(prog)s --link-file model.onnx.link
293
+
294
+ # Custom shape dimensions
295
+ %(prog)s --batch-size 4 --height 256 --width 256
296
+
297
+ # Force re-download
298
+ %(prog)s --force-download
299
+
300
+ # Skip model simplification (faster)
301
+ %(prog)s --no-simplifier
302
+
303
+ # Skip download (fix existing model only)
304
+ %(prog)s --skip-download
305
+
306
+ # Keep intermediate downloaded file
307
+ %(prog)s --keep-intermediate
308
+ """
309
+ )
310
+
311
+ parser.add_argument('--link-file', type=str, default='resnet50.onnx.link',
312
+ help='Link file containing download URL (default: resnet50.onnx.link)')
313
+ parser.add_argument('--batch-size', type=int, default=1,
314
+ help='Fixed batch size (default: 1)')
315
+ parser.add_argument('--channels', type=int, default=3,
316
+ help='Number of channels (default: 3)')
317
+ parser.add_argument('--height', type=int, default=224,
318
+ help='Image height (default: 224)')
319
+ parser.add_argument('--width', type=int, default=224,
320
+ help='Image width (default: 224)')
321
+ parser.add_argument('--force-download', action='store_true',
322
+ help='Force re-download even if model exists')
323
+ parser.add_argument('--skip-download', action='store_true',
324
+ help='Skip download, only fix existing model')
325
+ parser.add_argument('--no-simplifier', action='store_true',
326
+ help='Skip onnx-simplifier optimization')
327
+ parser.add_argument('--keep-intermediate', action='store_true',
328
+ help='Keep intermediate downloaded file (not cleaned up)')
329
+
330
+ args = parser.parse_args()
331
+
332
+ # Resolve paths
333
+ script_dir = Path(__file__).parent
334
+ link_file = script_dir / args.link_file
335
+
336
+ if not link_file.exists():
337
+ print(f"Error: Link file not found: {link_file}")
338
+ print(f"Expected format in link file: <URL> -o <filename>")
339
+ sys.exit(1)
340
+
341
+ # Parse link file
342
+ print("📄 Parsing Link File:")
343
+ print("=" * 80)
344
+ print(f"Link file: {link_file}")
345
+
346
+ download_url, model_filename = parse_link_file(link_file)
347
+
348
+ if download_url is None or model_filename is None:
349
+ sys.exit(1)
350
+
351
+ print(f"Download URL: {download_url}")
352
+ print(f"Model name (from .link file): {model_filename}")
353
+
354
+ # The final output uses the name from .link file
355
+ final_output = script_dir / model_filename
356
+
357
+ # Use temporary name for intermediate download (will be cleaned up)
358
+ temp_download = script_dir / f".tmp_{model_filename}"
359
+
360
+ print(f"Final output model: {final_output.name}")
361
+
362
+ # Determine which file to use as source for shape fixing
363
+ if args.skip_download:
364
+ # User wants to fix existing model, use it directly if it exists
365
+ if not final_output.exists():
366
+ print(f"\n✗ Error: Model file not found: {final_output}")
367
+ print(f" Run without --skip-download to download it first.")
368
+ sys.exit(1)
369
+ model_path = final_output
370
+ print(f"Using existing model: {model_path.name}")
371
+ else:
372
+ # Download to temporary location
373
+ model_path = temp_download
374
+
375
+ # Step 1: Download model (unless skipped)
376
+ if not args.skip_download:
377
+ success = download_model(download_url, model_path, force=args.force_download)
378
+ if not success:
379
+ print("\n✗ Download failed, aborting.")
380
+ # Clean up temporary file if download failed
381
+ if model_path.exists():
382
+ model_path.unlink()
383
+ sys.exit(1)
384
+
385
+ # Step 2: Fix shapes (output directly to final location)
386
+ success = fix_model_shape(
387
+ model_path,
388
+ final_output,
389
+ batch_size=args.batch_size,
390
+ channels=args.channels,
391
+ height=args.height,
392
+ width=args.width,
393
+ use_simplifier=not args.no_simplifier
394
+ )
395
+
396
+ if success:
397
+ # Step 3: Clean up intermediate file (unless --keep-intermediate)
398
+ if not args.skip_download and model_path != final_output:
399
+ if args.keep_intermediate:
400
+ print(f"\n📦 Keeping intermediate file: {model_path.name}")
401
+ else:
402
+ print(f"\n🗑️ Cleaning up intermediate file...")
403
+ try:
404
+ model_path.unlink()
405
+ print(f"✓ Removed: {model_path.name}")
406
+ except Exception as e:
407
+ print(f"⚠ Could not remove intermediate file: {e}")
408
+
409
+ print("\n" + "=" * 80)
410
+ print("✅ COMPLETE!")
411
+ print("=" * 80)
412
+ print(f"Final model: {final_output.name}")
413
+ print(f"Location: {script_dir}")
414
+ print(f"Input shape: [{args.batch_size}, {args.channels}, {args.height}, {args.width}]")
415
+ sys.exit(0)
416
+ else:
417
+ print("\n✗ Shape fixing failed")
418
+ # Clean up temporary file on failure
419
+ if not args.skip_download and model_path.exists() and model_path != final_output:
420
+ model_path.unlink()
421
+ sys.exit(1)
422
+
423
+
424
+ if __name__ == "__main__":
425
+ main()
resnet50-v1.onnx.link ADDED
@@ -0,0 +1 @@
 
 
1
+ https://huggingface.co/onnxmodelzoo/resnet50-v1-7/blob/main/resnet50-v1-7.onnx -o resnet50-v1.onnx
resnet50-v1_config.yaml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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:
24
+ - 123.675
25
+ - 116.28
26
+ - 103.53
27
+ input_scale:
28
+ - 0.017125
29
+ - 0.017507
30
+ - 0.017429
31
+ model_path: resnet50-v1.onnx
32
+ model_id: cl-mh6001
33
+ input_details: null
34
+ output_details: null
35
+ num_inputs: 1
36
+ model_info:
37
+ metric_reference:
38
+ accuracy_top1%: 74.93
39
+ compact_name: resnet50-v1
40
+ shortlisted: true
resnet50.onnx.link ADDED
@@ -0,0 +1 @@
 
 
1
+ https://huggingface.co/onnx-community/resnet-50-ONNX/blob/main/onnx/model.onnx -o resnet50.onnx
resnet50_config.yaml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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:
24
+ - 123.675
25
+ - 116.28
26
+ - 103.53
27
+ input_scale:
28
+ - 0.017125
29
+ - 0.017507
30
+ - 0.017429
31
+ model_path: resnet50.onnx
32
+ model_id: cl-mh6000
33
+ input_details: null
34
+ output_details: null
35
+ num_inputs: 1
36
+ model_info:
37
+ metric_reference:
38
+ accuracy_top1%: 76.15
39
+ compact_name: resNet50
40
+ shortlisted: true