EDJE: Efficient Discriminative Joint Encoders for Large Scale Vision-Language Re-ranking
A high-throughput vision-language re-ranker that combines SigLIP vision encoder with MiniLM for efficient image-text matching at scale.
Overview
Multimodal retrieval typically relies on embedding-based models like CLIP for fast vector search over pre-computed image embeddings. However, unlike text retrieval where joint-encoder re-rankers are standard, comparable vision-language re-rankers have been largely absent due to efficiency bottlenecks.
EDJE addresses this gap by introducing an Efficient Discriminative Joint Encoder that:
Precomputes vision tokens offline - Images are encoded once and stored on disk
Compresses visual features via a lightweight attention-based adapter using learnable queries
Runs only a compact joint encoder online over a small set of visual tokens plus text
This design enables fine-grained cross-modal interactions (unlike embedding-only models that simply compare vectors) while maintaining the efficiency required for large-scale retrieval.
Why Re-ranking?
Embedding-based models (CLIP, SigLIP) enable efficient similarity search through simple vector comparisons, but they process image and text independently. Joint encoders process both modalities together, allowing richer cross-modal interactions that can significantly improve retrieval quality.
EDJE is designed as a second-stage re-ranker : given the top-k candidates retrieved by an embedding model, EDJE scores each image-text pair to produce a refined ranking.
Key Features
Feature Value Throughput ~50k image-text pairs/second Storage ~49 kB per image (64 compressed tokens) Compression 576 → 64 tokens via attention-based adapter
Architecture
Vision Encoder : SigLIP2 ViT-L/16 @ 384px (google/siglip2-large-patch16-384)
Language Model : MiniLM-L12-H384 (microsoft/MiniLM-L12-H384-uncased)
Token Compression : Cross-attention adapter with 64 learnable queries
The model is split into two components for efficient deployment:
┌─────────────────────────────────────────────────────────────────────┐
│ OFFLINE (Index Time) │
│ ┌──────────┐ ┌─────────────────────┐ ┌───────────────────┐ │
│ │ Image │───▶│ SigLIP ViT-L/16 │───▶│ Token Compression │──▶ Store
│ └──────────┘ │ (576 tokens) │ │ Adapter (64 tok) │ │
│ └─────────────────────┘ └───────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ ONLINE (Query Time) │
│ ┌──────────────────┐ ┌──────────────────┐ ┌───────────────┐ │
│ │ Compressed Tokens│───▶│ │ │ │ │
│ │ (from index) │ │ MiniLM Joint │───▶│ Matching │ │
│ ├──────────────────┤───▶│ Encoder │ │ Score │ │
│ │ Text Query │ │ │ │ │ │
│ └──────────────────┘ └──────────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Model Components
EDJEModelForIndexing : Encodes images into compressed visual tokens (offline, run once per image)
EDJEModelForRanking : Scores image-text pairs using pre-computed visual tokens (online, run at query time)
Usage
1 import torch
2 import requests
3 from PIL import Image
4 from io import BytesIO
5 from transformers import AutoProcessor , AutoTokenizer
6 from huggingface_hub import hf_hub_download
7
8 from pretrain_model import EDJEModelForIndexing , EDJEModelForRanking
9
10 # =============================================================================
11 # Download and load model checkpoint
12 # =============================================================================
13 checkpoint_path = hf_hub_download (
14 repo_id = "shahafw/edje-vl-image-retrieval-reranker" ,
15 filename = "pytorch_model.pth"
16 )
17 checkpoint = torch . load ( checkpoint_path , map_location = "cpu" )
18
19 # Initialize both models (must match the checkpoint's architecture)
20 indexing_model = EDJEModelForIndexing (
21 siglip_path = "google/siglip2-large-patch16-384" , # Large model, 384px
22 language_model_path = "microsoft/MiniLM-L12-H384-uncased" ,
23 num_compressed_tokens = 64 ,
24 )
25 ranking_model = EDJEModelForRanking (
26 language_model_path = "microsoft/MiniLM-L12-H384-uncased" ,
27 num_compressed_tokens = 64 ,
28 )
29
30 # Load trained weights (strict=False since each model only uses a subset of weights)
31 indexing_model . load_state_dict ( checkpoint [ "model" ] , strict = False )
32 ranking_model . load_state_dict ( checkpoint [ "model" ] , strict = False )
33 indexing_model . eval ( )
34 ranking_model . eval ( )
35
36 # =============================================================================
37 # OFFLINE INDEXING PHASE
38 # Run once per image - encode and store compressed tokens in your database/index
39 # =============================================================================
40
41 # Load an image from URL
42 image_url = "https://images.unsplash.com/photo-1558788353-f76d92427f16?w=400"
43 response = requests . get ( image_url )
44 image = Image . open ( BytesIO ( response . content ) ) . convert ( "RGB" )
45
46 # Process image
47 processor = AutoProcessor . from_pretrained ( "google/siglip2-large-patch16-384" , use_fast = True )
48 pixel_values = processor ( images = image , return_tensors = "pt" ) [ "pixel_values" ]
49
50 # Generate compressed visual tokens (store these in your vector index)
51 with torch . no_grad ( ) :
52 compressed_tokens = indexing_model ( pixel_values )
53 # compressed_tokens shape: (1, 64, 384) → ~49 kB per image
54
55 print ( f"Compressed tokens shape: { compressed_tokens . shape } " )
56
57 # =============================================================================
58 # ONLINE RE-RANKING PHASE
59 # Given candidates retrieved by first-stage model (e.g., CLIP), re-rank them
60 # =============================================================================
61
62 # Example: rank the image against multiple candidate captions
63 candidate_captions = [
64 "a cute golden retriever puppy" ,
65 "a cat sleeping on a sofa" ,
66 "a beautiful sunset over the ocean" ,
67 ]
68
69 # Tokenize captions
70 tokenizer = AutoTokenizer . from_pretrained ( "microsoft/MiniLM-L12-H384-uncased" )
71 text_inputs = tokenizer (
72 candidate_captions ,
73 padding = True ,
74 truncation = True ,
75 max_length = 64 ,
76 return_tensors = "pt"
77 )
78
79 # Expand compressed tokens to match batch size (one image vs multiple captions)
80 compressed_tokens_batch = compressed_tokens . expand ( len ( candidate_captions ) , - 1 , - 1 )
81
82 # Compute matching scores for re-ranking
83 with torch . no_grad ( ) :
84 scores = ranking_model (
85 compressed_tokens = compressed_tokens_batch ,
86 input_ids = text_inputs [ "input_ids" ] ,
87 attention_mask = text_inputs [ "attention_mask" ] ,
88 )
89
90 # Display re-ranked results (higher score = better match)
91 print ( "\nRe-ranked Results:" )
92 for caption , score in sorted ( zip ( candidate_captions , scores . tolist ( ) ) , key = lambda x : x [ 1 ] , reverse = True ) :
93 print ( f" { score : .4f } : { caption } " )
Typical Retrieval Pipeline
Query ──▶ First-Stage Retrieval (CLIP/SigLIP) ──▶ Top-K Candidates ──▶ EDJE Re-ranking ──▶ Final Results
(fast, embedding-based) (accurate, joint-encoder)
First stage : Use an embedding model (CLIP, SigLIP) to retrieve top-K candidates via approximate nearest neighbor search
Second stage : Use EDJE to re-rank the candidates with fine-grained cross-modal scoring
Training
This model was trained using:
Image-Text Matching (ITM) loss - Binary classification of matched/unmatched pairs
Image-Text Contrastive (ITC) loss - Alignment with SigLIP's embedding space
Masked Language Modeling (MLM) loss - Language understanding
Knowledge distillation - From a larger teacher model
Results
Main Retrieval Performance (Recall@1)
EDJE matches prior joint encoders while being up to 53× faster with 36× less storage :
Method Training Data Flickr-ZS COCO-FT Storage Params Inference T2I I2T T2I I2T per image time (ms) Prior Joint Encoders ALBEF ViT-B/16 12M 82.8 94.1 60.7 77.6 1,769 kB 147M 45.92 BLIP ViT-B/16 12M 84.9 94.8 63.1 80.6 1,769 kB 139M 83.27 BLIP ViT-L/16 129M 86.7 96.7 65.1 82.4 2,359 kB 139M 101.61 EDJE (Ours) Local ViT-B/16 12M 84.3 94.3 60.9 76.1 442 kB 33M 2.86 Local ViT-L/16 12M 87.8 96.5 64.9 81.0 442 kB 33M 4.14 Compressed-128 ViT-L/16 12M 87.1 96.3 64.6 81.0 98 kB 33M 2.04 Compressed-64 ViT-L/16 12M 86.9 96.4 64.6 80.9 49 kB 33M 1.91
Full Dataset Retrieval
Evaluation on the full Flickr and COCO datasets (retrieval against all images/captions):
Flickr Full (Zero-Shot)
Model R@5 R@10 R@20 R@5 R@10 R@20 Text→Image Image→Text LightningDOT 60.1 69.5 78.3 75.1 83.9 90.5 EDJE 78.3 84.5 89.6 92.4 95.9 97.7
MS-COCO Full (Fine-tuned)
Model R@5 R@10 R@20 R@5 R@10 R@20 Text→Image Image→Text LightningDOT 37.3 46.8 56.4 48.0 59.0 68.9 EDJE 52.2 60.6 68.1 69.9 77.0 82.6
Efficiency Comparison
Metric EDJE Prior Joint Encoders (BLIP) Throughput ~50k pairs/sec ~1k pairs/sec Relative Speedup Up to 53× faster1× (baseline) Storage per image 49 kB ~1.2 MB (full ViT features) Online ViT forward ✗ Not needed ✓ Required
Citation
1 @inproceedings{edje2026,
2 author = {Mitchell Keren Taraday, Shahaf Wagner, Chaim Baskin},
3 title = {Efficient Discriminative Joint Encoders for Large Scale Vision-Language Re-ranking},
4 booktitle = {ICLR},
5 year = {2026},
6 }
License
BSD-3-Clause