Repository navigation
Document Vision v8 ONNX validation #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Complexity-ML
merged 1 commit into
Complexity-ML:main
from
milliyin:v8-onnx-validation-report
Aug 21, 2026
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| { | ||
| "architecture_version": 8, | ||
| "image_size": 640, | ||
| "num_classes": 80, | ||
| "num_cells": 34000, | ||
| "regression_width": 68, | ||
| "reg_max": 16, | ||
| "scale_factors": [ | ||
| 1, | ||
| 2, | ||
| 4 | ||
| ], | ||
| "grid_sizes": [ | ||
| 160, | ||
| 80, | ||
| 40, | ||
| 20 | ||
| ], | ||
| "p2_head": true, | ||
| "branch": "nms-free", | ||
| "requires_nms": false, | ||
| "output_semantics": "raw_ltrb_dfl_and_quality_class_logits" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| { | ||
| "architecture_version": 8, | ||
| "image_size": 640, | ||
| "num_classes": 80, | ||
| "num_cells": 34000, | ||
| "regression_width": 68, | ||
| "reg_max": 16, | ||
| "scale_factors": [ | ||
| 1, | ||
| 2, | ||
| 4 | ||
| ], | ||
| "grid_sizes": [ | ||
| 160, | ||
| 80, | ||
| 40, | ||
| 20 | ||
| ], | ||
| "p2_head": true, | ||
| "branch": "o2m", | ||
| "requires_nms": true, | ||
| "output_semantics": "raw_ltrb_dfl_and_quality_class_logits" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| # TR-HASH Vision v8 ONNX Validation | ||
|
|
||
| Validation was run from commit `0fcf05c146f84a857d392b7da7d2947a41eb6d62` | ||
| (`Make Vision v8 the only detector architecture`) with the native checkpoint | ||
| `AETHORIA-AI/TR-HASH-Vision-v8-2M-COCO-SFT`. | ||
|
|
||
| The generated ONNX binaries are intentionally not committed to the source | ||
| repository. Upload them as GitHub Release assets and link the release asset URLs | ||
| from the release notes or from a follow-up update to this report. The release | ||
| assets should include both ONNX binaries and their export metadata sidecars: | ||
|
|
||
| - `tr_hash_v8_o2m.onnx` | ||
| - `tr_hash_v8_o2m.json` | ||
| - `tr_hash_v8_nms_free.onnx` | ||
| - `tr_hash_v8_nms_free.json` | ||
|
|
||
| Use the following hashes and sizes to verify the uploaded release artifacts: | ||
|
|
||
| | Branch | Artifact | Size | SHA-256 | | ||
| |---|---:|---:|---| | ||
| | O2M | `tr_hash_v8_o2m.onnx` | 11,104,476 bytes / 10.590054 MiB | `24CADE1A285475DDD6D8AB25EF6775F34BB9B686A08355CD35A39342A493256A` | | ||
| | NMS-free | `tr_hash_v8_nms_free.onnx` | 11,108,683 bytes / 10.594066 MiB | `CA24D9577FF2224BC1A4949D09A2E1CC514DB04B5DFFECE6B42223DE3326FDD7` | | ||
|
|
||
| Branch metadata is committed beside this report: | ||
|
|
||
| | Branch | Metadata | | ||
| |---|---| | ||
| | O2M | [`tr_hash_v8_o2m.metadata.json`](tr_hash_v8_o2m.metadata.json) | | ||
| | NMS-free | [`tr_hash_v8_nms_free.metadata.json`](tr_hash_v8_nms_free.metadata.json) | | ||
|
|
||
| ## Reproducibility | ||
|
|
||
| Download the checkpoint snapshot: | ||
|
|
||
| ```powershell | ||
| python -c "from huggingface_hub import snapshot_download; snapshot_download(repo_id='AETHORIA-AI/TR-HASH-Vision-v8-2M-COCO-SFT', local_dir=r'models/TR-HASH-Vision-v8-2M-COCO-SFT')" | ||
| ``` | ||
|
|
||
| Export both raw prediction branches: | ||
|
|
||
| ```powershell | ||
| $env:PYTHONPATH='.' | ||
| python scripts/export_onnx.py models\TR-HASH-Vision-v8-2M-COCO-SFT --output tr_hash_v8_o2m.onnx --branch o2m --opset 17 --check | ||
| python scripts/export_onnx.py models\TR-HASH-Vision-v8-2M-COCO-SFT\best_nms_free --output tr_hash_v8_nms_free.onnx --branch nms-free --opset 17 --check | ||
| ``` | ||
|
|
||
| Validate parity with the calibrated v8 defaults: | ||
|
|
||
| ```powershell | ||
| $env:PYTHONPATH='.' | ||
| python scripts/check_onnx_parity.py models\TR-HASH-Vision-v8-2M-COCO-SFT tr_hash_v8_o2m.onnx --branch auto --num-tests 5 --batch-size 1 | ||
| python scripts/check_onnx_parity.py models\TR-HASH-Vision-v8-2M-COCO-SFT\best_nms_free tr_hash_v8_nms_free.onnx --branch auto --num-tests 5 --batch-size 1 | ||
| ``` | ||
|
|
||
| To reproduce the exact historical parity commands, pass the thresholds | ||
| explicitly: | ||
|
|
||
| ```powershell | ||
| python scripts/check_onnx_parity.py models\TR-HASH-Vision-v8-2M-COCO-SFT tr_hash_v8_o2m.onnx --branch auto --tolerance 0.002 --num-tests 5 --batch-size 1 | ||
| python scripts/check_onnx_parity.py models\TR-HASH-Vision-v8-2M-COCO-SFT\best_nms_free tr_hash_v8_nms_free.onnx --branch auto --tolerance 0.0035 --num-tests 5 --batch-size 1 | ||
| ``` | ||
|
|
||
| ## Contract | ||
|
|
||
| Both ONNX models were exported with opset 17 and expose raw detector logits | ||
| only. Decode and post-processing remain outside the graph. | ||
|
|
||
| | Branch | Input | Output | Post-processing | | ||
| |---|---|---|---| | ||
| | O2M | `pixel_values`, `float32`, `[1, 3, 640, 640]` | `predictions`, `float32`, `[1, 34000, 148]` | Decode plus NMS | | ||
| | NMS-free | `pixel_values`, `float32`, `[1, 3, 640, 640]` | `predictions`, `float32`, `[1, 34000, 148]` | Decode plus confidence filtering | | ||
|
|
||
| Output channel layout is `68` LTRB/DFL regression logits followed by `80` | ||
| quality-class logits. The grid pyramid is `[160, 80, 40, 20]`, for `34,000` | ||
| prediction cells. | ||
|
|
||
| ## Runtime Versions | ||
|
|
||
| | Component | Version | | ||
| |---|---| | ||
| | PyTorch | `2.6.0+cu118` | | ||
| | ONNX | `1.21.0` | | ||
| | ONNX Runtime | `1.23.2` | | ||
| | ONNX Runtime providers | `TensorrtExecutionProvider`, `CUDAExecutionProvider`, `CPUExecutionProvider` | | ||
| | GPU | NVIDIA GeForce GTX 1660 SUPER, driver `560.94` | | ||
|
|
||
| The CPU benchmark used `CPUExecutionProvider` on | ||
| `AMD64 Family 23 Model 113 Stepping 0, AuthenticAMD`. | ||
|
|
||
| The GPU benchmark used `CUDAExecutionProvider` on the GTX 1660 SUPER. On this | ||
| Windows environment, ONNX Runtime required `ort.preload_dlls()` plus explicit | ||
| `nvidia/*/bin` DLL directories from the installed CUDA 12 and cuDNN 9 wheels. | ||
|
|
||
| ## Export Results | ||
|
|
||
| Both exports succeeded: | ||
|
|
||
| ```text | ||
| o2m: Forward OK: output shape torch.Size([1, 34000, 148]) | ||
| nms-free: Forward OK: output shape torch.Size([1, 34000, 148]) | ||
| ``` | ||
|
|
||
| ## Parity Results | ||
|
|
||
| The legacy strict raw-logit threshold `1e-4` failed for both branches on CPU | ||
| ONNX Runtime: | ||
|
|
||
| ```text | ||
| o2m: max_diff range 1.36e-03 to 1.74e-03, mean_diff about 1.0e-04 | ||
| nms-free: max_diff range 2.36e-03 to 3.00e-03, mean_diff about 1.0e-04 | ||
| ``` | ||
|
|
||
| Tensor localization showed the largest raw differences are concentrated in | ||
| regression logits on the finest `160x160` grid. Class-logit drift is smaller. | ||
| Decoded-output drift is substantially lower: | ||
|
|
||
| | Branch | Decoded boxes max diff | Decoded class score max diff | | ||
| |---|---:|---:| | ||
| | O2M | `6.00814819e-05` | `3.02493572e-05` | | ||
| | NMS-free | `5.73396683e-05` | `1.35712326e-05` | | ||
|
|
||
| The calibrated v8 raw-logit thresholds are: | ||
|
|
||
| | Branch | Raw-logit tolerance | Justification | | ||
| |---|---:|---| | ||
| | O2M | `0.002` | Covers observed max drift up to `1.74e-03` with decoded box drift near `6e-05` | | ||
| | NMS-free | `0.0035` | Covers observed max drift up to `3.00e-03` with decoded box drift near `5.7e-05` | | ||
|
|
||
| Calibrated parity output: | ||
|
|
||
| ```text | ||
| O2M, tolerance 0.002: | ||
| Test 1/5: max_diff=1.61e-03, mean_diff=1.02e-04 [PASS] | ||
| Test 2/5: max_diff=1.36e-03, mean_diff=1.03e-04 [PASS] | ||
| Test 3/5: max_diff=1.63e-03, mean_diff=1.17e-04 [PASS] | ||
| Test 4/5: max_diff=1.36e-03, mean_diff=1.08e-04 [PASS] | ||
| Test 5/5: max_diff=1.74e-03, mean_diff=1.06e-04 [PASS] | ||
| Parity PASSED: branch=o2m, tolerance=0.002 | ||
|
|
||
| NMS-free, tolerance 0.0035: | ||
| Test 1/5: max_diff=2.65e-03, mean_diff=1.03e-04 [PASS] | ||
| Test 2/5: max_diff=2.36e-03, mean_diff=1.01e-04 [PASS] | ||
| Test 3/5: max_diff=2.83e-03, mean_diff=1.11e-04 [PASS] | ||
| Test 4/5: max_diff=2.51e-03, mean_diff=1.00e-04 [PASS] | ||
| Test 5/5: max_diff=3.00e-03, mean_diff=1.10e-04 [PASS] | ||
| Parity PASSED: branch=nms-free, tolerance=0.0035 | ||
| ``` | ||
|
|
||
| ## Benchmarks | ||
|
|
||
| Benchmarks used batch size 1, `10` warmup runs, and `50` measured runs. | ||
|
|
||
| CPU ONNX Runtime: | ||
|
|
||
| | Branch | Provider | Mean latency | P95 latency | | ||
| |---|---|---:|---:| | ||
| | O2M | `CPUExecutionProvider` | `230.712 ms` | `240.292 ms` | | ||
| | NMS-free | `CPUExecutionProvider` | `244.064 ms` | `258.964 ms` | | ||
|
|
||
| NMS-free was `13.351 ms` slower than O2M on mean latency, a `5.79%` increase. | ||
|
|
||
| GPU ONNX Runtime: | ||
|
|
||
| | Branch | Provider | Mean latency | P95 latency | | ||
| |---|---|---:|---:| | ||
| | O2M | `CUDAExecutionProvider` | `32.997 ms` | `33.890 ms` | | ||
| | NMS-free | `CUDAExecutionProvider` | `33.855 ms` | `34.724 ms` | | ||
|
|
||
| NMS-free was `0.858 ms` slower than O2M on mean latency, a `2.60%` increase. | ||
|
|
||
| ## Conclusion | ||
|
|
||
| TR-HASH Vision v8 exports successfully to ONNX for both raw prediction | ||
| branches. Branch behavior matches the expected architecture: NMS-free computes | ||
| the extra one-to-one head path and is empirically slower than O2M. Deployment | ||
| validation should use decoded-output drift and the calibrated v8 raw-logit | ||
| thresholds above rather than the legacy `1e-4` raw-logit threshold. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the ONNX sidecar is absent,
sidecar_metadata()returns{}, sometadata.get("branch", "auto")yields"auto"and this raises. That breaks the previous/default--branch autobehavior even thoughRawDetectorExportcan resolveauto, and it contradicts the CLI help saying metadata is optional. Please return"auto"when branch metadata is absent (while still rejecting an explicitly invalid value) and addassert branch_from_sidecar({}, "auto") == "auto"as a regression test.