Jina CLIP v2 split ONNX

Independent text and vision ONNX encoders derived from jinaai/jina-clip-v2.

File Precision Size Input
jina-clip-v2-text.onnx FP16 1.0 GB input_ids: int64 [batch, sequence]
jina-clip-v2-vision.onnx FP16 585 MB pixel_values: float32 [batch, 3, 512, 512]
jina-clip-v2-text-int8.onnx Dynamic INT8, optimized attention graph 540 MB input_ids: int64 [batch, sequence]
jina-clip-v2-vision-int8.onnx Dynamic INT8 301 MB pixel_values: float32 [batch, 3, 512, 512]

Every model is self-contained, supports dynamic batch sizes, and returns normalized float32 embeddings named embeddings with shape [batch, 1024]. The text models also support dynamic sequence lengths.

Which precision should I use?

  • CPU inference: use the dynamic INT8 models. They are substantially smaller and faster than FP16 on tested CPU runtimes. The INT8 text graph uses integer linear layers with FP32 attention activations and an optimized MatMul-based attention structure.
  • GPU inference: use the base FP16 models. FP16 is designed for GPU acceleration, while the dynamic quantization operators in the INT8 artifacts primarily target CPU execution.

FP16 is not recommended for CPU inference. CPU providers may promote unsupported FP16 operations to FP32 or insert casts, increasing both latency and memory use.

Preprocessing and inference

Use the tokenizer and image processor from the base model:

import onnxruntime as ort
from transformers import AutoImageProcessor, AutoTokenizer

base_model = "jinaai/jina-clip-v2"
tokenizer = AutoTokenizer.from_pretrained(base_model, trust_remote_code=True)
image_processor = AutoImageProcessor.from_pretrained(base_model, trust_remote_code=True)

text_session = ort.InferenceSession("jina-clip-v2-text-int8.onnx")
tokens = tokenizer(["A photo of a cat"], padding=True, truncation=True, return_tensors="np")
text_embeddings = text_session.run(["embeddings"], {"input_ids": tokens.input_ids})[0]

# `images` is a list of PIL images.
vision_session = ort.InferenceSession("jina-clip-v2-vision-int8.onnx")
pixels = image_processor(images=images, return_tensors="np").pixel_values
image_embeddings = vision_session.run(["embeddings"], {"pixel_values": pixels})[0]

Matryoshka dimensions

The trained dimensions are 32, 64, 128, 256, 512, 768, and 1024. To reproduce the base model's truncate_dim=N behavior, truncate the prefix and normalize it again:

import numpy as np

embedding = embedding[:, :dimension]
embedding /= np.linalg.norm(embedding, axis=1, keepdims=True)

Validation

The dynamic INT8 files were compared directly with the original, unsplit jinaai/jina-clip-v2 model through its public encode_text and encode_image methods.

Dimension Text mean cosine Text minimum cosine Vision cosine
32 0.9949 0.9933 0.9984
64 0.9951 0.9936 0.9985
128 0.9942 0.9930 0.9975
256 0.9929 0.9915 0.9964
512 0.9918 0.9907 0.9953
768 0.9913 0.9905 0.9946
1024 0.9911 0.9904 0.9943

Text validation used a multilingual batch. Vision validation used deterministic images and the base model's original image processor. INT8 outputs were finite and unit-normalized, and batching was verified at batch sizes 1 and 2.

Optimized INT8 text performance

The current jina-clip-v2-text-int8.onnx replaces the original attention Einsums with algebraically equivalent Transpose and MatMul operations. It remains bit-identical to the previous INT8 graph while giving ONNX Runtime a more efficient CPU execution structure.

The following measurements used ONNX Runtime 1.27 CPU on an 18-core Intel Core i9-7980XE. Inputs contained exactly 1024 real tokens with no padding. Times are warmed median inference times; peak RSS includes the model session.

Batch Previous INT8 time Current INT8 time Speedup Previous peak RSS Current peak RSS
1 1.425 s 0.686 s 51.9% 1.26 GiB 1.29 GiB
2 2.033 s 1.517 s 25.4% 1.77 GiB 1.83 GiB
4 4.250 s 3.250 s 23.5% 2.78 GiB 2.93 GiB
8 9.379 s 6.966 s 25.7% 5.48 GiB 5.07 GiB
16 19.686 s 14.455 s 26.6% 10.09 GiB 9.32 GiB

The optimized model is consistently faster. Peak memory is slightly higher at small batches on this Linux runtime, but becomes lower at batches 8 and 16. On a 16 GB Apple Silicon machine, the optimized graph also completed [16, 1024] where the previous graph was killed under memory pressure. Memory behavior depends on the CPU provider and allocator.

Correctness checks covered random inputs at sequence lengths 1, 12, 77, 511, 1024, and 2048, multiple batch sizes, a padded multilingual batch, normalization, and all trained Matryoshka dimensions. Outputs were bit-identical to the previous INT8 graph. The text input remains dynamic and supports up to 8192 tokens, although ordinary full attention still has quadratic memory use.

License and attribution

This is a quantized and structurally split derivative of jinaai/jina-clip-v2. It retains the base model's CC BY-NC 4.0 license and non-commercial restriction. Refer to the base model card for intended use, limitations, training details, and complete attribution.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for satorean/jina-clip-v2-split-onnx

Quantized
(1)
this model