A tiny embedding model that punches far above its weight.
Named after the colibri (hummingbird) β the smallest bird, yet it out-flies much larger ones.
Colibri is a compact Brazilian-Portuguese text-embedding model derived from
google/embeddinggemma-300m. Despite being half the size,
it matches or beats much larger multilingual embedders on MTEB-BR β including 7B and 27B models β and is
designed small on purpose so it runs comfortably on a simple CPU VPS, with no GPU required.
This repository holds the training / evaluation pipeline and the figures. The model itself lives on the Hub:
π tardellirs/colibri-embed-ptbr
- π Beats bigger models on MTEB-BR β including
embeddinggemma-300m, and 7B / 27B multilingual embedders. - πͺΆ Half the footprint of
embeddinggemma-300m: ~607 MB vs ~1.2 GB, and less RAM. - π» Runs on a $-few/month CPU VPS β benchmarked on 4 vCPU / 16 GB (no GPU).
- π Plain
SentenceTransformerβ no adapters, no LoRA at inference. Drop-in. - π Matryoshka dimensions (768 / 512 / 256 / 128) + an fp16 branch + a fast ONNX path.
Colibri sits on the open-model Pareto frontier for MTEB-BR β it dominates its own base
embeddinggemma-300m (half the size, higher score) and matches models up to ~10Γ larger:
| Model | Params | MTEB-BR |
|---|---|---|
| π¦ Colibri | ~157M | 0.6501 |
| google/embeddinggemma-300m | 300M | 0.6490 |
| Linq-AI-Research/Linq-Embed-Mistral | 7B | 0.6473 |
| openai/text-embedding-3-large | β | 0.6449 |
| intfloat/multilingual-e5-large-instruct | 560M | 0.6409 |
| Salesforce/SFR-Embedding-2_R | 7B | 0.6397 |
| Alibaba-NLP/gte-Qwen2-7B-instruct | 7B | 0.6392 |
| microsoft/harrier-oss-v1-27b | 27B | 0.6390 |
| BAAI/bge-m3 | 568M | 0.6157 |
Evaluated on MTEB-BR β 22 native Brazilian-Portuguese tasks (retrieval, reranking, STS, classification, clustering, pair-classification). Score = mean over the 22 tasks.
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("tardellirs/colibri-embed-ptbr")
query = "Como declarar imposto de renda de aluguel?"
docs = [
"Rendimentos de aluguel devem ser informados na ficha de Rendimentos TributΓ‘veis...",
"O Pix Γ© um meio de pagamento instantΓ’neo criado pelo Banco Central...",
]
q = model.encode(query, prompt_name="query") # "task: search result | query: "
d = model.encode(docs, prompt_name="document") # "title: none | text: "
print(model.similarity(q, d))Faster on CPU β ONNX backend (β2Γ throughput, no pipeline changes):
model = SentenceTransformer("tardellirs/colibri-embed-ptbr", backend="onnx")Smaller vectors β Matryoshka (truncate to 512 / 256 / 128):
model = SentenceTransformer("tardellirs/colibri-embed-ptbr", truncate_dim=256)Benchmarked head-to-head against google/embeddinggemma-300m on a 4 vCPU / 16 GB VPS:
| Precision | Model | Model size | Peak RAM | Latency (p50) | Throughput |
|---|---|---|---|---|---|
| fp32 | π¦ Colibri | 607 MB | 969 MB | 76 ms | 37 sent/s |
| fp32 | embeddinggemma-300m | 1211 MB | 1253 MB | 78 ms | 36 sent/s |
| ONNX | π¦ Colibri | ~600 MB | 2.9 GB | 33 ms | 49 sent/s |
| ONNX | embeddinggemma-300m | ~1200 MB | 5.3 GB | 38 ms | 41 sent/s |
Half the size and less RAM, same encode latency (the vocabulary trim shrinks the token-embedding matrix, not the
transformer compute) β you lose nothing in speed. See scripts/cpu_bench.py.
A three-stage pipeline: vocabulary trimming β multi-teacher distillation β model soup.
1. Vocabulary trimming β scripts/retrim_vocab.py
Trims embeddinggemma-300m's 262k multilingual vocabulary down to a ~64k Brazilian-Portuguese vocabulary,
cutting the model from ~300M to ~157M effective parameters with negligible quality loss. Base trimmer:
github.com/tardellirs/embedding-vocab-trimmer.
2. Multi-teacher distillation β scripts/distill_precompute.py Β· scripts/distill_train.py
Relational (similarity-preserving) knowledge distillation from two complementary teachers β
Qwen3-Embedding-4B (clustering) and
Qwen3-Embedding-8B (retrieval / reranking). The student learns
to reproduce the average of the two teachers' pairwise-similarity matrices (dimension-agnostic; preserves STS),
on a ~100k-passage native Brazilian-Portuguese corpus (scripts/build_distill_v2_corpus.py).
3. Model soup + merge β scripts/soup_eval.py Β· scripts/extend_sweep.py
Distillation checkpoints are combined (model soup) and linearly merged with the trimmed base
(ΞΈ = 0.35Β·base + 0.65Β·soup), with the mixing weight chosen on held-out validation. Everything yields ordinary
weights, so the published model is a single standalone encoder.
Evaluation integrity: trained only on training / non-evaluation splits β every MTEB-BR evaluation example is held out, so the scores reflect generalization, not memorization.
Full run log & numbers: RESULTS.md. Orchestrator: scripts/run_distill_v2.sh.
The pipeline runs in four stages β trim the vocab, distill from two teachers, soup & merge the checkpoints, then evaluate.
scripts/
β
ββ β Vocabulary trimming
β βββ build_retrim_corpus.py # token-selection corpus (domains + Stack Overflow PT)
β βββ get_stackoverflow_pt.py # Stack Overflow em PortuguΓͺs source
β βββ retrim_vocab.py # domain-aware 64k re-trim (300M β ~157M)
β βββ compare_trims.py # pick the best trim base on MTEB-BR
β
ββ β‘ Multi-teacher distillation
β βββ build_distill_v2_corpus.py # assemble the ~100k PT-BR corpus (eval rows held out)
β βββ distill_precompute.py # precompute teacher (Qwen3-4B + 8B) embeddings
β βββ distill_train.py # multi-teacher relational KD (avg of two sim-matrices)
β βββ select_best.py # checkpoint selection by FaqBacen proxy
β
ββ β’ Model soup + merge
β βββ soup_eval.py # checkpoint soup + alpha merge
β βββ extend_sweep.py # fine alpha sweep (mean_21 β mean_22 on the peak)
β βββ interpolate_eval.py # base β ft weight interpolation + MTEB harness
β
ββ β£ Evaluation Β· benchmark Β· figure
βββ run_mtebpt.py # official MTEB-BR 22-task evaluation
βββ cpu_bench.py # CPU latency / RAM benchmark
βββ variant_quality.py # Matryoshka dims + fp16 quality
βββ make_colibri_pareto.py # the frontier figure above
βββ run_*.sh # orchestrators (distill_v2 Β· compare Β· cpu_bench Β· bench Β· quality)
docs/teacher_survey.md # why Qwen3-4B + 8B (multi-teacher rationale)
figures/pareto.png # the size β quality frontier figure
RESULTS.md # full run log & per-task numbers
- Code in this repository: Apache-2.0.
- Model weights (
tardellirs/colibri-embed-ptbr): Gemma Terms of Use, inherited fromgoogle/embeddinggemma-300m.
We gratefully acknowledge Verda for the GPU compute credits that supported this work, and the MTEB-BR benchmark maintainers.
