Project Page | Paper | Demo | Documentation
Sheng-Yu Wang1, Yotam Nitzan2, Aaron Hertzmann2, Jun-Yan Zhu1,
Eli Shechtman2, Alexei A. Efros3, Richard Zhang2.
Carnegie Mellon University1, Adobe Research2, UC Berkeley3
In ArXiv, 2026.
TPIPS supports Python 3.10 and later. Install matching PyTorch and torchvision builds from the official PyTorch installer, then install TPIPS:
pip install tpipsStart with the recommended embedding model. The factor argument is free-form text, specifying the visual aspect that similarity is conditioned on (e.g., "lighting", "the pose of the person", "number of ducks"). Pass factor="overall" (or None, "") for prompt-independent similarity.
import torch
import tpips
from PIL import Image
model = tpips.load_model("embedding", device="cuda")
image_a = Image.open("a.jpg").convert("RGB")
image_b = Image.open("b.jpg").convert("RGB")
with torch.inference_mode():
similarity = model.similarity(image_a, image_b, factor="lighting")
distance = model.distance(image_a, image_b, factor="lighting")
print(similarity.item()) # higher means more similar
print(distance.item()) # lower means more similarThe first call downloads the selected TPIPS checkpoint.
TPIPS also take PyTorch tensors, by default assuming channel-first (CHW or BCHW), [0, 1] tensors:
tensor_a = torch.zeros(3, 512, 512) # CHW or BCHW, float in [0, 1]
tensor_b = torch.ones(3, 512, 512)
with torch.inference_mode():
similarity = model.similarity(tensor_a, tensor_b, factor="the window on the left")
distance = model.distance(tensor_a, tensor_b, factor="the window on the left")You can backpropagate through the images by dropping torch.inference_mode(). For more argument details, see the tpips.load_model, model.similarity, and model.distance references.
Note: CUDA GPU is recommended. FlashAttention is optional: TPIPS automatically uses the newest compatible FlashAttention backend and falls back to PyTorch SDPA when none is available.
| Model Type | Supported APIs | Base Model | Ckpt | Odd-One-Out Score | 2AFC Score |
|---|---|---|---|---|---|
embedding |
similarity, distance, embed |
Qwen3VL-8B-Embedding | link | 64.1% | 77.9% |
early_fusion |
similarity, distance |
Qwen3VL-8B-Embedding | link | 64.7% | 79.3% |
activation_dist |
distance |
Qwen3VL-8B-Embedding | link | 63.8% | 75.9% |
See the tpips.load_model reference
for more detail.
| Dataset | Splits | Size | HF Link |
|---|---|---|---|
| Odd-One-Out | Train/Val/Test | 26G | sywang/tpips-odd-one-out |
| Cross-Algorithm 2AFC | Test (unseen algorithms) | 1.7G | sywang/tpips-2afc |
The commands below are for the evaluation and demo utilities included in the source repository.
Clone the repository and install the full local requirements:
git clone https://github.com/adobe-research/TPIPS.git
cd TPIPS
pip install -r requirements.txtIf you need a specific CUDA build, install matching versions of PyTorch and torchvision first. FlashAttention is optional; TPIPS automatically falls back to PyTorch SDPA when no compatible FlashAttention installation is available.
scripts/inference.py compares two images over one or more comma-separated factors:
python scripts/inference.py \
--model-type embedding \
--img-a images/cow_ref.jpg \
--img-b images/cow_0.jpg \
--factors "overall,subject color,cow statue pose,ground surface,flag pattern"Use --model-type early_fusion or --model-type activation_dist to select another released model. Pass --model-path to use a local checkpoint directory or another Hugging Face repository.
The embedding-only web demo has Image Pair and Video tabs. It reports raw cosine similarity for image conditions and plots frame similarity against actual video time. Video analysis is limited to the first 10 seconds by default.
python scripts/demo.py --gpus 0Download and safely extract both official datasets into data/:
python scripts/download_data.pyThis creates data/odd_one_out/ and data/2afc/. Use --output-dir to choose another parent directory.
Each odd-one-out JSONL record contains three image paths and one or more factor-specific human judgments:
{
"p0_path": "data/odd_one_out/images/002004_0.png",
"p1_path": "data/odd_one_out/images/002004_1.png",
"p2_path": "data/odd_one_out/images/002004_2.png",
"factors": [
{
"name": "overall",
"label": "p1",
"probs": [0.2, 0.4, 0.4]
},
{
"name": "plate color",
"label": "p1",
"probs": [0.0, 1.0, 0.0]
}
]
}For odd-one-out, label is the human-majority odd image and probs is ordered as [p0, p1, p2]. For 2AFC, p0 is the reference, p1 and p2 are the two candidates, and the two-class probabilities are ordered as [p1, p2].
Run odd-one-out evaluation on one GPU with the default downloaded test split:
python scripts/evaluate.py \
--task odd_one_out \
--model-type embedding \
--output results/odd_one_out_embedding.jsonRun the same task on multiple gpus with Accelerate:
accelerate launch --multi_gpu --num_processes <num_gpus> scripts/evaluate.py \
--task odd_one_out \
--model-type embedding \
--output results/odd_one_out_embedding.jsonRun 2AFC evaluation:
# Run on single GPU
python scripts/evaluate.py \
--task 2afc \
--model-type embedding \
--output results/2afc_embedding.json
# Run on multiple GPUs with accelerate
accelerate launch --multi_gpu --num_processes <num_gpus> scripts/evaluate.py \
--task 2afc \
--model-type embedding \
--output results/2afc_embedding.jsonUse --data for another annotation JSONL, --image-root to change the base directory for image paths, and --model-path for custom weights. Each Accelerate process evaluates a separate shard; rank zero merges the results.
Train the recommended embedding model on one GPU:
python scripts/train.py --config configs/embedding.yamlRun the equivalent training job on multiple GPUs:
accelerate launch --multi_gpu --num_processes <num_gpus> scripts/train.py \
--config configs/embedding.yamlThe same commands accept configs/early_fusion.yaml and configs/activation_dist.yaml. Override any configuration field with dotted key=value arguments, for example:
python scripts/train.py --config configs/embedding.yaml \
run_name=embedding_2epochs \
train.num_epochs=2 \
train.gradient_checkpointing=trueRuns are written under checkpoints/<timestamp>_<run_name>/ by default, and the completed run is in final/. Set output_dir=/path/to/checkpoints to change the parent directory. Set train.gradient_checkpointing=true if you encounter out-of-memory issues during training.
No. TPIPS uses a compatible FlashAttention backend when one is available and otherwise falls back to PyTorch SDPA. If a FlashAttention installation is incompatible with your Torch or CUDA build, remove the explicit backend override or run with TPIPS_ATTN_IMPL=sdpa.
This usually means that the installed PyTorch wheel was compiled for a newer CUDA version than the NVIDIA driver supports. Compare the maximum CUDA version reported by nvidia-smi with the build reported by python -c "import torch; print(torch.__version__, torch.version.cuda)". Install matching PyTorch and torchvision builds from the official PyTorch installer whose CUDA version is supported by the driver, or upgrade the NVIDIA driver. Errors such as ProcessGroupNCCL is only supported with GPUs, no GPUs found may appear afterward because the CUDA mismatch prevented PyTorch from detecting the GPUs.
TPIPS uses a Qwen3-VL tokenizer, not a Mistral tokenizer. Some Transformers versions misclassify the TPIPS checkpoint because its loader-specific config.json does not contain the standard model metadata used by the tokenizer heuristic. The bundled tokenizer matches the official Qwen3-VL tokenizer and the warning does not affect TPIPS results. Do not apply fix_mistral_regex=True, because that can change tokenization relative to the tokenizer used for TPIPS training.
activation_dist is a distance-only model. Use distance(...), where lower values mean the images are more similar. Use embedding or early_fusion when you need cosine similarity.
By default, both the released TPIPS checkpoint and its Qwen backbone are downloaded to the standard Hugging Face cache (~/.cache/huggingface/hub). Pass cache_dir= to tpips.load_model(...) to choose a cache for that call, or set HF_HOME to relocate the Hugging Face cache globally. The two resources are stored in separate model directories inside the same cache and are reused on later runs, so they are not downloaded again unless the cache is missing or the requested revision changes.
If you find TPIPS useful for your research, please cite:
@article{wang2026tpips,
title={The Many Senses of Visual Similarity: A Text-Prompted Image Perceptual Metric},
author={Wang, Sheng-Yu and Nitzan, Yotam and Hertzmann, Aaron and Zhu, Jun-Yan and Shechtman, Eli and Efros, Alexei A. and Zhang, Richard},
journal={arXiv preprint arXiv:2607.18237},
year={2026}
}TPIPS is provided under the Adobe Research License for noncommercial research use. See the license for the complete terms.


