feat: add static-embeddings like F16 safetensors lookup table

#1
by itsclelia - opened
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fa798c355d9bc602f8314d7ca411c27467787cee19ad15e25390c2f9aaec37d0
3
+ size 31376776
scripts/convert-to-safensors.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env -S uv run --script
2
+ #
3
+ # /// script
4
+ # requires-python = ">=3.12"
5
+ # dependencies = ["safetensors", "numpy"]
6
+ # ///
7
+
8
+ import numpy as np
9
+ from safetensors.numpy import save_file
10
+
11
+ d = np.load("model.npz")
12
+ W = np.ascontiguousarray(d["rows_int8"]) # (30522, 1024) int8, the released table
13
+ scale = d["int8_scale"].astype(np.float32) # (30522,) per-row dequantization scale
14
+ assert W.shape == (30522, 1024) and W.dtype == np.int8 and scale.shape == (30522,)
15
+
16
+ # FastEmbed's static models multiply each token's row by `weights`, which dequantizes it.
17
+ save_file({"embeddings": W, "weights": scale}, "model.safetensors")
scripts/test-safentesor.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env -S uv run --script
2
+ #
3
+ # /// script
4
+ # requires-python = ">=3.12"
5
+ # dependencies = ["safetensors", "numpy", "tokenizers"]
6
+ # ///
7
+
8
+ # Checks that model.safetensors, pooled by the model card's rule, gives the released vectors.
9
+
10
+ import sys
11
+ from pathlib import Path
12
+
13
+ import numpy as np
14
+ from safetensors.numpy import load_file
15
+
16
+ model_dir = Path(__file__).parents[1]
17
+ sys.path.insert(0, str(model_dir))
18
+
19
+ from zero_encoder import ZeroQueryEncoder
20
+
21
+ model = ZeroQueryEncoder(model_dir, variant="int8")
22
+ t = load_file(model_dir / "model.safetensors")
23
+ texts = ["hello world", "data data data pipeline", "🤗 emoji query", ""]
24
+
25
+ for text, released in zip(texts, model.encode(texts)):
26
+ # special and unknown tokens included, a token seen c times weighs sqrt(c)
27
+ ids, counts = np.unique(model.tokenizer.encode(text).ids, return_counts=True)
28
+ v = (np.sqrt(counts) * t["weights"][ids]) @ t["embeddings"][ids].astype(np.float32)
29
+ v /= np.linalg.norm(v)
30
+ assert np.abs(v - released).max() < 1e-6, text
31
+ print("model.safetensors matches the released int8 encoder")