Instructions to use hotchpotch/bekko-static-embedding-v1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- sentence-transformers
How to use hotchpotch/bekko-static-embedding-v1 with sentence-transformers:
from sentence_transformers import SentenceTransformer model = SentenceTransformer("hotchpotch/bekko-static-embedding-v1") sentences = [ "The weather is lovely today.", "It's so sunny outside!", "He drove to the stadium." ] embeddings = model.encode(sentences) similarities = model.similarity(embeddings, embeddings) print(similarities.shape) # [3, 3] - Notebooks
- Google Colab
- Kaggle
bekko-static-embedding-v1
bekko-static-embedding-v1 is a multilingual static embedding model. It has no Transformer layers: each token maps to a fixed vector, and a sentence embedding is simply the mean of those vectors. That makes it cheap enough to run on any CPU, with no GPU required.
Among the public static embedding models we compared, it has the highest retrieval quality, in both multilingual and English retrieval.
For the full write-up, including comparisons, Matryoshka/INT8 trade-offs, and how the model was trained, see the blog post: bekko-static-embedding-v1: State-of-the-Art Retrieval for Multilingual Static Embeddings.
Highlights
- Best retrieval among the public static models we compared: 43.76 on MNanoBEIR (14 languages), about 11 points above other multilingual static models
- Also above English-only static models on English retrieval (NanoBEIR-en 53.71)
- Within about 1 point of multilingual-e5-small on MMTEB Retrieval, with zero Transformer layers
- Trained for 40 target languages with a custom 200k-token WordPiece tokenizer
- 1024-dim embeddings that truncate to 512 / 256 / 128 / 64 / 32 (Matryoshka); 512 dims lose about 0.9 points of retrieval score
- Per-dimension ONNX and OpenVINO files with FP16 or INT8 weights: the INT8 512-dim model is 103.2 MB
- No prefixes or instructions needed
- MIT license
How it compares
Against other static embedding models
| Static model | Language | Dims | NanoBEIR-en | MNanoBEIR | MMTEB Retrieval | MMTEB Mean |
|---|---|---|---|---|---|---|
| bekko-static-embedding-v1 | Multilingual | 1024 | 53.71 | 43.76 | 49.96 | 50.18 |
| static-similarity-mrl-multilingual-v1 | Multilingual | 1024 | 43.51 | 32.29 | 41.21 | 47.24 |
| potion-multilingual-128M | Multilingual | 256 | 37.07 | 32.23 | 37.86 | 47.23 |
| static-retrieval-mrl-en-v1 | English | 1024 | 50.35 | – | – | – |
| stable-static-embedding-fast-retrieval-mrl-en-v2 | English | 512 | 51.57 | – | – | – |
bekko-static-embedding-v1 leads every column. On multilingual retrieval (MNanoBEIR, 14 languages) it is about 11 points above the other multilingual static models, and on MMTEB Retrieval 8.75 and 12.10 points above. On English-only retrieval it also beats the two static models trained specifically for English, even when truncated to 512 dims (52.82).
Against contextual models
| Model | Transformer layers | Active params | NanoBEIR-en | MNanoBEIR | MMTEB Retrieval | MMTEB Mean |
|---|---|---|---|---|---|---|
| bekko-static-embedding-v1 | 0 | 0 | 53.71 | 43.76 | 49.96 | 50.18 |
| multilingual-e5-small | 12 | 21.6M | 58.37 | 51.17 | 50.9 | 56.4 |
| bekko-embedding-v1-a8m | 4 | 7.7M | 60.34 | 52.65 | 56.2 | 56.7 |
With no Transformer layers at all, bekko-static-embedding-v1 comes within about 1 point of multilingual-e5-small on MMTEB Retrieval (49.96 vs 50.9). multilingual-e5-small is still ahead on the Nano retrieval sets and on the overall MMTEB mean, where most of its lead comes from BitextMining, Reranking and STS.
If you can run a small Transformer, bekko-embedding-v1-a8m scores above multilingual-e5-small on every column here with only 7.7M active parameters, and it runs well on CPU.
Static embedding models avoid attention entirely. The Sentence Transformers post Train 400x faster Static Embedding Models reports 100x to 400x faster CPU encoding than common embedding models such as multilingual-e5-small for its static models. We have not published our own throughput measurements for this model; measure on your workload.
Rule of thumb: pick bekko-static-embedding-v1 when encoding cost must be as low as possible, for example very large corpora on CPU or tight latency budgets. Pick bekko-embedding-v1-a8m when retrieval quality matters more and you can run a small Transformer.
How these numbers were measured
NanoBEIR-en (13 English tasks) and MNanoBEIR (182 tasks in 14 languages) are nDCG@10 × 100 from HAKARI-Bench, averaged with equal weight per task. MMTEB is the 131-task MTEB(Multilingual, v2) suite, main score × 100 averaged over tasks; Retrieval is its 18-task category. bekko-static-embedding-v1 was evaluated locally. Static comparison models use published MMTEB results averaged over the same 131 tasks. MMTEB values for multilingual-e5-small and bekko-embedding-v1-a8m are taken from the bekko-embedding-v1-a8m model card, which uses the official 2026-06-28 MMTEB snapshot and the same task set and aggregation. Active parameters exclude the token embedding table; for a static model the table is the whole model (204.8M parameters).
Quickstart
pip install -U sentence-transformers
Queries and documents go through the same encode() call, with no prefixes. Pass normalize_embeddings=True when you search with cosine similarity or dot product.
from sentence_transformers import SentenceTransformer, util
model = SentenceTransformer("hotchpotch/bekko-static-embedding-v1", device="cpu")
query = "What are the characteristics of sushi?"
docs = [
"A warm noodle soup served in broth with sliced toppings.",
"天ぷらは魚や野菜に衣をつけて揚げた料理です。", # "Tempura is battered, deep-fried fish and vegetables."
"Une fine crepe garnie de sucre, de beurre ou de fruits.",
"A Japanese dish made with vinegared rice, often shaped with seafood, vegetables, or egg.",
]
query_emb = model.encode(query, normalize_embeddings=True)
doc_emb = model.encode(docs, normalize_embeddings=True)
scores = util.cos_sim(query_emb, doc_emb)[0]
print(scores)
print("best doc:", docs[int(scores.argmax())])
Output:
tensor([0.0578, 0.0743, 0.0913, 0.1738])
best doc: A Japanese dish made with vinegared rice, often shaped with seafood, vegetables, or egg.
Static embeddings produce lower absolute cosine scores than contextual models such as bekko-embedding-v1-a8m. Use the ranking, and tune any score threshold on your own data.
Queries and documents don't need to share a language. Continuing with the same model:
corpus = [
"Sushi is a Japanese dish of vinegared rice topped with seafood.",
"The Eiffel Tower is a wrought-iron lattice tower in Paris, France.",
"Mount Fuji is the highest mountain in Japan, at 3,776 meters.",
"Python is a programming language known for its readability.",
"La Sagrada Família es una basílica de Barcelona diseñada por Antoni Gaudí.",
]
corpus_emb = model.encode(corpus, normalize_embeddings=True)
for query in [
"日本で一番高い山は?", # "What is the highest mountain in Japan?"
"Who designed the famous basilica in Barcelona?",
]:
query_emb = model.encode(query, normalize_embeddings=True)
hits = util.semantic_search(query_emb, corpus_emb, top_k=2)[0]
print(query)
for hit in hits:
print(f" {hit['score']:.3f} {corpus[hit['corpus_id']]}")
日本で一番高い山は?
0.364 Mount Fuji is the highest mountain in Japan, at 3,776 meters.
0.137 Sushi is a Japanese dish of vinegared rice topped with seafood.
Who designed the famous basilica in Barcelona?
0.547 La Sagrada Família es una basílica de Barcelona diseñada por Antoni Gaudí.
0.125 The Eiffel Tower is a wrought-iron lattice tower in Paris, France.
Outputs above were produced on CPU with Sentence Transformers 6.1.0.
Benchmark details
MMTEB Multilingual v2 by category (131 tasks)
Scores are main score × 100, averaged per category. Δ is bekko-static-embedding-v1 minus static-similarity-mrl-multilingual-v1.
| Category | Tasks | bekko-static-embedding-v1 | static-similarity-mrl-multilingual-v1 | potion-multilingual-128M | Δ |
|---|---|---|---|---|---|
| All tasks | 131 | 50.18 | 47.24 | 47.23 | +2.93 |
| Classification | 43 | 52.40 | 48.60 | 52.36 | +3.81 |
| Clustering | 16 | 40.03 | 30.67 | 37.63 | +9.36 |
| MultilabelClassification | 5 | 14.99 | 14.74 | 15.95 | +0.25 |
| Retrieval | 18 | 49.96 | 41.21 | 37.86 | +8.75 |
| Reranking | 6 | 51.59 | 49.45 | 47.39 | +2.14 |
| STS | 16 | 64.50 | 64.02 | 61.23 | +0.47 |
| BitextMining | 13 | 43.68 | 50.62 | 40.72 | -6.94 |
| PairClassification | 11 | 72.81 | 74.34 | 71.39 | -1.53 |
| InstructionReranking | 3 | -1.65 | -1.24 | -2.08 | -0.41 |
HAKARI-Bench retrieval, including contextual models and BM25
HAKARI-Bench covers 37 benchmarks and 550 tasks. Ten are shown here; the full results are on the leaderboard.
| Benchmark | Tasks | bekko-static 1024d | bekko-static 512d | static-similarity | potion | mE5-small | bekko a8m | BM25 |
|---|---|---|---|---|---|---|---|---|
| MNanoBEIR | 182 | 43.76 | 42.89 | 32.29 | 32.23 | 51.17 | 52.65 | 46.46 |
| NanoMMTEB-v2 | 18 | 43.30 | 42.87 | 36.08 | 35.22 | 44.55 | 50.25 | 45.50 |
| NanoMIRACL | 18 | 68.03 | 67.67 | 45.37 | 47.79 | 78.71 | 75.57 | 57.15 |
| NanoRTEB | 14 | 37.50 | 36.53 | 25.73 | 25.58 | 47.11 | 54.98 | 35.53 |
| NanoCoIR | 10 | 58.19 | 57.55 | 48.01 | 45.38 | 69.15 | 74.68 | 54.36 |
| NanoBRIGHT | 20 | 26.38 | 26.31 | 20.27 | 19.67 | 17.58 | 31.49 | 27.90 |
| NanoMLDR | 13 | 55.72 | 54.55 | 35.96 | 34.89 | 39.20 | 54.48 | 73.96 |
| NanoLongEmbed | 6 | 61.96 | 60.58 | 48.90 | 43.90 | 50.14 | 68.19 | 82.17 |
| NanoJMTEB-v2 | 11 | 65.36 | 64.40 | 51.37 | 51.61 | 71.65 | 75.93 | 74.65 |
| NanoIndicQA | 11 | 35.35 | 35.23 | 34.91 | 53.69 | 70.09 | 65.12 | 56.53 |
Columns: bekko-static-embedding-v1 at 1024 and 512 dims, static-similarity-mrl-multilingual-v1 (1024d), potion-multilingual-128M (256d), multilingual-e5-small (384d), bekko-embedding-v1-a8m (384d), and BM25.
Against static-similarity-mrl-multilingual-v1, bekko-static-embedding-v1 is higher on all 37 benchmark averages and 523 of 550 tasks. Against potion-multilingual-128M it is higher on 36 of 37 benchmarks; NanoIndicQA is the exception. BM25 is higher on 21 of 37 benchmark averages, notably long-document retrieval, so test it as a baseline when retrieval is your only goal.
Optimized inference
Smaller embeddings with Matryoshka (truncate_dim)
The model was trained with Matryoshka representation learning at 1024, 512, 256, 128, 64 and 32 dimensions.
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("hotchpotch/bekko-static-embedding-v1", device="cpu", truncate_dim=512)
emb = model.encode("What are the characteristics of sushi?", normalize_embeddings=True)
print(emb.shape) # (512,)
| Dims | NanoBEIR-en | MNanoBEIR | HAKARI 550-task average |
|---|---|---|---|
| 1024 | 53.71 | 43.76 | 45.88 |
| 512 | 52.82 | 42.89 | 45.03 |
| 256 | 50.83 | 41.04 | 43.29 |
| 128 | 47.83 | 38.03 | 40.12 |
| 64 | 43.96 | 32.87 | 34.82 |
| 32 | 35.74 | 24.97 | 26.46 |
512 dims is a good default. Even at 128 dims, MNanoBEIR (38.03) stays above other multilingual static models at full size.
ONNX and OpenVINO files with only the weights you need
truncate_dim shortens the output, but the full 1024-dim table is still loaded. The onnx/ and openvino/ directories contain models that store only the weights for one dimension, in FP16 or INT8:
| Dims | FP16 weights | INT8 weights |
|---|---|---|
| 1024 | 409.6 MB | 205.6 MB |
| 512 | 204.8 MB | 103.2 MB |
| 256 | 102.4 MB | 52.0 MB |
| 128 | 51.2 MB | 26.4 MB |
| 64 | 25.6 MB | 13.6 MB |
| 32 | 12.8 MB | 7.2 MB |
Sizes exclude the shared 5.1 MB tokenizer. INT8 here quantizes the stored weights only; pooling and output vectors stay FP32. On HAKARI-Bench, INT8 and FP16 weights differ by less than 0.15 points at every dimension.
The built-in StaticEmbedding module does not route backend= to these files, so use the bundled loader:
pip install -U sentence-transformers onnxruntime # or: openvino
from transformers.dynamic_module_utils import get_class_from_dynamic_module
def get_model(backend="onnx", dim=512, precision="int8", revision="main"):
repo = "hotchpotch/bekko-static-embedding-v1"
ext = {"onnx": "onnx", "openvino": "xml"}[backend]
return get_class_from_dynamic_module(
"bekko_static_backend.BekkoStaticBackend", repo, revision=revision,
).load_sentence_transformer(
repo, revision=revision, backend=backend,
file_name=f"{backend}/model_{precision}_dim{dim}.{ext}",
)
model = get_model(backend="onnx", dim=512, precision="int8")
vectors = model.encode(["日本語の検索文", "An English document"], normalize_embeddings=True)
print(vectors.shape) # (2, 512)
# OpenVINO with FP16 weights:
model = get_model(backend="openvino", dim=256, precision="fp16")
backend accepts "onnx" or "openvino", precision accepts "int8" or "fp16", and dim accepts 1024, 512, 256, 128, 64 or 32. The helper loads Python code from this repository (bekko_static_backend.py) and downloads only the configuration, tokenizer and selected model file. Set revision to a commit SHA for reproducible deployments.
Languages
The training data and tokenizer target these 40 languages:
English (en), Arabic (ar), Bulgarian (bg), Bengali (bn), Catalan (ca), Czech (cs), Danish (da), German (de), Greek (el), Spanish (es), Estonian (et), Persian (fa), Finnish (fi), French (fr), Hebrew (he), Hindi (hi), Croatian (hr), Hungarian (hu), Indonesian (id), Italian (it), Japanese (ja), Korean (ko), Dutch (nl), Norwegian (no), Polish (pl), Portuguese (pt), Romanian (ro), Russian (ru), Slovak (sk), Slovenian (sl), Serbian (sr), Swedish (sv), Swahili (sw), Telugu (te), Thai (th), Turkish (tr), Ukrainian (uk), Vietnamese (vi), Yoruba (yo), Chinese (zh).
Text in other languages still gets an embedding, since the WordPiece tokenizer can split unseen words into subwords, but quality outside these languages has not been a training target. The list comes from the data-selection config in training_scripts/.
Model details
| Item | Value |
|---|---|
| Model type | Sentence Transformer static embedding model |
| Architecture | StaticEmbedding (token lookup + mean pooling), no Transformer layers |
| Parameters | 204,800,000 (200,000 × 1,024 embedding table) |
| Tokenizer | Custom uncased WordPiece, 200,000 tokens with a 30,000-token English core |
| Embedding dimension | 1024 |
| Supported truncate dimensions | 512, 256, 128, 64, 32 |
| Max sequence length | No architectural limit; the tokenizer caps inputs at 32,768 tokens (trained on 512) |
| Weight storage | FP16 (model.safetensors, 409.6 MB) |
| Similarity | Cosine similarity |
Training
The embedding table was initialized randomly and trained from scratch with Multiple Negatives Ranking Loss (MNRL), applied at every Matryoshka dimension. There is no distillation from a teacher model.
Training data comes from hotchpotch/bekko-embedding-v1-unsupervised: 265 data configurations covering 40 target languages, about 814 million text pairs (titles and bodies, questions and answers, generated queries, translation pairs). The selection includes data derived from the MIRACL train split and NLI.
Hyperparameters
| Setting | Value |
|---|---|
| Loss | MNRL, temperature 0.03 (scale = 1 / 0.03) |
| MRL dimensions | 32, 64, 128, 256, 512, 1,024 |
| MRL weights | 0.025, 0.05, 0.1, 0.15, 0.3, 1.0 (same order) |
| Epochs, steps | 1, 49,727 |
| Global batch size | 16,384 |
| Learning rate | 0.25, 10% warmup, cosine decay |
| Optimizer | AdamW, weight decay 0, β₂ = 0.999, ε = 1e−8 |
| Precision | BF16 mixed precision, FP32 master weights, FP16 release |
| Max input length in training | 512 tokens |
| Seed | 42 |
Tokenizer selection
In a static model, the tokenizer's units are exactly the units whose vectors are averaged. We trained eight models on 10% of the data, one per tokenizer, and evaluated them on MNanoBEIR and NanoMIRACL (200 tasks, nDCG@10 × 100). This ablation used a different loss from the final model, so its scores are not comparable with the final results.
| Tokenizer | 1024d | 512d |
|---|---|---|
| Multilingual BERT uncased | 37.87 | 37.17 |
| Multilingual BERT cased | 38.51 | 38.01 |
| Gemma 2 | 38.73 | 38.08 |
| Custom 100k, 24k English, uncased | 40.19 | 39.29 |
| Custom 100k, 30k English, uncased | 39.86 | 39.21 |
| Custom 200k, 30k English, cased | 41.60 | 40.69 |
| Custom 200k, 30k English, script-balanced | 41.20 | 40.40 |
| Custom 200k, 30k English, uncased (selected) | 41.89 | 41.18 |
The custom vocabulary was trained with WordPiece: a 30k English core from equal parts Wikipedia and FineWeb, then vocabulary for 39 more languages added while keeping the English token IDs.
The tokenizer trainer, model trainer, FP16 export script and data-selection config are in training_scripts/.
FAQ
- Do I need a prefix like
query:orpassage:? No. Encode raw text for both queries and documents. - Why are the cosine scores so low? This static model gives lower absolute cosine scores than contextual models, as in the Quickstart output. Rankings are what matter; calibrate thresholds on your data.
- Does word order matter? No. The embedding is the mean of token vectors, so sentences with the same tokens in a different order get the same embedding. Use a contextual model such as bekko-embedding-v1-a8m when order matters.
- Which file should I load? PyTorch: the default
model.safetensors. Memory-constrained CPU deployments: an INT8 file fromonnx/oropenvino/at the dimension you need. - Should I use this or BM25? For pure retrieval, test both. In our benchmarks BM25 is stronger on long-document retrieval; this model is stronger on natural-language questions (NanoMIRACL: 68.03 vs 57.15).
Limitations
Evaluation scope and deployment considerations
- The model is optimized for retrieval. On MMTEB, BitextMining and PairClassification are below static-similarity-mrl-multilingual-v1; evaluate it separately for those tasks.
- MMTEB results were measured at 1024 dims. Truncated dimensions were evaluated on retrieval only.
- Contextual models (multilingual-e5-small, bekko-embedding-v1-a8m) and BM25 remain stronger on many retrieval benchmarks.
- MMTEB comparison values for other models come from published results, with different evaluation library and dataset versions.
- HAKARI-Bench is maintained by the model author; read it alongside MMTEB.
- Quality varies by language and domain. Evaluate on your target data before deployment.
- Results come from a single training seed.
The name "bekko"
bekko (/ˈbek.koː/) is a coined name that joins two pieces of Japanese tradition:
- akabeko (赤べこ): the red ox cherished in Japan for centuries as a guardian charm, believed to ward off illness and misfortune.
- bekko-iro (鼈甲色): a traditional Japanese color, a warm, translucent, amber-like hue.
Related
- Blog post: bekko-static-embedding-v1: State-of-the-Art Retrieval for Multilingual Static Embeddings
- bekko-embedding-v1-a8m and bekko-embedding-v1-a25m: contextual bekko models trained on the same data family.
- HAKARI-Bench leaderboard
Paper
For full technical details of the bekko project and its training data, see Bekko Embedding: Parameter-Efficient Multilingual Retrieval with Ultra-Compact Encoders.
Citation
If you use bekko-static-embedding-v1 in your work, please cite:
@misc{tateno2026bekkoembedding,
title = {Bekko Embedding: Parameter-Efficient Multilingual Retrieval with Ultra-Compact Encoders},
author = {Yuichi Tateno},
year = {2026},
eprint = {2607.25180},
archivePrefix = {arXiv},
primaryClass = {cs.IR},
url = {https://arxiv.org/abs/2607.25180}
}
License
MIT License.
Author
Yuichi Tateno @hotchpotch