Model reference · open weights
mmbert-embed-32k-2d-matryoshka is an open-weight embedding model from vllm-sr. mmbert-embed-32k-2d-matryoshka (BF16) weighs 614 MB; the smallest configuration that runs it is RTX 3060 12 GB.
Summary of the vllm-sr/mmbert-embed-32k-2d-matryoshka model card, 2026-10-03
What it is
| Released by | vllm-sr |
|---|---|
| Released | 2026-01-26 |
| Parameters | 307M |
| VRAM | 614 MB for the weights |
What it runs on
| Card | Runs | Memory |
|---|---|---|
| RTX 3060 12 GB | fits | 11.6 GB |
| RTX 4060 Ti 16 GB | fits | 15.4 GB |
| RTX 3090 24 GB | fits | 23.4 GB |
| RTX 4090 24 GB | fits | 23.4 GB |
| RTX 5090 32 GB | fits | 31.0 GB |
| L40S 48 GB | fits | 44.0 GB |
| A100 80 GB | fits | 78.2 GB |
| H100 80 GB | fits | 78.1 GB |
| RTX PRO 6000 Blackwell 96 GB | fits | 93.8 GB |
| DGX Spark (GB10) 128 GB unified | fits | 107 GB |
| H200 141 GB | fits | 138 GB |
| B200 180 GB | fits | 176 GB |
From the model card
A multilingual embedding model with 32K context window and 2D Matryoshka support for flexible efficiency-quality tradeoffs.
| Feature | Value |
|---|---|
| Parameters | 307M |
| Context Length | 32,768 tokens |
| Languages | 1800+ (via Glot500) |
| Embedding Dim | 768 (supports 64-768 via Matryoshka) |
| Architecture | ModernBERT encoder with YaRN scaling |
| Metric | Score |
|---|---|
| MTEB Mean (24 tasks) | 61.4 |
| STS Benchmark | 80.5 (exceeds Qwen3-0.6B's 76.17) |
| Dimension Retention | 99% @ 256d, 98% @ 64d |
| Layer Speedup | 3.3× @ 6L, 5.8× @ 3L |
| Latency vs BGE-M3 | 1.6-3.1× faster (FA2 advantage) |
This model supports two dimensions of flexibility:
| Config | Quality | Speedup | Storage |
|---|---|---|---|
| 22L, 768d | 100% | 1.0× | 100% |
| 22L, 256d | 99% | 1.0× | 33% |
| 22L, 64d | 98% | 1.0× | 8% |
| 6L, 768d | 56% | 3.3× | 100% |
| 6L, 256d | 56% | 3.3× | 33% |
from sentence_transformers import SentenceTransformer
# Load model
model = SentenceTransformer("vllm-sr/mmbert-embed-32k-2d-matryoshka")
# Encode sentences
sentences = [
"This is a test sentence.",
"这是一个测试句子。",
"Dies ist ein Testsatz.",
]
embeddings = model.encode(sentences)
print(embeddings.shape) # (3, 768)
import torch.nn.functional as F
# Encode with full dimensions
embeddings = model.encode(sentences, convert_to_tensor=True)
# Truncate to smaller dimension (e.g., 256)
embeddings_256d = embeddings[:, :256]
embeddings_256d = F.normalize(embeddings_256d, p=2, dim=1)
# Or truncate to 64 dimensions for maximum compression
embeddings_64d = embeddings[:, :64]
embeddings_64d = F.normalize(embeddings_64d, p=2, dim=1)
# For long documents, set max_seq_length
model.max_seq_length = 8192 # or up to 32768
long_document = "..." * 10000 # Very long text
embedding = model.encode(long_document)
For latency-critical applications, you can extract embeddings from intermediate layers:
from transformers import AutoModel, AutoTokenizer
import torch
import torch.nn.functional as F
model = AutoModel.from_pretrained(
"vllm-sr/mmbert-embed-32k-2d-matryoshka",
trust_remote_code=True,
output_hidden_states=True
)
tokenizer = AutoTokenizer.from_pretrained("vllm-sr/mmbert-embed-32k-2d-matryoshka")
# Encode
inputs = tokenizer(sentences, padding=True, truncation=True, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
# Use layer 6 for 3.3× speedup (56% quality)
hidden = outputs.hidden_states[6]
hidden = model.final_norm(hidden)
# Mean pooling
mask = inputs["attention_mask"].unsqueeze(-1).float()
pooled = (hidden * mask).sum(1) / mask.sum(1)
embeddings = F.normalize(pooled, p=2, dim=1)
| Category | Score |
|---|---|
| STS (7 tasks) | 79.3 |
| Classification (6) | 62.4 |
| Pair Classification (2) | 76.2 |
| Reranking (2) | 64.4 |
| Clustering (4) | 36.9 |
| Retrieval (3) | 38.2 |
| Overall Mean | 61.4 |
| Model | Parameters | STS Score |
|---|---|---|
| Qwen3-Embed-0.6B | 600M | 76.17 |
| mmBERT-Embed | 307M | 80.5 |
| Qwen3-Embed-8B | 8B | 81.08 |
| Layers | 768d | 256d | 64d |
|---|---|---|---|
| 22L | 80.5 | 79.9 | 78.5 |
| 11L | 53.7 | 48.0 | 44.4 |
| 6L | 45.2 | 45.2 | 43.5 |
| 3L | 44.0 | 44.1 | 41.8 |
| Metric | Score |
|---|---|
| R@1 | 68.8% |
| R@10 | 81.2% |
| MRR | 71.9% |
| Layers | Throughput | Speedup |
|---|---|---|
| 22L | 477/s | 1.0× |
| 11L | 916/s | 1.9× |
| 6L | 1573/s | 3.3× |
| 3L | 2761/s | 5.8× |
mmBERT-Embed is significantly faster due to:
| Seq Len | mmBERT-Embed | Qwen3-0.6B | BGE-M3 | mmBERT Speedup |
|---|---|---|---|---|
| 512 | 17.6ms (57/s) | 20.7ms (48/s) | 10.8ms (93/s) | 0.6× |
| 1024 | 18.6ms (54/s) | 21.2ms (47/s) | 16.3ms (61/s) | 0.9× |
| 2048 | 19.5ms (51/s) | 24.1ms (42/s) | 31.1ms (32/s) | 1.6× |
| 4096 | 21.3ms (47/s) | 43.5ms (23/s) | 60.5ms (17/s) | 2.8× |
| Seq Len | mmBERT-Embed | Qwen3-0.6B | BGE-M3 | mmBERT Speedup |
|---|---|---|---|---|
| 512 | 21.1ms (379/s) | 33.0ms (243/s) | 40.0ms (200/s) | 1.9× |
| 1024 | 34.5ms (232/s) | 58.5ms (137/s) | 77.4ms (103/s) | 2.2× |
| 2048 | 65.2ms (123/s) | 117.0ms (68/s) | 162.9ms (49/s) | 2.5× |
| 4096 | 130.7ms (61/s) | 254.9ms (31/s) | 411.3ms (19/s) | 3.1× |
Key insight: The FA2 advantage grows with sequence length and batch size:
Benchmarked on AMD MI300X, bf16 precision.
Trained on BAAI/bge-m3-data (73GB, 279 JSONL files) with:
Quoted from the model card on Hugging Face. The full card is behind the Hugging Face link above.
Benchmarks
As published on the model card: the maker's own numbers, not measured by AxForge.
| Task | Dataset | Metric | Score |
|---|---|---|---|
| STS | STS Benchmark | spearman | 80.500 |