Instructions to use guruansh/siglip2-so400m-naflex-onnx with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- TensorRT
How to use guruansh/siglip2-so400m-naflex-onnx with TensorRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
v2: fix ONNX dtype mismatch that blocked TensorRT parsing; add 5070Ti/5090 benchmarks
Browse files
README.md
CHANGED
|
@@ -19,8 +19,8 @@ An ONNX export of the **vision-encoder tail** of
|
|
| 19 |
built so the model can be compiled with **TensorRT without breaking NaFlex's
|
| 20 |
native-aspect-ratio handling**.
|
| 21 |
|
| 22 |
-
|
| 23 |
-
|
| 24 |
|
| 25 |
---
|
| 26 |
|
|
@@ -45,21 +45,23 @@ patch grid like `[36, 16]`, a square one gets `[24, 24]`. Crucially, the
|
|
| 45 |
`(B, 576, 768)`. What varies is the *value* of `spatial_shapes`, which drives a
|
| 46 |
per-image interpolation of the learned position-embedding grid.
|
| 47 |
|
| 48 |
-
That interpolation is **data-dependent control flow**
|
|
|
|
| 49 |
whichever aspect ratios happened to be in the export batch, so every other
|
| 50 |
-
aspect ratio then silently receives the wrong position embeddings
|
| 51 |
-
still runs,
|
|
|
|
| 52 |
|
| 53 |
Keeping the embeddings in PyTorch and exporting only the static tail avoids this
|
| 54 |
entirely. It costs almost nothing: the embeddings block measured **2.7% of total
|
| 55 |
runtime**.
|
| 56 |
|
| 57 |
-
**Verification.** Two
|
| 58 |
|
| 59 |
| check | result |
|
| 60 |
|---|---|
|
| 61 |
-
| split path vs full `get_image_features` | max abs diff **0.
|
| 62 |
-
| ONNX vs PyTorch on aspect ratios **not in the export batch** | cosine min **0.
|
| 63 |
|
| 64 |
The second is the one that matters — a baked-in interpolation passes on traced
|
| 65 |
shapes and fails on held-out ones.
|
|
@@ -72,7 +74,7 @@ shapes and fails on held-out ones.
|
|
| 72 |
| input | `attention_mask` | **int32** | `[batch, 576]` |
|
| 73 |
| output | `pooled` | **float16** | `[batch, 1152]` |
|
| 74 |
|
| 75 |
-
opset 17 ·
|
| 76 |
|
| 77 |
`attention_mask` is the processor's `pixel_attention_mask` (1 = real patch,
|
| 78 |
0 = padding; 551–576 of the 576 slots are typically real).
|
|
@@ -80,6 +82,7 @@ opset 17 · 2743 nodes · 854 MB · `batch` is dynamic
|
|
| 80 |
**Bind these dtypes exactly.** TensorRT's `set_tensor_address` takes a raw
|
| 81 |
pointer and performs *no* dtype checking — binding fp32 buffers to this engine
|
| 82 |
yields normal-looking latencies and non-finite outputs, with no error raised.
|
|
|
|
| 83 |
|
| 84 |
## Usage
|
| 85 |
|
|
@@ -117,11 +120,11 @@ emb = pooled / np.linalg.norm(pooled, axis=-1, keepdims=True) # L2 normalise
|
|
| 117 |
|
| 118 |
```bash
|
| 119 |
trtexec --onnx=siglip2_tail_fp16.onnx \
|
| 120 |
-
--saveEngine=
|
| 121 |
--shapes=hidden_states:8x576x1152,attention_mask:8x576
|
| 122 |
```
|
| 123 |
|
| 124 |
-
Builds in **
|
| 125 |
|
| 126 |
> A TensorRT `.plan` is compiled for **one GPU architecture, one TensorRT
|
| 127 |
> version, and one batch profile**. No engine is shipped here on purpose — this
|
|
@@ -134,35 +137,45 @@ Builds in **~56 s** on an L4.
|
|
| 134 |
SigLIP2 vision tower alone, CUDA-event timed, inputs resident on GPU,
|
| 135 |
`max_num_patches=576`. "crops/s" = images encoded per second.
|
| 136 |
|
| 137 |
-
| GPU |
|
| 138 |
-
|---|---|---|---|
|
| 139 |
-
| **
|
| 140 |
-
| **
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
|
| 142 |
-
**The
|
| 143 |
-
|
| 144 |
-
|
|
|
|
|
|
|
| 145 |
|
| 146 |
-
torch 2.7.0+cu128 · TensorRT 11.2.1.2 · transformers 5.15.1
|
| 147 |
|
| 148 |
## Accuracy
|
| 149 |
|
| 150 |
Evaluated on **1016 person crops** (COCO-derived) against **21,450**
|
| 151 |
-
image–prompt similarity scores, versus the PyTorch fp16 reference:
|
| 152 |
|
| 153 |
| | value |
|
| 154 |
|---|---|
|
| 155 |
-
| embedding cosine vs PyTorch fp16 | **
|
| 156 |
-
| mean absolute
|
| 157 |
-
|
|
| 158 |
| ranking accuracy (best positive vs best negative prompt) | **unchanged, ±0.00 pp** |
|
| 159 |
|
|
|
|
|
|
|
|
|
|
| 160 |
This is fp16 numerics throughout — not quantisation — so the residual difference
|
| 161 |
is only kernel selection and accumulation order.
|
| 162 |
|
| 163 |
-
For calibration: running the *same* fp16 maths on two different GPUs
|
| 164 |
-
|
| 165 |
-
|
| 166 |
|
| 167 |
## Limitations
|
| 168 |
|
|
@@ -171,7 +184,19 @@ is small but above that floor.
|
|
| 171 |
- Exported from **revision `cc24074f...`** of the base model.
|
| 172 |
- No text tower — encode prompts with the original model and cache them.
|
| 173 |
- Not evaluated beyond person crops; the base model's own limitations
|
| 174 |
-
(attribute binding, counting, gaze, expression) are unchanged
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
|
| 176 |
## License and attribution
|
| 177 |
|
|
|
|
| 19 |
built so the model can be compiled with **TensorRT without breaking NaFlex's
|
| 20 |
native-aspect-ratio handling**.
|
| 21 |
|
| 22 |
+
Benchmarked on four GPUs. **Up to 2.08× faster** than PyTorch fp16, with no
|
| 23 |
+
measurable accuracy loss.
|
| 24 |
|
| 25 |
---
|
| 26 |
|
|
|
|
| 45 |
`(B, 576, 768)`. What varies is the *value* of `spatial_shapes`, which drives a
|
| 46 |
per-image interpolation of the learned position-embedding grid.
|
| 47 |
|
| 48 |
+
That interpolation is **data-dependent control flow** — a Python loop calling
|
| 49 |
+
`F.interpolate` with a size read out of the tensor. Tracing it bakes in
|
| 50 |
whichever aspect ratios happened to be in the export batch, so every other
|
| 51 |
+
aspect ratio then silently receives the wrong position embeddings. The model
|
| 52 |
+
still runs, still returns finite, normalised, plausible-looking vectors. Nothing
|
| 53 |
+
errors.
|
| 54 |
|
| 55 |
Keeping the embeddings in PyTorch and exporting only the static tail avoids this
|
| 56 |
entirely. It costs almost nothing: the embeddings block measured **2.7% of total
|
| 57 |
runtime**.
|
| 58 |
|
| 59 |
+
**Verification.** Two gates, both in `export_tail.py` (`--verify`):
|
| 60 |
|
| 61 |
| check | result |
|
| 62 |
|---|---|
|
| 63 |
+
| split path vs full `get_image_features` | max abs diff **0.00000000**, cosine **0.99999988** |
|
| 64 |
+
| ONNX vs PyTorch on aspect ratios **not in the export batch** | cosine min **0.999577** |
|
| 65 |
|
| 66 |
The second is the one that matters — a baked-in interpolation passes on traced
|
| 67 |
shapes and fails on held-out ones.
|
|
|
|
| 74 |
| input | `attention_mask` | **int32** | `[batch, 576]` |
|
| 75 |
| output | `pooled` | **float16** | `[batch, 1152]` |
|
| 76 |
|
| 77 |
+
opset 17 · 854 MB · `batch` is dynamic · all 445 initializers are fp16
|
| 78 |
|
| 79 |
`attention_mask` is the processor's `pixel_attention_mask` (1 = real patch,
|
| 80 |
0 = padding; 551–576 of the 576 slots are typically real).
|
|
|
|
| 82 |
**Bind these dtypes exactly.** TensorRT's `set_tensor_address` takes a raw
|
| 83 |
pointer and performs *no* dtype checking — binding fp32 buffers to this engine
|
| 84 |
yields normal-looking latencies and non-finite outputs, with no error raised.
|
| 85 |
+
Query `engine.get_tensor_dtype()` rather than assuming.
|
| 86 |
|
| 87 |
## Usage
|
| 88 |
|
|
|
|
| 120 |
|
| 121 |
```bash
|
| 122 |
trtexec --onnx=siglip2_tail_fp16.onnx \
|
| 123 |
+
--saveEngine=engine.plan \
|
| 124 |
--shapes=hidden_states:8x576x1152,attention_mask:8x576
|
| 125 |
```
|
| 126 |
|
| 127 |
+
Builds in **51–61 s** across the GPUs tested.
|
| 128 |
|
| 129 |
> A TensorRT `.plan` is compiled for **one GPU architecture, one TensorRT
|
| 130 |
> version, and one batch profile**. No engine is shipped here on purpose — this
|
|
|
|
| 137 |
SigLIP2 vision tower alone, CUDA-event timed, inputs resident on GPU,
|
| 138 |
`max_num_patches=576`. "crops/s" = images encoded per second.
|
| 139 |
|
| 140 |
+
| GPU | arch | PyTorch fp16 | + `torch.compile` | **TensorRT (end-to-end)** | TensorRT (engine only) | speedup |
|
| 141 |
+
|---|---|---|---|---|---|---|
|
| 142 |
+
| **Tesla T4** | sm_75 | 33.7 | 36.9 | 36.8 | 37.3 | **1.09×** |
|
| 143 |
+
| **NVIDIA L4** | sm_89 | 67.0 | 70.3 | **89.7** | 91.1 | **1.34×** |
|
| 144 |
+
| **RTX 5070 Ti** | sm_120 | 52.9 | 57.2 | **109.8** | 115.0 | **2.08×** |
|
| 145 |
+
| **RTX 5090** | sm_120 | 232.9 | 263.4 | **457.1** | 497.2 | **1.96×** |
|
| 146 |
+
|
| 147 |
+
"end-to-end" includes the PyTorch NaFlex front end; "engine only" is the ONNX
|
| 148 |
+
graph alone.
|
| 149 |
|
| 150 |
+
**The benefit is strongly architecture-dependent.** On T4 TensorRT merely ties
|
| 151 |
+
`torch.compile`; on consumer Blackwell it roughly doubles throughput. Benchmark
|
| 152 |
+
on your own target rather than assuming. Note also that the RTX 5070 Ti is
|
| 153 |
+
*slower* than an L4 in plain PyTorch fp16 (52.9 vs 67.0) yet *faster* once
|
| 154 |
+
compiled with TensorRT (109.8 vs 89.7).
|
| 155 |
|
| 156 |
+
Stacks: torch 2.7.0–2.7.1 + cu128 · TensorRT 11.2.1.2 · transformers 5.15.1
|
| 157 |
|
| 158 |
## Accuracy
|
| 159 |
|
| 160 |
Evaluated on **1016 person crops** (COCO-derived) against **21,450**
|
| 161 |
+
image–prompt similarity scores, versus the PyTorch fp16 reference (L4 engine):
|
| 162 |
|
| 163 |
| | value |
|
| 164 |
|---|---|
|
| 165 |
+
| embedding cosine vs PyTorch fp16 | mean **0.999736**, min 0.997570 |
|
| 166 |
+
| mean absolute change in similarity score | **0.00058** (scores span ~0–0.24) |
|
| 167 |
+
| signed mean change | **+0.000003** — no systematic bias |
|
| 168 |
| ranking accuracy (best positive vs best negative prompt) | **unchanged, ±0.00 pp** |
|
| 169 |
|
| 170 |
+
Per-batch sanity checks on the other GPUs agreed: cosine min **0.999967**
|
| 171 |
+
(RTX 5090) and **0.999974** (RTX 5070 Ti) against PyTorch on identical inputs.
|
| 172 |
+
|
| 173 |
This is fp16 numerics throughout — not quantisation — so the residual difference
|
| 174 |
is only kernel selection and accumulation order.
|
| 175 |
|
| 176 |
+
For calibration: running the *same* fp16 maths on two different GPUs already
|
| 177 |
+
moves the scores by **0.000088** on average. The TensorRT difference is small
|
| 178 |
+
but above that floor.
|
| 179 |
|
| 180 |
## Limitations
|
| 181 |
|
|
|
|
| 184 |
- Exported from **revision `cc24074f...`** of the base model.
|
| 185 |
- No text tower — encode prompts with the original model and cache them.
|
| 186 |
- Not evaluated beyond person crops; the base model's own limitations
|
| 187 |
+
(small objects, attribute binding, counting, gaze, expression) are unchanged
|
| 188 |
+
by this export.
|
| 189 |
+
|
| 190 |
+
## Changelog
|
| 191 |
+
|
| 192 |
+
- **v2** — re-exported natively in fp16. The first upload was produced by
|
| 193 |
+
converting an fp32 export with `onnxconverter_common.float16`, which left some
|
| 194 |
+
constants as Float; TensorRT ≥ 11 is strict about mixed types and **refused to
|
| 195 |
+
parse it** (`ElementWiseOperation SUB must have same input types`). This
|
| 196 |
+
version traces directly in fp16, so all 445 initializers are fp16 and the
|
| 197 |
+
graph builds cleanly. Added RTX 5070 Ti and RTX 5090 benchmarks.
|
| 198 |
+
- **v1** — initial release (T4 and L4 benchmarks). **Do not use — TensorRT
|
| 199 |
+
cannot parse it.**
|
| 200 |
|
| 201 |
## License and attribution
|
| 202 |
|