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.1.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.1-py3-none-any.whl (12.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: quadembed-0.1.1.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.1.tar.gz
Algorithm Hash digest
SHA256 6fffbe77f914f51fa794655fa3d986f48239fbea630d4d416b14e0d7df6df7e8
MD5 eb979efbe49110ed7e83e816aa3226ed
BLAKE2b-256 9dec022dab90784d23ef57b89b9a0c48053c125974904ac7a3be9afab0943576

See more details on using hashes here.

File details

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

File metadata

  • Download URL: quadembed-0.1.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9c21a73faa926964fad4d83b206d06dc5b7d793184b5a0b249e534c0cd82b0de
MD5 fe4db274ca1f338867cf213490f282e0
BLAKE2b-256 636d3cd0862a91f7efca586847e652932f696ee03eb8dbd75d19ba2be7f02267

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.2

2 files

This release

0.1.1 This release

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