intfloat/multilingual-e5-small exported to ONNX, stored in fp16, with the embedding matrix
zeroed for scripts the product does not serve. Built for on-device semantic search in the Naver Memo
Android app.
No fine-tuning. This is a mechanical transformation of the MIT-licensed base model: the weights
that survive are bit-identical to the fp32 export, cast to fp16. Nothing was trained, and no user or
proprietary data went into producing it.
Size
120.7 MB (fp32 export is 448 MB, int8 is 112.8 MB)
Embedding dim
384
Max sequence
512
Vocab entries
250,002 — unchanged, see below
Tokenizer
XLM-R SentencePiece, same ids as the base model
What "trimmed" means here, and what it does NOT mean
Token ids are preserved. The vocabulary keeps all 250,002 entries; rows for dropped pieces are
replaced with ⬜padNNNNN⬜ placeholders carrying log-probability -1e9, so they can never be
selected. Any tokenizer written against the base model's id space keeps working unchanged.
This matters: a vocabulary that renumbers ids would silently shift every token after the first
dropped piece, and the failure is invisible — the model still returns plausible vectors.
Kept: Hangul, basic Latin, CJK ideographs (Hanja), digits, and every symbol, punctuation mark and
emoji regardless of codepoint.
Dropped: letters of Cyrillic, Arabic, Devanagari, Thai, Hebrew, Kana, Ethiopic, Armenian, Georgian,
Tamil, Bengali, Khmer, Lao and Burmese.
The criterion is by script, not by frequency. A frequency cut (top-40k pieces) was tried first and
rejected: it dropped 647 pieces the evaluation corpus actually needed, all of them Latin or numeric
(▁Interview, ▁coffee, ▁QR, 2,000).
vocab.txt is the plain-text token<TAB>logProb form, not HuggingFace tokenizer.json — the
Android tokenizer is pure Kotlin so that the APK stays 16 KB page-size compatible.
Anisotropy: this model needs a geometry transform
Raw E5 vectors are strongly anisotropic — unrelated Korean text still scores ~0.78 cosine — so a
display threshold cannot separate "the memo you meant" from "the least unrelated memo". The consuming
app applies an all-but-the-top transform before comparing:
v' = normalize((v - mu) - ((v - mu) · pc1) * pc1)
with separate mu for documents and queries and a shared pc1, fitted once on a held-out split and
shipped as constants. Without it, cosine is not usable as a gate. Anyone reusing this model for
retrieval should expect to fit their own equivalent.
Intended use
On-device retrieval over a personal note collection (tens to hundreds of documents). Not evaluated
for general-purpose multilingual retrieval, and the dropped scripts make it unsuitable for any
language written in them.