Views
No views yet


jina-v5-omni-nano and jina-v5-omni-small define the open-weight frontier (Table 1 in the ArXiv report).
jina-embeddings-v5-omni-small-retrieval is a multimodal embedding model that accepts text, images, video, and audio and produces embeddings in a shared vector space aligned with the text-only jinaai/jina-embeddings-v5-text-small-retrieval — so you can index with text and query with any modality, no reindexing. For a more compact alternative, see jinaai/jina-embeddings-v5-omni-nano-retrieval.jina-embeddings-v5-omni-small family. The combined repo containing all task adapters is jinaai/jina-embeddings-v5-omni-small.| Feature | Value |
|---|---|
| Parameters | ~1.56B |
| Embedding Dimension | 1024 |
| Supported Tasks | retrieval |
| Max Sequence Length | 32768 |
| Pooling Strategy | Last-token |
| Supported Inputs | text, image, video, audio |
| Supported File Types | images: .jpg, .jpeg, .png, .gif, .webp, .bmp, .tif, .tiff, .avif, .heic, .svg; video: .mp4, .avi, .mov, .mkv, .webm, .flv, .wmv; audio: .wav, .mp3, .flac, .ogg, .m4a, .opus; documents: .pdf |
| Matryoshka Dimensions | 32, 64, 128, 256, 512, 768, 1024 |
1# Retrieve the configuration of the preconfigured omni-small inference endpoint
2GET /_inference/embedding/.jina-embeddings-v5-omni-small
3
4# Generate an embedding for a single piece of text using the predefined endpoint
5POST _inference/embedding/.jina-embeddings-v5-omni-small
6{
7 "input": [
8 "This is a test"
9 ]
10}
11
12# Fuse a text description and an image into a single embedding via a multimodal content block
13POST _inference/embedding/.jina-embeddings-v5-omni-small
14{
15 "input": [
16 {
17 "content": [
18 { "type": "text", "value": "A small blue square" },
19 { "type": "image", "format": "base64", "value": "<BASE64_IMAGE_DATA>" }
20 ]
21 }
22 ]
23}
24
25# Create a custom endpoint that truncates omni-small embeddings to 32 dimensions
26PUT _inference/embedding/jina-omni-small-32d
27{
28 "service": "elastic",
29 "service_settings": {
30 "model_id": "jina-embeddings-v5-omni-small",
31 "dimensions": 32
32 }
33}1# core
2pip install transformers torch pillow numpy
3
4# Optional — install only the extras for the modalities you actually use:
5pip install librosa soundfile # audio decoding
6pip install torchcodec # video decoding for proc(videos=path) (transformers default backend)
7pip install av # video decoding for SentenceTransformer model.encode("clip.mp4")
8pip install pdf2image pypdfium2 # PDF rendering
9pip install cairosvg pillow # SVG rendering
10pip install "vllm==0.20.1" # high-throughput serving (validated)
11pip install sentence-transformers # one-call multimodal API1from PIL import Image
2import librosa, torch
3from transformers import AutoModel, AutoProcessor, WhisperFeatureExtractor
4
5repo = "jinaai/jina-embeddings-v5-omni-small-retrieval"
6model = AutoModel.from_pretrained(repo, trust_remote_code=True).eval()
7proc = AutoProcessor.from_pretrained(repo, trust_remote_code=True)
8
9# model.embed(**inputs) returns L2-normalized last-token embeddings.
10q_vec = model.embed(**proc(text="Query: Which planet is known as the Red Planet?", return_tensors="pt").to(model.device))
11d_vec = model.embed(**proc(text="Document: Mars is often referred to as the Red Planet due to its reddish appearance.", return_tensors="pt").to(model.device))
12
13# Equivalent high-level call — handles the Query:/Document: prefix for you:
14q_vec = model.encode(["Which planet is known as the Red Planet?"], task="retrieval", prompt_name="query")
15d_vec = model.encode(["Mars is often referred to as the Red Planet due to its reddish appearance."], task="retrieval", prompt_name="document")
16i_vec = model.embed(**proc(images=Image.open("photo.jpg"), text="<|vision_start|><|image_pad|><|vision_end|>", return_tensors="pt").to(model.device))
17v_vec = model.embed(**proc(videos="clip.mp4", text="<|vision_start|><|video_pad|><|vision_end|>", return_tensors="pt").to(model.device))
18# Needs torchcodec or torchvision. On Windows or envs without either, use model.encode("clip.mp4") from the sentence-transformers section below (av-only, no codec libs required).
19
20# Audio has no string placeholder — build the prompt from config. Size the
21# audio run from the REAL Whisper frame mask: the feature extractor pads every
22# clip out to the 30s window, so counting padded frames emits 750 audio tokens
23# for a 2s clip and a 30s clip alike, which is not how the model was trained.
24# (The sentence-transformers path below does all of this for you.)
25audio, _ = librosa.load("speech.wav", sr=16000)
26feats = WhisperFeatureExtractor(feature_size=128)(
27 audio, sampling_rate=16000, return_tensors="pt",
28 padding="max_length", return_attention_mask=True,
29)
30feat, feat_mask = feats["input_features"], feats["attention_mask"]
31real = int(feat_mask.sum()) # unpadded mel frames
32n = ((real - 1) // 2 + 1 - 2) // 2 + 1 # audio encoder output length
33cfg, tok = model.config, proc.tokenizer
34audio_run = (tok.convert_ids_to_tokens(cfg.audio_start_token_id)
35 + tok.convert_ids_to_tokens(cfg.audio_token_id) * n
36 + tok.convert_ids_to_tokens(cfg.audio_end_token_id))
37prompt = tok.apply_chat_template([{"role": "user", "content": audio_run}],
38 tokenize=False, add_generation_prompt=False)
39ids = torch.tensor([tok(prompt)["input_ids"]]) # keep the tokenizer's specials
40a_vec = model.embed(
41 input_ids=ids.to(model.device),
42 attention_mask=torch.ones_like(ids).to(model.device),
43 input_features=feat.to(model.device, dtype=next(model.parameters()).dtype),
44 feature_attention_mask=feat_mask.to(model.device),
45)model.embed(...) path above uses explicit Query: / Document: text prefixes, and the model.encode(..., prompt_name=...) path handles the prefix for you. Via sentence-transformers (below) the same intent is expressed with encode_query() / encode_document() helpers. A bare encode(text) without a prefix or prompt_name is ambiguous and will not match either retrieval side cleanly. This applies to every modality, not just text: to encode an image, video, or audio clip as a query or document, either prepend the same Query: / Document: prefix to the text alongside the media placeholder on the raw path (e.g. text="Query: <|vision_start|><|image_pad|><|vision_end|>"), or pass the media straight to encode_query(...) / encode_document(...) via sentence-transformers.dtype, device, min_pixels, or custom pooling code needed — sensible defaults live in the model config (bf16 weights, 256–1280 vision tokens).transformers>=4.57 (recommend >=5.1 for the small variants)torch>=2.5sentence-transformers — one-call API for all 4 modalitieslibrosa — audio decodingtorchcodec (or torchvision) — video decoding when calling proc(videos=…) directly (transformers' video processor selects torchcodec by default, falling back to torchvision)av — video decoding via model.encode("clip.mp4") (SentenceTransformer path); in-memory np.ndarray frames need no decodervllm==0.20.1 — high-throughput serving; H100 deployments may also need DeepGEMM installed for vLLM FP8 kernels1from transformers import AutoModel
2
3AutoModel.from_pretrained("jinaai/jina-embeddings-v5-omni-small-retrieval", trust_remote_code=True, modality="omni") # all (default)
4AutoModel.from_pretrained("jinaai/jina-embeddings-v5-omni-small-retrieval", trust_remote_code=True, modality="vision") # vision + text
5AutoModel.from_pretrained("jinaai/jina-embeddings-v5-omni-small-retrieval", trust_remote_code=True, modality="audio") # audio + text
6AutoModel.from_pretrained("jinaai/jina-embeddings-v5-omni-small-retrieval", trust_remote_code=True, modality="text") # text onlysentence-transformers:SentenceTransformer("jinaai/jina-embeddings-v5-omni-small-retrieval", trust_remote_code=True, model_kwargs={"modality": "vision"})1from sentence_transformers import SentenceTransformer
2
3model = SentenceTransformer("jinaai/jina-embeddings-v5-omni-small-retrieval", trust_remote_code=True)
4
5# URLs, local paths (with or without extension), PIL.Image, np.ndarray,
6# torch.Tensor, bytes, and BytesIO are all accepted directly.
7q_vec = model.encode_query("Which planet is known as the Red Planet?")
8d_vec = model.encode_document("Mars is often referred to as the Red Planet due to its reddish appearance.")
9
10# The Query:/Document: distinction applies to EVERY modality, not just text —
11# pass the image / video / audio (URL, path, or object) straight to
12# encode_query() / encode_document() to encode it as that retrieval side:
13img_as_document = model.encode_document("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg")
14img_as_query = model.encode_query("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg")
15i_vec = model.encode("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg")
16v_vec = model.encode("https://huggingface.co/datasets/raushan-testing-hf/videos-test/resolve/main/sample_demo_1.mp4") # needs `pip install av`
17a_vec = model.encode("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac") # needs `pip install librosa soundfile`
18
19# Fused multimodal — a tuple becomes ONE embedding in a single forward pass:
20emb = model.encode(("Winter boots, waterproof leather upper",
21 "https://.../boot.jpg",
22 "https://.../boot.mp4"))dtype, device, min_pixels, or custom pooling code needed — sensible defaults live in the model config (bf16 weights, 256–1280 vision tokens).model.encode(("narration.wav", "clip.mp4"))..mp4 .avi .mov .mkv .webm .flv .wmv, or extensionless — content-sniffed), HTTP(S) URL, bytes/io.BytesIO, and in-memory np.ndarray / torch.Tensor of shape (T, H, W, 3|4) with dtype uint8. In-memory frames go straight to the processor — no MP4 round-trip, no extra decoder.1import numpy as np
2# (T, H, W, 3) uint8 — e.g. from decord, imageio, or an rgb frame buffer
3frames = np.zeros((16, 224, 224, 3), dtype=np.uint8)
4v_vec = model.encode(frames)vllm==0.20.1. The model card already provides the pooling config, so no custom PoolerConfig is needed.1from vllm import LLM
2llm = LLM(
3 model="jinaai/jina-embeddings-v5-omni-small-retrieval",
4 runner="pooling",
5 trust_remote_code=True,
6)
7outs = llm.embed([{"prompt": "Document: Mars is often referred to as the Red Planet."}])vllm serve jinaai/jina-embeddings-v5-omni-small-retrieval --trust-remote-code.1# transformers
2vec = model.embed(truncate_dim=256, **proc(text="hello", return_tensors="pt"))
3# or
4vec = model.encode(["hello"], task="retrieval", truncate_dim=256)
5
6# sentence-transformers
7vec = model.encode("hello", truncate_dim=256)
8
9# vLLM — ask the pooler for a smaller embedding
10from vllm import PoolingParams
11outs = llm.embed(prompts, pooling_params=PoolingParams(dimensions=256))
12# or truncate + renormalize the full-dim output yourself:
13import numpy as np
14full = np.asarray(outs[0].outputs.embedding)
15vec = full[:256] / np.linalg.norm(full[:256])1# sentence-transformers — any modality
2t_vecs = model.encode(["query 1", "query 2"])
3i_vecs = model.encode([Image.open("a.jpg"), Image.open("b.jpg")])
4v_vecs = model.encode(["clip1.mp4", "clip2.mp4"])
5a_vecs = model.encode(["speech1.wav", "speech2.wav"])
6
7# raw transformers — text (native padded batch)
8inputs = proc(text=["query 1", "query 2"], padding=True, truncation=True, return_tensors="pt").to(model.device)
9vecs = model.embed(**inputs) # (2, dim)
10
11# vLLM — list of request dicts, any modality
12outs = llm.embed([
13 {"prompt": "query 1"},
14 {"prompt": "query 2"},
15])sentence-transformers, images / video / audio are forwarded per-sample (one forward pass each). Text is truly batched. For large-scale multimodal throughput, prefer vLLM.jinaai/jina-embeddings-v5-text-small-retrieval — text-onlyjinaai/jina-embeddings-v5-text-small (via matching adapter)v5-text-small model and query it with image,
video, or audio embeddings from jina-embeddings-v5-omni-small-retrieval — no reindexing.