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) asH*Wuint8 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..."}}
keypointsare[x, y]in pixels of the original image (the position in the 480x640 network frame timesscale), sorted by descendingscores; the rows ofdescriptorsare in the same order. Keypoints with equal scores have no fixed order: their order, and which of them are kept when they tie at themax_keypointscut, can differ between requests with differentmax_keypoints.descriptors.datais a base64 NPZ:np.load(io.BytesIO(base64.b64decode(data)))["descriptors"]gives the(N, 256)float16 rows, L2-normalised.timing_msgives the server-side stages:preprocess(base64 and image decode),device_forward(upload, device run, readback),postprocessandtotal.serving_path.device_nmsisfalsewhen 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 incode/PYTHON.md, with an example incode/examples/quickstart.py. It needs a host ttnn build of the tt-metal commit in Provenance withpatches/tt-metal-8b98410.local.patchapplied.
Example output
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
transformersimage 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_radiusthat 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
transformerspost-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
/predictandmodel()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 bytt serveat 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-Identifierheaders). The device network follows thetransformersSuperPointForKeypointDetectionmodel (huggingface/transformers, Apache-2.0), which the CPU reference incode/models/reference/loads; it contains no code of Magic Leap.code/models/common/lightweightmodule.pyis 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, andmedia/demo_keypoints.jpg(this package's keypoints drawn on it): the image is the same file asmodels/sample_data/house_in_field_1080p.jpgin 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 |
Model tree for changh95/superpoint-p150
Base model
magic-leap-community/superpoint