Download code/scripts/diag_frame_taps.py from changh95/frnet-p150: direct link, hf CLI and curl.
- Browser
- Download file 6.42 kB
-
https://huggingface.co/changh95/frnet-p150/resolve/main/code/scripts/diag_frame_taps.py
- Command line
-
hf download hf://changh95/frnet-p150/code/scripts/diag_frame_taps.py
-
curl -L -o diag_frame_taps.py https://huggingface.co/changh95/frnet-p150/resolve/main/code/scripts/diag_frame_taps.py
6.42 kB
| #!/usr/bin/env python3 | |
| # SPDX-License-Identifier: Apache-2.0 | |
| """Device diagnostic: per-module error of the device graph on one catalogued frame, next to the CPU emulation. | |
| cd bundles/frnet-p150 && bin/devrun -t 1200 -- env PYTHONPATH=code python code/scripts/diag_frame_taps.py \\ | |
| --frame nuscenes_scene-0916_40.ot128 --out /home/ubuntu/experiments/tt-models/logs/frnet/m1b/diag_0916_40.json | |
| The exact fp32 TT dataflow (``reference/rewrites.py FRNetPlanTorch``) is the reference of every tap; the CPU | |
| emulation (``--emulation``, default the ``plan_exact_points`` row of ``code/scripts/precision_study.py``: bf16 conv | |
| operands, gathers and segment tables, exact point layers) and the device ``taps`` variant (one replay; knobs from the | |
| ``FRNET_*`` environment) are compared with it tap by tap: where the device's ``1 - PCC`` grows faster than the | |
| emulation's is where the device loses accuracy that the emulation does not model. Also reported: ``pred_probs`` PCC | |
| and raw-point argmax agreement vs ONNX Runtime for the device and the emulation. The CPU work runs first (in the | |
| device lock: ~1-2 min at OT128). | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import sys | |
| import time | |
| from pathlib import Path | |
| import numpy as np | |
| HERE = Path(__file__).resolve() | |
| sys.path.insert(0, str(HERE.parents[1])) | |
| sys.path.insert(0, str(HERE.parent)) | |
| TAPS = ("encoder.pf3", "encoder.voxel_feats", "backbone.stem", "backbone.point_stem", "backbone.fusion_stem", | |
| *(f"backbone.{k}{i}" for i in range(1, 5) for k in ("layer", "point_fusion", "pixel_fusion", "attention", | |
| "stage")), | |
| "decoder.fuse1", "decoder.fuse2", "decoder.point_fuse1", "decoder.point_fuse2", | |
| *(f"head.mlp{i}" for i in range(4)), "head.logits", "pred_probs") | |
| def main() -> int: | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--frame", required=True) | |
| ap.add_argument("--out", type=Path, required=True) | |
| ap.add_argument("--emulation", default="plan_exact_points") | |
| ap.add_argument("--threads", type=int, default=4) | |
| ap.add_argument("--cpu-only", action="store_true", help="stop after the CPU part (a dry run without a device)") | |
| args = ap.parse_args() | |
| import torch | |
| torch.set_num_threads(args.threads) | |
| from precision_study import CONFIGS | |
| from tt_frnet.host.preprocess import build_plan | |
| from tt_frnet.reference.config import FRNetConfig | |
| from tt_frnet.reference.rewrites import Emulation, FRNetPlanTorch | |
| from tt_frnet.reference.weights import load_weights | |
| from tt_frnet.tests import _data | |
| from tt_frnet.ttaw.golden import TapRegistry | |
| from tt_frnet.ttaw.metrics import argmax_agreement, pcc | |
| variant = args.frame.rpartition(".")[2] | |
| wdir = _data.weights_dir() | |
| cfg = FRNetConfig.from_model_dir(wdir, variant) | |
| w = load_weights(wdir, variant) | |
| inputs, ort_probs, _ = _data.load_frame(args.frame) | |
| plan = build_plan(inputs, cfg, pre_norm=(w.pre_norm_scale, w.pre_norm_shift)) | |
| n, n_raw = plan.n, inputs.num_points_raw | |
| H, W = plan.frustum_hw | |
| t0 = time.time() | |
| exact = TapRegistry(include=list(TAPS)) | |
| FRNetPlanTorch(w)(plan, taps=exact) | |
| emu = TapRegistry(include=list(TAPS)) | |
| emu_probs = plan.unsort(FRNetPlanTorch(w, emulation=Emulation.parse(CONFIGS[args.emulation]))(plan, taps=emu)) | |
| cpu_s = time.time() - t0 | |
| def rows(name, a): | |
| """point taps: the first N sorted rows; voxel taps: the first M rows.""" | |
| a = np.asarray(a) | |
| if a.shape[0] == plan.n_cap: | |
| return a[:n] | |
| return a[: plan.m] if a.shape[0] in (cfg.m_cap, cfg.m_cap + 1) else a | |
| if args.cpu_only: | |
| ort = np.asarray(ort_probs, np.float32) | |
| print(f"cpu {cpu_s:.0f} s; emulation pred_probs pcc {pcc(emu_probs, ort):.6f} argmax " | |
| f"{argmax_agreement(emu_probs[:n_raw], ort[:n_raw]):.5f}") | |
| return 0 | |
| from tt_frnet.device import device_session | |
| from tt_frnet.tt.model import TtFRNet, build_runner, frame_arrays | |
| report = {"frame": args.frame, "N": n, "M": plan.m, "emulation": args.emulation, "cpu_s": round(cpu_s, 1), | |
| "taps": {}} | |
| with device_session() as device: | |
| graph = TtFRNet(device, w, cfg) | |
| arrays = frame_arrays(plan, cfg.m_cap) | |
| runner = build_runner(graph, variants=("taps",), name="frnet_diag", init=arrays) | |
| try: | |
| runner.capture() | |
| dev = runner("taps", inputs=arrays) | |
| report["knobs"] = graph.knobs.as_dict() | |
| for name in TAPS: | |
| if name not in dev or name not in exact: | |
| continue | |
| ref = np.asarray(exact[name], np.float32) | |
| d = np.asarray(dev[name], np.float32) | |
| if ref.ndim == 4: | |
| _, c, h, ww = ref.shape | |
| d = d.reshape(-1, d.shape[-1])[: h * ww, :c].reshape(1, h, ww, c).transpose(0, 3, 1, 2) | |
| e = np.asarray(emu[name], np.float32) | |
| else: | |
| ref = rows(name, ref)[:, : ref.shape[-1]] | |
| d = rows(name, d.reshape(-1, d.shape[-1]))[:, : ref.shape[-1]] | |
| e = rows(name, np.asarray(emu[name], np.float32))[:, : ref.shape[-1]] | |
| p_dev, p_emu = float(pcc(d, ref)), float(pcc(e, ref)) | |
| ratio = (1 - p_dev) / max(1 - p_emu, 1e-12) | |
| report["taps"][name] = {"pcc_dev": p_dev, "pcc_emu": p_emu, "err_ratio": ratio} | |
| print(f"{name:26s} dev {p_dev:.6f} emu {p_emu:.6f} (1-pcc) ratio {ratio:6.2f}", flush=True) | |
| probs = plan.unsort(np.asarray(dev["pred_probs"], np.float32).reshape(-1, 32)[:, :27]) | |
| finally: | |
| runner.release() | |
| graph.release() | |
| ort = np.asarray(ort_probs, np.float32) | |
| report["device"] = {"pred_probs_pcc": float(pcc(probs, ort)), | |
| "argmax_agreement_raw": float(argmax_agreement(probs[:n_raw], ort[:n_raw]))} | |
| report["emulation_result"] = {"pred_probs_pcc": float(pcc(emu_probs, ort)), | |
| "argmax_agreement_raw": float(argmax_agreement(emu_probs[:n_raw], ort[:n_raw]))} | |
| print("device", report["device"], "emulation", report["emulation_result"]) | |
| args.out.parent.mkdir(parents=True, exist_ok=True) | |
| args.out.write_text(json.dumps(report, indent=1)) | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |