superpoint-p150 on Tenstorrent p150

Derived from magic-leap-community/superpoint (SuperPoint by Magic Leap), with unmodified weights at commit 734450e9. Paper: arXiv:1712.07629. Upstream code: magicleap/SuperPointPretrainedNetwork. Port: changh95/tt-superpoint. See the original model card for training details.

SuperPoint, a 1.3M-parameter self-supervised interest-point detector and descriptor: a fully-convolutional VGG-style encoder (eight 3x3 convolutions, three 2x2 max-pools) with a keypoint head (a 65-way softmax per 8x8 cell) and a 256-d descriptor head. One image goes in and is resized to 480x640; only its first channel is read. Out come keypoints in the pixel coordinates of the original image, their scores, and L2-normalised 256-d descriptors sampled at the keypoints. Non-maximum suppression (radius 4), the keypoint list and the descriptor sampling run on the device together with the network.

Runs on Tenstorrent p150 (mesh P150).

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

At a glance

Hardware p150
License Magic Leap SuperPoint licence

Intended use

Sparse keypoint detection and description for feature matching, homography and relative-pose estimation, visual odometry, SLAM and structure-from-motion research, one image at a time. The weights' licence allows only noncommercial research use (see Licensing).

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/superpoint-p150

tt serve downloads the Docker image and the magic-leap-community/superpoint at 734450e9ffe229074f5998494ddc615475cdb20a 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/superpoint-p150.

Send the sample image of this repo to /predict, on the port tt serve reported:

curl -sLO https://huggingface.co/changh95/superpoint-p150/resolve/main/code/sample_data/house_in_field_1080p.jpg
printf '{"image":"%s"}' "$(base64 -w0 house_in_field_1080p.jpg)" > req.json
curl -s localhost:20000/predict -H 'Content-Type: application/json' -d @req.json

The smoke test of this repo (Python 3 with numpy and Pillow) sends the same image to every route and checks the responses:

curl -sLO https://huggingface.co/changh95/superpoint-p150/resolve/main/code/models/server/smoke_test.py
python smoke_test.py --url http://localhost:20000 --image house_in_field_1080p.jpg

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 image as JSON and returns its keypoints, scores and descriptors. POST /predict_raw and POST /predict_plane take the image as a binary body and return the same response. GET /health and GET /info report the server and device state; GET /v1/models is a stub, not a chat API.

request field (POST /predict) meaning
image base64 PNG or JPEG, RGB or grayscale
max_keypoints (optional) keep the top k keypoints by score; -1 keeps every keypoint above the threshold; default 1024, at most 307,200
keypoint_threshold (optional) minimum score after non-maximum suppression (NMS), 0 to 1; default 0.005
nms_radius (optional) NMS radius in pixels of the 480x640 network frame, 0 (no NMS) to 32; default 4. Radii 1 to 8 run on the device; 0 and above 8 run on the host and are slower
return_descriptors (optional) default true; false leaves out descriptors
  • POST /predict_raw: the body is the PNG or JPEG file (application/octet-stream); the optional fields are query parameters.
  • POST /predict_plane?height=H&width=W: the body is the image's first channel (R of an RGB image, the gray plane of a grayscale one) as H*W uint8 bytes, row-major, which skips the image decode; the optional fields are query parameters.

Response for the sample image (code/sample_data/house_in_field_1080p.jpg, 1600x900), arrays shortened:

