Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/detector-export.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ on:
- ".github/workflows/detector-export.yml"
- "complexity/deploy/onnx_detector/**"
- "complexity/generative/detection/**"
- "scripts/build_onnx_release.py"
- "scripts/check_onnx_parity.py"
- "scripts/onnx_detect.py"
- "scripts/export_onnx.py"
- "scripts/export_tensorrt.py"
- "docs/onnx/release.json"
- "tests/test_detector_export.py"
- "tests/test_onnx_release.py"
- "tests/test_onnx_detect_cli.py"
- "tests/test_onnx_detector_*.py"
- "pyproject.toml"
Expand All @@ -20,11 +23,14 @@ on:
- ".github/workflows/detector-export.yml"
- "complexity/deploy/onnx_detector/**"
- "complexity/generative/detection/**"
- "scripts/build_onnx_release.py"
- "scripts/check_onnx_parity.py"
- "scripts/onnx_detect.py"
- "scripts/export_onnx.py"
- "scripts/export_tensorrt.py"
- "docs/onnx/release.json"
- "tests/test_detector_export.py"
- "tests/test_onnx_release.py"
- "tests/test_onnx_detect_cli.py"
- "tests/test_onnx_detector_*.py"
- "pyproject.toml"
Expand Down Expand Up @@ -52,6 +58,7 @@ jobs:
ruff check
complexity/deploy/onnx_detector
complexity/generative/detection/exporting.py
scripts/build_onnx_release.py
scripts/check_onnx_parity.py
scripts/onnx_detect.py
scripts/export_onnx.py
Expand All @@ -62,6 +69,7 @@ jobs:
tests/test_onnx_detector_metadata.py
tests/test_onnx_detector_pipeline.py
tests/test_onnx_detector_skeleton.py
tests/test_onnx_release.py
- name: Test ONNX branches and dynamic batch parity
run: >-
pytest -q
Expand All @@ -71,3 +79,4 @@ jobs:
tests/test_onnx_detector_metadata.py
tests/test_onnx_detector_pipeline.py
tests/test_onnx_detector_skeleton.py
tests/test_onnx_release.py
108 changes: 108 additions & 0 deletions .github/workflows/onnx-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: ONNX release

on:
workflow_dispatch:
inputs:
tag:
description: "Release tag to create or update (e.g. onnx-v8-2026.08)"
required: true
type: string
draft:
description: "Publish as a draft release"
required: false
default: true
type: boolean
push:
tags:
- "onnx-v8-*"

permissions:
contents: write

concurrency:
group: onnx-release-${{ github.event.inputs.tag || github.ref_name }}
cancel-in-progress: false

jobs:
publish:
runs-on: ubuntu-latest
# Two 640px exports plus 50-seed parity gates on both branches.
timeout-minutes: 60
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip

- name: Read the pinned toolchain
id: pins
run: |
python - <<'PY' >> "$GITHUB_OUTPUT"
import json
toolchain = json.load(open("docs/onnx/release.json"))["toolchain"]
for package, version in toolchain.items():
print(f"{package}={version}")
PY

- name: Install the pinned export toolchain
run: |
python -m pip install --upgrade pip
python -m pip install -e ".[dev,export]" huggingface_hub
# Installed last so the pins win over the extras' version ranges.
python -m pip install "torch==${{ steps.pins.outputs.torch }}" \
--index-url https://download.pytorch.org/whl/cpu
python -m pip install \
"onnx==${{ steps.pins.outputs.onnx }}" \
"onnxruntime==${{ steps.pins.outputs.onnxruntime }}"

- name: Test the release tooling
run: pytest -q tests/test_onnx_release.py

- name: Build, gate and verify the release
env:
PYTHONPATH: .
run: python scripts/build_onnx_release.py --output-dir dist/onnx

- name: Re-verify the published files against the manifest
run: >-
python scripts/build_onnx_release.py
--verify dist/onnx/manifest.json
--expect-commit "$GITHUB_SHA"

- name: Require the release tag to resolve to the built commit
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.event.inputs.tag || github.ref_name }}
run: |
# An existing tag pointing elsewhere would publish a manifest whose
# framework_commit cannot be checked out from the release itself.
TAG_SHA=$(gh api "repos/$GITHUB_REPOSITORY/commits/$TAG" --jq .sha 2>/dev/null || true)
if [ -z "$TAG_SHA" ]; then
echo "Tag $TAG does not exist yet; it will be created at $GITHUB_SHA."
elif [ "$TAG_SHA" != "$GITHUB_SHA" ]; then
echo "Tag $TAG resolves to $TAG_SHA but the manifest records $GITHUB_SHA."
echo "Refusing to publish artifacts the tagged tree cannot reproduce."
exit 1
fi

