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
38 changes: 30 additions & 8 deletions .github/workflows/onnx-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,21 @@ on:
required: false
default: true
type: boolean
evidence_run_id:
description: "Workflow run ID containing vision-v8-quantized-release-inputs"
required: false
type: string
runner:
description: "Runner label with CUDA support for FP16 ONNX gates"
required: false
default: "self-hosted"
type: string
push:
tags:
- "onnx-v8-*"

permissions:
actions: read
contents: write

concurrency:
Expand All @@ -25,7 +35,7 @@ concurrency:

jobs:
publish:
runs-on: ubuntu-latest
runs-on: ${{ inputs.runner || 'self-hosted' }}
# Two 640px exports plus 50-seed parity gates on both branches.
timeout-minutes: 60
steps:
Expand Down Expand Up @@ -55,10 +65,26 @@ jobs:
--index-url https://download.pytorch.org/whl/cpu
python -m pip install \
"onnx==${{ steps.pins.outputs.onnx }}" \
"onnxruntime==${{ steps.pins.outputs.onnxruntime }}"
"onnxruntime-gpu==${{ steps.pins.outputs.onnxruntime }}" \
psutil

- name: Download quantized release evidence
env:
GH_TOKEN: ${{ github.token }}
EVIDENCE_RUN_ID: ${{ github.event.inputs.evidence_run_id || vars.ONNX_RELEASE_EVIDENCE_RUN_ID }}
run: |
test -n "$EVIDENCE_RUN_ID"
mkdir -p artifacts/vision_v8_quantized_eval
gh run download "$EVIDENCE_RUN_ID" \
--name vision-v8-quantized-release-inputs \
--dir artifacts/vision_v8_quantized_eval
test -f artifacts/vision_v8_quantized_eval/calibration.json
test -d artifacts/vision_v8_quantized_eval/calibration_images
test -f artifacts/vision_v8_quantized_eval/accuracy.json
test -f artifacts/vision_v8_quantized_eval/accuracy.md

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

