Add files using upload-large-folder tool
Browse files- README.md +34 -144
- tt_kernel_manifest.json +2 -2
README.md
CHANGED
|
@@ -1,30 +1,16 @@
|
|
| 1 |
---
|
| 2 |
tags:
|
| 3 |
- blackhole
|
| 4 |
-
- open-vocabulary
|
| 5 |
- p150
|
| 6 |
-
- qwen2.5
|
| 7 |
-
- tenstorrent
|
| 8 |
- tt-dit-server
|
| 9 |
-
- tt-metal
|
| 10 |
- tt-model-cache
|
| 11 |
-
- tt-model-catalog
|
| 12 |
- tt-model-container
|
| 13 |
-
- tt-nn
|
| 14 |
-
- ttnn
|
| 15 |
-
- visual-grounding
|
| 16 |
-
- vlm
|
| 17 |
-
base_model:
|
| 18 |
-
- nvidia/LocateAnything-3B
|
| 19 |
-
license: other
|
| 20 |
-
license_name: nvidia-license
|
| 21 |
-
license_link: https://huggingface.co/nvidia/LocateAnything-3B/blob/main/LICENSE
|
| 22 |
-
pipeline_tag: object-detection
|
| 23 |
---
|
| 24 |
|
| 25 |
# locate-anything-3b-p150
|
| 26 |
|
| 27 |
-
NVIDIA LocateAnything-3B (MoonViT-SO-400M vision tower + Qwen2.5-3B
|
|
|
|
| 28 |
|
| 29 |
Runs on **p150** (mesh `P150`).
|
| 30 |
|
|
@@ -39,153 +25,57 @@ tt-model serve changh95/locate-anything-3b-p150
|
|
| 39 |
|
| 40 |
`pull --with-weights` downloads the Docker image and the [`nvidia/LocateAnything-3B`](https://huggingface.co/nvidia/LocateAnything-3B) weights at `c32291ca5e996f5a7a485845b4f57a233936bba0` (into your HF cache; they are not in the image). `serve` 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, and the server is ready when it logs `Application startup complete`.
|
| 41 |
|
| 42 |
-
### tt-cli
|
| 43 |
|
| 44 |
```bash
|
| 45 |
-
tt serve changh95/locate-anything-3b-p150
|
|
|
|
|
|
|
| 46 |
tt model stop changh95/locate-anything-3b-p150
|
| 47 |
```
|
| 48 |
|
| 49 |
-
|
|
|
|
| 50 |
|
| 51 |
-
###
|
| 52 |
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
| `GET /health` | `{"status": "ok" \| "starting", "model", "device"}` - `ok` only after warm-up |
|
| 60 |
-
| `GET /info` | model, weights repo + revision loaded, source commit, input limits, license |
|
| 61 |
-
| `POST /predict` | one image + one query -> labelled boxes (JSON) |
|
| 62 |
|
| 63 |
-
|
| 64 |
-
PORT=20000 # the port serve printed
|
| 65 |
-
curl -s localhost:$PORT/health
|
| 66 |
-
curl -s localhost:$PORT/info | python -m json.tool
|
| 67 |
-
|
| 68 |
-
# media/demo_input.png (1920x1080) with the README's query "car"; several categories are
|
| 69 |
-
# joined with </c>, e.g. "person</c>car". The PNG is 3.6 MB (4.8 MB as base64), far above
|
| 70 |
-
# the shell's 128 KiB per-argument limit, so an inline "$(base64 -w0 ...)" fails with
|
| 71 |
-
# "Argument list too long": write the body to a file and post it with -d @file.
|
| 72 |
-
python3 - <<'EOF'
|
| 73 |
-
import base64, json
|
| 74 |
-
img = base64.b64encode(open("media/demo_input.png", "rb").read()).decode()
|
| 75 |
-
json.dump({"image": img, "query": "car", "max_new_tokens": 128}, open("/tmp/la_req.json", "w"))
|
| 76 |
-
EOF
|
| 77 |
-
curl -s localhost:$PORT/predict -H 'Content-Type: application/json' -d @/tmp/la_req.json \
|
| 78 |
-
| python3 -m json.tool
|
| 79 |
-
```
|
| 80 |
|
| 81 |
-
|
| 82 |
-
1-1000 chars; join categories with `</c>`), `max_new_tokens` (optional, default 128, cap 1024;
|
| 83 |
-
each box costs ~6-8 tokens plus its label), `return_overlay` (optional bool; adds
|
| 84 |
-
`overlay_png_b64`, the boxes drawn on your image).
|
| 85 |
-
|
| 86 |
-
Response: `detections: [{label, box: [x1, y1, x2, y2], box_norm: [..0..1000..]}]` with `box`
|
| 87 |
-
in ORIGINAL image pixels, `points` (the model's 2-coordinate outputs, same shape), `raw_text`
|
| 88 |
-
(the generated `<ref>car</ref><box><282><414><606><794></box><|im_end|>` string for the demo image),
|
| 89 |
-
`width`/`height`, `canonical_size` and `grid_hw` (what the model actually saw, see below),
|
| 90 |
-
`prompt_tokens`, `num_generated_tokens`, `stopped_on_eos`, `decode_mode`
|
| 91 |
-
(`ar_greedy_trace`), and `timing_ms` (`vision`, `prefill`, `decode`, `total`, `decode_tok_s`).
|
| 92 |
-
Errors: 400 for a bad image / empty query / prompt too long, 503 while starting, 500 with
|
| 93 |
-
the exception text otherwise. One request at a time is served (batch 1, stateful KV cache);
|
| 94 |
-
concurrent calls queue.
|
| 95 |
-
|
| 96 |
-
A one-line check that the hardware phase also runs:
|
| 97 |
-
`python code/locate_anything/server/smoke_test.py --url http://127.0.0.1:$PORT` prints
|
| 98 |
-
`PASS ...` with the box count and timings.
|
| 99 |
-
|
| 100 |
-
### Input handling
|
| 101 |
-
|
| 102 |
-
Every image is preprocessed like the HF processor at `LA_IN_TOKEN_LIMIT=1024` (all README
|
| 103 |
-
numbers use this cap; upstream's default is 25600) and then squash-resized onto ONE canonical
|
| 104 |
-
vision grid so MoonViT is built once: by default the grid the demo image (16:9) gets at that
|
| 105 |
-
cap, 24x44 patches = 336x616 px = 264 image tokens. Boxes are normalized over that view, so
|
| 106 |
-
they map back to your original pixels exactly; non-16:9 images are distorted before the
|
| 107 |
-
model sees them. The grid is fixed for the life of the server and comes from the
|
| 108 |
-
`LA_CANON_GRID=HxW` environment variable (even numbers of 14-px patches, e.g. `32x32` for
|
| 109 |
-
square inputs). `tt-model serve` passes the container only the manifest's `serve.env`
|
| 110 |
-
(there is no `--env` flag), so this package always serves the 24x44 grid; to serve another
|
| 111 |
-
one, run the app on a host with tt-metal (see `SERVING.md`) or repackage with the variable
|
| 112 |
-
added to `serve.env` in `tt-model.yaml`.
|
| 113 |
-
|
| 114 |
-
### First boot
|
| 115 |
-
|
| 116 |
-
- `tt-model serve` downloads ~7.7 GB of weights (2 safetensors shards + tokenizer/config)
|
| 117 |
-
into your HF cache before the container starts.
|
| 118 |
-
- Inside the container the app writes a vanilla Qwen2.5-3B checkpoint (6.8 GB) to
|
| 119 |
-
`~/.cache/tt-model/locate-anything-3b-p150/weights/la-qwen2_5-3b` (once), converts the
|
| 120 |
-
LLM weights to BFP8 into `.../tensors/P150/tensor_cache_bfp8` (once), JIT-compiles kernels
|
| 121 |
-
into `.../cache` (once), uploads MoonViT and runs two warm-up passes (prefill + 4 decode
|
| 122 |
-
steps; the decode trace is captured on the first). Measured on the validation host: a
|
| 123 |
-
cold first boot is a few minutes (extraction ~5 s, BFP8 conversion ~25 s, JIT + warm-up
|
| 124 |
-
~1-2 min), later boots ~15 s; `tt-model logs -f changh95/locate-anything-3b-p150`
|
| 125 |
-
shows `Loading weights`, `Warming up`, `Warmup complete`. Host RAM peak ~10 GB.
|
| 126 |
-
- Disk: 7.7 GB (HF cache) + 6.8 GB (extracted LLM) + 4.3 GB (BFP8 tensor cache) + ~0.4 GB JIT cache.
|
| 127 |
-
- The weights repo is public and ungated; no `hf auth login` is needed for it.
|
| 128 |
-
|
| 129 |
-
### Results (from the port README; single p150a, everything on device, warm, trace decode)
|
| 130 |
-
|
| 131 |
-
| Input (`media/demo_input.png`) | Greedy AR decode (`media/demo_ar.png`) |
|
| 132 |
|:---:|:---:|
|
| 133 |
|  |  |
|
| 134 |
|
| 135 |
-
Accuracy
|
| 136 |
|
| 137 |
-
|
|
| 138 |
|---|---:|
|
| 139 |
-
|
|
| 140 |
-
|
|
| 141 |
-
|
|
| 142 |
-
| LLM prefill last-token logits | 0.9922 |
|
| 143 |
-
| **Full on-device logits (vision -> LLM)** | **0.9928** |
|
| 144 |
|
| 145 |
-
|
| 146 |
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
| End-to-end | ~2.32 frames/s |
|
| 153 |
-
|
| 154 |
-
The LLM runs BF16 attention + BFP8 MLP weights (the `accuracy` preset; BFP8 MLP is what the
|
| 155 |
-
>= 0.99 gate needs, BFP4 reaches ~0.935). Decode is weight-bandwidth bound (~3 GB/token), so
|
| 156 |
-
trace replay is the big win (7.5 -> 38 tok/s) and a second command queue is not. The
|
| 157 |
-
experimental on-device Parallel Box Decoding (MTP, `media/demo_mtp.png`) is approximate,
|
| 158 |
-
not accuracy-gated, and not served. The validated run needed one change to tt-metal's
|
| 159 |
-
`models/tt_transformers/tt/mlp.py`, and this package ships it as an overlay
|
| 160 |
-
(`code/models/tt_transformers/tt/mlp.py`, otherwise byte-identical to the stock file): in
|
| 161 |
-
single-chip decode the `w1`/`w3` outputs are moved to DRAM before the next matmul, because
|
| 162 |
-
with stock bf16 L1-sharded intermediates the `w3` weight-stream circular buffers do not fit
|
| 163 |
-
L1 on one p150a (`Statically allocated circular buffers ... clash with L1 buffers` at the
|
| 164 |
-
first decode step). Measured with the overlay on the validation host: `media/demo_input.png`
|
| 165 |
-
+ `car` -> the same box as `media/demo_ar.png`, vision 49 ms, prefill 58 ms, decode 41 tok/s,
|
| 166 |
-
346 ms end-to-end. `LA_PREC=bfp8attn` (all-BFP8 attention, PCC 0.9912) remains available.
|
| 167 |
-
|
| 168 |
-
### Layout notes
|
| 169 |
-
|
| 170 |
-
`code/locate_anything/` is the port (`tt/vision.py` MoonViT, `tt/model_la.py` the embeds-fed
|
| 171 |
-
Qwen2.5-3B `Transformer` subclass, `tt/pipeline.py` the serving recipe, `tt/mtp.py` the
|
| 172 |
-
experimental MTP decoder, `reference/` the torch-CPU reference and the LLM-checkpoint
|
| 173 |
-
extractor, `tests/` the PCC/benchmark/demo pytest suites, `server/` this app + smoke test).
|
| 174 |
-
`code/models/{common,tt_transformers,demos/qwen25_vl}` are the tt-metal packages the LLM
|
| 175 |
-
path reuses (stock Qwen2.5 `Transformer`/`Generator`/paged `Attention`), with the one
|
| 176 |
-
overlay file `models/tt_transformers/tt/mlp.py` described above. The tests need a device
|
| 177 |
-
and the torch-CPU goldens (`reference/run_reference.py`), which are not shipped.
|
| 178 |
|
| 179 |
### Licensing
|
| 180 |
|
| 181 |
-
|
| 182 |
-
https://
|
| 183 |
-
not an OSI licence; read it before any use. The weights are **not redistributed** here; they
|
| 184 |
-
are fetched from the upstream repo under whatever terms that repo sets. The **port code**
|
| 185 |
-
(Apache-2.0 SPDX headers; written by Hyunggi Chang, github.com/changh95/tt-locate-anything)
|
| 186 |
-
is published under the same upstream terms, since a port cannot grant more than its upstream
|
| 187 |
-
does. Backbone: Qwen2.5-3B-Instruct (Apache-2.0); vision tower: MoonViT (Kimi-VL, Moonshot AI);
|
| 188 |
-
runtime: Tenstorrent tt-metal / tt-nn (Apache-2.0).
|
| 189 |
|
| 190 |
## Provenance
|
| 191 |
|
|
@@ -195,5 +85,5 @@ The exact sources the image was built from — `code/` in this repo is byte-iden
|
|
| 195 |
| --- | --- |
|
| 196 |
| tt-metal | [`8b98410e730bb504fea43a88609756e34821d91d`](https://github.com/tenstorrent/tt-metal/commit/8b98410e730bb504fea43a88609756e34821d91d) |
|
| 197 |
| `code/` digest | `eb2ce7d7357c84e3` (sha256, first 16 hex digits) |
|
| 198 |
-
| built | 2026-09-
|
| 199 |
|
|
|
|
| 1 |
---
|
| 2 |
tags:
|
| 3 |
- blackhole
|
|
|
|
| 4 |
- p150
|
|
|
|
|
|
|
| 5 |
- tt-dit-server
|
|
|
|
| 6 |
- tt-model-cache
|
|
|
|
| 7 |
- tt-model-container
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
# locate-anything-3b-p150
|
| 11 |
|
| 12 |
+
NVIDIA LocateAnything-3B (Eagle-family visual grounding / open-vocabulary detection VLM: MoonViT-SO-400M vision tower + Qwen2.5-3B-Instruct with a detection vocabulary) running entirely on one Tenstorrent Blackhole p150a via tt-nn: image + free-text query in, labelled boxes out.
|
| 13 |
+
Weights: [nvidia/LocateAnything-3B](https://huggingface.co/nvidia/LocateAnything-3B) · Paper: [arXiv:2605.27365](https://arxiv.org/abs/2605.27365) · Upstream code: [NVlabs/Eagle (Embodied)](https://github.com/NVlabs/Eagle/tree/main/Embodied) · Port: [changh95/tt-locate-anything](https://github.com/changh95/tt-locate-anything)
|
| 14 |
|
| 15 |
Runs on **p150** (mesh `P150`).
|
| 16 |
|
|
|
|
| 25 |
|
| 26 |
`pull --with-weights` downloads the Docker image and the [`nvidia/LocateAnything-3B`](https://huggingface.co/nvidia/LocateAnything-3B) weights at `c32291ca5e996f5a7a485845b4f57a233936bba0` (into your HF cache; they are not in the image). `serve` 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, and the server is ready when it logs `Application startup complete`.
|
| 27 |
|
| 28 |
+
### Run with tt-cli
|
| 29 |
|
| 30 |
```bash
|
| 31 |
+
tt serve changh95/locate-anything-3b-p150
|
| 32 |
+
{ printf '{"query":"car","image":"'; base64 -w0 media/demo_input.png; printf '"}'; } > req.json
|
| 33 |
+
curl -s localhost:20000/predict -H 'Content-Type: application/json' -d @req.json
|
| 34 |
tt model stop changh95/locate-anything-3b-p150
|
| 35 |
```
|
| 36 |
|
| 37 |
+
- `POST /predict`: `image` (base64 PNG/JPEG, one image), `query` (free text, 1-1000 chars; join categories with `</c>`, e.g. `person</c>car`); optional `max_new_tokens` (128, cap 1024), `return_overlay` (false).
|
| 38 |
+
- `GET /health`, `GET /info`.
|
| 39 |
|
| 40 |
+
### Response
|
| 41 |
|
| 42 |
+
```json
|
| 43 |
+
{"query": "car", "width": 1920, "height": 1080, "canonical_size": [616, 336], "grid_hw": [24, 44],
|
| 44 |
+
"raw_text": "<ref>car</ref><box><282><414><606><794></box><|im_end|>",
|
| 45 |
+
"detections": [{"label": "car", "box": [541.44, 447.12, 1163.52, 857.52], "box_norm": [282, 414, 606, 794]}],
|
| 46 |
+
"points": [], "num_generated_tokens": 10, "stopped_on_eos": true, "decode_mode": "ar_greedy_trace",
|
| 47 |
+
"timing_ms": {"vision": 47.4, "prefill": 55.8, "decode": 224.0, "total": 343.4, "decode_tok_s": 40.17}}
|
| 48 |
+
```
|
| 49 |
|
| 50 |
+
- `box` is `[x1, y1, x2, y2]` in original image pixels; `box_norm` is the model's own 0..1000 output over the squashed `canonical_size` view. `points` holds 2-coordinate outputs the same way.
|
| 51 |
+
- `return_overlay: true` adds `overlay_png_b64`, the boxes drawn on your image as a base64 PNG.
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
+
### Demo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
+
| Input (`media/demo_input.png`), query `car` | Greedy decode on p150a (`media/demo_ar.png`) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
|:---:|:---:|
|
| 57 |
|  |  |
|
| 58 |
|
| 59 |
+
### Accuracy and speed
|
| 60 |
|
| 61 |
+
| Metric | Value |
|
| 62 |
|---|---:|
|
| 63 |
+
| Full on-device logits PCC vs torch-CPU reference (vision → LLM) | 0.9928 (gate ≥ 0.99; vision projector 0.9911, LLM prefill 0.9922) |
|
| 64 |
+
| Decoded box string on the demo image | matches the HF reference |
|
| 65 |
+
| `/predict` served over HTTP (warm, batch 1, `car`, 10 tokens) | ~343 ms server-side (vision 47 · prefill 56 · decode 224 ms, ~40 tok/s) · ~0.38 s wall |
|
|
|
|
|
|
|
| 66 |
|
| 67 |
+
### Caveats
|
| 68 |
|
| 69 |
+
- One image + one query per request, batch 1, requests are serialized. Every image is squash-resized onto a fixed 24×44-patch grid (616×336, 16:9; `LA_IN_TOKEN_LIMIT=1024`, upstream default 25600): non-16:9 images are distorted before the model sees them, boxes still map back to original pixels.
|
| 70 |
+
- bf16 vision, BF16 attention + BFP8 MLP LLM; the package ships an `mlp.py` overlay (`code/models/tt_transformers/tt/mlp.py`, decode `w1`/`w3` spilled to DRAM) so the LLM fits L1 on one p150a. Only greedy AR decode is served; the experimental Parallel Box Decoding (MTP) is not.
|
| 71 |
+
- Weights are public and ungated but under NVIDIA's own license (not OSI); ~7.7 GB download, and the first boot extracts a 6.8 GB Qwen2.5-3B checkpoint, converts it to BFP8 and JIT-compiles (~100 s cold, ~25 s afterwards).
|
| 72 |
+
- Not an OpenAI-compatible API; `GET /v1/models` is a stub so the tt-model ready card does not 404.
|
| 73 |
+
- Validated on tt-metal `v0.78.0-dev20260820` (main `8b98410e730`), single p150a only.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
### Licensing
|
| 76 |
|
| 77 |
+
- Weights: [nvidia/LocateAnything-3B](https://huggingface.co/nvidia/LocateAnything-3B), `other` ([NVIDIA license](https://huggingface.co/nvidia/LocateAnything-3B/blob/main/LICENSE), not OSI); fetched from upstream, not redistributed here.
|
| 78 |
+
- Port and serving code (`code/locate_anything`, `code/scripts`): Apache-2.0 SPDX headers, from [changh95/tt-locate-anything](https://github.com/changh95/tt-locate-anything), published under the same upstream terms; the vendored [tt-metal](https://github.com/tenstorrent/tt-metal) overlay `code/models/tt_transformers/tt/mlp.py` is Apache-2.0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
## Provenance
|
| 81 |
|
|
|
|
| 85 |
| --- | --- |
|
| 86 |
| tt-metal | [`8b98410e730bb504fea43a88609756e34821d91d`](https://github.com/tenstorrent/tt-metal/commit/8b98410e730bb504fea43a88609756e34821d91d) |
|
| 87 |
| `code/` digest | `eb2ce7d7357c84e3` (sha256, first 16 hex digits) |
|
| 88 |
+
| built | 2026-09-12T13:42:57+00:00 by tt-model 0.1.0 |
|
| 89 |
|
tt_kernel_manifest.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
| 6 |
"device_count": 1,
|
| 7 |
"producer": {
|
| 8 |
"tt_kernel_version": "0.1.0",
|
| 9 |
-
"created_at": "2026-09-
|
| 10 |
"hostname": "deepgadget"
|
| 11 |
},
|
| 12 |
"weights": {
|
|
@@ -102,7 +102,7 @@
|
|
| 102 |
"image": "tt-model/locate-anything-3b-p150:04871c7cfa03",
|
| 103 |
"repo": "changh95/locate-anything-3b-p150",
|
| 104 |
"tt_model_version": "0.1.0",
|
| 105 |
-
"created_at": "2026-09-
|
| 106 |
"tt_metal": {
|
| 107 |
"sha": "8b98410e730bb504fea43a88609756e34821d91d",
|
| 108 |
"describe": "v0.78.0-dev20260820-25-g8b98410e73",
|
|
|
|
| 6 |
"device_count": 1,
|
| 7 |
"producer": {
|
| 8 |
"tt_kernel_version": "0.1.0",
|
| 9 |
+
"created_at": "2026-09-12T13:43:23.393943+00:00",
|
| 10 |
"hostname": "deepgadget"
|
| 11 |
},
|
| 12 |
"weights": {
|
|
|
|
| 102 |
"image": "tt-model/locate-anything-3b-p150:04871c7cfa03",
|
| 103 |
"repo": "changh95/locate-anything-3b-p150",
|
| 104 |
"tt_model_version": "0.1.0",
|
| 105 |
+
"created_at": "2026-09-12T13:42:57+00:00",
|
| 106 |
"tt_metal": {
|
| 107 |
"sha": "8b98410e730bb504fea43a88609756e34821d91d",
|
| 108 |
"describe": "v0.78.0-dev20260820-25-g8b98410e73",
|