frnet-p150 on Tenstorrent p150

Derived from AutowareFoundation/lidar_frnet (tag v2.0), the FRNet networks that TIER IV trained with AWML for Autoware's autoware_lidar_frnet LiDAR segmentation node, with unmodified weights. FRNet: Xu et al., arXiv:2312.04484. See the original model card for training details.

FRNet, a 10.0M-parameter LiDAR semantic-segmentation network (a frustum feature encoder of point-wise MLPs with a per-cell max, a frustum-range 2D CNN with four residual stages and point-pixel fusion, and a per-point head), one network per sensor: the Hesai OT128 on a 128x1024 frustum grid (about 1.25 TFLOPs per sweep at 80,000 points) and the Hesai QT128 on 128x256 (about 0.36 TFLOPs at 60,000 points), selected by serve profile. One LiDAR sweep in the sensor frame (x, y, z, raw 0-255 intensity) goes in. Out come a class id and its probability for every point (27 T4 classes) and the node's filtered-cloud mask, with the pre- and post-processing of the autoware_lidar_frnet node (ego crop box, frustum projection, Autoware's point interpolation, argmax, class filter).

Runs on Tenstorrent p150 β€” see the serving profiles below.

Packaged and published with tt-model-manager 0.1.0 (manifest schema 5.1).

At a glance

Hardware p150
License apache-2.0

Intended use

LiDAR 3D semantic segmentation for Autoware-style perception with a Hesai OT128 or QT128 sensor: research, prototyping and offline processing of recorded sweeps, with the outputs of the autoware_lidar_frnet node.

Prerequisites

  • The Tenstorrent CLI, tt: uv tool install tenstorrent (or use tt-model alone, see the Quickstart)
  • Docker
  • Tenstorrent hardware: p150

Quickstart

tt serve changh95/frnet-p150

tt serve downloads the Docker image and the AutowareFoundation/lidar_frnet at a53a1c11b0b28d31fd50a03abef5db0e830a5b3c weights (into your HF cache; they are not in the image), then starts the model's own HTTP server on port 20000 (or the next free port, if that one is busy). The first start compiles kernels for your device, which takes several minutes; the server is ready when it logs Application startup complete.

Without tt-cli: tt-model serve changh95/frnet-p150.

Send the synthetic OT128 sweep shipped in this repo to /predict, on the port tt serve reported (for the qt128 profile use synthetic_qt128.npz and the preset synthetic_qt128):

curl -sLO https://huggingface.co/changh95/frnet-p150/resolve/main/code/tt_frnet/samples/synthetic_ot128.npz
printf '{"points": {"format": "npz", "data": "%s"}, "calibration": {"preset": "synthetic_ot128"}}' "$(base64 -w0 synthetic_ot128.npz)" > req.json
curl -s localhost:20000/predict -H 'Content-Type: application/json' -d @req.json

Serving profiles

Select a different serving profile using --profile.

