changh95's picture
tt-model push meteor-p150 (container)
51defdc verified
Raw History Blame Contribute Delete
9.36 kB
# SPDX-License-Identifier: Apache-2.0
"""Compile-time constants of the METEOR port (``meteor_v157c3Z.onnx``, AutowareFoundation/meteor@v1.0).
Every value here is either a static shape of the deployed graph or a constant baked into it; the source of each is
the ONNX node it comes from (``research/meteor/SPEC.md``, cited as ``S:<line>``) or METEOR's runtime
(``tier4/METEOR`` @ ``dc193a81e995``, ``deploy/cpp``). Changing one of them means a different graph, a new trace and
a new image (PLAN.md section 0.4, class COMPILE). Host post-processing defaults (class RT-host) live in
``host/postprocess.py`` (``PostConfig``); load-time options (``input_norm``, ``depth_mean_bins``) in
:class:`MeteorConfig`.
"""
from __future__ import annotations
import math
from dataclasses import dataclass, field
from typing import Tuple
__all__ = [
"ONNX_FILE", "ONNX_SHA256", "PARAM_YAML", "HF_REPO", "HF_TAG", "HF_REVISION", "METEOR_UPSTREAM_COMMIT",
"CAMERAS", "N_CAMS", "IMG_H", "IMG_W", "FEAT_H", "FEAT_W", "FPN_C", "CTX_C", "BEV_C", "BEV_H", "BEV_W",
"BEV_RES", "BEV_XF", "BEV_YH", "LIFT_H", "LIFT_W", "LIFT_RES", "DET_H", "DET_W", "DET_RES", "DEPTH_BINS",
"DEPTH_MIN", "DEPTH_STEP", "DEPTH_LOG_MAX", "LANE_CLASSES", "SEG2D_CLASSES", "DET2D_CLASSES", "DET3D_CLASSES",
"OCC_CLASSES", "TL_CLASSES", "DET2D_STRIDES", "PAINT_CLASSES", "OCC_CROP", "RISK_CROP", "EGO_MODES", "EGO_STEPS",
"EGO_DT", "EGO_DIM", "TRAJ_C", "DONOR", "IMAGENET_MEAN", "IMAGENET_STD", "INPUT_NORMS", "DEPTH_MEAN_BINS",
"MeteorConfig", "default_config", "depth_bin_centres",
]
# ---- artifact pins (S:99-118) ---------------------------------------------------------------------------------------
ONNX_FILE = "meteor_v157c3Z.onnx"
ONNX_SHA256 = "50397b4df76d33df2a71e8063b38d164399255008e1f0758c2a83675a200b1a7"
PARAM_YAML = "meteor_v157.param.yaml"
HF_REPO = "AutowareFoundation/meteor"
HF_TAG = "v1.0"
HF_REVISION = "01a5f6d71df5ecbbb5853ec600825481d57b9c6b"
METEOR_UPSTREAM_COMMIT = "dc193a81e9959de57b751e269127ae9b67e3f300" # tier4/METEOR, defines pre/post (no Autoware pkg)
# ---- cameras and image branch (param.yaml:10, S:136-140) ------------------------------------------------------------
CAMERAS: Tuple[str, ...] = ("CAM_FRONT_WIDE", "CAM_FRONT_LEFT", "CAM_FRONT_RIGHT", "CAM_BACK_WIDE", "CAM_BACK_LEFT",
"CAM_BACK_RIGHT", "CAM_FRONT_NARROW", "CAM_BACK_NARROW")
N_CAMS = 8
IMG_H, IMG_W = 432, 768 # network input per camera (the graph normalises u by 767, v by 431)
FEAT_H, FEAT_W = 108, 192 # stride-4 FPN map
FPN_C = 160 # FPN width
CTX_C = 96 # painted context channels lifted to the BEV
# the absent-camera donor rule of training (bevlane/dataset.py:17-21): zero image + the donor's K and pose
DONOR = {"CAM_BACK_NARROW": "CAM_BACK_WIDE", "CAM_FRONT_NARROW": "CAM_FRONT_WIDE"}
# ---- BEV (model.py:34-47, 82-89, 877-879; S:155-160) ----------------------------------------------------------------
BEV_C = 96
BEV_H, BEV_W = 800, 500 # rows: x = +80 .. -80 m, cols: y = +50 .. -50 m
BEV_RES = 0.2
BEV_XF, BEV_YH = 80.0, 50.0 # forward extent, half width
LIFT_H, LIFT_W = 400, 250 # 0.4 m lift grid (V52, LIFT_DIV 2): x 79.8 .. -79.8, y 49.8 .. -49.8
LIFT_RES = 0.4
DET_H, DET_W = 400, 250 # 3D detection / traj / stationary / risk grids
DET_RES = 0.4
# ---- depth bins (S:325-336; SPEC section 10 risk 2) -----------------------------------------------------------------
DEPTH_BINS = 64
DEPTH_MIN, DEPTH_STEP = 1.0, 1.25 # LINEAR bins of the lift and the trained head: 1.0 + 1.25 * b metres
DEPTH_LOG_MAX = 4.378896236419678 # ln(79.75) as the float32 constant of /Div_1: depth_mean's log-spaced centres
LIFT_MIN_Z = 0.5 # camera z clamp and validity threshold
LIFT_MAX_DIST = 90.0 # validity: Euclidean range from the camera < 90 m
LIFT_BIN_CLIP = 62.9999 # clip of the continuous bin index (/net/Clip_4, float32 62.99990081787109)
LIFT_W_EPS = 0.05 # + 0.05 on the interpolated bin probability (/net/Add_10)
LIFT_DEN_EPS = 1e-4 # max(sum_n w, 1e-4) (/net/Clip_6)
# ---- heads -----------------------------------------------------------------------------------------------------
LANE_CLASSES = ("bg", "road", "sidewalk", "crosswalk", "laneline", "stopline", "road_edge", "marking", "parking")
SEG2D_CLASSES = ("bg", "obstacle", "car", "truck", "bus", "motorcycle", "bicycle", "pedestrian", "marking",
"traffic_light", "sign", "road", "sidewalk", "lane_stop_line", "crosswalk", "unused", "wall",
"building", "vegetation", "sky", "pole") # comlops-21cls-autolabel-2504.csv (0, 15 unused)
DET2D_CLASSES = ("obs", "car", "truck", "bus", "bicycle", "motorcycle", "pedestrian", "road_paint", "traffic_light",
"traffic_sign") # comlops-instance-2510.csv
DET3D_CLASSES = ("vehicle", "vru")
OCC_CLASSES = ("free", "obstacle", "vehicle", "two_wheeler", "pedestrian", "road", "sidewalk", "vegetation",
"building_wall", "pole_sign_light") # extract_occ.py:4-8; 16 z-bins of 0.4 m from -1 m
OCC_Z_BINS = 16
TL_CLASSES = ("none", "green", "yellow", "red")
DET2D_STRIDES = (4, 8, 16)
PAINT_CLASSES = (2, 3, 4, 5, 6, 7, 8, 13) # seg2d classes painted into the context (/net/Gather indices; checked)
SEG2D_CLAMP = 30.0 # +-30 clamp, ONLY before the seg2d argmax (the paint softmax is unclamped)
OCC_CROP = ((200, 600), (50, 450)) # rows, cols of the RAW BEV (/net/Slice_8, Slice_9)
RISK_CROP = ((200, 600), (125, 375)) # rows, cols of the FUSED BEV (/net/Slice_11, Slice_12)
TGATE_SCALE = 4.0 # fused = bev + tfuse(bev * 4 * softmax(tgate)[0]) (/net/Mul_12)
# ---- planner (S:315, 4.4) --------------------------------------------------------------------------------------
EGO_MODES, EGO_STEPS, EGO_DT = 3, 6, 0.5
EGO_DIM = 42 # [0:36] 3 paths x 6 x (x, y); [36:39] mode logits; 39 steer, 40 accel, 41 brake
TRAJ_C = 39 # per-cell agent futures: 3 modes x 6 x (dx, dy) + 3 mode logits
V0_SCALE = 15.0 # kin_delta input [v0 / 15, 0, ..., 0] (7 wide)
KIN_DIM = 7
DEC_SPEED_MAX = 25.0 # decoupled decoder: v = min(softplus(.), 25)
RISK_X_HALF, RISK_Y_HALF = 40.0, 25.0 # risk grid +-40 m x +-25 m at 0.2 m (400 x 250)
E2E_LN_EPS = 1e-5 # LayerNormalization(139) epsilon (float32 9.99999974738e-06)
E2E_SCALE = 3.0 # ego[:36] += 3 * tanh(mlp(LN(...)))
SEG_REFINE_CLAMP, SEG_REFINE_SCALE = 20.0, 8.0 # lane_logit = clamp(lane_pre, +-20) + 8 tanh(res / 8)
BOX_HM_CLAMP, BOX_REG_CLAMP, BOX_REFINE_SCALE = 15.0, 20.0, 6.0
# ---- input normalisation (D12; S:209-229, section 10 risk 1) ---------------------------------------------------------
IMAGENET_MEAN = (0.485, 0.456, 0.406)
IMAGENET_STD = (0.229, 0.224, 0.225)
INPUT_NORMS = ("onnx", "imagenet") # onnx: x / 255 as released (default); imagenet: (x / 255 - mean) / std
DEPTH_MEAN_BINS = ("log", "linear") # depth_mean bin centres: log as exported (default, parity) or linear (trained)
def depth_bin_centres(kind: str = "log"):
"""The 64 bin centres of ``depth_mean`` in metres: ``log`` = exp(r * ln(79.75) / 63) in float32 exactly as the
graph (/Mul_1 -> /Exp), ``linear`` = 1 + 1.25 r (the bins the head and the lift were trained with)."""
import numpy as np
r = np.arange(DEPTH_BINS, dtype=np.float32)
if kind == "log":
step = np.float32(DEPTH_LOG_MAX) / np.float32(DEPTH_BINS - 1)
return np.exp(r * step + np.float32(0.0)).astype(np.float32)
if kind == "linear":
return (np.float32(DEPTH_MIN) + np.float32(DEPTH_STEP) * r).astype(np.float32)
raise ValueError(f"depth_mean bins must be one of {DEPTH_MEAN_BINS}, not {kind!r}")
@dataclass(frozen=True)
class MeteorConfig:
"""Load-time options of the reference (and of the TT port, ``METEOR_INPUT_NORM`` / ``METEOR_DEPTH_MEAN_BINS``).
``input_norm="onnx"`` reproduces the released graph (only /255; D12 default, validated against ORT);
``"imagenet"`` adds the training normalisation after /255 (SPEC section 10 risk 1; an in-memory patched ONNX is
its oracle). ``depth_mean_bins="log"`` keeps ONNX parity, ``"linear"`` gives metric depth as trained."""
input_norm: str = "onnx"
depth_mean_bins: str = "log"
cameras: Tuple[str, ...] = field(default=CAMERAS)
def check(self) -> "MeteorConfig":
if self.input_norm not in INPUT_NORMS:
raise ValueError(f"input_norm must be one of {INPUT_NORMS}, not {self.input_norm!r}")
if self.depth_mean_bins not in DEPTH_MEAN_BINS:
raise ValueError(f"depth_mean_bins must be one of {DEPTH_MEAN_BINS}, not {self.depth_mean_bins!r}")
if tuple(self.cameras) != CAMERAS:
raise ValueError("the camera order is fixed by training (param.yaml:10)")
return self
def default_config(**overrides) -> MeteorConfig:
return MeteorConfig(**overrides).check()
# sanity: the log centres span 1 .. 79.75 m (S:183)
assert abs(math.exp(DEPTH_LOG_MAX) - 79.75) < 1e-4