Instructions to use sanjay920/voyage-4-nano-mlx-4bit with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use sanjay920/voyage-4-nano-mlx-4bit with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] huggingface-cli download --local-dir voyage-4-nano-mlx-4bit sanjay920/voyage-4-nano-mlx-4bit
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
voyage-4-nano-mlx-4bit
voyageai/voyage-4-nano converted for MLX,
so it runs on Apple silicon. Smallest. Measurably degraded; see the note below.
voyage-4-nano is not served by the Voyage API — the open checkpoint is the only
way to run it. Embeddings from this port land in the same space as the hosted
voyage-4 models, so you can index locally and query with those: same-text cosine
0.969 against voyage-4-lite, 0.952 against voyage-4, 0.894 against
voyage-4-large (12 texts, versus 0.32–0.36 for non-matching text).
Unofficial community port. Not affiliated with Voyage AI or MongoDB.
Use
pip install voyage-4-nano-mlx
from voyage_4_nano_mlx import load
emb = load("sanjay920/voyage-4-nano-mlx-4bit")
q = emb.encode_query("Which planet is known as the Red Planet?")
d = emb.encode_document([
"Venus is often called Earth's twin because of its similar size.",
"Mars, known for its reddish appearance, is called the Red Planet.",
])
emb.similarity(q, d) # [[0.4052 0.6514]]
Queries and documents take different trained prefixes; encode_query and
encode_document apply them. Use encode() for symmetric tasks.
Matryoshka dims (2048 / 1024 / 512 / 256) and compact outputs:
emb.encode_document(docs, dims=256) # 256-d, unit norm
emb.encode_document(docs, dims=512, output_dtype="int8") # 512 int8 values
emb.encode_document(docs, output_dtype="ubinary") # 2048 bits = 256 bytes
To shrink an index, prefer dims=256 + int8 over a smaller weight file — it
cuts the index 32x and leaves the encoder faithful.
Variants
| repo | size | min cosine vs fp64 reference |
|---|---|---|
sanjay920/voyage-4-nano-mlx-bf16 |
672 MB | 0.99997 |
sanjay920/voyage-4-nano-mlx-8bit |
362 MB | 0.99966 |
sanjay920/voyage-4-nano-mlx-6bit |
280 MB | 0.99691 |
sanjay920/voyage-4-nano-mlx-4bit |
198 MB | 0.97465 |
Weight quantization saves disk, not time: at typical sequence lengths this model is compute-bound, and 8-bit and 4-bit both run ~7% slower than bf16.
Verification
Against the reference PyTorch implementation, with a float64 run as ground truth:
| this variant, pooled cosine vs fp64 reference | 0.97465 |
| bf16 on MTEB SciFact / NFCorpus (nDCG@10) | 0.75262 / 0.39576 |
| PyTorch reference, same tasks | 0.75191 / 0.39568 |
On MLX's CPU backend the unquantized port matches float64 as closely as PyTorch's own float32 does (max error 1.03e-04 vs 1.07e-04). Tokenization is byte-identical to the reference across 14 texts covering CJK, emoji, URLs and whitespace edge cases. Method and full numbers: docs/PARITY.md.
Model
A Qwen3 backbone run bidirectionally, not an encoder-only model:
Qwen3, 12 layers, d=1024, 16 heads / 8 KV heads, head_dim=128
RMSNorm, SwiGLU, RoPE theta=1e6, per-head q/k RMSNorm, bidirectional attention
-> final norm
-> linear 1024 -> 2048 (per token, before pooling)
-> mean pool over the attention mask
-> L2 normalize
346M parameters, 32k context, multilingual.
Notes
- Metal's float32 matmul accumulates at reduced precision, so GPU fp32 is slightly less exact than CPU fp32 (0.9999995 vs 1.0000000 cosine). It does not affect retrieval.
- 32k-token inputs use dense attention and take ~6 s each.
- This 4-bit build loses real quality (cosine 0.97465, versus 0.99966 at
8-bit) and is not faster. Use it only when 198 MB genuinely matters; otherwise
take 8-bit, or 4-bit with
dims=256accepted as a quality trade.
Source, tests and benchmarks: https://github.com/sanjay920/voyage-4-nano-mlx
- Downloads last month
- -
Quantized
Model tree for sanjay920/voyage-4-nano-mlx-4bit
Base model
voyageai/voyage-4-nano