profile hardware mesh description
ot128 (default) p150 P150 FRNet for the Hesai OT128 (Autoware's default sensor_model; 1024x128 frustum grid)
qt128 p150 P150 FRNet for the Hesai QT128 (256x128 frustum grid, +-52.6 deg FOV)

Capabilities

This package exposes the model's own HTTP server on port 20000, not an OpenAI-compatible chat API β€” its request and response shapes are the model's own. See the author's notes for the payload it expects.

POST /predict takes one LiDAR sweep as JSON and returns a class and probability for every point. GET /health and GET /info report the server and device state (/info lists the calibration presets); GET /v1/models is a stub, not a chat API.

request field meaning
points one sweep in the sensor frame (x forward, y left, z up, metres; raw intensity), not motion-compensated: {"format": "bin" | "npy" | "npz" | "pcd", "data": "<base64 file bytes>"} (bin: float32 rows of fields, default x, y, z, intensity; npz: optional key, default points)
calibration {"T_base_link_from_sensor": <4x4 or translation + rotation>} for the ego crop box, or {"preset": "<name>"} (shipped: synthetic_ot128, synthetic_qt128); optional ego_crop_box in base_link (default Autoware's), null disables it
params (optional) class_probability_threshold (default 0.05), filter_classes (default "drivable_surface"); they change filter_keep only, never the classes
output_format (optional) json (default) or npz (adds the arrays as a lossless base64 npz)

Response for the OT128 sample (arrays are base64 npz, their data elided; class lists shortened):

{"model": "frnet-p150", "frame_id": "sensor", "num_points": 52613, "num_points_raw": 52613,
 "labels": {"format": "npz", "key": "labels", "dtype": "uint8", "shape": [52613], "data": "..."},
 "scores": {"format": "npz", "key": "scores", "dtype": "float32", "shape": [52613], "data": "..."},
 "points": {"format": "npz", "key": "points", "dtype": "float32", "shape": [52613, 4], "data": "..."},
 "filter_keep": {"format": "npz", "key": "filter_keep", "dtype": "bool", "shape": [52613], "data": "..."},
 "input_index": {"format": "npz", "key": "input_index", "dtype": "int32", "shape": [52613], "data": "..."},
 "class_names": ["drivable_surface", "other_flat_surface", "sidewalk", "manmade", "vegetation", "car", "..."],
 "class_counts": {"drivable_surface": 2927, "other_flat_surface": 20082, "sidewalk": 6, "manmade": 22903, "vegetation": 6546, "car": 13, "semi_trailer": 136, "...": 0},
 "meta": {"variant": "ot128", "num_points_input": 53411, "cropped_by_ego_box": 798, "num_points_interpolated": 0, "num_unique_coors": 52613,
          "filter": {"classes": ["drivable_surface"], "class_probability_threshold": 0.05, "kept": 44690}, "...": "..."},
 "timing_ms": {"decode": 25.078, "preprocess": 16.734, "device": 67.801, "postprocess": 3.418, "model_call": 87.992, "total": 117.089}}
  • Points are in the sensor frame. Output order is the node's: the input points that survive the ego crop box, in input order (input_index maps them back to the request rows), then the points Autoware's interpolation appends (num_points minus num_points_raw; the QT128 network adds them).
  • labels is Autoware's class_id (index into class_names), scores the softmax probability of that class, filter_keep the membership of the node's filtered cloud (~/output/pointcloud/filtered).
  • A sweep outside the profile's ranges (ot128: 5,000-160,000 points, qt128: 5,000-120,000, both at most 60,000 cells) returns 200 with num_points: 0 and the node's message in meta.skipped, as the node publishes nothing.
  • A Python API with the same outputs (tt_frnet.FRNet) is described in code/PYTHON.md; it needs a tt-metal build with the two patches in this repo's patches/ directory.

Example output

FRNet OT128 on a Tenstorrent p150: every LiDAR point coloured by its class, PandaSet sequence 090, a suburban road in daylight

Per-point classes computed by this package (ot128 profile) on 50 sweeps of PandaSet sequence 090 (El Camino Real, suburban, daylight, 10 Hz, a Pandar64 sweep inside the OT128's vertical field of view), with the front camera as an inset, also as MP4. The video was rendered with this port's initial version (same weights). Rendered from PandaSet, CC BY 4.0 and the PandaSet Dataset Terms (Scale AI and Hesai); Scale AI and Hesai do not endorse this work. Attributions for every file in media/: media/ATTRIBUTION.md.

Expected performance

Agreement with the fp32 CPU reference of the same network (ONNX Runtime on the deployed ONNX, same Autoware pre- and post-processing), on every point the node scores:

eval ot128 (default) qt128 fp32 CPU reference clouds
Points with the reference's class, shipped synthetic sample 99.53 % of 52,613 99.66 % of 69,553 – 1
Filtered-cloud mask equal to the reference, shipped synthetic sample 99.70 % 99.91 % – 1
Points with the reference's class, PandaSet 019 / 029: pooled (worst frame) 99.71 % (99.53 %) 99.35 % (98.72 %) – 32
Points with the reference's class, nuScenes mini_val: pooled (worst frame) 99.42 % (98.49 %) 99.51 % (98.49 %) – 81
Gate frames (PandaSet, nuScenes, Autoware's sample rosbag): minimum class agreement / minimum probability PCC 99.264 % / 0.99986 99.299 % / 0.99984 – 17 / 5
Held-out public frames (outside the gate set): mean / minimum class agreement, frames below 98.5 % 99.477 % / 98.494 %, 1 99.459 % / 98.495 %, 1 – 97 / 109

The public frames are PandaSet sequences 019 and 029 (every 5th frame, Pandar64) and the 81 nuScenes v1.0-mini mini_val key-frames (HDL-32E), converted to the sensor frame; no public dataset has OT128 / QT128 sweeps or the 27 T4 labels, so these rows measure agreement, not accuracy. The weights repo publishes no dataset-level accuracy to compare with.

speed (batch 1, warm) profile input median throughput
Device time per sweep, back-to-back trace replays ot128 shipped sample (52,613 points) / PandaSet sweep (107,146 points) 61.46 / 81.37 ms 16.3 / 12.3 sweeps/s
Device time per sweep, back-to-back trace replays qt128 shipped sample (69,553 points) / PandaSet sweep 43.54 / 45.02 ms 23.0 / 22.2 sweeps/s
Python model() call (pre-processing, device, post-processing) ot128 shipped sample / PandaSet sweep 94.9 / 143.3 ms 10.5 / 7.0 sweeps/s
Python model() call qt128 shipped sample / PandaSet sweep 76.7 / 93.0 ms 13.0 / 10.8 sweeps/s
Served POST /predict, server timing_ms.total ot128 / qt128 shipped sample 116.4 / 95.9 ms –
Served POST /predict, client round trip on loopback ot128 / qt128 shipped sample 134.7 / 114.9 ms –

Measured with this package's code on one p150 in an 8-vCPU AMD EPYC-Rome host: code/scripts/bench.py (50 warm iterations per stage) and 50 served requests of the sample to the package's server app run with uvicorn on the host; inside the container the server median over 350 requests of the sample was 116.8 / 96.6 ms. The model() and served times are host-bound: the host pre-processing takes 23.7 / 20.7 ms and request decoding 24.7 / 20.8 ms (ot128 / qt128).

Limitations

  • Do not use it to drive or control a vehicle or as any safety function: it is not a certified Autoware component and has no functional-safety qualification. FRNet is an opt-in Autoware node that the default perception stack does not launch.
  • Do not use its outputs as an FRNet accuracy benchmark or on other LiDARs without checking: the weights are TIER IV's fine-tune on about 16,000 frames of the non-public T4 dataset (Hesai OT128 / QT128), and accuracy on other sensors and domains is not characterized.
  • Not a ROS 2 node: it serves HTTP and Python only. Inputs are arrays or files, not PointCloud2 messages, and the filtered cloud comes back as a mask (filter_keep).
  • Batch 1, one sweep per request; requests are served one at a time; one network per process (the serve profile). A sweep runs padded to the smallest of three fixed capacities that holds it (ot128 40,000 / 80,000 / 160,000 points, qt128 29,984 / 60,000 / 120,000; at most 60,000 cells).
  • One p150 only. The image runs device dispatch on the chip's Ethernet cores, so multi-chip meshes are not supported.
  • Outputs were compared with the fp32 ONNX Runtime reference, not with the node's TensorRT engine (fp16 by default).
  • Points near a class boundary can take the other class: the device's probabilities differ slightly from the fp32 reference, and on the out-of-domain nuScenes scene-0916 one frame per profile falls just below 98.5 % class agreement (98.494 % / 98.495 %).
  • Autoware's CUDA races are replaced by fixed policies, so the output is deterministic: interpolated points are appended in row-major pixel order, and a duplicated cell keeps the last point (as ONNX Runtime does).
  • Class names 22 / 23 follow Autoware's class_names (debris / stroller); the weights were trained with stroller = 22 and debris = 23.
  • On public sensors the weights themselves (on CPU and on p150 alike) show the domain gap: with dataset labels mapped to the T4 classes, the fp32 reference reaches a coarse mIoU of 0.715 on PandaSet (Pandar64) and 0.483 on nuScenes (HDL-32E), the QT128 network 0.19 on PandaSet; traffic cones are almost never found and pedestrians next to structures often become manmade.

Licensing

  • Weights: AutowareFoundation/lidar_frnet at tag v2.0 (commit a53a1c11b0b28d31fd50a03abef5db0e830a5b3c), Apache-2.0 per its model card. Downloaded by tt serve at that commit, not redistributed here. Trained by TIER IV with AWML on the T4 dataset (about 16,000 frames); the upstream card states no further data licence notice.
  • Pre- and post-processing ported from autoware_universe perception/autoware_lidar_frnet (Apache-2.0).
  • Port and serving code (code/) and the tt-metal patches in patches/: Apache-2.0.
  • Samples code/tt_frnet/samples/synthetic_ot128.npz and synthetic_qt128.npz: synthetic scans generated by this package (code/scripts/make_sample.py, no dataset involved), Apache-2.0.
  • Demo media in media/ are renders, not part of the package. The demo video and the other PandaSet renders: CC BY 4.0 and the PandaSet Dataset Terms (Scale AI and Hesai). The nuScenes renders media/*_NC.png: non-commercial use only, CC BY-NC-SA 4.0, Β© Motional AD Inc. Neither dataset owner endorses this work. Full attributions: media/ATTRIBUTION.md.

Related packages

  • The Autoware collection: the other Autoware perception and planning models packaged for the p150.

Feedback

Questions or problems with this package: open a discussion at https://huggingface.co/changh95/frnet-p150/discussions β€” that is what reaches its author. A problem with the tt tooling itself: tt report issue (collects your environment and opens a prefilled issue against tenstorrent/tt-cli). Product feedback: [email protected].

Provenance

The exact sources the image was built from β€” code/ in this repo is byte-identical to the model code inside the image:

component built from
tt-metal 44d66500520fda9f2c7060c0f6b41ec48f7ab37e (dirty tree β€” the image includes uncommitted changes)
code/ digest 910ac5d6e69abe57 (sha256, first 16 hex digits)
built 2026-10-17T03:45:14+00:00 by tt-model 0.1.0
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for changh95/frnet-p150

Finetuned
(1)
this model

Collection including changh95/frnet-p150

Paper for changh95/frnet-p150