Skip to main content

QuadEmbed

Multimodal embeddings for text, image, audio, and video in one shared 768-dimensional vector space. Compare any modality against any other with a dot product.

Trained end-to-end on a single RTX 4060 laptop GPU (8GB VRAM) by freezing three pretrained encoders and training only two small projection heads, reproducing the GELATO architecture behind Jina AI's jina-embeddings-v5-omni.

⚠️ Non-commercial license. QuadEmbed builds on jina-embeddings-v5-text-nano, which is CC-BY-NC-4.0. That restriction carries through to this package and its weights. Research and educational use is fine; commercial use is not, without a separate license from Jina AI.

Install

pip install quadembed              # text + image + audio
pip install quadembed[video]       # adds video support (OpenCV)
pip install quadembed[all]         # everything, plus audio file loading helpers

Quickstart

from quadembed import QuadEmbed
from PIL import Image

model = QuadEmbed.from_pretrained()   # downloads weights from the Hub on first run

texts = ["a dog running on the beach", "a bowl of ramen noodles"]
text_embeds = model.embed_text(texts)
image_embeds = model.embed_image([Image.open("photo.jpg").convert("RGB")])

# embeddings are L2-normalized, so this is cosine similarity
similarity = text_embeds @ image_embeds.T
for text, score in zip(texts, similarity[:, 0].tolist()):
    print(f"{score:.3f}  {text}")

Audio

Pass mono float32 arrays at 16 kHz (what the frozen Whisper encoder expects):

import soundfile as sf

audio, sr = sf.read("clip.wav")
audio_embeds = model.embed_audio([audio.astype("float32")], sampling_rate=sr)
similarity = model.embed_text(["a dog barking"]) @ audio_embeds.T

Video

model = QuadEmbed.from_pretrained(modalities=("text", "video"))
video_embeds = model.embed_video_file("clip.mp4", num_frames=4)
similarity = model.embed_text(["a person skateboarding"]) @ video_embeds.T

Loading only what you need

Each encoder costs memory and download time. Load a subset:

model = QuadEmbed.from_pretrained(modalities=("text", "vision"))   # skip audio
model = QuadEmbed.from_pretrained(device="cpu")                    # force CPU

How it works

Three frozen encoders, two trained projectors:

Role Model (frozen) Trainable on top
Text (anchor) jinaai/jina-embeddings-v5-text-nano (239M) nothing, it defines the space
Vision google/siglip2-base-patch16-naflex vision projector (2.36M params)
Audio openai/whisper-large-v3 encoder audio projector (0.98M params)

Only ~3.3M parameters were ever trained, against nearly a billion frozen ones. Video needs no encoder or projector of its own: frames are sampled, run through the vision path, and mean-pooled over time.

Training used bidirectional in-batch InfoNCE (temperature 0.02) plus Matryoshka representation learning over prefix dims {32, 64, 128, 256, 768}, so truncated embeddings remain usable if you need a smaller index.

Measured performance

Cross-modal retrieval recall@k on held-out splits, text-query direction:

Modality R@1 R@5 R@10 n
Image 13.7% 68.6% 81.1% 1024
Audio 67% 97% 100% 33
Video 40% 86% 94% 50

Random-chance R@1 on the 1024-candidate image eval is ~0.1%.

These are honest small-scale numbers. Vision was trained on ~172k image-caption pairs, orders of magnitude less than production embedding models, and image R@1 is the weakest metric as a result. R@5 and R@10 are considerably stronger, so this is more useful for candidate retrieval and reranking than for exact top-1 matching.

Links

Credit

QuadEmbed reproduces the architecture described in Jina AI's GELATO paper (arXiv:2605.08384). All credit for the original architecture and training recipe belongs there. This is an independent reproduction, not affiliated with or endorsed by Jina AI.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

quadembed-0.1.2.tar.gz (10.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

quadembed-0.1.2-py3-none-any.whl (12.3 kB view details)

Uploaded Python 3

File details

Details for the file quadembed-0.1.2.tar.gz.

File metadata

  • Download URL: quadembed-0.1.2.tar.gz
  • Upload date:
  • Size: 10.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.10

File hashes

Hashes for quadembed-0.1.2.tar.gz
Algorithm Hash digest
SHA256 59fa2e1f206533c5dc42820709bcb5aa524b593b65cbda3faff577ba373ffb8e
MD5 ac749fa7a4619dfd5a3086d1afdac1c6
BLAKE2b-256 229869af35a6395104c593ea1b34360e45b92e71dd1d86dd3c5843197f40b729

See more details on using hashes here.

File details

Details for the file quadembed-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: quadembed-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 12.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.10

File hashes

Hashes for quadembed-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 ab2b0614f99550c69bdfff557e74fe5cac56e8f8e7ff237993a4e3a73163b641
MD5 6ab3ff57502cd3447c757018864ddd6e
BLAKE2b-256 f5fc17dc5f384adf4db3a159583b62bece50f80cd24c23d10ed59d09a9d0c591

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page