{"num_keypoints": 534,
 "keypoints": [[610.0, 703.125], [1042.5, 446.25], [1122.5, 442.5], ..., [512.5, 61.875]],
 "scores": [0.601562, 0.589844, 0.582031, ..., 0.005005],
 "original_size": {"height": 900, "width": 1600}, "image_size": {"height": 480, "width": 640}, "scale": {"x": 2.5, "y": 1.875},
 "params": {"max_keypoints": 1024, "keypoint_threshold": 0.005, "nms_radius": 4, "border_removal_distance": 4},
 "serving_path": {"traced": true, "device_nms": true},
 "timing_ms": {"preprocess": 27.35, "device_forward": 1.83, "postprocess": 0.23, "total": 29.42},
 "descriptors": {"format": "npz", "key": "descriptors", "dtype": "float16", "shape": [534, 256], "data": "UEsDBC0AAAAAAAAAIQArSVeD..."}}
  • keypoints are [x, y] in pixels of the original image (the position in the 480x640 network frame times scale), sorted by descending scores; the rows of descriptors are in the same order. Keypoints with equal scores have no fixed order: their order, and which of them are kept when they tie at the max_keypoints cut, can differ between requests with different max_keypoints.
  • descriptors.data is a base64 NPZ: np.load(io.BytesIO(base64.b64decode(data)))["descriptors"] gives the (N, 256) float16 rows, L2-normalised.
  • timing_ms gives the server-side stages: preprocess (base64 and image decode), device_forward (upload, device run, readback), postprocess and total. serving_path.device_nms is false when the NMS ran on the host.
  • Errors: 400 for an image that cannot be decoded, invalid base64, a plane whose size is not height*width, or a field out of range; 503 while the server is starting.
  • A Python API with the same outputs (tt_superpoint.SuperPoint) is described in code/PYTHON.md, with an example in code/examples/quickstart.py. It needs a host ttnn build of the tt-metal commit in Provenance with patches/tt-metal-8b98410.local.patch applied.

Example output

SuperPoint on a Tenstorrent p150: the 534 keypoints of the response above drawn as rings on the sample image, a house and trees by a lake with their reflection

The 534 keypoints of the response above on the sample image, scaled to 960x540; the ring colour goes from red (score 0.005) to yellow (score 0.60).

Expected performance

HPatches homography estimation and repeatability, the benchmark of the SuperPoint paper, and agreement with the upstream model run in fp32 on the CPU:

eval this package upstream model, fp32 CPU SuperPoint paper (Table 4) data
HPatches homography estimation, correct at Ξ΅ = 1 / 3 / 5 px 0.493 / 0.821 / 0.888 0.466 / 0.798 / 0.893 0.310 / 0.684 / 0.829 580 pairs
Same at Ξ΅ = 3 px, illumination / viewpoint scenes 0.905 / 0.739 0.891 / 0.708 – 285 / 295 pairs
HPatches repeatability / localisation error (Ξ΅ = 3 px) 0.604 / 1.155 px 0.612 / 1.176 px 0.581 / 1.158 px 580 pairs
Keypoints within 2 px of the upstream model's (F1, top 1000) 0.940 – – 696 images
Same, against the fp32 network with this package's post-processing 0.980 – – 696 images
Score / descriptor PCC on the keypoints found by both 0.9985 / 0.9996 – – 696 images

HPatches sequences (hpatches-sequences-release.zip of vbalnt/hpatches), all 116 scenes (57 illumination, 59 viewpoint; 696 images, 580 pairs of the first image with each other image), as in the paper's Table 4 (arXiv:1712.07629): gray images resized to 480x640, at most 1000 keypoints, nearest-neighbour matching of all descriptors and an OpenCV RANSAC homography; NMS radius 4 for every column measured here. The upstream column is transformers SuperPointForKeypointDetection with the same weights, scored with the same protocol by code/scripts/eval_hpatches.py; the weights repo publishes no benchmark figure.

speed (batch 1, warm) input median p99 throughput
Device time per image, back-to-back trace replays 480x640 network frame 0.485 ms 0.485 ms 2,060 images/s
Same, with the device resize in front 1600x900 image plane 0.546 ms 0.575 ms 1,830 images/s
Python model() call 480x640 uint8 plane 1.21 ms 1.60 ms –
Python model() call 1600x900 uint8 RGB array 2.70 ms 3.40 ms –
Python model() call, JPEG decode included the sample JPEG, 1600x900 27.2 ms 52.9 ms –
Served POST /predict, server timing_ms.total the sample JPEG, 1600x900 28.9 ms 34.9 ms –
Served POST /predict, client round trip on loopback the sample JPEG, 1600x900 35.2 ms 42.1 ms –
Served POST /predict_plane, client round trip on loopback the sample's first channel, 1600x900 7.8 ms 10.5 ms –

