mlboydaisuke's picture
Upload README.md with huggingface_hub
42c5be7 verified
|
Raw
History Blame Contribute Delete
6.02 kB
---
license: apache-2.0
tags:
- executorch
- xnnpack
- pte
- on-device
- object-detection
- zero-shot-object-detection
base_model:
- IDEA-Research/grounding-dino-tiny
---
# Grounding DINO tiny β€” ExecuTorch (open-vocabulary detection)
You name the thing in text and it finds it. No fixed class list: the prompt is
"a person. a car. a bicycle. a dog." today and "a fire hydrant. a traffic cone."
on the next call, with the same weights.
```
(pixel_values (1,3,640,640), input_ids (1,32), token_type_ids (1,32),
attention_mask (1,32), text_masks (1,32,32), position_ids (1,32))
-> scores (1,900,256), boxes (1,900,4)
```
| build | file | MB | scores corr | boxes corr | detections agreeing | Mac ms* |
|---|---|---|---|---|---|---|
| fp32 | `grounding_dino_tiny_xnnpack_fp32.pte` | 690.3 | 0.999833 | 0.998992 | **26/26** | 584.1 |
| int8 (dynamic) | `grounding_dino_tiny_xnnpack_int8.pte` | **254.4** | 0.804530 | 0.777331 | **26/27** | 738.7 |
\*Mac arm64, single process, median of 5 β€” a reference point for relative cost, not a
device number. Torch eager fp32 on the same machine: 376.7 ms. XNNPACK delegate coverage
63.0% (3503/5559 ops) for fp32, 71.5% for int8.
**Read that int8 row carefully.** Its correlations are 0.80 and 0.78, which on any other
model on this shelf would withdraw the build. Here they are dominated by the queries that
detect nothing, whose coordinates are free to move without changing an answer β€” and the
detections themselves hold: all 26 that eager finds are found, at IoU > 0.5 with the same
prompt token, plus one box eager does not have. It is 37% of the fp32 file and it is what
you would put on a phone, but the evidence behind it is 26 detections over five
photographs, not a COCO run, and one of those 27 boxes already disagrees. It is also
slower than fp32 on this Mac (738.7 ms against 584.1).
**There is no Core ML build.** The graph reshapes to rank 6 and Core ML's ceiling is 5 β€”
the same wall RAFT-small hits with its correlation volume. This one is XNNPACK only, and
the same file runs on Android and on the Mac.
## Running it
**1. The image.** RGB, divide by 255, ImageNet normalise (mean .485/.456/.406, std
.229/.224/.225), resize to 640Γ—640.
**2. The prompt.** Lower-case phrases separated by `". "`, ending in a period. Tokenise
with the repo's tokenizer at `padding="max_length", max_length=32`. `input_ids`,
`token_type_ids` and `attention_mask` are int64 `(1,32)`.
**3. The two text tensors that are not the tokenizer's.** `text_masks` and `position_ids`
come from transformers' `generate_masks_with_special_tokens_and_transfer_map(input_ids)`
β€” the mask that keeps each phrase's tokens attending only to their own phrase. It is
built with `cummax`/`cummin`, which are not in the Core ATen opset, so it is lifted out of
the graph and passed in β€” `text_masks` is **bool** `(1,32,32)` and `position_ids` is int64
`(1,32)`, and ExecuTorch will not coerce either. Both depend on `input_ids` alone, never
on the image, so compute them once when the user types the prompt. The model stays
open-vocabulary; only the token count is fixed.
**4. Reading the answer.** `boxes` is `(cx, cy, w, h)` normalised to the input square.
`scores[0, q, t]` is how much query `q` points at text position `t`. A detection is a
query whose best score clears your threshold (0.3 is a reasonable default), and its label
is the `input_ids` token at that argmax.
Two things about that text axis. It is always 256 wide β€” the model's `max_text_len` β€” no
matter how long your prompt is, and every column past your prompt's tokens is exactly 0.
And the peak often lands on an article rather than the noun: a query for a person may
argmax on the `a` of "a person". Map the winning token back to the **phrase** it belongs
to, the way transformers' own post-processor does, rather than reading the single token
as the label.
## What is measured
The number that decides is detections, not correlation. Against eager PyTorch on five
street photographs at threshold 0.3:
**fp32 reproduces 26 of 26**, each at IoU > 0.5 with the same prompt token, and invents
nothing. That includes a photo with 17 detections in it. **int8 scores 26 of 27** β€” it
finds all of eager's and one box besides. The denominator is whichever build found more,
so an invented detection costs the same as a missed one; counting only the reference's
detections would give a build that returns every box in the image a perfect score.
```bash
python convert/audit_int8.py grounding_dino_tiny --variant fp32 # or int8
python convert/verify_cards.py grounding_dino_tiny
```
Correlation is in the table above for completeness, and the boxes figure (0.998992) is
below this shelf's usual fp32 bar of 0.999. It is not measuring what it looks like: the
largest box differences are on queries that fire at nothing, where a coordinate is free to
wander without changing any answer. The detection count is what was gated on.
### The number that had this model filed as broken
Grounding DINO writes **-inf** into every text column the prompt does not use. The score
tensor is 900 queries Γ— 256 columns; a four-phrase prompt uses 14 of them, so **94.5% of
the raw logits are -inf**. Correlation over that tensor is undefined, and subtracting two
builds gives NaN rather than a difference. Measured that way this conversion read "corr
0.857, returns the stopword 'a' where eager finds four people" and sat parked. Both halves
were artefacts: eager returns that same `a` query at the same 0.385, and the detections
were identical all along.
The shipped graph ends in a `sigmoid`, so those positions are exactly 0, the output is in
the 0..1 an app wants, and the gate measures the model instead of its padding.
- **Source**: [IDEA-Research/grounding-dino-tiny](https://huggingface.co/IDEA-Research/grounding-dino-tiny)
- **License**: Apache-2.0
torch.export -> to_edge_transform_and_lower(partitioner) -> .pte
(conversion scripts: [executorch-models](https://github.com/john-rocky/executorch-models))