- name: Upload release assets
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.event.inputs.tag || github.ref_name }}
DRAFT: ${{ github.event.inputs.draft == 'true' && '--draft' || '' }}
run: |
gh release view "$TAG" >/dev/null 2>&1 \
|| gh release create "$TAG" \
--target "$GITHUB_SHA" \
--title "TR-HASH Vision v8 ONNX artifacts" \
--notes-file dist/onnx/RELEASE_NOTES.md \
$DRAFT
gh release upload "$TAG" \
dist/onnx/manifest.json \
dist/onnx/tr_hash_v8_o2m.onnx \
dist/onnx/tr_hash_v8_o2m.json \
dist/onnx/tr_hash_v8_nms_free.onnx \
dist/onnx/tr_hash_v8_nms_free.json \
--clobber
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ weights/
*.gguf
*.ggml

# Exported inference graphs: published as release assets, never committed
*.onnx
*.engine
/dist/

# Training outputs
artifacts/
runs/
Expand Down
25 changes: 25 additions & 0 deletions docs/onnx/release.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"checkpoint_repo": "AETHORIA-AI/TR-HASH-Vision-v8-2M-COCO-SFT",
"checkpoint_revision": "f3b3e659612e543ca9ff91892c0662d38dc1a1d6",
"opset": 17,
"parity_num_tests": 50,
"toolchain": {
"torch": "2.13.0",
"onnx": "1.21.0",
"onnxruntime": "1.24.4"
},
"branches": [
{
"branch": "o2m",
"checkpoint_subdir": null,
"stem": "tr_hash_v8_o2m",
"post_processing": "decode plus NMS"
},
{
"branch": "nms-free",
"checkpoint_subdir": "best_nms_free",
"stem": "tr_hash_v8_nms_free",
"post_processing": "decode plus confidence filtering"
}
]
}
56 changes: 48 additions & 8 deletions docs/onnx/tr_hash_v8_validation_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,56 @@ Validation was run from commit `0fcf05c146f84a857d392b7da7d2947a41eb6d62`
`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:
repository — `*.onnx` is ignored — and are published as GitHub Release assets
instead.

## Releases

The `ONNX release` workflow (`.github/workflows/onnx-release.yml`) builds and
publishes them. It is triggered manually, or by pushing a tag matching
`onnx-v8-*`, and it aborts before uploading anything if the export fails, a
parity gate fails, or a checksum does not match the manifest.

Every input is pinned by [`release.json`](release.json): checkpoint repository
and revision, opset, and the export toolchain. The toolchain pin is what makes
the artifacts reproducible from a repository commit — a commit and a checkpoint
revision alone do not determine the digest.

The cheapest demonstration: re-exporting this same checkpoint under PyTorch
`2.13.0` instead of `2.6.0` yields binaries exactly **one byte larger** on both
branches (`11,104,477` and `11,108,684` against `11,104,476` and `11,108,683`
above), and therefore entirely different digests. `torch.onnx.export` stamps its
own version into the model's `producer_version` field, and `"2.13.0"` is one
character longer than `"2.6.0"`. The graph is otherwise unchanged — the parity
gates pass identically — but the bytes are not.

The release gate runs the parity checks at 50 seeds rather than the development
default of 5, for the reason given under Sample-size sensitivity: five seeds
underestimate the observed maximum by about 60%. A release is published rarely
enough that the extra cost is irrelevant.

The published tag is bound to the commit the manifest records: the workflow
creates it at that commit, and refuses to publish if an existing tag resolves
anywhere else. Otherwise a release could document digests that its own tagged
tree cannot reproduce.

Each release publishes five assets: both `.onnx` binaries, both metadata
sidecars, and `manifest.json`. The manifest records the checkpoint revision, the
framework commit, the opset, the parity depth, the input/output contract, and
the size and SHA-256 of every asset. Verify a download against it:

- `tr_hash_v8_o2m.onnx`
- `tr_hash_v8_o2m.json`
- `tr_hash_v8_nms_free.onnx`
- `tr_hash_v8_nms_free.json`
```bash
python scripts/build_onnx_release.py --verify manifest.json
```

Rebuild the same artifacts locally with:

```bash
PYTHONPATH=. python scripts/build_onnx_release.py --output-dir dist/onnx
```

Use the following hashes and sizes to verify the uploaded release artifacts:
The historical artifacts below predate this workflow. Use the following hashes
and sizes to verify them:

| Branch | Artifact | Size | SHA-256 |
|---|---:|---:|---|
Expand Down
Loading
Loading