frnet-p150 / VERIFICATION_2026-10-09.md
changh95's picture
tt-model push frnet-p150 (container)
fe51a63 verified
|
Raw History Blame
14.1 kB

frnet-p150: independent verification, 2026-10-09

Verdict

PASS. This is the light verification pass of the first publish (research/PLAN.md §6.3): the frozen gates re-run, the baseline numbers re-checked, and every device-open path audited for ETH dispatch. It was made by the agent that wrote the release docs, which is neither the porter, nor the adversarial verifier of VERIFY_PORT.md, nor the baseline agent, on the release-code commit 04c39b5 (the model code of the baseline 0dd52b2; the shipped sample became a synthetic scan per serve profile, the PandaSet sample is staged and not shipped, test hardening; the docs commit that follows changes make_demo.py's render captions and the docs only). The device runs ran on 2026-10-09 15:53-16:10 UTC in one bin/devrun window (a first queueing attempt died while waiting for the lock, when the workspace's bin/devrun was edited under it; it had not touched the device). Against the baseline commit 0dd52b2:

  • Frozen gates: the device suite (test_pcc_device.py + test_e2e_device.py, one pytest) passed 14 / 14 tests. Every existing gate passes with values bit-identical to the baseline run (the _m5 and _m5docs reports: 2,144 leaves compared, 0 differ; timings excluded), including the binding frame: OT128 min agreement 98.907 % (nuScenes 0916 kf40) against the 98.5 % gate. The two new tests (test_shipped_sample, and test_public_frames now requiring all 17 / 5 frames) passed; the four new shipped-sample gates were frozen at this first green run (label agreement OT128 0.99550, QT128 0.99623; filtered-cloud agreement 0.99772 / 0.99872; threshold 0.985).
  • Baseline re-check: the device rows of OPT_BASELINE.md repeat to within 0.03 ms (OT128 210.02 / 209.95 ms trace / b2b on the synthetic sample vs 210.00 / 209.95 ms now; QT128 133.53 / 133.43 vs 133.50 / 133.43 ms). Host rows within the load noise (OT128 model() 292.6 -> 289.3 ms p50 on the synthetic sample, 355.7 -> 360.1 ms on PandaSet, at load average 4.1).
  • Shipped samples: the shipped synthetic_<variant>.npz are byte-identical to the baseline's synthetic bench inputs (cmp), so the baseline's synthetic rows are the shipped sample's. p150 vs the stored CPU reference: OT128 99.550 % of 52,613 points, QT128 99.623 % of 69,553, the same through bench.py, the device test, the quickstart, make_demo.py and the served smoke test.
  • Public data (113 frames per profile, production API): pooled class agreement OT128 PandaSet 99.66 % / nuScenes 99.19 %, QT128 99.29 % / 99.44 %; identical scored rows to the CPU reference on all 226 frame-profile pairs, no profile skip. 3 pairs fall below 98.5 % (not gated; see "Review findings"). Mapped-label mIoU on the p150 equals the CPU reference's within 0.002.
  • ETH dispatch: every device-open path opens ETH / 1 CQ / 12×10 by default; every run of this pass printed dispatch eth, grid 12x10, cores 120, fallback null, eth_patch true (both serve profiles, API and server).
  • No numerics change and no new bug: nothing in the model code was changed by this pass.

Setup

