zero v1 — M7 lookup table, run p35w-2m-s2500
Browse files- README.md +37 -4
- config.json +25 -0
- tokenizer.json +0 -0
- tokenizer_config.json +59 -59
- zero_encoder.py +1 -1
README.md
CHANGED
|
@@ -87,7 +87,8 @@ client.upsert("docs", points=[
|
|
| 87 |
models.PointStruct(id=i, vector=D[i].tolist(), payload={"text": t})
|
| 88 |
for i, t in enumerate(docs)]) # D from the document encoder above
|
| 89 |
|
| 90 |
-
hits = client.query_points("docs", query=
|
|
|
|
| 91 |
```
|
| 92 |
|
| 93 |
**On the edge, put the table in the store too.** A second collection holds one point per vocab
|
|
@@ -99,7 +100,8 @@ tokenize → fetch rows by id → pool → search, with no model weights in your
|
|
| 99 |
uses **convex score fusion at w=0.8**, not RRF: on development sets RRF scored 0.5504 against
|
| 100 |
convex's 0.5727. Qdrant's native `Fusion.RRF` is therefore a *different, weaker* operating point,
|
| 101 |
not the published one — combine the scores yourself to reproduce it. Dense-only in Qdrant
|
| 102 |
-
reproduces 0.4339 exactly
|
|
|
|
| 103 |
|
| 104 |
Scalar-quantizing the document index to int8 halves it to ~1.02 GB per 1M vectors, but **that
|
| 105 |
was never measured for quality here** — treat it as untested. (The int8 quality-free result
|
|
@@ -111,7 +113,7 @@ Tokenize with the bundled WordPiece tokenizer (`add_special_tokens=True`, trunca
|
|
| 111 |
**no padding**, no prefix). A token appearing `c` times in the query carries **total weight
|
| 112 |
`sqrt(c)`**, not `c`. Sum the rows, divide by the weight sum, L2-normalize. An empty or
|
| 113 |
near-zero-norm bag falls back to the normalized `[CLS]` row (id **101**; row 0 is `[PAD]`).
|
| 114 |
-
`zero_encoder.py` is
|
| 115 |
fingerprint (`adb24fb2e8cad66f`).
|
| 116 |
|
| 117 |
## Files
|
|
@@ -121,7 +123,27 @@ fingerprint (`adb24fb2e8cad66f`).
|
|
| 121 |
| `model.npz` | `rows_int8` (30522×1024) + `int8_scale`, and `rows_fp16` for reference |
|
| 122 |
| `config.json` | the frozen preprocessing rule, teacher pin, document-encoder spec, shas |
|
| 123 |
| `zero_encoder.py` | the whole query path — numpy + tokenizers, no torch |
|
| 124 |
-
| `tokenizer.json`, `vocab.txt`, … | stella's WordPiece tokenizer, copied at the pinned revision |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
|
| 126 |
Per-token learned weights are **folded into the rows**, so the int8 artifact is self-contained.
|
| 127 |
`int8` is the variant every published number below was measured on; it was measured
|
|
@@ -193,6 +215,17 @@ still misses the bar. The gap is architectural, not licensing.)
|
|
| 193 |
NQ, SQuAD, HotpotQA, FEVER and Mr. TyDi derive from Wikipedia and are **CC BY-SA** (3.0/4.0).
|
| 194 |
Amazon ESCI is Apache-2.0. The teacher, `NovaSearch/stella_en_400M_v5`, is MIT.
|
| 195 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
## Citation / provenance
|
| 197 |
|
| 198 |
```
|
|
|
|
| 87 |
models.PointStruct(id=i, vector=D[i].tolist(), payload={"text": t})
|
| 88 |
for i, t in enumerate(docs)]) # D from the document encoder above
|
| 89 |
|
| 90 |
+
hits = client.query_points("docs", query=q[0].tolist(), limit=5).points
|
| 91 |
+
print(hits[0].payload["text"]) # q is the (1, 1024) array from Usage above
|
| 92 |
```
|
| 93 |
|
| 94 |
**On the edge, put the table in the store too.** A second collection holds one point per vocab
|
|
|
|
| 100 |
uses **convex score fusion at w=0.8**, not RRF: on development sets RRF scored 0.5504 against
|
| 101 |
convex's 0.5727. Qdrant's native `Fusion.RRF` is therefore a *different, weaker* operating point,
|
| 102 |
not the published one — combine the scores yourself to reproduce it. Dense-only in Qdrant
|
| 103 |
+
reproduces 0.4339 exactly **with exact search** — the HNSW advice above is about cost, and ANN
|
| 104 |
+
recall is a separate confound the published numbers deliberately avoid.
|
| 105 |
|
| 106 |
Scalar-quantizing the document index to int8 halves it to ~1.02 GB per 1M vectors, but **that
|
| 107 |
was never measured for quality here** — treat it as untested. (The int8 quality-free result
|
|
|
|
| 113 |
**no padding**, no prefix). A token appearing `c` times in the query carries **total weight
|
| 114 |
`sqrt(c)`**, not `c`. Sum the rows, divide by the weight sum, L2-normalize. An empty or
|
| 115 |
near-zero-norm bag falls back to the normalized `[CLS]` row (id **101**; row 0 is `[PAD]`).
|
| 116 |
+
`zero_encoder.py` is 89 lines and is the reference. `config.json` carries the rule and its
|
| 117 |
fingerprint (`adb24fb2e8cad66f`).
|
| 118 |
|
| 119 |
## Files
|
|
|
|
| 123 |
| `model.npz` | `rows_int8` (30522×1024) + `int8_scale`, and `rows_fp16` for reference |
|
| 124 |
| `config.json` | the frozen preprocessing rule, teacher pin, document-encoder spec, shas |
|
| 125 |
| `zero_encoder.py` | the whole query path — numpy + tokenizers, no torch |
|
| 126 |
+
| `tokenizer.json`, `vocab.txt`, … | stella's WordPiece tokenizer, copied at the pinned revision — with the two edits below |
|
| 127 |
+
|
| 128 |
+
**Two deliberate edits to the copied tokenizer files.** stella's own files declare
|
| 129 |
+
`model_max_length: 32768`, `max_length: 8000` and fixed-512 padding; the frozen rule here — and
|
| 130 |
+
the document index — are **512 with no padding**. This bundle ships `model_max_length: 512`,
|
| 131 |
+
`max_length: 512` and `padding: null`. `config.json` records the original values under
|
| 132 |
+
`tokenizer_deviation_from_teacher`.
|
| 133 |
+
|
| 134 |
+
Precisely what that changes, by caller:
|
| 135 |
+
|
| 136 |
+
| caller | before | after |
|
| 137 |
+
|---|---|---|
|
| 138 |
+
| `zero_encoder.py` (the reference path) | 512, no padding | unchanged — **byte-identical output**; it calls `no_padding()` and reads truncation from `config.json` |
|
| 139 |
+
| `tokenizers` directly | every `encode` padded to 512 | ragged unless you enable padding yourself |
|
| 140 |
+
| `transformers` / Sentence Transformers | `model_max_length` 32768, so `truncation=True` with no explicit length truncated at 32768 | 512 — but truncation and padding still happen only when the *call* asks for them |
|
| 141 |
+
| fastembed's tokenizer loader | truncation 8000, fixed-512 padding kept | truncation 512, dynamic padding |
|
| 142 |
+
|
| 143 |
+
The reference path is unaffected either way, so no published number changes; only what a
|
| 144 |
+
third-party loader does with the same files. The fastembed row is about
|
| 145 |
+
`fastembed.common.preprocessor_utils.load_tokenizer` only — **this repo ships no ONNX graph**, so
|
| 146 |
+
there is no fastembed inference path to describe yet.
|
| 147 |
|
| 148 |
Per-token learned weights are **folded into the rows**, so the int8 artifact is self-contained.
|
| 149 |
`int8` is the variant every published number below was measured on; it was measured
|
|
|
|
| 215 |
NQ, SQuAD, HotpotQA, FEVER and Mr. TyDi derive from Wikipedia and are **CC BY-SA** (3.0/4.0).
|
| 216 |
Amazon ESCI is Apache-2.0. The teacher, `NovaSearch/stella_en_400M_v5`, is MIT.
|
| 217 |
|
| 218 |
+
## Revisions
|
| 219 |
+
|
| 220 |
+
| | |
|
| 221 |
+
|---|---|
|
| 222 |
+
| first published | 2026-09-03 — the frozen M7 bundle, with stella's tokenizer files copied verbatim |
|
| 223 |
+
| this revision | 2026-09-03 — `tokenizer_config.json` `model_max_length`/`max_length` → 512, `tokenizer.json` `padding` → `null`, and one broken snippet in this card fixed |
|
| 224 |
+
|
| 225 |
+
`model.npz` is byte-identical across both (sha `a7007b1a…`) and the reference encoder's output is
|
| 226 |
+
unchanged, so **no published number differs between revisions**. Pass `revision=` to
|
| 227 |
+
`snapshot_download` if you need to pin one.
|
| 228 |
+
|
| 229 |
## Citation / provenance
|
| 230 |
|
| 231 |
```
|
config.json
CHANGED
|
@@ -34,6 +34,31 @@
|
|
| 34 |
"source_table_sha256": "a7007b1a6af120b976f093fd69ddcb5001996ec0b84b5864b4fd25d7af878abf",
|
| 35 |
"teacher": "NovaSearch/stella_en_400M_v5",
|
| 36 |
"teacher_revision": "ffeb2b7ee715c226d4ffe5e4619f7dbb48624c20",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
"version": "v1",
|
| 38 |
"vocab": 30522,
|
| 39 |
"weights_folded": true
|
|
|
|
| 34 |
"source_table_sha256": "a7007b1a6af120b976f093fd69ddcb5001996ec0b84b5864b4fd25d7af878abf",
|
| 35 |
"teacher": "NovaSearch/stella_en_400M_v5",
|
| 36 |
"teacher_revision": "ffeb2b7ee715c226d4ffe5e4619f7dbb48624c20",
|
| 37 |
+
"tokenizer_deviation_from_teacher": {
|
| 38 |
+
"tokenizer_config": {
|
| 39 |
+
"after": {
|
| 40 |
+
"max_length": 512,
|
| 41 |
+
"model_max_length": 512
|
| 42 |
+
},
|
| 43 |
+
"before": {
|
| 44 |
+
"max_length": 8000,
|
| 45 |
+
"model_max_length": 32768
|
| 46 |
+
}
|
| 47 |
+
},
|
| 48 |
+
"tokenizer_json_padding": {
|
| 49 |
+
"after": null,
|
| 50 |
+
"before": {
|
| 51 |
+
"direction": "Right",
|
| 52 |
+
"pad_id": 0,
|
| 53 |
+
"pad_to_multiple_of": null,
|
| 54 |
+
"pad_token": "[PAD]",
|
| 55 |
+
"pad_type_id": 0,
|
| 56 |
+
"strategy": {
|
| 57 |
+
"Fixed": 512
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
},
|
| 62 |
"version": "v1",
|
| 63 |
"vocab": 30522,
|
| 64 |
"weights_folded": true
|
tokenizer.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
tokenizer_config.json
CHANGED
|
@@ -1,62 +1,62 @@
|
|
| 1 |
{
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
},
|
| 11 |
-
"100": {
|
| 12 |
-
"content": "[UNK]",
|
| 13 |
-
"lstrip": false,
|
| 14 |
-
"normalized": false,
|
| 15 |
-
"rstrip": false,
|
| 16 |
-
"single_word": false,
|
| 17 |
-
"special": true
|
| 18 |
-
},
|
| 19 |
-
"101": {
|
| 20 |
-
"content": "[CLS]",
|
| 21 |
-
"lstrip": false,
|
| 22 |
-
"normalized": false,
|
| 23 |
-
"rstrip": false,
|
| 24 |
-
"single_word": false,
|
| 25 |
-
"special": true
|
| 26 |
-
},
|
| 27 |
-
"102": {
|
| 28 |
-
"content": "[SEP]",
|
| 29 |
-
"lstrip": false,
|
| 30 |
-
"normalized": false,
|
| 31 |
-
"rstrip": false,
|
| 32 |
-
"single_word": false,
|
| 33 |
-
"special": true
|
| 34 |
-
},
|
| 35 |
-
"103": {
|
| 36 |
-
"content": "[MASK]",
|
| 37 |
-
"lstrip": false,
|
| 38 |
-
"normalized": false,
|
| 39 |
-
"rstrip": false,
|
| 40 |
-
"single_word": false,
|
| 41 |
-
"special": true
|
| 42 |
-
}
|
| 43 |
},
|
| 44 |
-
"
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
"
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
"
|
| 61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"added_tokens_decoder": {
|
| 3 |
+
"0": {
|
| 4 |
+
"content": "[PAD]",
|
| 5 |
+
"lstrip": false,
|
| 6 |
+
"normalized": false,
|
| 7 |
+
"rstrip": false,
|
| 8 |
+
"single_word": false,
|
| 9 |
+
"special": true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
},
|
| 11 |
+
"100": {
|
| 12 |
+
"content": "[UNK]",
|
| 13 |
+
"lstrip": false,
|
| 14 |
+
"normalized": false,
|
| 15 |
+
"rstrip": false,
|
| 16 |
+
"single_word": false,
|
| 17 |
+
"special": true
|
| 18 |
+
},
|
| 19 |
+
"101": {
|
| 20 |
+
"content": "[CLS]",
|
| 21 |
+
"lstrip": false,
|
| 22 |
+
"normalized": false,
|
| 23 |
+
"rstrip": false,
|
| 24 |
+
"single_word": false,
|
| 25 |
+
"special": true
|
| 26 |
+
},
|
| 27 |
+
"102": {
|
| 28 |
+
"content": "[SEP]",
|
| 29 |
+
"lstrip": false,
|
| 30 |
+
"normalized": false,
|
| 31 |
+
"rstrip": false,
|
| 32 |
+
"single_word": false,
|
| 33 |
+
"special": true
|
| 34 |
+
},
|
| 35 |
+
"103": {
|
| 36 |
+
"content": "[MASK]",
|
| 37 |
+
"lstrip": false,
|
| 38 |
+
"normalized": false,
|
| 39 |
+
"rstrip": false,
|
| 40 |
+
"single_word": false,
|
| 41 |
+
"special": true
|
| 42 |
+
}
|
| 43 |
+
},
|
| 44 |
+
"clean_up_tokenization_spaces": true,
|
| 45 |
+
"cls_token": "[CLS]",
|
| 46 |
+
"do_lower_case": true,
|
| 47 |
+
"mask_token": "[MASK]",
|
| 48 |
+
"max_length": 512,
|
| 49 |
+
"model_max_length": 512,
|
| 50 |
+
"pad_to_multiple_of": null,
|
| 51 |
+
"pad_token": "[PAD]",
|
| 52 |
+
"pad_token_type_id": 0,
|
| 53 |
+
"padding_side": "right",
|
| 54 |
+
"sep_token": "[SEP]",
|
| 55 |
+
"stride": 0,
|
| 56 |
+
"strip_accents": null,
|
| 57 |
+
"tokenize_chinese_chars": true,
|
| 58 |
+
"tokenizer_class": "BertTokenizer",
|
| 59 |
+
"truncation_side": "right",
|
| 60 |
+
"truncation_strategy": "longest_first",
|
| 61 |
+
"unk_token": "[UNK]"
|
| 62 |
}
|
zero_encoder.py
CHANGED
|
@@ -9,7 +9,7 @@ revision pinned in config.json), so it is only meaningful against document vecto
|
|
| 9 |
by that exact encoder. Cosine similarity is the score.
|
| 10 |
|
| 11 |
Conformance: this file reproduces the frozen training-time query path (m7src/table.py
|
| 12 |
-
`encode_pooled`) to < 1e-5 max-abs on the release fixtures; see m11/release/
|
| 13 |
"""
|
| 14 |
import json
|
| 15 |
from pathlib import Path
|
|
|
|
| 9 |
by that exact encoder. Cosine similarity is the score.
|
| 10 |
|
| 11 |
Conformance: this file reproduces the frozen training-time query path (m7src/table.py
|
| 12 |
+
`encode_pooled`) to < 1e-5 max-abs on the release fixtures; see m11/release/verify_bundle.py.
|
| 13 |
"""
|
| 14 |
import json
|
| 15 |
from pathlib import Path
|