ONNX
quantized
retrieval
reranker
embeddings
retrieval-quant / README.md
DevNexon's picture
Add files using upload-large-folder tool
6a274a1 verified
|
Raw History Blame Contribute Delete
16.7 kB
---
license: cc-by-4.0
tags:
- onnx
- quantized
- retrieval
- reranker
- embeddings
datasets:
- nynefold/FreshRet-Small
- mteb/MIRACLReranking
---
# retrieval-quant: quantized ONNX retrievers
Four open retrieval models, two embedders and two rerankers, quantized to 4 and 8 bit for ONNX
Runtime and measured against their own FP32 versions. Every variant we built is published, failed
ones included, so the size/quality trade-off can be read from the tables below. Tested with ONNX
Runtime 1.31.
Repos: [`nynefold/pplx-embed-v1-0.6b-ONNX`](https://huggingface.co/nynefold/pplx-embed-v1-0.6b-ONNX),
[`nynefold/F2LLM-v2-1.7B-ONNX`](https://huggingface.co/nynefold/F2LLM-v2-1.7B-ONNX),
[`nynefold/Qwen3-Reranker-0.6B-ONNX`](https://huggingface.co/nynefold/Qwen3-Reranker-0.6B-ONNX),
[`nynefold/zerank-1-small-ONNX`](https://huggingface.co/nynefold/zerank-1-small-ONNX), and the evaluation set
[`nynefold/FreshRet-Small`](https://huggingface.co/datasets/nynefold/FreshRet-Small). `pipeline_example.py` in this repo
retrieves with pplx-embed and reranks with zerank, using `inference.py` (ONNX Runtime, `tokenizers`
and NumPy only). All six repos are in the collection
[retrieval-quant: quantized ONNX retrievers](https://huggingface.co/collections/nynefold/retrieval-quant-quantized-onnx-retrievers-6adb9c3a7f6012982d819511).
**Also here:** [pplx-embed-v2-late 0.6B and 9B](pplx-embed-v2-late.md), late-interaction models quantized the same way,
and how to index with the 9B and query with the 0.6B.
## Results in short
- Each model has a pick that stays within 1 nDCG@10 point of its FP32 version at **3.4 to 6x smaller**
files and **1.8 to 3.3x less RAM**.
- **pplx-embed + zerank-1-small** is the recommended pair: 0.870 nDCG@10 on FreshRet Small in 1.9 GB.
The reranker adds about 12 points over the embedder alone.
- The cheapest useful setup is **pplx-embed alone**: 0.746 in 401 MB.
- Qwen3-Reranker-0.6B adds nothing on FreshRet Small over the embedder alone, at FP32 as well as quantized.
- The two Qwen3-1.7B-based models (F2LLM, zerank) have MLP activation outliers. F2LLM needs
SmoothQuant for INT8 compute; zerank only gains a little from it at 4 bit. The 0.6B models don't
need it.
## Picks
One recommended variant per model. Size is the ONNX file; RAM is peak process memory while embedding
one 256-token passage (embedders) or scoring 20 candidates of 170 tokens (rerankers), in a process
with only ONNX Runtime, `tokenizers` and NumPy loaded. Quality deltas are paired against FP32 in nDCG@10 points, with 95%
bootstrap intervals (10,000 resamples). Picks were chosen on FreshRet Small; MIRACL ([mteb/MIRACLReranking](https://huggingface.co/datasets/mteb/MIRACLReranking)) is
the held-out check.
| model | repo | pick | size MB (FP32) | RAM MB (FP32) | FreshRet Small nDCG@10 vs FP32 | MIRACL nDCG@10 vs FP32 |
|---|---|---|---:|---:|---|---|
| pplx-embed-v1-0.6b | [`nynefold/pplx-embed-v1-0.6b-ONNX`](https://huggingface.co/nynefold/pplx-embed-v1-0.6b-ONNX) | `mix02-gptq-a4-pc` | 401 (2387) | 571 (1892) | -0.08 [-0.91, +0.74] | -0.38 [-1.38, +0.55] |
| F2LLM-v2-1.7B | [`nynefold/F2LLM-v2-1.7B-ONNX`](https://huggingface.co/nynefold/F2LLM-v2-1.7B-ONNX) | `mix50-gptq-sq50-a4` | 1629 (6885) | 1788 (5603) | +0.19 [-0.44, +0.85] | -0.38 [-1.22, +0.28] |
| Qwen3-Reranker-0.6B | [`nynefold/Qwen3-Reranker-0.6B-ONNX`](https://huggingface.co/nynefold/Qwen3-Reranker-0.6B-ONNX) | `e8-w8-rtn-a4` | 692 (2386) | 1473 (2589) | -0.02 [-0.48, +0.43] | -0.07 [-1.08, +0.89] |
| zerank-1-small | [`nynefold/zerank-1-small-ONNX`](https://huggingface.co/nynefold/zerank-1-small-ONNX) | `mix30-gptq-sq50-a4` | 1483 (6885) | 2505 (6445) | -0.30 [-0.93, +0.33] | -0.36 [-1.42, +0.54] |
![size and RAM, FP32 against the recommended variant](fig/savings.png)
![FreshRet Small nDCG@10 vs FP32 for every measured variant](fig/quality-vs-fp32.png)
## Pipelines
The embedder retrieves the top 20 from FreshRet Small, the reranker reorders them, and the top 10
are scored. All models are the quantized picks.
![nDCG@10 against total size](fig/pipeline-frontier.png)
| embedder | reranker | total MB | nDCG@10 | R@10 | MRR@10 | vs best (pt, 95% CI) |
|---|---|---:|---:|---:|---:|---|
| pplx-embed-v1-0.6b `mix02-gptq-a4-pc` | none | 401 | 0.746 | 0.898 | 0.775 | -12.57 [-14.96, -10.17] |
| pplx-embed-v1-0.6b `mix02-gptq-a4-pc` | Qwen3-Reranker-0.6B `e8-w8-rtn-a4` | 1093 | 0.735 | 0.908 | 0.747 | -13.68 [-15.95, -11.39] |
| F2LLM-v2-1.7B `mix50-gptq-sq50-a4` | none | 1629 | 0.742 | 0.891 | 0.762 | -12.98 [-15.47, -10.50] |
| pplx-embed-v1-0.6b `mix02-gptq-a4-pc` | zerank-1-small `mix30-gptq-sq50-a4` | 1885 | 0.870 | 0.935 | 0.921 | -0.16 [-1.02, +0.65] |
| F2LLM-v2-1.7B `mix50-gptq-sq50-a4` | Qwen3-Reranker-0.6B `e8-w8-rtn-a4` | 2321 | 0.737 | 0.907 | 0.750 | -13.45 [-15.58, -11.31] |
| F2LLM-v2-1.7B `mix50-gptq-sq50-a4` | zerank-1-small `mix30-gptq-sq50-a4` | 3113 | 0.872 | 0.937 | 0.922 | best |
pplx-embed + zerank: 0.870 in 1885 MB, +12.40 [+10.13, +14.69] points over pplx-embed alone (0.746,
401 MB). F2LLM + zerank scores the same within noise at 1.2 GB more. Nothing sits usefully
between the two sizes. The embedders already put about 95% of the relevant documents in their top
20, so the reranker's ordering is what moves nDCG.
**Rerank depth** (zerank pick, pplx-embed pool, vs reranking 20): 15 candidates cost 0.38 points
[-0.80, +0.01], 10 cost 1.45 [-2.30, -0.67], 5 cost 3.33. Reranking cost grows with the number of
candidates, so 15 is a reasonable saving and 10 still keeps about 11 points over the embedder alone.
On the MIRACL slice (120 queries, BM25 top-20 pools, sparse labels) neither FP32 reranker beats
pplx-embed alone; MIRACL has few judged passages per query, so FreshRet Small, fully judged, is the
set that separates the rerankers.
## Method
**Quantizer.** Our own writer for ONNX Runtime's `MatMulNBits` (linear layers) and
`GatherBlockQuantized` (token table) contrib ops, so bits, block size, algorithm and compute mode can
be set per tensor. Blocks of 32 input channels, asymmetric unless noted. Algorithms: round-to-nearest
(RTN), clip search (MSE, optionally Hessian-weighted), HQQ, and GPTQ with act-order (Hessians from a
calibration split of MIRACL dev queries).
**Mixed precision.** A sensitivity scan in PyTorch (fake-quant on cached layer inputs) estimates the
damage of putting each tensor at 4 bit. `mixNN` starts from all-4-bit and promotes the most damaging
tensors to 8 bit until NN% of the size gap to all-8-bit is spent.
**Gates.** Stage A, fidelity to FP32 on public MIRACL sets: embedders need cosine mean >= 0.99 and
p1 >= 0.97; rerankers need per-query Spearman mean >= 0.98. Stage B (embedders) and C (rerankers),
retrieval quality on FreshRet Small (300 queries, 6 languages, a third cross-lingual): nDCG@10 may
drop at most 1.0 point vs FP32. "Strict" means the whole 95% interval clears -1.0. Embedder picks
are the smallest variant passing both gates strictly. For rerankers, stage C was run on candidates
near Spearman 0.99, since 0.987 already lost 1.2 points; their picks are the smallest variant that
passed stage C strictly, and smaller variants that only just passed stage A were not measured.
FreshRet Small is never used for calibration or recipe choice.
**Sets.** Fidelity: 60 MIRACL queries + 360 passages (embedders), 360 query-passage pairs
(rerankers). Quality: FreshRet Small in full; reranker pools are its top 20 by reciprocal-rank fusion
of BM25 and both FP32 embedders. Held-out check: 120 MIRACL dev queries (20 per language: en, es,
fr, de, zh, ar) with BM25 top-20 pools. All MIRACL data is the dev split of [mteb/MIRACLReranking](https://huggingface.co/datasets/mteb/MIRACLReranking),
MTEB's reranking version of [MIRACL](https://huggingface.co/datasets/miracl/miracl); calibration,
fidelity and held-out queries are disjoint.
![fidelity against size](fig/fidelity-vs-size.png)
## What we learned
- **GPTQ is what makes 4 bit work for the 0.6B embedder.** pplx-embed at uniform 4 bit: RTN, MSE and
HQQ all land near cosine 0.90; GPTQ reaches 0.992 at the same size. The base model's own 4-bit ONNX
sits at 0.90 too.
- **Fidelity damage is uneven.** F2LLM's damage piles up in its last layers (layer 27's up-projection
alone drops cosine to 0.74); a few percent of the tensors at 8 bit fixes most of it. Qwen3-Reranker's
is spread thin, so mixing barely helps and it stays at 8 bit.
- **Per-block INT8 compute breaks F2LLM without SmoothQuant.** F2LLM at 8-bit
weights falls from cosine 0.995 to 0.977 once the activations are INT8 too; the MLP inputs have 2-3x
the outlier ratio of pplx-embed's. SmoothQuant (alpha 0.5, folded exactly into the weights) brings
it back to 0.992. zerank, the other Qwen3-1.7B model, has the same outliers but doesn't need it:
at 8-bit weights INT8 compute keeps Spearman 0.9963 with or without SmoothQuant, and at 4 bit it
raises 0.9808 to 0.9865. On pplx-embed and Qwen3-Reranker it changes nothing.
- **Stage A has to be tight for rerankers.** Spearman ~0.987 still lost 1.2 nDCG points on FreshRet
Small (zerank uniform 4 bit); ~0.990 was safe.
- **Pruning pplx-embed's vocabulary** to the tokens seen in the MIRACL corpus (six languages) saves
69 MB. It keeps every MIRACL token, so MIRACL results are unchanged by construction; on FreshRet
Small, which was not used to build it, it costs -0.29 points [-0.78, +0.22] against the unpruned
variant, -1.00 [-1.95, -0.27] on Arabic documents.
- The `a4` variants (INT8 compute) are meant for CPUs with fast INT8 instructions; `a0` variants
compute in FP32 from the quantized weights.
## All variants
Stage A fidelity for every variant; FreshRet Small quality where it was measured (finalists only).
"Below quality gate" means it failed stage A, or its nDCG@10 drop is more than 1.0 point.
"pass (estimate only)" means the estimate is within 1.0 point but the interval is not; "pass (stage A
only)" means it was not measured on FreshRet Small.
### pplx-embed-v1-0.6b
Base model [`perplexity-ai/pplx-embed-v1-0.6b`](https://huggingface.co/perplexity-ai/pplx-embed-v1-0.6b), FP32 2387 MB. Files: [`nynefold/pplx-embed-v1-0.6b-ONNX`](https://huggingface.co/nynefold/pplx-embed-v1-0.6b-ONNX).
| variant | MB | cos mean (gate 0.99) | FreshRet Small nDCG@10 vs FP32 (gate -1.0 pt) | verdict |
|---|---:|---:|---|---|
| `e4-w4-rtn-a4` | 385 | 0.9014 | | below quality gate |
| **`mix02-gptq-a4-pc`** | 401 | 0.9932 | -0.08 [-0.91, +0.74] | **pick**, pass |
| `e8-w4-rtn-b128-a4` | 419 | 0.8669 | | below quality gate |
| `e8-w4-rtn-sym-a4` | 458 | 0.8714 | | below quality gate |
| `e8-w4-gptq-a0` | 465 | 0.9922 | | pass (stage A only) |
| `e8-w4-gptq-a4` | 465 | 0.9921 | +0.19 [-0.53, +0.93] | pass |
| `e8-w4-gptq-sq50-a4` | 465 | 0.9921 | | pass (stage A only) |
| `e8-w4-mse-a4` | 465 | 0.9020 | | below quality gate |
| `e8-w4-rtn-a4` | 465 | 0.9019 | | below quality gate |
| `mix02-gptq-a4` | 470 | 0.9932 | +0.20 [-0.49, +0.90] | pass |
| `mix02-gptq-sq50-a4` | 470 | 0.9931 | | pass (stage A only) |
| `mix02-mse-a4` | 470 | 0.9837 | | below quality gate |
| `mix02-msew-a4` | 470 | 0.9860 | | below quality gate |
| `mix02-rtn-a4` | 470 | 0.9828 | | below quality gate |
| `mix10-gptq-a4` | 488 | 0.9958 | +0.06 [-0.54, +0.63] | pass |
| `mix10-mse-a4` | 488 | 0.9904 | | pass (stage A only) |
| `mix10-msew-a4` | 488 | 0.9917 | | pass (stage A only) |
| `mix10-rtn-a4` | 488 | 0.9898 | | below quality gate |
| `e8-w4-hqq-a0` | 513 | 0.9055 | | below quality gate |
| `mix30-gptq-a4` | 533 | 0.9977 | | pass (stage A only) |
| `mix30-mse-a4` | 533 | 0.9952 | | pass (stage A only) |
| `mix30-msew-a4` | 533 | 0.9958 | | pass (stage A only) |
| `mix30-rtn-a4` | 533 | 0.9949 | | pass (stage A only) |
| `e8-w8-rtn-a0` | 692 | 0.9994 | | pass (stage A only) |
| `e8-w8-rtn-a4` | 692 | 0.9993 | +0.15 [-0.05, +0.40] | pass |
| `e32-w8-rtn-a4` | 1135 | 0.9993 | | pass (stage A only) |
### F2LLM-v2-1.7B
Base model [`codefuse-ai/F2LLM-v2-1.7B`](https://huggingface.co/codefuse-ai/F2LLM-v2-1.7B), FP32 6885 MB. Files: [`nynefold/F2LLM-v2-1.7B-ONNX`](https://huggingface.co/nynefold/F2LLM-v2-1.7B-ONNX).
| variant | MB | cos mean (gate 0.99) | FreshRet Small nDCG@10 vs FP32 (gate -1.0 pt) | verdict |
|---|---:|---:|---|---|
| `e8-w4-gptq-a0` | 1266 | 0.9540 | | below quality gate |
| `e8-w4-gptq-a4` | 1266 | 0.9370 | | below quality gate |
| `e8-w4-gptq-gu0` | 1266 | 0.9508 | | below quality gate |
| `e8-w4-gptq-sq50-a4` | 1266 | 0.9490 | | below quality gate |
| `mix02-gptq-a4` | 1280 | 0.9471 | | below quality gate |
| `mix10-gptq-gu0` | 1338 | 0.9808 | | below quality gate |
| `mix30-gptq-gu0` | 1483 | 0.9872 | | below quality gate |
| `mix30-gptq-sq50-a4` | 1483 | 0.9895 | | below quality gate |
| `mix50-gptq-gu0` | 1629 | 0.9943 | | pass (stage A only) |
| **`mix50-gptq-sq50-a4`** | 1629 | 0.9922 | +0.19 [-0.44, +0.85] | **pick**, pass |
| `e8-w8-rtn-a0` | 1993 | 0.9953 | +0.33 [-0.01, +0.74] | pass |
| `e8-w8-rtn-a4` | 1993 | 0.9772 | | below quality gate |
| `w8-qkv0` | 1993 | 0.9780 | | below quality gate |
| `w8-qkvgu0` | 1993 | 0.9929 | | pass (stage A only) |
| `w8-sq50-a4` | 1993 | 0.9919 | | pass (stage A only) |
| `w8-sq75-a4` | 1993 | 0.9924 | | pass (stage A only) |
| `e32-w8-rtn-a4` | 2877 | 0.9772 | | below quality gate |
### Qwen3-Reranker-0.6B
Base model [`Qwen/Qwen3-Reranker-0.6B`](https://huggingface.co/Qwen/Qwen3-Reranker-0.6B), FP32 2386 MB. Files: [`nynefold/Qwen3-Reranker-0.6B-ONNX`](https://huggingface.co/nynefold/Qwen3-Reranker-0.6B-ONNX).
| variant | MB | Spearman mean (gate 0.98) | FreshRet Small nDCG@10 vs FP32 (gate -1.0 pt) | verdict |
|---|---:|---:|---|---|
| `e8-w4-gptq-a0` | 465 | 0.9694 | | below quality gate |
| `e8-w4-gptq-a4` | 465 | 0.9687 | | below quality gate |
| `e8-w4-gptq-sq50-a4` | 465 | 0.9657 | | below quality gate |
| `e8-w4-rtn-a4` | 465 | 0.9209 | | below quality gate |
| `mix02-gptq-a4` | 469 | 0.9700 | | below quality gate |
| `mix10-gptq-a4` | 488 | 0.9700 | | below quality gate |
| `mix30-gptq-a4` | 533 | 0.9704 | | below quality gate |
| `mix30-gptq-sq50-a4` | 533 | 0.9801 | | pass (stage A only) |
| `mix50-gptq-a4` | 578 | 0.9781 | -0.92 [-1.77, -0.11] | below quality gate |
| `mix50-gptq-sq50-a4` | 578 | 0.9785 | | below quality gate |
| `e8-w8-rtn-a0` | 692 | 0.9976 | | pass (stage A only) |
| **`e8-w8-rtn-a4`** | 692 | 0.9899 | -0.02 [-0.48, +0.43] | **pick**, pass |
### zerank-1-small
Base model [`zeroentropy/zerank-1-small-reranker`](https://huggingface.co/zeroentropy/zerank-1-small-reranker), FP32 6885 MB. Files: [`nynefold/zerank-1-small-ONNX`](https://huggingface.co/nynefold/zerank-1-small-ONNX).
| variant | MB | Spearman mean (gate 0.98) | FreshRet Small nDCG@10 vs FP32 (gate -1.0 pt) | verdict |
|---|---:|---:|---|---|
| `e8-w4-gptq-a0` | 1266 | 0.9825 | | pass (stage A only) |
| `e8-w4-gptq-a4` | 1266 | 0.9808 | | pass (stage A only) |
| `e8-w4-gptq-sq50-a4` | 1266 | 0.9865 | -1.22 [-1.91, -0.58] | below quality gate |
| `mix10-gptq-a4` | 1338 | 0.9825 | | pass (stage A only) |
| `mix10-gptq-sq50-a4` | 1338 | 0.9872 | | pass (stage A only) |
| `mix30-gptq-a4` | 1483 | 0.9875 | | pass (stage A only) |
| **`mix30-gptq-sq50-a4`** | 1483 | 0.9899 | -0.30 [-0.93, +0.33] | **pick**, pass |
| `mix50-gptq-a4` | 1629 | 0.9859 | | pass (stage A only) |
| `mix50-gptq-sq50-a4` | 1629 | 0.9899 | | pass (stage A only) |
| `e8-w8-rtn-a0` | 1993 | 0.9973 | | pass (stage A only) |
| `e8-w8-rtn-a4` | 1993 | 0.9963 | | pass (stage A only) |
| `w8-sq50-a4` | 1993 | 0.9963 | +0.14 [-0.08, +0.45] | pass |
### Variant names
| part | meaning |
|---|---|
| `e8`, `e4`, `e32` | token table at 8 bit, 4 bit, or kept FP32 |
| `w4`, `w8` | linear layers at 4 or 8 bit |
| `mixNN` | 4 bit, with the most sensitive tensors at 8 bit (NN% of the 4-to-8-bit size gap) |
| `rtn`, `mse`, `msew`, `hqq`, `gptq` | quantization algorithm (`msew` = Hessian-weighted MSE) |
| `b128`, `sym` | block size 128 (default 32); symmetric (default asymmetric) |
| `a0`, `a4` | ONNX Runtime `accuracy_level`: FP32 compute, or INT8 compute |
| `sq50`, `sq75` | SmoothQuant on the MLP inputs, alpha 0.5 / 0.75 |
| `gu0`, `qkv0`, `qkvgu0` | INT8 compute except FP32 for gate/up, q/k/v, or both |
| `pc` | vocabulary pruned to the tokens seen in the MIRACL corpus (pplx-embed) |
## Licences
The quantized models are derivatives of their base models and keep their licences: pplx-embed-v1-0.6b
MIT; F2LLM-v2-1.7B, Qwen3-Reranker-0.6B and zerank-1-small Apache-2.0. FreshRet Small is CC-BY-4.0.
## Licence of this repo
Text and figures: CC-BY-4.0. The example scripts `inference.py` and `pipeline_example.py`: MIT. See `LICENSE`.