item value
Hardware one Blackhole p150b, ETH dispatch, 1 CQ, 12×10 compute grid (120 cores), AICLK 1350 MHz median (min 1343) during the benches
tt-metal 44d66500520 with patches/tt-metal-eth-dispatch.patch (sha256 08d0ddf6…, byte-identical to the workspace copy)
Weights AutowareFoundation/lidar_frnet @ a53a1c11b0b28d31fd50a03abef5db0e830a5b3c (tag v2.0): the device suite and the demo run read the sha256-pinned workspace copy; the quickstart, the served runs and the load-time runs resolved the HF cache at the pinned revision offline (downloaded without a token for this pass; every file identical to the workspace copy, ONNX sha256 ot128 d29bf595…, qt128 647af927…)
Verified commit 04c39b5 (ttaw 0.20.0, common 89dec49, source_dirty: false)
Baseline commit 0dd52b2 (OPT_BASELINE.md)
Workload the shipped samples code/tt_frnet/samples/synthetic_{ot128,qt128}.npz and the staged PandaSet 019 f40 (107,146 points, local), batch 1, warm; the 17 / 5 gate frames; 113 converted public frames per profile (local only)
Bench method code/scripts/bench.py --iters 100 --warmup 10 --b2b-iters 50 --b2b-rounds 5, one run per serve profile (the baseline's settings), with each output checked against its stored CPU reference
Served method uvicorn on the host with the serve pins of tt-model.yaml (the container's app; FRNET_VARIANT per profile), the bundle's smoke_test.py against it, then 5 warm-up + 50 requests of the shipped sample from a loopback client, the README's client.py + curl recipe, a knobs request and a request without calibration
Accuracy reference the fp32 CPU reference (code/tt_frnet/reference/, ONNX Runtime on the deployed ONNX; VERIFY_PORT: within 1e-11 of an independent ORT run); for the 113-frame sets the research ORT runs (research/frnet/public_data/runs)
Host AMD EPYC VM, 8 vCPUs, shared with other agents' jobs (load average 4.1-6.1 during the runs)
Logs logs/frnet/m5_docs/ of the workspace (job scripts in scripts/)

Measured baseline vs re-check

All times in ms, p50 of 100 iterations (b2b: 5 rounds of 50 replays). Baseline: OPT_BASELINE.md (0dd52b2); re-check: code/scripts/bench.py with the baseline's settings on 04c39b5 (logs/frnet/m5_docs/bench_recheck_{ot128,qt128}.json).

row baseline re-check
OT128, shipped sample: trace, one replay / back-to-back 210.02 / 209.948 210.00 / 209.946
OT128, PandaSet 019 f40: trace / back-to-back 211.72 / 211.643 211.73 / 211.639
QT128, shipped sample: trace / back-to-back 133.53 / 133.434 133.50 / 133.429
QT128, PandaSet 019 f40: trace / back-to-back 134.91 / 134.866 134.92 / 134.856
OT128 H2D / D2H, shipped sample 5.42 / 7.65 5.42 / 7.56
OT128 host pre-processing, shipped sample / PandaSet 55.3 / 107.2 54.7 / 107.4
OT128 model() p50, shipped sample / PandaSet 292.6 / 355.7 289.3 / 360.1
QT128 model() p50, shipped sample / PandaSet 221.1 / 244.3 205.4 / 241.5
served /predict timing_ms.total, OT128 / QT128 (median of 50) – 310.4 / 228.9
served client round trip, loopback – 328.1 / 247.3
from_pretrained, empty JIT cache / warm cache, OT128 – / 6.5 s 156.6 / 7.5 s
from_pretrained, empty JIT cache / warm cache, QT128 – / 6.9 s 151.9 / 6.6 s

The served and cold-load rows are new for the card (the baseline measured neither). The first two calls after a load took 320.0 / 304.7 ms (OT128) and 241.1 / 214.9 ms (QT128): the trace is captured during the load. The cold JIT cache holds 682 MB (OT128) / 644 MB (QT128) after the load.

Accuracy gate results

logs/frnet/m5_docs/suite.log; reports logs/frnet/{pcc,pcc_small,e2e,latency}_{ot128,qt128}_m5docs.json.

check gate OT128 QT128
every gated module tap (PCC vs the fp32 reference, PandaSet sample, replay outputs) ≥ 0.999 min 0.999729 (point_fusion1) min 0.999649 (attention4)
pred_probs PCC / raw-point agreement, PandaSet sample (staged) ≥ 0.998 / ≥ 98.5 % 0.999942 / 99.581 % 0.999844 / 99.295 %
public frames (17 / 5): min pred_probs PCC ≥ 0.998 0.999688 0.999805
public frames: min raw-point agreement ≥ 98.5 % 98.907 % (nuScenes 0916 kf40) 99.158 % (PandaSet 029 f40)
shipped sample vs its stored reference body: labels / filtered-cloud mask (new) ≥ 98.5 % 99.550 % / 99.772 % 99.623 % / 99.872 %
replay == eager bit-exact 45 / 45 taps 45 / 45 taps
API == /predict handler identical yes yes

Host suite (fake ttnn, gates read-only): 117 passed, 15 skipped (the 14 device tests and the onnxruntime-only test), logs/frnet/m5_docs/host_suite.log. Research venv (ONNX Runtime + torch): 85 passed, 2 skipped (by design), logs/frnet/m5_docs/research_venv.log. The counts differ from VERIFY_PORT's (112 / 13 host, 83 / 2 research venv) by the tests the release added or changed (release hygiene of the shipped samples, the top-level PYTHON.md copy, the shipped-sample device test).

Public-frame agreement beyond the gates

code/scripts/make_demo.py run (the production API, model(points, calibration=...)) on every converted public frame of research/frnet/public_data/inputs, both profiles, against the research ORT runs (logs/frnet/m5_docs/demo/agreement.json):

set frames scored raw points OT128 pooled (worst frame) QT128 pooled (worst frame)
PandaSet 019 + 029, every 5th frame 32 3,442,737 99.66 % (99.35 %) 99.29 % (98.69 %)
nuScenes v1.0-mini mini_val, all key-frames 81 2,067,589 99.19 % (98.37 %) 99.44 % (98.10 %)

Scored rows equal the reference's on all 226 frame-profile pairs (same crop, same profile decisions); no frame was skipped. Mapped-label mIoU (research/frnet/public_data/scripts/frnet_public_eval.py, not a paper metric; logs/frnet/m5_docs/miou/): OT128 PandaSet coarse 0.7136 (p150) vs 0.7146 (CPU), fine 0.4471 vs 0.4479; nuScenes coarse 0.4827 vs 0.4831, fine 0.4515 vs 0.4531 (fine = mean over the classes with at least 1,000 labelled points, miou_classes_ge_1000_gt_points; over all labelled classes: PandaSet 0.3229 vs 0.3235, nuScenes 0.3285 vs 0.3292); QT128 PandaSet coarse 0.1869 vs 0.1873, nuScenes 0.3255 vs 0.3266.

Disclosed numerics changes

None: the model code, the precision knobs and the kernels are those of the baseline, and every existing gate value is bit-identical to it. The release changed what ships (samples), the tests (stricter) and the docs.

Review findings

  • VERIFY_PORT round 1, low findings (all resolved or disclosed):
    1. stale PORT_LOG header and latency: fixed (ttaw 0.20.0 @ 89dec49; the superseded first-cut latency replaced by the current numbers; the duplicated known-issue paragraphs removed);
    2. test_public_frames skipped missing goldens silently: inside the workspace a missing golden, research frame or staged sample now FAILS (tests/_data.py need()), and the test asserts 17 / 5 frames;
    3. narrow precision margin (0.41 pt on nuScenes 0916 kf40): disclosed on the card (Caveats) and in OPT_REPORT.md as the binding constraint and backlog item 14;
    4. end-to-end latency depends on the host load: the card quotes the stage bench with its load conditions and the device rows separately;
    5. test_stage_pcc replays on its capture inputs: unchanged (hardening note); input rewriting is covered by test_small_graph, test_public_frames (17 / 5 frames through one trace per profile) and the new test_shipped_sample.
  • New, low: on the wider (ungated) public set, 3 of 226 frame-profile pairs agree below 98.5 %: nuScenes scene-0916 key-frames 11 (98.374 %) and 1 (98.499 %) on OT128, key-frame 0 (98.105 %) on QT128. They are on the same out-of-domain scene (32-beam HDL-32E, Singapore) as the binding gated frame, are consistent with its 0.41-pt margin, and are disclosed on the card. They do not touch a frozen gate. The optimization phase should add them to the frames it judges precision changes on.
  • Gates: no threshold was changed; the gate JSON gained only the four shipped-sample entries (0.985, the PLAN.md 2.8 argmax gate). No test compares TT with TT except replay == eager.
  • Samples and data: code/ ships only the two synthetic scans with their presets and references (test_only_redistributable_samples_ship); no PandaSet, nuScenes or rosbag data is tracked; the PandaSet sample lives in the git-ignored staging_samples_pandaset/. nuScenes appears only as two renders labelled non-commercial.

p150 ETH-dispatch compliance

Every path that opens the device goes through ttaw.device.open_device, whose default is DispatchCoreConfig(ETH) (falling back to WORKER only with a RuntimeWarning, or never with allow_fallback=False):

path how it opens dispatch evidence
FRNet.from_pretrained (API, quickstart, bench, profile, make_demo) ModelBase.device_config -> DeviceConfig (DEVICE_DEFAULTS < FRNET_* env < args) -> open_device eth default; FRNET_DISPATCH / dispatch= switch every run printed dispatch eth, grid 12x10, fallback None
HTTP server (tt_frnet.server.app, the container) the lifespan calls FRNet.from_pretrained with the env; serve.env pins FRNET_DISPATCH=eth, FRNET_NUM_CQS=1 eth (pinned; check_bundle.py refuses another value) served runs: /info dispatch eth, grid 12x10; smoke_test.py fails on anything else
device tests (conftest.py device fixture) tt_frnet.device.open_device(allow_fallback=False) eth, no fallback suite log
code/scripts/visualizer_report.py open_device(allow_fallback=False) eth baseline log
code/scripts/diag_conv_precision.py, diag_frame_taps.py tt_frnet.device.device_session() eth default code read
tests/test_tt_host.py ttaw.device.open_device(0, dispatch="eth") on the fake ttnn only – (no device) host suite

The grid is never hard-coded: it comes from device.compute_with_storage_grid_size() (tt/layers.py, K1 segment.py); the only 12×10 literal is the expected-grid warning in ttaw/device.py and the smoke test's assertion. The image's verify: line asserts the patch marker in tt_metal/impl/dispatch/topology.cpp.

Not covered by this pass

  • The container image: it is built and smoke-tested per serve profile (ot128, qt128) at packaging (code/scripts/container_smoke.sh), after this pass.
  • A full adversarial verification of the release (that is VERIFY_PORT.md for the port; the next full verification follows the first optimization round).
  • TensorRT parity: the reference is the fp32 ONNX Runtime run of the deployed ONNX, not Autoware's fp16 TensorRT engine.