Instructions to use litert-community/Vela-1.0-Encoder-307M-Embedding-LiteRT with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use litert-community/Vela-1.0-Encoder-307M-Embedding-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
- LiteRT-LM
How to use litert-community/Vela-1.0-Encoder-307M-Embedding-LiteRT with LiteRT-LM:
# LiteRT-LM runs on various platforms (Android, iOS, Windows, Linux, macOS, IoT, Web/WASM) # and supports many APIs (C++, Python, Kotlin, Swift, JavaScript, Flutter). # For platform-specific integration guides, please refer to the official developer website: # https://ai.google.dev/edge/litert-lm # To try LiteRT-LM, the easiest way is to use our CLI tool. # 1. Install the LiteRT-LM CLI tool: pip install -U litert-lm # 2. Download and run this model locally: # See: https://ai.google.dev/edge/litert-lm/cli # A single .litertlm file in the repo is picked automatically; otherwise the CLI asks which one to run # (or pass its name right after the repo id). litert-lm run \ --from-huggingface-repo=litert-community/Vela-1.0-Encoder-307M-Embedding-LiteRT \ --prompt="Write me a poem"
- sentence-transformers
How to use litert-community/Vela-1.0-Encoder-307M-Embedding-LiteRT with sentence-transformers:
from sentence_transformers import SentenceTransformer model = SentenceTransformer("litert-community/Vela-1.0-Encoder-307M-Embedding-LiteRT") sentences = [ "The weather is lovely today.", "It's so sunny outside!", "He drove to the stadium." ] embeddings = model.encode(sentences) similarities = model.similarity(embeddings, embeddings) print(similarities.shape) # [3, 3] - Notebooks
- Google Colab
- Kaggle
Vela-1.0-Encoder-307M-Embedding β LiteRT
LiteRT (.tflite) and LiteRT-LM (.litertlm) conversions of vllm-sr/Vela-1.0-Encoder-307M-Embedding (revision 290318fd), a 22-layer ModernBERT sentence embedder (768-d, mean pooling + L2 normalization, Matryoshka 64β768) with the Gemma 256k tokenizer. The graph takes input_ids + attention_mask and returns the normalized sentence embedding; pooling and normalization are inside the graph, so the output is the same vector sentence-transformers returns for the same text.
Files
| file | input β output | weights | size |
|---|---|---|---|
vela_L64_fp16.tflite / vela_L128_fp16.tflite / vela_L256_fp16.tflite / vela_L512_fp16.tflite β CPU (one file, token ids in) |
input_ids int32 [1,L], attention_mask float32 [1,L] β embedding float32 [1,768] |
float16 (FC weights and the token table, dequantized at load), float32 activations | 614β616 MB each |
vela_L64_embeds_fp16.tflite β¦ vela_L512_embeds_fp16.tflite + tok_embeddings_fp16.bin β GPU / NPU (the host looks the token rows up) |
inputs_embeds float32 [1,L,768], attention_mask float32 [1,L] β embedding float32 [1,768]; the host looks the token rows up in the table (float16, row-major [256000,768]) |
float16 | 221β223 MB + 393 MB table |
Vela-1.0-Encoder-307M-Embedding_fp16.litertlm |
text β embedding through LiteRT-LM EmbeddingEngine (embedder + encoder_64/128/256/512 + the repo's tokenizer; the engine adds <bos> / <eos> and normalizes) |
float16 | 624 MB |
One file per static window L: a text of n tokens (including <bos> and <eos>) runs in the smallest window with L β₯ n; the rows beyond n are padding (attention_mask 0, input_ids 0). Tokenize with the repo's tokenizer.json (post-processor adds <bos> = 2 and <eos> = 1); strip the text first β sentence-transformers strips before tokenizing, and a trailing space otherwise becomes a lone β token.
Conversion
- Direct trace of the encoder (attention written out, alternating global / sliding-window(Β±64) layers, the publisher's YaRN RoPE tables as constants) + mean pooling + L2 normalization with litert-torch 0.10.0 / litert-converter 0.5.0.dev20260912 β one
.tfliteper window; weights to float16 with ai-edge-quantizer (weight-only; activations float32). - The LayerNorms of layers 12β21 and the final norm are computed on xΒ·2β»βΆ (epsΒ·2β»ΒΉΒ²), layers 9β11 on xΒ·2β»Β²: the sum of squares of their inputs reaches 4e7 in float32, beyond float16's 65,504, and this rewrite keeps float16-storage GPU paths finite. Exact in float32 (bit-identical to the plain graph).
- An int8 token table was tried and rejected: the per-row int8 rounding error of this table (0.75 % per row on average, 2.1 % on
<bos>) moves short sentences by up to 0.7 % in cosine (floor 0.9929 over 3,918 texts), and no set of exactly-kept rows restores the 0.999 floor; float16 keeps it at 0.9998. Int8 FC weights fail harder (cosine floor 0.964). Everything shipped here is float16. - Two shapes because of the GPU delegate: it does not take a float16 token table inside the graph (
EMBEDDING_LOOKUP: Empty quantization params), so the one-file form is a CPU form, and the_embeds_files take the looked-up rows from the host and run fully on the GPU (Metal: every op accelerated) and on the NPU. The pooling is written as multiply / sum / rsqrt rather than a masked select, which the delegate also refuses (SELECT_V2with a broadcast condition). - Reference for every number: the publisher's own stack (sentence-transformers 5.1.2, transformers 4.57.6, CPU float32, SDPA math kernel), which reproduces the card's STS-B v2 Spearman (0.811867 vs the card's 0.811864) on the same 1,362 test pairs.
Parity
Bar: cosine β₯ 0.999 to the reference on every text, top-1 retrieval agreement 100 % on non-near-tie queries, Spearman of pair cosines vs the reference β₯ 0.999, the attention mask live (cutting 5 tokens off the longest text moves the vector), every output finite. Check set: PAWS-X test (en 300 pairs, es / ja / zh 100 each), STS-B v2 test (1,362 pairs), plus concatenated PAWS-X sentences for the 128 / 256 / 512 windows β 4,184 texts in all; the rows are referenced by dataset id, revision and index in the conversion record, not copied.
Results on the full check set (Mac CPU, every window): the float16 one-file and host-table files reach cosine β₯ 0.99977 to the reference on every text, top-1 agreement 100 % (1,738β1,873 queries per window), pair Spearman 0.9999995, STS-B v2 Spearman +0.000004 vs the reference; the float32 export sits at 0.99999977 (the converter's noise floor). On the phones the device subsets (140β497 texts per window) pass the same bar on the S26 NPU (cosine β₯ 0.9994), on the S26 and Pixel 8a GPUs at FP32 (β₯ 0.99997) and on both CPUs (β₯ 0.99997); the LiteRT-LM bundle passes the full set through EmbeddingEngine (cosine β₯ 0.99977), and the control with special tokens off fails (0.31), which is the engine inserting <bos> / <eos> as sentence-transformers does. Int8 weights were tried and rejected (see Conversion).
Performance
One text per call (write the inputs, run, read the 768-d vector back), median of 20 calls after 5 warm-ups, on a rested phone (thermal status 0, no CPU frequency cap). Every file is a static window, so the time is the window's, not the text's: an app picks the smallest window that holds the text.
| device Β· backend | file | L64 | L128 | L256 | L512 | parity (cosine floor vs the reference) |
|---|---|---|---|---|---|---|
| Galaxy S26 Β· NPU (Qualcomm HTP, LiteRT 2.2.0 C-API, JIT) | _embeds_fp16 + host table |
6.8 ms | 13.1 ms | 28.0 ms | 68.4 ms | β₯ 0.9994 on every window, top-1 100 % |
| Galaxy S26 Β· NPU | _fp16 one file (the HTP takes the fp16 table) |
6.8 ms | 13.1 ms | 29.0 ms | 71.0 ms | the same vectors |
| Galaxy S26 Β· GPU (Adreno, FP32 arithmetic) | _embeds_fp16 + host table |
16.5 ms | 24.0 ms | 47 ms | 120 ms | β₯ 0.99997 |
| Galaxy S26 Β· CPU (XNNPACK, 4 threads) | _fp16 one file |
19.8 ms | 39β41 ms | 85β88 ms | 210β237 ms | β₯ 0.99997 |
| Pixel 8a Β· GPU (Mali-G715, FP32) | _embeds_fp16 + host table |
76 ms | 92 ms | 181 ms | 408 ms | β₯ 0.99997 (gate-leg medians, phone not rested) |
| Pixel 8a Β· CPU (4 threads) | _fp16 one file |
181 ms | 473 ms | 936 ms | 2,045 ms | β₯ 0.99997 (gate-leg medians) |
| Mac M4 Max Β· Metal (FP32 arithmetic) | _embeds_fp16 + host table |
6.1 ms | 7.3 ms | 11.0 ms | 20.2 ms | 0.99977 on 3,918β4,184 texts |
| Mac M4 Max Β· CPU (8 threads) | _fp16 one file |
22 ms | 30 ms | 45 ms | 79 ms | 0.99977 |
NPU JIT compile on the S26: 4β34 s per window on the first run (cache it). GPU fp16 arithmetic (the GPU defaults on Metal, Adreno and Mali) keeps every top-1 and the pair ranking but drops the per-row cosine floor to 0.991β0.998 on about 1 % of the texts, so the GPU numbers above are at FP32; on the S26, FP16_WITH_FP32_ACCUM passes the full bar on L128βL512 at 84 ms (L512) if a 0.9994 floor is enough for you. Int8 weights were tried and rejected (see Conversion).
Usage
Python (LiteRT 2.2.0, ai-edge-litert; tokenizers):
import numpy as np
from ai_edge_litert.compiled_model import CompiledModel, CpuOptions, HardwareAccelerator, Options
from tokenizers import Tokenizer
L = 64 # the file's window: vela_L64_fp16.tflite takes up to 64 tokens
tok = Tokenizer.from_file("tokenizer.json") # the repo's tokenizer.json (adds <bos> = 2 and <eos> = 1)
model = CompiledModel.from_file("vela_L64_fp16.tflite", options=Options(HardwareAccelerator.CPU, cpu_options=CpuOptions(num_threads=4)))
sig = list(model.get_signature_list())[0] # "serving_default"
ins = {n: model.create_input_buffer_by_name(sig, n) for n in model.get_input_tensor_details(sig)}
outs = {n: model.create_output_buffer_by_name(sig, n) for n in model.get_output_tensor_details(sig)}
def embed(text: str) -> np.ndarray:
ids = tok.encode(text.strip()).ids # strip first: sentence-transformers does, and a trailing space adds a token
assert len(ids) <= L, f"{len(ids)} tokens > window {L}: use the next window file"
input_ids = np.zeros((1, L), np.int32); input_ids[0, : len(ids)] = ids
mask = np.zeros((1, L), np.float32); mask[0, : len(ids)] = 1.0
ins["input_ids"].write(input_ids); ins["attention_mask"].write(mask)
model.run_by_name(sig, ins, outs)
return np.asarray(outs["embedding"].read(768, np.float32), dtype=np.float32).reshape(768) # L2-normalized, 768-d
q, d1, d2 = "How do I reset my password?", "Steps to change a forgotten password", "Best pizza toppings for a party"
e = [embed(t) for t in (q, d1, d2)]
print("cos(q, d1) =", float(e[0] @ e[1]), " cos(q, d2) =", float(e[0] @ e[2]))
Run on 2026-10-18 on the fp16 L64 file (card/snippet_check.py, the same code against the files of this conversion): cos(q, d1) = 0.842 cos(q, d2) = -0.007, and the vectors of 8 check-set texts match the publisher's stack at cosine 1.000000.
Android: the .litertlm bundle runs through LiteRT-LM's EmbeddingEngine (EmbeddingEngineConfig(modelPath) β computeEmbedding(text); leave insertSpecialTokens at its default, the bundle declares <bos> 2 and <eos> 1). The .tflite files run through LiteRT CompiledModel on the CPU or GPU with the host doing the tokenization (the repo's tokenizer.json) and, for the _embeds_ files, the table lookup.
Matryoshka
The checkpoint was trained with Matryoshka dimensions 64 / 128 / 256 / 512 / 768. The graph returns the full 768-d normalized vector; to use a smaller dimension, take the first d values and re-normalize on the host (sentence-transformers truncate_dim does the same).
Source and licence
Model: vllm-sr/Vela-1.0-Encoder-307M-Embedding, Apache-2.0 β this conversion keeps the licence. Conversion scripts and the full record: hf-to-litertlm.
- Downloads last month
- 90
Model tree for litert-community/Vela-1.0-Encoder-307M-Embedding-LiteRT
Base model
jhu-clsp/mmBERT-base