Measured with this package's image on one p150 in an 8-vCPU AMD EPYC-Rome host whose load average was about 6 to 9 from other jobs, with code/scripts/bench_p150.py (20 rounds of 500 trace replays for the device rows, 500 calls after 20 warm-up calls for each Python row) and code/scripts/bench_http.py (1,000 requests per served row, one at a time on one keep-alive connection); base64 and JPEG decoding on the host take about 26 ms of the served /predict request.

Limitations

  • Not for commercial use, and not for giving others access to the model or the weights: the weights' licence allows only your own noncommercial internal research use as an academic or non-profit organisation or an individual, without sublicensing or distribution (see Licensing).
  • Not for safety-critical localisation, navigation or control of vehicles, robots or drones without independent validation for that use.
  • Not a reproduction of the SuperPoint paper's evaluation: the HPatches rows use the released weights and the protocol stated under Expected performance.
  • Inference only, with these weights: no training or fine-tuning, and no other SuperPoint checkpoint was tested.
  • One image per request, batch 1, requests served one at a time. Every image is resized to 480x640 without keeping its aspect ratio, and EXIF orientation is not applied.
  • Only the first channel of an image is read (R of an RGB image), as with the default of the upstream transformers image processor: colour images are not converted to gray. The network was trained on gray images, and the HPatches rows above use gray input.
  • One p150 only (one chip): multi-chip meshes are not supported, and other boards were not tested.
  • The first request with an image size or an nms_radius that the server has not prepared builds its device variant first and is slower. Images of 640x480 need no resize; the 1280x720, 1600x900 and 1920x1080 resizes and radius 4 are prepared at startup, and at most 8 image sizes stay prepared at a time. Sizes the device resize does not cover (for example 4032x3024) are resized on the host.
  • Keypoint sets differ from the upstream fp32 model's: the device computes in bfloat16, which produces tied scores that the single-pass NMS keeps, and the NMS removes keypoints within 4 px of all four borders, where the upstream transformers post-processing removes them only near the top and left borders. Over the 696 HPatches images this package keeps 535,538 keypoints against upstream's 564,198 (top 1000), with an F1 of 0.940 within 2 px.
  • Image decoding and the host part of the post-processing run on the host CPU, so the latency of /predict and model() depends on the host's CPU and rises with its load; the device time does not.

Licensing

  • Weights: magic-leap-community/superpoint at commit 734450e9ffe229074f5998494ddc615475cdb20a, under Magic Leap's SuperPoint software licence agreement: academic or non-profit organisation noncommercial research use only, without sublicensing, distribution or third-party access. Downloaded by tt serve at that commit, not redistributed here; using this package with them is bound by those terms.
  • Port and serving code (code/): Apache-2.0 (SPDX-License-Identifier headers). The device network follows the transformers SuperPointForKeypointDetection model (huggingface/transformers, Apache-2.0), which the CPU reference in code/models/reference/ loads; it contains no code of Magic Leap. code/models/common/lightweightmodule.py is a copy from tt-metal (Apache-2.0).
  • patches/tt-metal-8b98410.local.patch: the changes the image's tt-metal carries on top of the public commit in Provenance (Blackhole dispatch on Ethernet cores, a row-major reshape fix); tt-metal is Apache-2.0.
  • code/sample_data/house_in_field_1080p.jpg, and media/demo_keypoints.jpg (this package's keypoints drawn on it): the image is the same file as models/sample_data/house_in_field_1080p.jpg in tt-metal (Apache-2.0).

Feedback

Questions or problems with this package: open a discussion at https://huggingface.co/changh95/superpoint-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: support@tenstorrent.com.

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 8b98410e730bb504fea43a88609756e34821d91d (dirty tree β€” the image includes uncommitted changes)
code/ digest d21aee876764d318 (sha256, first 16 hex digits)
built 2026-11-12T21:04:01+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/superpoint-p150

Finetuned
(1)
this model

Collection including changh95/superpoint-p150

Paper for changh95/superpoint-p150