Instructions to use litert-community/Qwen3-Embedding-0.6B-LiteRT with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use litert-community/Qwen3-Embedding-0.6B-LiteRT with LiteRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
Qwen3-Embedding-0.6B β LiteRT on-device text embeddings (fully GPU)
Qwen3-Embedding-0.6B (Apache-2.0), the 2025
state-of-the-art small text-embedding model, re-authored to run entirely on the LiteRT
CompiledModel GPU (ML Drift). Embed a query and a set of documents on-device and rank by cosine
similarity β the retrieval half of a RAG pipeline, no server and no CPU fallback. The Hexagon NPU runs this graph too, and faster; see the section below.
Because sentence embedding uses last-token pooling of a single forward pass (no generation, no KV
cache), the model is a plain single-graph .tflite β not a .litertlm β and runs on the same GPU
path as any CNN/ViT.
Verified on a Pixel 8a / Tensor G3: CompiledModel GPU compile OK, all 3264/3264 nodes on the
GPU delegate (zero CPU fallback), ~390 ms per embedding, fp16 881 MB, output cosine 0.9997 vs
the HF fp32 reference. Semantic ranking is correct β query "What is the capital of China?" β
"The capital of China is Beijing" at 0.77, unrelated docs at <0.1.
Files
| file | purpose | runs on |
|---|---|---|
qwen3emb_gpu_fp16.tflite |
28-layer Qwen3 transformer, inputs_embeds[1,128,1024] β hidden[1,128,1024] |
GPU |
embeddings_fp16.bin |
tied token-embedding table [151669,1024] fp16, for the host-side lookup |
host |
vocab.json, merges.txt |
Qwen byte-level BPE tokenizer | host |
Pipeline
text β[BPE tokenize]β ids β[host embed lookup]β inputs_embeds[1,128,1024]
β[GPU: 28-layer Qwen3 decoder]β hidden[1,128,1024]
β[pool last token + L2-normalize (+ optional Matryoshka 1024βN)]β embedding
β[cosine]β ranked documents
The token-embedding lookup is a GATHER (GPU-banned), so it is done on the host and fed in as
inputs_embeds, exactly like mel/log-mel preprocessing in the audio samples.
Why it runs fully on GPU β a Mali fp16 finding
A 28-layer decoder is the first decoder-transformer verified end-to-end on this GPU path. The one
device-only fix: the residual stream grows across depth, so the deep RMSNorm's mean(xΒ²) overflows
fp16 (>65504) β rsqrt(inf)=0 β the whole output collapses to 0 (even though Qwen3 already
RMSNorm+qk-norms every sub-layer input β it is the residual that overflows). The fix is a
per-row max-normalized RMSNorm, mathematically identical to the original:
m = max(|x|).clamp_min(1e-4) # per-row scale
xs = x / m # xΒ² now in [0,1] β the 1024-term sum never overflows
y = xs * rsqrt(mean(xsΒ²) + eps/mΒ²) * w
GQA heads are cat-repeated to 16 (a broadcast matmul would emit the Mali-rejected BROADCAST_TO),
RoPE and the causal mask are baked constants, and every tensor stays β€4D.
Minimal usage
Python (reference embeddings with the original model):
from sentence_transformers import SentenceTransformer
m = SentenceTransformer("Qwen/Qwen3-Embedding-0.6B")
q = m.encode("What is the capital of China?", prompt_name="query")
docs = m.encode(["The capital of China is Beijing.", "Paris is the capital of France."])
print((q @ docs.T)) # cosine similarity β the .tflite reproduces this at corr 0.9997
Kotlin (on-device, LiteRT CompiledModel GPU):
val model = CompiledModel.create("qwen3emb_gpu_fp16.tflite",
CompiledModel.Options(Accelerator.GPU), null)
val inputs = model.createInputBuffers(); val outputs = model.createOutputBuffers()
// host: BPE tokenize -> lookup embeddings_fp16.bin -> inputs_embeds[1,128,1024]
inputs[0].writeFloat(embedLookup(tokenize(text)))
model.run(inputs, outputs)
val hidden = outputs[0].readFloat() // [128,1024]
val emb = l2normalize(hidden, poolPos) // last real token -> 1024-d embedding
Full tokenizer + embedding-lookup + semantic-search app: see the official LiteRT sample.
Conversion
The GPU-clean re-authoring is fully reproducible β conversion scripts (build_qwen3emb.py,
export_embeddings.py) and a device-parity harness are provided with the official sample.
Performance
Measured on a Pixel 8a (Tensor G3, Android 16) with the standard TFLite benchmark_model tool β 10 warm-up runs then 50 timed runs, reported as the tool's mean.
| Runtime | Backend | Graph on GPU | Latency |
|---|---|---|---|
LiteRT CompiledModel (LITERT_CL) |
GPU | 3264 / 3264 | ~390 ms |
TFLite benchmark_model (TfLiteGpuDelegateV2) |
GPU (OpenCL) | 108 / 3264 | 5191.2 ms |
TFLite benchmark_model |
CPU (XNNPACK, 4 threads) | β | 2076.8 ms |
The two GPU rows are different runtimes, not a contradiction. The LITERT_CL figure is the one recorded when this model shipped, taken through LiteRT's own CompiledModel accelerator β the path the Kotlin sample app and the LiteRT API use. The TfLiteGpuDelegateV2 figure is the classic TFLite OpenCL delegate, measured with a tool anyone can download and re-run. They agree on how much of the graph the GPU takes; they disagree on speed, and the classic delegate is the slower of the two here. Read the TfLiteGpuDelegateV2 row as a reproducible floor, not as this model's speed on LiteRT.
On this delegate the CPU is the faster choice (2076.8 ms on CPU against 5191.2 ms on GPU) β worth knowing before you reach for the GPU on a mid-range phone.
Note that the GPU does not take the whole graph here (108 / 3264); the remainder runs on the CPU and the split costs a per-partition round trip.
Snapdragon NPU (Hexagon)
The NPU is 1.76x faster than the GPU (25.44 ms against 44.74 ms) and loads 13.16x faster (292 ms against 3842 ms).
| backend | compiled | inference (median / min) | load |
|---|---|---|---|
| NPU (Hexagon v81) | AOT (SM8850) | 25.44 ms / 25.06 ms | 292 ms |
| GPU (Adreno) | β | 44.74 ms / 43.75 ms | 3842 ms |
Measured on a Samsung Galaxy S26 (Snapdragon 8 Elite Gen 5 / SM8850, Hexagon v81, Android 16) with LiteRT CompiledModel 2.2.0, one accelerator per process, 5 warm-up runs then N=50 timed runs, median reported. Every run held thermal status NONE throughout. Headroom 0.76β0.78, where 1.0 is the throttling threshold.
The NPU row marked AOT ran an artifact compiled ahead of time for SM8850 (ai-edge-litert 2.2.0 + QAIRT 2.47.0), not the published file. That artifact is not distributed here; the compile is one command in the NPU guide.
GPU wiring: GPU guide.
- Downloads last month
- 58
