This repository contains the code used to study and improve ColPali retrieval in Qdrant. The main goal is to reduce latency while keeping retrieval quality close to the full baseline.
ColPali is a late-interaction model that turns each document image into many patch token vectors. Search then compares query tokens with image tokens using MaxSim scoring.
common/: shared Python utilities for collection setup, retrieval methods, evaluation metrics, and plotting.data/: main evaluation dataset assets (images/, queries.json, relevance.csv) and the download script.data_preso/: smaller presentation dataset with the same layout as data/.local_model_demo/: local embedding flow (GPU model execution with ColQwen3).server_engine_demo/: server-based embedding flow (calls a running ColPali server).optimization_experiments/: core experiments for pooling, clustering, ablations, and final comparison.pip install -r requirements.txt
.env file in the project root:COLPALI_SERVER_URL=http://localhost:8000
http://localhost:6333 (demo notebooks)http://localhost:6335 (optimization notebooks)python data/download_vidore.py --max-pages 500
The data comes from vidore/docvqa_test_subsampled on Hugging Face.
Expected output after running the download script:
data/images/*.png: document page imagesdata/queries.json: query listdata/relevance.csv: query-to-image relevance labelsTypical dataset size used in experiments:
queries.json format[
{"id": "q1", "text": "coffee mug on a desk"},
{"id": "q2", "text": "transformer architecture diagram"}
]
relevance.csv formatquery_id,image_id,relevance
q1,image_0001,1
q1,image_0023,1
q2,image_0104,2
Note: image_id is expected to match the image filename (without extension), unless a custom resolver is used.
All main experiment notebooks are in optimization_experiments/.
00_setup_collection.ipynbPurpose:
Named vectors created:
colpali_originalmuvera_fdescalar_quantizedbinary_quantizedhierarchical_2xhierarchical_4xrow_pooledcolumn_pooledclustered_8x, clustered_16x, clustered_32x, clustered_64xObserved run from notebook output:
01_dual_axis_pooling.ipynbPurpose:
row_pooled, column_pooled, and dual-axis prefetch.Key result:
0.7640.4220.4200.384Candidate overlap check:
0.995802_token_clustering.ipynbPurpose:
colpali_original.Cluster settings:
clustered_8x, clustered_16x, clustered_32xKey result from notebook:
0.764, latency 194.76 msclustered_32x_rerank: recall 0.754, latency 48.41 msThis is close recall with much lower latency.
03_ablation_studies.ipynbPurpose:
Ablations covered:
20, 30, 50, 100)8, 16, 32, 64)colpali_original, binary_quantized, hierarchical_2x)Important findings:
0.452 at prefetch 100)clustered_64x reaches recall around or above baseline in this setup04_final_comparison.ipynbPurpose:
Final table from notebook output:
| Method | Recall@10 | MRR | NDCG@10 | Latency (ms) |
|---|---|---|---|---|
| clustered_64x_rerank | 0.766 | 0.589 | 0.631 | 23.7 |
| full_baseline | 0.764 | 0.588 | 0.630 | 49.7 |
| clustered_32x_rerank | 0.754 | 0.582 | 0.623 | 23.1 |
| clustered_16x_rerank | 0.732 | 0.566 | 0.606 | 23.0 |
| muvera_rerank | 0.720 | 0.560 | 0.599 | 67.3 |
| dual_axis_rerank | 0.422 | 0.351 | 0.368 | 63.5 |
| row_only_rerank | 0.420 | 0.349 | 0.366 | 41.0 |
Notebook recommendation:
clustered_64x_rerankoptimization_experiments/pooling_utils.py contains the helper functions used in multiple notebooks:
safe_row_column_pool: computes row/column pooled vectors when patch grid metadata is valid.hierarchical_pool: groups adjacent tokens by fixed size (for example 2x or 4x).cluster_tokens_kmeans: runs KMeans on image tokens and returns centroid tokens.candidate_ids: extracts candidate IDs from ranked results.jaccard: computes candidate-set overlap.requirements.txt..env is ignored by git (.gitignore) and should stay local.*.png) are also ignored, so downloaded data is not committed by default.8 commits
Jupyter Notebook
95.7%
Python
4.3%
This repository contains the code used to study and improve ColPali retrieval in Qdrant. The main goal is to reduce latency while keeping retrieval quality close to the full baseline.
ColPali is a late-interaction model that turns each document image into many patch token vectors. Search then compares query tokens with image tokens using MaxSim scoring.
common/: shared Python utilities for collection setup, retrieval methods, evaluation metrics, and plotting.data/: main evaluation dataset assets (images/, queries.json, relevance.csv) and the download script.data_preso/: smaller presentation dataset with the same layout as data/.local_model_demo/: local embedding flow (GPU model execution with ColQwen3).server_engine_demo/: server-based embedding flow (calls a running ColPali server).optimization_experiments/: core experiments for pooling, clustering, ablations, and final comparison.pip install -r requirements.txt
.env file in the project root:COLPALI_SERVER_URL=http://localhost:8000
http://localhost:6333 (demo notebooks)http://localhost:6335 (optimization notebooks)python data/download_vidore.py --max-pages 500
The data comes from vidore/docvqa_test_subsampled on Hugging Face.
Expected output after running the download script:
data/images/*.png: document page imagesdata/queries.json: query listdata/relevance.csv: query-to-image relevance labelsTypical dataset size used in experiments:
queries.json format[
{"id": "q1", "text": "coffee mug on a desk"},
{"id": "q2", "text": "transformer architecture diagram"}
]
relevance.csv formatquery_id,image_id,relevance
q1,image_0001,1
q1,image_0023,1
q2,image_0104,2
Note: image_id is expected to match the image filename (without extension), unless a custom resolver is used.
All main experiment notebooks are in optimization_experiments/.
00_setup_collection.ipynbPurpose:
Named vectors created:
colpali_originalmuvera_fdescalar_quantizedbinary_quantizedhierarchical_2xhierarchical_4xrow_pooledcolumn_pooledclustered_8x, clustered_16x, clustered_32x, clustered_64xObserved run from notebook output:
01_dual_axis_pooling.ipynbPurpose:
row_pooled, column_pooled, and dual-axis prefetch.Key result:
0.7640.4220.4200.384Candidate overlap check:
0.995802_token_clustering.ipynbPurpose:
colpali_original.Cluster settings:
clustered_8x, clustered_16x, clustered_32xKey result from notebook:
0.764, latency 194.76 msclustered_32x_rerank: recall 0.754, latency 48.41 msThis is close recall with much lower latency.
03_ablation_studies.ipynbPurpose:
Ablations covered:
20, 30, 50, 100)8, 16, 32, 64)colpali_original, binary_quantized, hierarchical_2x)Important findings:
0.452 at prefetch 100)clustered_64x reaches recall around or above baseline in this setup04_final_comparison.ipynbPurpose:
Final table from notebook output:
| Method | Recall@10 | MRR | NDCG@10 | Latency (ms) |
|---|---|---|---|---|
| clustered_64x_rerank | 0.766 | 0.589 | 0.631 | 23.7 |
| full_baseline | 0.764 | 0.588 | 0.630 | 49.7 |
| clustered_32x_rerank | 0.754 | 0.582 | 0.623 | 23.1 |
| clustered_16x_rerank | 0.732 | 0.566 | 0.606 | 23.0 |
| muvera_rerank | 0.720 | 0.560 | 0.599 | 67.3 |
| dual_axis_rerank | 0.422 | 0.351 | 0.368 | 63.5 |
| row_only_rerank | 0.420 | 0.349 | 0.366 | 41.0 |
Notebook recommendation:
clustered_64x_rerankoptimization_experiments/pooling_utils.py contains the helper functions used in multiple notebooks:
safe_row_column_pool: computes row/column pooled vectors when patch grid metadata is valid.hierarchical_pool: groups adjacent tokens by fixed size (for example 2x or 4x).cluster_tokens_kmeans: runs KMeans on image tokens and returns centroid tokens.candidate_ids: extracts candidate IDs from ranked results.jaccard: computes candidate-set overlap.requirements.txt..env is ignored by git (.gitignore) and should stay local.*.png) are also ignored, so downloaded data is not committed by default.8 commits
Jupyter Notebook
95.7%
Python
4.3%