- name: Build, gate and verify the release
env:
Expand Down Expand Up @@ -104,9 +130,5 @@ jobs:
--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 \
dist/onnx/* \
--clobber
89 changes: 84 additions & 5 deletions .github/workflows/vision-v8-coco-accuracy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,33 @@ on:
onnx_nms_free_metadata:
description: "Local path to the NMS-free Vision v8 ONNX metadata sidecar on the runner"
required: false
onnx_o2m_fp16_model:
description: "Local path to the FP16 O2M Vision v8 ONNX model on the runner"
required: false
onnx_o2m_fp16_metadata:
description: "Local path to the FP16 O2M Vision v8 ONNX metadata sidecar"
required: false
onnx_nms_free_fp16_model:
description: "Local path to the FP16 NMS-free Vision v8 ONNX model"
required: false
onnx_nms_free_fp16_metadata:
description: "Local path to the FP16 NMS-free Vision v8 ONNX metadata sidecar"
required: false
onnx_o2m_int8_model:
description: "Local path to the INT8 O2M Vision v8 ONNX model on the runner"
required: false
onnx_o2m_int8_metadata:
description: "Local path to the INT8 O2M Vision v8 ONNX metadata sidecar"
required: false
onnx_nms_free_int8_model:
description: "Local path to the INT8 NMS-free Vision v8 ONNX model"
required: false
onnx_nms_free_int8_metadata:
description: "Local path to the INT8 NMS-free Vision v8 ONNX metadata sidecar"
required: false
calibration_manifest:
description: "Local path to the quantization calibration manifest"
required: false
annotations:
description: "Local path to instances_val2017.json on the runner"
required: true
Expand All @@ -66,7 +93,19 @@ on:
- pytorch
- onnx
provider:
description: "ONNX Runtime provider alias for backend=onnx"
description: "Legacy ONNX provider alias; precision-specific provider inputs are used for release evidence"
required: false
default: "cpu"
fp32_provider:
description: "ONNX Runtime provider alias for FP32 evaluation"
required: true
default: "cpu"
fp16_provider:
description: "ONNX Runtime provider alias for FP16 evaluation"
required: true
default: "cuda"
int8_provider:
description: "ONNX Runtime provider alias for INT8 evaluation"
required: true
default: "cpu"
release_tag:
Expand Down Expand Up @@ -136,6 +175,8 @@ jobs:
run: |
python -m pip install --upgrade pip
python -m pip install -e ".[detection,export]"
ONNXRUNTIME_VERSION=$(python -c "import json; print(json.load(open('docs/onnx/release.json'))['toolchain']['onnxruntime'])")
python -m pip install "onnxruntime-gpu==$ONNXRUNTIME_VERSION"
- name: Run deterministic COCO evaluation twice
run: |
if [ "${{ inputs.backend }}" = "pytorch" ]; then
Expand All @@ -147,11 +188,11 @@ jobs:
test -n "${{ inputs.onnx_o2m_metadata }}"
test -n "${{ inputs.onnx_nms_free_model }}"
test -n "${{ inputs.onnx_nms_free_metadata }}"
python scripts/evaluate_onnx_coco.py --model "${{ inputs.onnx_o2m_model }}" --metadata "${{ inputs.onnx_o2m_metadata }}" --annotations "${{ inputs.annotations }}" --images "${{ inputs.images }}" --output artifacts/vision_v8_coco_eval/run_a_o2m --branch o2m-nms --provider "${{ inputs.provider }}" --seed 0
python scripts/evaluate_onnx_coco.py --model "${{ inputs.onnx_nms_free_model }}" --metadata "${{ inputs.onnx_nms_free_metadata }}" --annotations "${{ inputs.annotations }}" --images "${{ inputs.images }}" --output artifacts/vision_v8_coco_eval/run_a_nms_free --branch nms-free --provider "${{ inputs.provider }}" --seed 0
python scripts/evaluate_onnx_coco.py --model "${{ inputs.onnx_o2m_model }}" --metadata "${{ inputs.onnx_o2m_metadata }}" --annotations "${{ inputs.annotations }}" --images "${{ inputs.images }}" --output artifacts/vision_v8_coco_eval/run_a_o2m --branch o2m-nms --provider "${{ inputs.fp32_provider }}" --precision fp32 --seed 0
python scripts/evaluate_onnx_coco.py --model "${{ inputs.onnx_nms_free_model }}" --metadata "${{ inputs.onnx_nms_free_metadata }}" --annotations "${{ inputs.annotations }}" --images "${{ inputs.images }}" --output artifacts/vision_v8_coco_eval/run_a_nms_free --branch nms-free --provider "${{ inputs.fp32_provider }}" --precision fp32 --seed 0
python scripts/merge_vision_v8_coco_reports.py artifacts/vision_v8_coco_eval/run_a_o2m/evaluation.json artifacts/vision_v8_coco_eval/run_a_nms_free/evaluation.json --output artifacts/vision_v8_coco_eval/run_a
python scripts/evaluate_onnx_coco.py --model "${{ inputs.onnx_o2m_model }}" --metadata "${{ inputs.onnx_o2m_metadata }}" --annotations "${{ inputs.annotations }}" --images "${{ inputs.images }}" --output artifacts/vision_v8_coco_eval/run_b_o2m --branch o2m-nms --provider "${{ inputs.provider }}" --seed 0
python scripts/evaluate_onnx_coco.py --model "${{ inputs.onnx_nms_free_model }}" --metadata "${{ inputs.onnx_nms_free_metadata }}" --annotations "${{ inputs.annotations }}" --images "${{ inputs.images }}" --output artifacts/vision_v8_coco_eval/run_b_nms_free --branch nms-free --provider "${{ inputs.provider }}" --seed 0
python scripts/evaluate_onnx_coco.py --model "${{ inputs.onnx_o2m_model }}" --metadata "${{ inputs.onnx_o2m_metadata }}" --annotations "${{ inputs.annotations }}" --images "${{ inputs.images }}" --output artifacts/vision_v8_coco_eval/run_b_o2m --branch o2m-nms --provider "${{ inputs.fp32_provider }}" --precision fp32 --seed 0
python scripts/evaluate_onnx_coco.py --model "${{ inputs.onnx_nms_free_model }}" --metadata "${{ inputs.onnx_nms_free_metadata }}" --annotations "${{ inputs.annotations }}" --images "${{ inputs.images }}" --output artifacts/vision_v8_coco_eval/run_b_nms_free --branch nms-free --provider "${{ inputs.fp32_provider }}" --precision fp32 --seed 0
python scripts/merge_vision_v8_coco_reports.py artifacts/vision_v8_coco_eval/run_b_o2m/evaluation.json artifacts/vision_v8_coco_eval/run_b_nms_free/evaluation.json --output artifacts/vision_v8_coco_eval/run_b
fi
- name: Gate full COCO report
Expand All @@ -160,6 +201,35 @@ jobs:
artifacts/vision_v8_coco_eval/run_a/evaluation.json
--repeat-report artifacts/vision_v8_coco_eval/run_b/evaluation.json
--config configs/vision_v8_coco_accuracy_gate.json
- name: Build quantized release evidence artifact
if: inputs.backend == 'onnx' && inputs.calibration_manifest != ''
env:
CALIBRATION_MANIFEST: ${{ inputs.calibration_manifest }}
run: |
test -n "${{ inputs.onnx_o2m_fp16_model }}"
test -n "${{ inputs.onnx_o2m_fp16_metadata }}"
test -n "${{ inputs.onnx_nms_free_fp16_model }}"
test -n "${{ inputs.onnx_nms_free_fp16_metadata }}"
test -n "${{ inputs.onnx_o2m_int8_model }}"
test -n "${{ inputs.onnx_o2m_int8_metadata }}"
test -n "${{ inputs.onnx_nms_free_int8_model }}"
test -n "${{ inputs.onnx_nms_free_int8_metadata }}"
mkdir -p artifacts/vision_v8_quantized_eval
python -c "import os; from pathlib import Path; from scripts.check_onnx_quantized_artifacts import materialize_calibration_manifest_images; materialize_calibration_manifest_images(Path(os.environ['CALIBRATION_MANIFEST']), artifact_root=Path('artifacts/vision_v8_quantized_eval'), output_manifest_path=Path('artifacts/vision_v8_quantized_eval/calibration.json'))"
python scripts/evaluate_onnx_coco.py --model "${{ inputs.onnx_o2m_fp16_model }}" --metadata "${{ inputs.onnx_o2m_fp16_metadata }}" --annotations "${{ inputs.annotations }}" --images "${{ inputs.images }}" --output artifacts/vision_v8_quantized_eval/o2m_fp16 --branch o2m-nms --provider "${{ inputs.fp16_provider }}" --precision fp16 --seed 0
python scripts/evaluate_onnx_coco.py --model "${{ inputs.onnx_nms_free_fp16_model }}" --metadata "${{ inputs.onnx_nms_free_fp16_metadata }}" --annotations "${{ inputs.annotations }}" --images "${{ inputs.images }}" --output artifacts/vision_v8_quantized_eval/nms_free_fp16 --branch nms-free --provider "${{ inputs.fp16_provider }}" --precision fp16 --seed 0
python scripts/evaluate_onnx_coco.py --model "${{ inputs.onnx_o2m_int8_model }}" --metadata "${{ inputs.onnx_o2m_int8_metadata }}" --annotations "${{ inputs.annotations }}" --images "${{ inputs.images }}" --output artifacts/vision_v8_quantized_eval/o2m_int8 --branch o2m-nms --provider "${{ inputs.int8_provider }}" --precision int8 --seed 0
python scripts/evaluate_onnx_coco.py --model "${{ inputs.onnx_nms_free_int8_model }}" --metadata "${{ inputs.onnx_nms_free_int8_metadata }}" --annotations "${{ inputs.annotations }}" --images "${{ inputs.images }}" --output artifacts/vision_v8_quantized_eval/nms_free_int8 --branch nms-free --provider "${{ inputs.int8_provider }}" --precision int8 --seed 0
python scripts/merge_vision_v8_coco_reports.py \
artifacts/vision_v8_coco_eval/run_a_o2m/evaluation.json \
artifacts/vision_v8_coco_eval/run_a_nms_free/evaluation.json \
artifacts/vision_v8_quantized_eval/o2m_fp16/evaluation.json \
artifacts/vision_v8_quantized_eval/nms_free_fp16/evaluation.json \
artifacts/vision_v8_quantized_eval/o2m_int8/evaluation.json \
artifacts/vision_v8_quantized_eval/nms_free_int8/evaluation.json \
--output artifacts/vision_v8_quantized_eval
cp artifacts/vision_v8_quantized_eval/evaluation.json artifacts/vision_v8_quantized_eval/accuracy.json
cp artifacts/vision_v8_quantized_eval/evaluation.md artifacts/vision_v8_quantized_eval/accuracy.md
- uses: actions/upload-artifact@v4
with:
name: vision-v8-coco-accuracy-report
Expand All @@ -168,6 +238,15 @@ jobs:
artifacts/vision_v8_coco_eval/run_a/evaluation.md
artifacts/vision_v8_coco_eval/run_b/evaluation.json
artifacts/vision_v8_coco_eval/run_b/evaluation.md
- uses: actions/upload-artifact@v4
if: inputs.backend == 'onnx' && inputs.calibration_manifest != ''
with:
name: vision-v8-quantized-release-inputs
path: |
artifacts/vision_v8_quantized_eval/calibration.json
artifacts/vision_v8_quantized_eval/calibration_images/**
artifacts/vision_v8_quantized_eval/accuracy.json
artifacts/vision_v8_quantized_eval/accuracy.md
- name: Upload gated reports to GitHub Release
if: inputs.release_tag != ''
env:
Expand Down
24 changes: 16 additions & 8 deletions complexity/deploy/onnx_detector/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,19 @@ def from_files(
model_path: str | Path,
metadata_path: str | Path,
providers: Sequence[str] = ("CPUExecutionProvider",),
*,
warmup_runs: int = 1,
intra_op_num_threads: int | None = None,
inter_op_num_threads: int | None = None,
) -> "OnnxDetectorPipeline":
metadata = load_metadata(metadata_path)
session = cls.create_session(model_path, providers).open()
session = cls.create_session(
model_path,
providers,
warmup_runs=warmup_runs,
intra_op_num_threads=intra_op_num_threads,
inter_op_num_threads=inter_op_num_threads,
).open()
validate_output_shape(metadata, session._require_session().get_outputs()[0].shape)
if session.config.warmup_runs:
session.warmup((1, 3, metadata.image_size, metadata.image_size))
Expand Down Expand Up @@ -74,13 +84,11 @@ def postprocess_single_image(
scores: np.ndarray,
classes: np.ndarray,
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
filtered_boxes, filtered_scores, filtered_classes, _ = (
postprocess.filter_by_confidence(
boxes,
scores,
classes,
self.metadata.confidence_threshold,
)
filtered_boxes, filtered_scores, filtered_classes, _ = postprocess.filter_by_confidence(
boxes,
scores,
classes,
self.metadata.confidence_threshold,
)
if self.metadata.branch == "o2m":
keep = postprocess.class_aware_nms(
Expand Down
19 changes: 19 additions & 0 deletions configs/vision_v8_quantization_calibration.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"schema_version": 1,
"dataset": {
"name": "coco-2017-train-calibration",
"split": "train2017-calibration",
"image_ids_sha256": "replace-with-calibration-image-id-manifest-sha256",
"annotations_sha256": "replace-with-annotations-sha256",
"disjoint_from": "coco-2017-val2017"
},
"quantization": {
"calibration_method": "minmax",
"per_channel": true,
"symmetric_activations": false,
"symmetric_weights": true,
"activation_type": "quint8",
"weight_type": "qint8",
"batch_size": 1
}
}
49 changes: 49 additions & 0 deletions configs/vision_v8_quantization_thresholds.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"schema_version": 1,
"release_policy": {
"required_precisions": ["fp32", "fp16", "int8"],
"require_artifact_bindings": true,
"provider_by_precision": {
"fp32": "CPUExecutionProvider",
"fp16": "CUDAExecutionProvider",
"int8": "CPUExecutionProvider"
},
"partial_release": "block",
"optional_provider_precisions": []
},
"precisions": {
"fp16": {
"max_raw_logit_abs_error": 0.01,
"max_decoded_box_px_error": 1.0,
"max_score_abs_error": 0.01,
"max_map50_95_drop": 0.005,
"max_map50_drop": 0.01,
"unexpected_fp32_nodes": "fail"
},
"int8": {
"max_raw_logit_abs_error": 0.12,
"max_decoded_box_px_error": 4.0,
"max_score_abs_error": 0.05,
"max_map50_95_drop": 0.02,
"max_map50_drop": 0.03,
"unexpected_fp32_nodes": "allow"
}
},
"providers": {
"CPUExecutionProvider": ["fp32", "int8"],
"CUDAExecutionProvider": ["fp32", "fp16"],
"TensorrtExecutionProvider": ["fp32", "fp16", "int8"]
},
"benchmark": {
"warmup_iterations": 25,
"measured_iterations": 100,
"report": [
"median_ms",
"mean_ms",
"stddev_ms",
"p95_ms",
"throughput_images_per_second",
"peak_memory_mb"
]
}
}
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ GQA + TR-MoE architecture.
- [TR-Hash object detection and serving](tr-hash-object-detection.md)
- [TR-Hash Vision ONNX deployment](onnx_deploy.md)
- [Vision v8 COCO accuracy gates](vision-v8-coco-accuracy-gates.md)
- [Vision v8 ONNX quantization](vision-v8-onnx-quantization.md)
- [Detector specialization and ablations](TR_HASH_DETECTOR_SPECIALIZATION.md)
- [TR-Hash sensor fusion](tr_hash_sensor_fusion.md)
- [Vision dependency stack](vision-dependency-stack.md)
Expand Down
15 changes: 14 additions & 1 deletion docs/onnx/release.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,23 @@
"checkpoint_revision": "f3b3e659612e543ca9ff91892c0662d38dc1a1d6",
"opset": 17,
"parity_num_tests": 50,
"quantization": {
"enabled_precisions": ["fp16", "int8"],
"calibration_manifest": "artifacts/vision_v8_quantized_eval/calibration.json",
"thresholds": "configs/vision_v8_quantization_thresholds.json",
"accuracy_report": "artifacts/vision_v8_quantized_eval/accuracy.json",
"accuracy_markdown": "artifacts/vision_v8_quantized_eval/accuracy.md",
"fp32_op_allowlist": [],
"provider_gates": [
{"provider": "CPUExecutionProvider", "precision": "fp32"},
{"provider": "CUDAExecutionProvider", "precision": "fp16"},
{"provider": "CPUExecutionProvider", "precision": "int8"}
]
},
"toolchain": {
"torch": "2.13.0",
"onnx": "1.21.0",
"onnxruntime": "1.24.4"
"onnxruntime": "1.23.2"
},
"branches": [
{
Expand Down
Loading