File size: 9,428 Bytes
fe51a63 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | # SPDX-License-Identifier: Apache-2.0
"""Where the tests find data that does not ship in code/: the AutowareFoundation/lidar_frnet weights, the research
scripts and goldens of the workspace, the large module-tap goldens and the staged PandaSet sample. Outside the
tt-models workspace (the container image, a Hub clone) missing data skips the test that needs it. Inside the
workspace (``research/frnet`` exists) a missing golden, research frame or staged sample FAILS the test instead
(:func:`need`): a frozen gate must not vanish silently or run on a subset (VERIFY_PORT round 1, finding 2).
The shipped samples are the synthetic scans ``samples/synthetic_<variant>.npz`` (``code/scripts/make_sample.py``,
Apache-2.0) with the calibration presets of the same name. The PandaSet 019 frame 40 sample (CC BY 4.0 + PandaSet
Dataset Terms) does not ship until the user approves PandaSet-derived samples (PLAN.md 6.3, research/DATASETS.md N5):
it is staged in the git-ignored ``staging_samples_pandaset/`` of the bundle checkout (``$FRNET_PANDASET_DIR``
overrides; laid out like the package: ``samples/``, ``calib/``), and the frozen ``sample`` gates and the module-tap
frame still use it.
- weights: ``$FRNET_WEIGHTS_DIR``, else the workspace download ``assets/frnet/hf_lidar_frnet`` (sha256-verified,
S:frnet:84-93), else the local HF cache snapshot at the pinned revision (``local_files_only``: tests never
download);
- research: ``$FRNET_RESEARCH_DIR``, else ``research/frnet`` of the workspace (scripts, ``golden/`` VLS-128 and
synthetic goldens, ``public_data/golden/`` PandaSet / nuScenes goldens; never shipped);
- large goldens: ``$FRNET_GOLDEN_DIR``, else ``research/frnet/goldens`` (``code/scripts/make_goldens.py``).
:data:`FRAMES` is the frame catalogue shared by the tests and ``code/scripts/make_goldens.py``.
"""
from __future__ import annotations
import json
import os
import sys
from pathlib import Path
from typing import Dict, List, Optional, Tuple
import pytest
PKG_DIR = Path(__file__).resolve().parents[1]
BUNDLE_DIR = PKG_DIR.parents[1]
SAMPLES = PKG_DIR / "samples"
GOLDENS = Path(__file__).resolve().parent / "goldens"
WORKSPACE = Path(os.environ.get("TT_MODELS_ROOT", "/home/ubuntu/experiments/tt-models"))
STAGING_PANDASET = BUNDLE_DIR / "staging_samples_pandaset" # git-ignored, never shipped (PLAN.md 6.3)
def shipped(variant: str) -> Path:
"""The shipped synthetic sample of a variant (its calibration preset has the same stem)."""
return SAMPLES / f"synthetic_{variant}.npz"
def shipped_calib(variant: str) -> dict:
return {"preset": f"synthetic_{variant}"}
def _pandaset_root() -> Path:
env = os.environ.get("FRNET_PANDASET_DIR")
if env:
return Path(env)
if (SAMPLES / "pandaset_019_40.npz").is_file(): # swapped in after the user's OK
return PKG_DIR
return STAGING_PANDASET
# The PandaSet 019 f40 sample (the frozen ``sample`` gates and the module-tap frame): staged, not shipped.
PANDASET_ROOT = _pandaset_root()
SAMPLE_STEM = "pandaset_019_40"
SAMPLE_DIR = PANDASET_ROOT / "samples"
SAMPLE = SAMPLE_DIR / f"{SAMPLE_STEM}.npz"
SAMPLE_CALIB_FILE = PANDASET_ROOT / "calib" / f"{SAMPLE_STEM}.json"
# The explicit transform (not ``{"preset": ...}``: the preset is not in the package's calib/ while it is staged).
SAMPLE_CALIB = ({"T_base_link_from_sensor": json.loads(SAMPLE_CALIB_FILE.read_text())["T_base_link_from_sensor"]}
if SAMPLE_CALIB_FILE.is_file() else None)
def in_workspace() -> bool:
"""True inside the tt-models workspace, where every golden and the staged sample must be present."""
return (WORKSPACE / "research" / "frnet").is_dir()
def need(ok: bool, what: str) -> None:
"""Skip (outside the workspace) or FAIL (inside it) when ``ok`` is false: data a frozen gate needs."""
if ok:
return
if in_workspace():
pytest.fail(f"{what} is missing: inside the workspace a frozen gate must not be skipped")
pytest.skip(f"{what} is missing")
def need_pandaset() -> Path:
"""The staged PandaSet 019 f40 sample (see the module docstring); skip outside / fail inside the workspace."""
need(SAMPLE.is_file() and SAMPLE_CALIB is not None,
f"the PandaSet 019 f40 sample {SAMPLE} and its calibration {SAMPLE_CALIB_FILE} (staging_samples_pandaset/ of "
"the bundle checkout or $FRNET_PANDASET_DIR; it does not ship until the user approves PandaSet samples)")
return SAMPLE
def _first_dir(*candidates: Optional[Path]) -> Optional[Path]:
for c in candidates:
if c is not None and c.is_dir():
return c
return None
def find_weights_dir() -> Optional[Path]:
env = os.environ.get("FRNET_WEIGHTS_DIR")
found = _first_dir(Path(env) if env else None, WORKSPACE / "assets" / "frnet" / "hf_lidar_frnet")
if found is not None and (found / "frnet_ot128.onnx").is_file():
return found
try:
from huggingface_hub import snapshot_download
from tt_frnet.api import FRNet
snap = Path(snapshot_download(FRNet.DEFAULT_REPO, revision=FRNet.DEFAULT_REVISION,
allow_patterns=list(FRNet.ALLOW_PATTERNS), local_files_only=True))
if (snap / "frnet_ot128.onnx").is_file():
return snap
except Exception: # noqa: BLE001 -- not cached / no huggingface_hub: the caller skips
pass
return None
def weights_dir() -> Path:
d = find_weights_dir()
need(d is not None, "the lidar_frnet weights (FRNET_WEIGHTS_DIR, assets/frnet/hf_lidar_frnet or the HF cache)")
return d
def research_dir() -> Path:
env = os.environ.get("FRNET_RESEARCH_DIR")
d = _first_dir(Path(env) if env else None, WORKSPACE / "research" / "frnet")
need(d is not None and (d / "scripts" / "frnet_preproc_ref.py").is_file(),
"research/frnet (the research reference scripts and goldens)")
return d
def research_module(name: str):
"""Import a research script by name (``frnet_preproc_ref``, ``verify_preproc_ort_independent``, ...); their
directory is workspace code, not a download. Importing them reads no data and runs nothing."""
scripts = str(research_dir() / "scripts")
if scripts not in sys.path:
sys.path.insert(0, scripts)
import importlib
return importlib.import_module(name)
def golden_dir() -> Path:
env = os.environ.get("FRNET_GOLDEN_DIR")
d = _first_dir(Path(env) if env else None, WORKSPACE / "research" / "frnet" / "goldens")
need(d is not None, "large goldens (research/frnet/goldens; run code/scripts/make_goldens.py)")
return d
# ------------------------------------------------------------------------------------------ frame catalogue
# name -> (golden .npz relative to research/frnet, key prefix, variant). The public goldens hold the cloud handed
# to the node (raw_points), its crop transform and the four network inputs + ORT pred_probs (`autoware_` prefix);
# the VLS-128 goldens hold the x > 0 half's network inputs (no crop) + ORT pred_probs (S:frnet:361-365).
PUBLIC_OT128 = [f"pandaset_019_{f}" for f in (10, 25, 40, 55, 70)] + \
[f"pandaset_029_{f}" for f in (10, 25, 40, 55, 70)] + \
[f"nuscenes_scene-0103_{f:02d}" for f in (0, 20, 39)] + \
[f"nuscenes_scene-0916_{f:02d}" for f in (0, 20, 40)]
PUBLIC_QT128 = ["pandaset_019_40", "pandaset_029_40", "nuscenes_scene-0103_20", "nuscenes_scene-0916_20"]
def frames() -> Dict[str, Tuple[str, str, str]]:
out: Dict[str, Tuple[str, str, str]] = {}
for name in PUBLIC_OT128:
out[f"{name}.ot128"] = (f"public_data/golden/{name}_ot128.npz", "autoware_", "ot128")
for name in PUBLIC_QT128:
out[f"{name}.qt128"] = (f"public_data/golden/{name}_qt128.npz", "autoware_", "qt128")
for v in ("ot128", "qt128"):
out[f"vls128_frame000_fronthalf.{v}"] = (f"golden/vls128_frame000_fronthalf_{v}.npz", "autoware_", v)
return out
FRAMES = frames()
# The frames whose module taps are stored in full (research/frnet/goldens/<variant>/<stem>.taps.npz): the shipped
# sample in both variants.
TAP_FRAMES: List[str] = [f"{SAMPLE_STEM}.ot128", f"{SAMPLE_STEM}.qt128"]
# The hardest public frame for bf16 (research/frnet/public_data README section 3) and the densest-cell frame.
HARD_FRAMES: List[str] = ["nuscenes_scene-0916_20.ot128", "vls128_frame000_fronthalf.qt128"]
def frame_path(name: str) -> Path:
rel, _, _ = FRAMES[name]
path = research_dir() / rel
need(path.is_file(), f"golden {rel}")
return path
def load_frame(name: str):
"""``(NetworkInputs, pred_probs (N, 27) ORT, golden npz)`` of a catalogued frame (unpadded)."""
import numpy as np
from tt_frnet.host.preprocess import NetworkInputs
_, prefix, _ = FRAMES[name]
g = np.load(frame_path(name), allow_pickle=False)
n0 = len(g["raw_points"]) if "raw_points" in g.files else len(g[prefix + "points"])
keep = g[prefix + "keep_mask"] if prefix + "keep_mask" in g.files else np.ones(n0, bool)
n_raw = int(g[prefix + "num_points_raw"]) if prefix + "num_points_raw" in g.files else int(keep.sum())
inputs = NetworkInputs(points=g[prefix + "points"], coors=g[prefix + "coors"],
voxel_coors=g[prefix + "voxel_coors"], inverse_map=g[prefix + "inverse_map"],
num_points_raw=n_raw, keep_mask=keep)
return inputs, g[prefix + "pred_probs"], g
|