4-bit AWQ quantization of Qwen/Qwen3-VL-Embedding-8B,
exported in the compressed-tensors format for fast serving with vLLM
(Marlin INT4 kernels on Ampere/Ada/Hopper and Jetson Orin sm_87).
The model produces dense multimodal embeddings (text, image, video) in a shared
4096-dim space using last-token pooling. This quant keeps the entire vision
tower in BF16 and only quantizes the language decoder, which preserves embedding
quality (see Evaluation).
Base model
Qwen/Qwen3-VL-Embedding-8B (8B, qwen3_vl)
Method
AWQ (activation-aware), llm-compressor
Scheme
W4A16, 4-bit int weights / 16-bit activations, asymmetric
Granularity
group-wise, group_size = 128, pack-quantized
Kept in BF16
full vision tower (visual.*, merger, patch_embed), lm_head
Format
compressed-tensors (vLLM-native)
Embedding dim
4096 (Matryoshka: usable down to 64)
Pooling
last-token, include_prompt: true
Size on disk
~5.7 GB (vs ~16 GB BF16, ≈64% smaller)
What is and isn't quantized
Only the language-model Linear layers are quantized to INT4. Quantizing the
vision encoder of a VLM embedding model causes severe "cosine drift", so the
following are explicitly excluded and remain bit-identical to the BF16 reference:
The AWQ smoothing uses the standard Qwen3 mappings (input_layernorm→q/k/v,
v→o, post_attention_layernorm→gate/up, up→down). The v_proj→o_proj
smoothing is skipped per layer because of grouped-query attention (different
head dims) — this is expected and harmless.
Do not pass --load-format fastsafetensors — it regresses multimodal
embedding similarity (vLLM issue #33954).
compressed-tensors quantization is auto-detected; no --quantization flag needed.
python
1from openai import OpenAI
2client = OpenAI(base_url="http://localhost:8000/v1", api_key="x")3e = client.embeddings.create(model="gonuit/Qwen3-VL-Embedding-8B-AWQ-4bit",4input=["A dog on the beach","A cat on a sofa"])5print(len(e.data[0].embedding))# 4096
(compressed-tensors must be installed to load the packed INT4 weights.)
Calibration
Activation statistics were collected with llm-compressor (AWQModifier +
QuantizationModifier, duo_scaling, n_grid=20) using the sequential
pipeline (one decoder subgraph at a time).
BF16 vs. this AWQ model, both served through vLLM, comparing /v1/embeddings
output on mixed EN/PL text:
Metric
Value
mean cosine(BF16, AWQ), same input
0.973
min cosine
0.966
similar-pair cosine (BF16 → AWQ)
0.77 → 0.75, 0.60 → 0.57
unrelated-pair cosine
~0.20 (preserved)
The similarity geometry is preserved — similar inputs stay close, unrelated
inputs stay far — so retrieval ranking matches the BF16 model. (Validation shown
here is text-only; the vision tower is unquantized BF16 and runs identically to
the base model.)
Reproduce
Quantized with llm-compressor 0.11 on an NVIDIA Jetson AGX Orin (JetPack 6.2,
CUDA 12.6). One upstream workaround is required before loading the base model:
set tie_word_embeddings = true to handle the missing lm_head.weight shard
(Qwen3-VL-Embedding bug #89).
The full Dockerized recipe (quantize.py, recipe, serve script) is included as
recipe.yaml in this repo.
Limitations
INT4 introduces ~2-3% per-vector cosine drift vs BF16; for most RAG retrieval
this does not change top-k ranking, but exact-similarity-threshold workflows
should re-tune thresholds.
Validation above is text-only.
Inherits all capabilities and limitations of the base
Qwen/Qwen3-VL-Embedding-8B.
License & citation
Released under Apache-2.0, inherited from the base model. Please cite the
original Qwen3-VL-Embedding work and credit Qwen/Qwen3-VL-Embedding-8B as the
base model.