Download code/scripts/bringup.py from changh95/ptv3-p150: direct link, hf CLI and curl.
- Browser
- Download file 8.15 kB
-
https://huggingface.co/changh95/ptv3-p150/resolve/main/code/scripts/bringup.py
- Command line
-
hf download hf://changh95/ptv3-p150/code/scripts/bringup.py
-
curl -L -o bringup.py https://huggingface.co/changh95/ptv3-p150/resolve/main/code/scripts/bringup.py
8.15 kB
| # SPDX-License-Identifier: Apache-2.0 | |
| """Device bring-up of the PTv3 graph on a (cropped) frame: build the graph at a capacity bucket fitted to the frame, | |
| capture the tap variants, replay them on the frame's tables and compare every module tap with the fp32 CPU | |
| reference fed the identical host tables (PCC over the frame's real rows); optionally replay vs eager bit check. | |
| bin/devrun -t 1800 -- python code/scripts/bringup.py --crop 8 [--det] [--no-teacher] [--eager-check] | |
| PLAN.md 4.4: the first run of a new config is a small crop under ``TT_METAL_WATCHER=2``. Writes a JSON report | |
| (``--json``). Device-opening: run it through ``bin/devrun``. | |
| """ | |
| 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])) | |
| def _rows_nchw(a): | |
| a = np.asarray(a, np.float32) | |
| return a[0].transpose(1, 2, 0).reshape(-1, a.shape[1]) | |
| def compare(dev_taps, ref_taps, counts, *, det_names=()): | |
| from tt_ptv3.ttaw.metrics import error_stats | |
| out = {} | |
| for name, ref in ref_taps.items(): | |
| if name not in dev_taps: | |
| continue | |
| d = np.asarray(dev_taps[name], np.float32) | |
| r = np.asarray(ref, np.float32) | |
| if r.ndim == 4: # det NCHW maps -> rows | |
| r = _rows_nchw(r) | |
| d = d.reshape(-1, d.shape[-1]) | |
| n = r.shape[0] | |
| d = d[:n, :r.shape[1]] | |
| out[name] = {k: float(v) for k, v in error_stats(d, r).items()} | |
| return out | |
| def main(argv=None) -> int: | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--frame", default="sample") | |
| ap.add_argument("--crop", type=float, default=8.0, help="keep |x|, |y| < crop metres (0: the whole frame)") | |
| ap.add_argument("--det", action="store_true") | |
| ap.add_argument("--no-teacher", action="store_true") | |
| ap.add_argument("--qhead", action="store_true", help="also run the C26 head on the reference's dense maps") | |
| ap.add_argument("--eager-check", action="store_true") | |
| ap.add_argument("--mode", default="alias-first") | |
| ap.add_argument("--margin", type=int, default=0) | |
| ap.add_argument("--json", default=None) | |
| ap.add_argument("--threads", type=int, default=2) | |
| args = ap.parse_args(argv) | |
| from tt_ptv3.host import preprocess as pre | |
| from tt_ptv3.reference.pipeline import Reference, onnx_dir_default, set_threads | |
| from tt_ptv3.tests._data import load_frame | |
| from tt_ptv3.tt import inputs as tin | |
| set_threads(args.threads) | |
| pts = load_frame(args.frame) | |
| if args.crop > 0: | |
| keep = (np.abs(pts[:, 0]) < args.crop) & (np.abs(pts[:, 1]) < args.crop) | |
| pts = pts[keep] | |
| frame = pre.prepare_frame(pts, neighbour_mode=args.mode, capacities=None) | |
| caps = tin.fitted_capacities(frame.counts, args.margin) | |
| print(f"points {len(pts)} counts {frame.counts} caps {caps}", flush=True) | |
| t0 = time.time() | |
| ref = Reference(onnx_dir_default(), det=args.det) | |
| taps = {} | |
| res = ref.run(None, frame=frame, det=args.det, taps=taps) | |
| print(f"reference {time.time() - t0:.1f} s", flush=True) | |
| from tt_ptv3.device import close_device, describe_device, open_device | |
| from tt_ptv3.tt.model import TtPTv3, build_runner, teacher_indices, unpack_seg | |
| dev = open_device(allow_fallback=False) | |
| report = {"frame": args.frame, "crop": args.crop, "counts": frame.counts, "caps": list(caps), | |
| "device": describe_device(dev)} | |
| try: | |
| graph = TtPTv3(dev, ref.weights, det=args.det) | |
| variants = ["taps"] + (["dettaps"] + ([] if args.no_teacher else ["detteacher"]) if args.det else []) | |
| variants += ["qhead"] if (args.det and args.qhead) else [] | |
| runner = build_runner(graph, {"b": caps}, variants=variants) | |
| t0 = time.time() | |
| runner.capture() | |
| report["capture_s"] = time.time() - t0 | |
| print(f"capture {report['capture_s']:.1f} s", flush=True) | |
| inputs = {f"b.{k}": v for k, v in tin.frame_inputs(frame, caps, det=args.det).items()} | |
| if args.det and not args.no_teacher: | |
| inputs["b.topk"] = teacher_indices(taps["det.topk_indices"], graph.kp) | |
| t0 = time.time() | |
| dev_taps = runner("taps_b", inputs=inputs) | |
| report["replay_taps_s"] = time.time() - t0 | |
| seg = unpack_seg(dev_taps["seg"], frame.counts[0], caps[0]) | |
| report["seg_label_agreement"] = float((seg["labels"] == res.pred_labels).mean()) | |
| p = np.asarray(res.pred_probs, np.float64) | |
| ent = -(np.where(p > 0, p * np.log(np.where(p > 0, p, 1)), 0)).sum(1) / np.log(15) | |
| report["seg_prob_max_abs"] = float(np.abs(seg["prob"] - p.max(1)).max()) | |
| report["seg_entropy_max_abs"] = float(np.abs(seg["entropy"] - ent).max()) | |
| report["taps"] = compare(dev_taps, taps, frame.counts) | |
| if args.eager_check: | |
| eager = runner.run_eager("taps_b") | |
| eager_np = {k: np.asarray(v) for k, v in eager.items()} if isinstance(eager, dict) else eager | |
| report["replay_vs_eager_seg_equal"] = bool(np.array_equal(np.asarray(dev_taps["seg"]), | |
| np.asarray(eager_np["seg"]))) | |
| if args.det: | |
| d = runner("dettaps_b") | |
| report["det_taps"] = compare(d, taps, frame.counts) | |
| from tt_ptv3.ttaw.ops.topk import selection_metrics | |
| idx = np.rint(np.asarray(d["indices"], np.float64).reshape(-1)[:graph.num_proposals]).astype(np.int64) | |
| report["det_topk_shared"] = int(len(set(idx.tolist()) & set(taps["det.topk_indices"].tolist()))) | |
| if not args.no_teacher: | |
| t = runner("detteacher_b") | |
| rep = {"det.norm1": t["det.decoder.self_attn"], "det.norm2": t["det.decoder.cross_attn"], | |
| "det.norm3": t["det.decoder.out"]} | |
| det_out = graph.assemble({"heads": t["heads"], "query_heat": t["query_heat"], | |
| "indices": t["indices"]}) | |
| for name in ("center", "height", "dim", "rot", "vel", "heatmap"): | |
| rep[f"det.head.{name}"] = det_out[name][0].T | |
| report["det_teacher"] = compare(rep, taps, frame.counts) | |
| report["det_teacher"]["query_heatmap_score"] = compare( | |
| {"q": det_out["query_heatmap_score"][0].T}, {"q": res.det["query_heatmap_score"][0].T}, | |
| frame.counts)["q"] | |
| if args.qhead: | |
| qin = {"b.lidar": _rows_nchw(taps["det.shared"]).reshape(1, 1, -1, 128), | |
| "b.topk": teacher_indices(taps["det.topk_indices"], graph.kp)} | |
| h = np.zeros((1, 1, graph.cells, 32), np.float32) | |
| h[0, 0, :, :graph.num_det_classes] = _rows_nchw(taps["det.heat_nms"]) | |
| qin["b.heatin"] = h | |
| q = runner("qhead_b", inputs=qin) | |
| rep = {"det.norm1": q["det.decoder.self_attn"], "det.norm2": q["det.decoder.cross_attn"], | |
| "det.norm3": q["det.decoder.out"]} | |
| det_out = graph.assemble({"heads": q["heads"], "query_heat": q["query_heat"], "indices": q["indices"]}) | |
| for name in ("center", "height", "dim", "rot", "vel", "heatmap"): | |
| rep[f"det.head.{name}"] = det_out[name][0].T | |
| report["det_qhead_golden_inputs"] = compare(rep, taps, frame.counts) | |
| runner.release() | |
| finally: | |
| close_device(dev) | |
| worst = {k: v["pcc"] for k, v in report["taps"].items()} | |
| for k in sorted(worst, key=lambda k: worst[k])[:8]: | |
| print(f" {k:28s} pcc {worst[k]:.6f}") | |
| print(json.dumps({k: v for k, v in report.items() if k not in ("taps", "det_taps", "det_teacher", "det_qhead_golden_inputs")}, indent=1)) | |
| for sec in ("det_taps", "det_teacher", "det_qhead_golden_inputs"): | |
| for k, v in report.get(sec, {}).items(): | |
| print(f" {sec} {k:26s} pcc {v['pcc']:.6f} max_abs {v['max_abs']:.4g}") | |
| if args.json: | |
| Path(args.json).write_text(json.dumps(report, indent=1)) | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |