feat: add static-embeddings like F16 safetensors lookup table
#1
by itsclelia - opened
- model.safetensors +3 -0
- scripts/convert-to-safensors.py +17 -0
- scripts/test-safentesor.py +31 -0
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")
|