Views
No views yet
| Head | Output | Shape | Use Case |
|---|---|---|---|
| Dense | CLS pooling → L2 normalization | float[1024] | Semantic similarity (cosine) |
| Sparse | linear → ReLU → log(1+x) per token | [token_id, weight] pairs | Lexical / hybrid search |
| ColBERT | linear → L2 norm per token | n_tokens × float[1024] | Token-level late interaction |
llama_decode() computes all three. No separate models, no external BM25.cls.sparse and cls.colbert weights extracted from the original
sentence-transformers checkpoint.| File | Quantization | Size | Heads |
|---|---|---|---|
bge-m3-multivector-q8.gguf | Q8_0 | ~600 MB | Dense + Sparse + ColBERT |
bge-m3-multivector-f16.gguf | F16 | ~1.1 GB | Dense + Sparse + ColBERT |
1llama-server --model bge-m3-multivector-q8.gguf \
2 --pooling cls --no-mmap --embedding \
3 --host 0.0.0.0 --port 8080 \
4 -c 8192 -b 8192 -ub 8192 -np 1 --fit off \
5 -ngl 99
6
7Companion fork with inference code: [llama.cpp-mv](https://github.com/iz0eyj/llama.cpp-mv)
81curl -X POST http://127.0.0.1:8080/v1/embeddings \
2 -H "Content-Type: application/json" \
3 -d '{"input": "Samarcanda è una città meravigliosa"}'?colbert=true (or "colbert": true in the JSON body) for all three:1curl -X POST "http://127.0.0.1:8080/v1/embeddings?colbert=true" \
2 -H "Content-Type: application/json" \
3 -d '{"input": "Samarcanda è una città meravigliosa"}'1{
2 "data": [{
3 "embedding": [0.001, -0.023, ...], // dense: 1024 floats
4 "sparse_embedding": [ // sparse: [token_id, weight] pairs
5 [0, 0.116],
6 [121283, 0.154],
7 [2, 0.095]
8 ],
9 "colbert_embedding": [ // colbert: n_tokens × 1024
10 [-0.768, -0.048, ...],
11 [ 0.312, 1.205, ...],
12 [-0.015, -0.823, ...]
13 ],
14 "index": 0,
15 "object": "embedding"
16 }],
17 "model": "bge-m3-multivector-q8.gguf",
18 "usage": {"prompt_tokens": 5, "total_tokens": 5}
19}colbert_embedding is only present when ?colbert=true is set1import numpy as np
2
3def colbert_score(vecs_a, vecs_b):
4 """MaxSim per token, then average."""
5 sim = np.dot(vecs_a, vecs_b.T) # [n_a, n_b]
6 return np.mean(np.max(sim, axis=1))
7
8# Example: "Samarcanda è bella" vs "Samarcanda è meravigliosa"
9# score ≈ 1010 (similar) vs ≈ 330 (different topic)sparse_linear.pt, colbert_linear.pt) are stored
separately from the main model checkpoint and were silently skipped.gguf-py/gguf/constants.py — Added CLS_SPARSE and CLS_COLBERT tensor typesgguf-py/gguf/tensor_mapping.py — Mapped sparse_linear → cls.sparse, colbert_linear → cls.colbertconversion/bert.py — Load .pt files from model directory via generate_extra_tensors()python convert_hf_to_gguf.py BAAI/bge-m3 --outtype q8_0 --outfile bge-m3-multivector-q8.ggufTransformer (24 layers XLM-RoBERTa)
│
▼ hidden_states [1024, n_tokens]
│
├── [CLS] ──► L2 normalize ──► dense [1024]
├── sparse_linear → ReLU → log1p ──► sparse [n_tokens] scalars
└── colbert_linear → L2 norm ──► colbert [n_tokens × 1024]log1p for sparse is applied on CPU after GPU transfer (avoids new GGML op)ggml_norm for per-token L2 normalization