|
Download README.md from nynefold/retrieval-quant: direct link, hf CLI and curl.
- Browser
- Download file 16.7 kB
-
https://huggingface.co/nynefold/retrieval-quant/resolve/main/README.md
- Command line
-
hf download hf://nynefold/retrieval-quant/README.md
-
curl -L -o README.md https://huggingface.co/nynefold/retrieval-quant/resolve/main/README.md
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] | | |
|  | |
|  | |
| ## 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. | |
|  | |
| | 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. | |
|  | |
| ## 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`. | |