# SPDX-License-Identifier: Apache-2.0 # tt-model-manager container manifest (schema 5.1): METEOR (TIER IV, AutowareFoundation/meteor) on one Blackhole p150. # Conventions: research/BUNDLE_CONVENTIONS.md (workspace) -- section 3 explains every field. # # Run EVERY tt-model command FROM THIS DIRECTORY: source.tt_metal and extra_code[].root resolve against the # process CWD, not this file; --out must point OUTSIDE this directory (package deletes / first). # python -c "from tt_kernel.container_manifest import load_container_manifest as L; L('tt-model.yaml', check_sources=True)" # sg docker -c "tt-model package --container tt-model.yaml --out /home/ubuntu/experiments/tt-models/build" # (serve + smoke + stop under bin/devrun, once per serve profile: code/scripts/container_smoke.sh, SERVING.md 2) # HF_TOKEN= tt-model push /home/ubuntu/experiments/tt-models/build/meteor-p150 --publish schema: "5.1" repo: "changh95/meteor-p150" name: "meteor-p150" # A POINTER to the released METEOR network (AutowareFoundation/meteor @ v1.0; no Autoware package or ansible # artifacts role ships METEOR), never baked into the image. Pinned to the COMMIT the tag points to -- HfApi().model_info(repo, revision="v1.0").sha, not # list_repo_refs().tags[].target_commit (that is the annotated-tag object) -- because tags can move and `package` # does not resolve weights refs. `serve` / `pull --with-weights` pre-download exactly these files at this sha; the # launcher exports the sha as TT_MODEL_WEIGHTS_REVISION (and serve.env repeats it as TT_WEIGHTS_REVISION). weights: repo: "AutowareFoundation/meteor" revision: "01a5f6d71df5ecbbb5853ec600825481d57b9c6b" allow_patterns: ["meteor_v157c3Z.onnx", "meteor_v157.param.yaml", "LICENSE", "SHA256SUMS"] kind: tt-dit-server # the model's own FastAPI app under uvicorn (no vLLM); see the conventions doc arch: blackhole source: # tt-metal main 44d6650 (v0.80.0-dev20261006) WITH patches/tt-metal-eth-dispatch.patch and # patches/tt-metal-reshape-rm-sys1419.patch applied: a dirty tree, # packaged as-is (the image is built from it, so it carries ETH dispatch). torch 2.11.0 pin read from it. tt_metal: "/home/ubuntu/experiments/tt-models/tt-metal" # Schema minimum (>= 1 path relative to the tt-metal tree). The port imports nothing from tt-metal's models/. code: - models/common/lightweightmodule.py # The port itself. code/ on the Hub becomes EXACTLY this set (+ the file above) at every push, and it is # COPY'd over /opt/tt-metal/ in the image (PYTHONPATH=/opt/tt-metal) BEFORE tt-metal's C++ build and its # `uv pip install -e /opt/tt-metal`. So never list a file that tt-metal's root also has and its build reads # (pyproject.toml, setup.py, setup.cfg, MANIFEST.in, README.md, uv.toml, CMakeLists.txt, build_metal.sh, ...) or # anything under its build trees (tt_metal/, ttnn/, cmake/, tools/, ...): check_bundle.py refuses them. The pip # project is the repo-ROOT pyproject.toml (`pip install -e .`), published as an overlay file, never from here. # conftest.py is deliberate: it replaces tt-metal's root conftest.py in the builder stage, which no build step # reads, and the runtime stage never copies tt-metal's, so in the image it is the only root conftest. extra_code: - root: code paths: - "tt_meteor" - scripts - conftest.py - PYTHON.md ubuntu: "22.04" python: "3.12" runtime: app: "tt_meteor.server.app:app" mesh_shape_env: TT_MESH_SHAPE # On top of the kind defaults (fastapi, uvicorn, pydantic>=2, pillow) and the auto-pinned torch==2.11.0+cpu. # numpy stays < 2 (ttnn). Add per model: scipy, opencv-python-headless>=4.9,<4.12, ... packages: - "numpy>=1.24.4,<2" - huggingface_hub - safetensors - pyyaml - "onnx>=1.17,<2" # METEOR's host post-processing needs OpenCV (the seg-fusion warp, the rotated-box intersection of the BEV NMS; # PORT_LOG I3): tt-metal's ttnn install does not bring it. <4.12 keeps numpy < 2 (PLAN.md 6.2 step 1). - "opencv-python-headless>=4.8,<4.12" # After the first green build: copy /meteor-p150/requirements.lock next to this file, check it, and # uncomment (resolved relative to THIS file): # lock: requirements.lock serve: port: 20000 hardware: p150 mesh_device: P150 env: TT_WEIGHTS_REVISION: "01a5f6d71df5ecbbb5853ec600825481d57b9c6b" # older tt-model exports no revision; the app also reads TT_MODEL_WEIGHTS_REVISION TT_METAL_VISIBLE_DEVICES: "0" # The weights repos are public and ungated: never send a token. serve mounts the host HF cache (which may hold a # stored token file) at /hf, so tell huggingface_hub not to pick one up implicitly (PACKAGING_PILOT.md problem 10). HF_HUB_DISABLE_IMPLICIT_TOKEN: "1" # Pinned dispatch: ETH, the 12x10 grid every published number uses (D14). Profiles must not override it: # check_bundle.py refuses any *_DISPATCH other than eth, and the container smoke fails unless /info reports # dispatch=eth, grid=12x10 and these pins. "METEOR_DISPATCH": "eth" "METEOR_NUM_CQS": "1" "METEOR_VARIANT": "default" # OPTIONAL: load-time variants of ONE image as serve profiles (`tt-model serve --profile `), e.g. the # CenterPoint base / tiny pair. Each profile deep-merges over serve: (hardware / mesh_device are inherited) and is # smoke-tested on its own (`container_smoke.sh --profile `). # serve_profiles: # - name: base # description: CenterPoint (Autoware default) # env: # "METEOR_VARIANT": base # - name: tiny # description: CenterPoint-tiny # env: # "METEOR_VARIANT": tiny # default_profile: base # Build-time assertions run INSIDE the finished image as uid 1000, no device, no weights. verify: # the image must carry the ETH-dispatch patch (12x10 grid): fail the build otherwise (PLAN.md 6.2 step 1) - "assert 'single_chip_arch_1cq_no_dispatch_s' in open('/opt/tt-metal/tt_metal/impl/dispatch/topology.cpp').read()" - "from tt_meteor.ttaw.device import eth_dispatch_patch_present as p; assert p(), 'ttaw does not see the ETH patch'" # ... and the reshape patch (Blackhole SYS-1419: ETH-dispatch hang of the dual-kernel ROW_MAJOR reshape; PORT_LOG 12) - "assert 'dual_kernel_min_dram_dest_page_bytes' in open('/opt/tt-metal/ttnn/cpp/ttnn/operations/data_movement/reshape_view/device/reshape_rm_program_factory.cpp').read()" - "import tt_meteor.server.app as a; assert a.app" - "from tt_meteor.server.app import parse_mesh_shape as p; assert p('1x1') == p('(1, 1)') == p('1,1') == (1, 1)" - "import numpy; assert int(numpy.__version__.split('.')[0]) < 2, numpy.__version__" - "import onnx, yaml, huggingface_hub, safetensors, PIL, cv2" - "from tt_meteor.api import METEOR; assert METEOR.DEFAULT_REVISION == '01a5f6d71df5ecbbb5853ec600825481d57b9c6b'" - "import ttnn; assert hasattr(ttnn, 'DispatchCoreConfig') and hasattr(ttnn, 'begin_trace_capture') and hasattr(ttnn, 'execute_trace') and hasattr(ttnn, 'release_trace')" - "from pathlib import Path; assert Path('/opt/tt-metal/tt_meteor/samples/synthetic_8cam.json').is_file() and Path('/opt/tt-metal/tt_meteor/calib/synthetic_8cam.json').is_file()" # one line per custom kernel / data file the code reads with a silent fallback, e.g.: # - "from pathlib import Path; assert Path('/opt/tt-metal/tt_meteor/tt/kernels/_compute.cpp').is_file()" card: # Lede under the title of the GENERATED card (tt-model package). The published README.md is the hand-written # card of this directory (overlaid before push); keep the facts here and there identical. description: > METEOR (TIER IV; AutowareFoundation/meteor v1.0, meteor_v157c3Z.onnx), the surround-view multi-task driving network released by the Autoware Foundation, running on one Tenstorrent Blackhole p150 via tt-nn as one metal trace per frame: eight surround-view camera images (768x432 RGB, raw and unrectified) with intrinsics, camera extrinsics and the ego speed in; a BEV lane map, 3D boxes (vehicle / VRU) with stationary flags and agent futures, per-camera 2D boxes, 2D segmentation and depth, 3D occupancy, the ego-relevant traffic light, a risk field and three ego paths with steer / accel / brake out. There is no Autoware package for METEOR: pre- and post-processing follow METEOR's own runtimes (tier4/METEOR deploy/cpp). architecture: "DepthSegIPMNetV52 (v157): ResNet-34 + FPN image encoder (8 cameras as batch), image heads (21-class seg2d, 64-bin depth, 10-class det2d at strides 4/8/16, traffic light), PointPainting context, a depth-gated IPM lift to one 96-channel 800x500 BEV at 0.2 m, BEV heads (lane decoder, 3D centre-heatmap detector, occupancy, agent forecasting, stationary, risk), an ego planner (MLP + 2 attention pools + risk-aware logits + decoupled decoder) and 3 residual refiners; one static ONNX graph (opset 17, 2,021 nodes, 48.25 M parameters, 2.58 TFLOP per 8-camera frame)" status: Community port (first release; optimization pending), validated against the fp32 CPU reference on public sample data intended_use: > Camera-only multi-task perception and end-to-end planning research for eight-camera rigs laid out like TIER IV's DRS, on one Blackhole p150: a drop-in for METEOR's TensorRT runtimes on the released meteor_v157c3Z.onnx. out_of_scope_use: > Safety-critical driving decisions (METEOR is a research model; this is not a certified Autoware component and there is no Autoware node); multi-chip meshes; batch > 1; rigs far from the training rig without re-validation (other cameras run, since K and T are inputs, but lose accuracy); rectified-only camera pipelines (METEOR was trained on raw, unrectified frames). quickstart: | The first start compiles the kernels and captures the trace (minutes on a cold cache, about 45-50 s later); the server is ready when its log shows `Application startup complete`. Build a request from the shipped sample with `python3 code/tt_meteor/server/client.py --sample code/tt_meteor/samples/synthetic_8cam.json --out req.json` (your own frame: `--image NAME=PATH` x 8, `--calib rig.json`, `--ego-speed `), then `curl -s localhost:20000/predict -H 'Content-Type: application/json' -d @req.json`. usage: | `POST /predict` (JSON): `images` (all eight cameras CAM_FRONT_WIDE, CAM_FRONT_LEFT, CAM_FRONT_RIGHT, CAM_BACK_WIDE, CAM_BACK_LEFT, CAM_BACK_RIGHT, CAM_FRONT_NARROW, CAM_BACK_NARROW as base64 JPEG / PNG / .npy; an absent narrow camera as an all-zero image), `calibration` (per camera intrinsics and T_ref_from_camera, or `{"preset": name}`), `ego_speed` (m/s, required); optional `stream` (id, reset, T_world_from_ego: METEOR's host temporal state), `params` (host post-processing thresholds), `output_format`. Response: 3D BEV boxes with stationary flags and futures, the selected ego path and the plan (3 modes, steer / accel / brake), 2D boxes per camera, unknown obstacles, the traffic light, the BEV lane map (PNG), `timing_ms`. `GET /health`, `GET /info`, `GET /v1/models` (stub). Full request / response contract: `SERVING.md` section 3. performance: | One p150, ETH dispatch, 1 CQ, 12x10 grid, AICLK 1350 MHz, warm, batch 1, eight cameras (2026-10-10). | Metric | Performance | |---|---:| | Device, one frame (one metal trace, 4,678 programs) | 556.85 ms; back to back 556.75 ms (1.80 frames/s) | | Python `model()` p50, PandaSet 019 frame / shipped sample | 918.2 / 871.6 ms (upload 66.5, readback + conversion 82, host decode 124-131) | | Served `/predict` `timing_ms.total`, shipped sample | 904-909 ms; client round trip 0.92-0.93 s | | Stage PCC vs the fp32 CPU reference (26 teacher-forced gates) | >= 0.999989; lane / seg2d / depth argmax agreement 0.9984 / 0.9965 / 0.9936 | | 38 public frames (PandaSet 019 / 090, nuScenes scene-0103) vs the CPU reference | argmax agreement >= 0.9925; same plan mode and traffic light on all; path within 0.11 m; 3D boxes precision 1.0, recall 0.976 (misses at the class threshold) | | 3D boxes, gated frames (strict recall / precision) | 1.0 / 1.0 on PandaSet and nuScenes; 0.971 / 0.971 on an in-domain METEOR frame (gate 0.95) | | Shipped sample vs its stored CPU reference | 8 / 8 boxes, max score difference 0.0020, lane agreement 0.9987, path ADE 0.018 m | | ETH-dispatch stress (rig change every frame, bit-compared reads) | 2,000 + 200 frames clean | No GPU comparison (no GPU on the build host); upstream reports 67.4 ms on a Jetson AGX Orin (INT8, 2:4 sparse, not like-for-like). First release: optimization pending (OPT_REPORT.md). limitations: | - No Autoware package exists for METEOR; this is not a ROS node or a certified Autoware component. - First release: no optimization round yet (one frame replays in 556.8 ms; `model()` 0.88-0.92 s). - Needs tt-metal 44d66500520 with BOTH patches in `patches/` (ETH dispatch, and the SYS-1419 row-major reshape fix that ended an intermittent ETH-dispatch hang of this model); the image carries both. - bf16 / fp32 numerics on the chip (three-term fp32 image branch and 3D detection path, bf16 BEV trunk): outputs differ slightly from the fp32 reference; near-threshold boxes and plan modes can flip. - Released-graph behaviour kept for parity: the `/255` input normalisation (the trained ImageNet normalisation is the `input_norm="imagenet"` option) and the log-spaced `depth_mean` bins (`depth_mean_bins="linear"`). - Trained on TIER IV's eight-camera rig in Japan only: other rigs lose accuracy (depth head first). - Fixed shapes (eight 768x432 slots, 800x500 BEV), batch 1, requests serialised; one p150, no multi-chip mesh (ETH dispatch); a new calibration costs about 0.2 s once. - Validated by agreement with the fp32 CPU reference on public frames (PandaSet, nuScenes), an in-domain METEOR demo frame and the synthetic sample; no dataset-level metric (METEOR has no paper or public split). risks: > bf16 / fp32 on device: scores, boxes and plan logits differ slightly from the fp32 reference (see the agreement figures); near-threshold objects and plan modes can flip. Validated by agreement on public sample data only, not on a dataset. A research model: it must not control a vehicle. licensing: | - Weights: [AutowareFoundation/meteor](https://huggingface.co/AutowareFoundation/meteor) at tag `v1.0` (commit `01a5f6d71df5ecbbb5853ec600825481d57b9c6b`), Apache-2.0 per its model card; not redistributed here. Trained by TIER IV on its own Co-MLOps DRS recordings with auto-generated ground truth (no public training data); the AutowareFoundation/meteor-demo-scenes frames are for research and demonstration use only and are never redistributed here. - Pre-/post-processing ported from METEOR's own runtimes, tier4/METEOR `deploy/cpp` @ `dc193a81e9959de57b751e269127ae9b67e3f300` (Apache-2.0); there is no Autoware package. - Port and serving code (`code/`): Apache-2.0. - Sample data: `code/tt_meteor/samples/synthetic_8cam*` and `calib/synthetic_8cam.json`, generated by this repository, Apache-2.0. Demo media: PandaSet renders (CC BY 4.0 + PandaSet Dataset Terms, attribution in media/ATTRIBUTION.md) and nuScenes renders (CC BY-NC-SA 4.0, non-commercial, marked _NC). related: | Other Autoware models on Blackhole: the "Autoware" collection of https://huggingface.co/changh95 license: id: apache-2.0 pipeline_tag: "robotics" base_model: - "AutowareFoundation/meteor"