Paper · 2023-06-06 · cs.CV
Emergent Correspondence from Image Diffusion
DIFT: take a pretrained image diffusion model, noise a real image to level t, run one denoiser pass and keep an intermediate U-Net layer, averaged over noise draws. Nearest-neighbour matching on these features finds correspondences with no training. Author-reported: Stable Diffusion features reach 52.9 PCK per image on SPair-71k, against 33.9 for DINO and 38.4 for OpenCLIP.
Diffusion modelsLatent diffusionSelf-supervised learningDense correspondencecorrespondencediffusion-featuresself-supervisedfeature-extractionsemantic-correspondence
arXivPDFCodeMarkdown11 min read
AI-compiled by claude-haiku-5-5 on 2026-10-24, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
Matching points between two photos, such as the same cat's ear in two pictures, is easy for people and hard to teach a program without labelled examples. This paper observes that image generators already contain this knowledge. A diffusion model learns to clean up noisy images, and while it does, its inner layers organise pixels by what they mean.
The method is simple. Take a real photo, blur it with a chosen amount of noise, and pass it through the generator's denoising network once. Keep the values from one of the inner layers and treat them as a description of each pixel. Run this on two photos, and for a point in the first, pick the pixel in the second whose description looks most alike. Repeating the noise and averaging the results makes the descriptions steadier.
Nothing is trained for this task. The choice of noise level and inner layer matters and is tuned per task. The authors report that these generic features beat self-supervised image features on matching tasks, and sometimes match methods trained with labels.
TL;DR
- DIFT reads features out of a pretrained diffusion U-Net, with no fine-tuning and no correspondence labels §1 §4.
- A real image is first noised to a level t, then passed once through the network. Features come from one upsampling block, averaged over several noise draws §4.2 app. C.
- Matching is nearest neighbour by cosine distance §3.
- Author-reported: on SPair-71k, DIFT from Stable Diffusion gets 52.9 PCK per image, against 33.9 for DINO and 38.4 for OpenCLIP tab. 1.
- Several settings are not in the paper or differ from the code. Read Paper vs code and Pitfalls before implementing.
Problem
Dense correspondence between two images is needed for reconstruction, tracking, segmentation and editing §1. Supervised methods need annotated pairs, which are costly to collect §2. Self-supervised contrastive features give useful correspondences, but the training objective is image-level app. B. The question is whether diffusion models, trained to denoise, learn correspondence too §1.
Two obstacles exist. The network is trained on noisy inputs, and a real image is clean, so the authors add noise before feeding it in §4.2. Also, the intermediate noisy images that the generator sees when producing an image are not available for a real photo §4.2.
Method
Correspondence as nearest neighbour §3 eq. 1. Given feature maps F_1 and F_2 and a pixel p_1, the match is the pixel p_2 whose feature has the smallest distance to F_1(p_1). Features are read between pixels by bilinear interpolation. The distance is cosine by default §3.
p_2 = \arg\min_{p} \; d\big(F_1(p_1),\, F_2(p)\big) eq. 1
Diffusion forward process §4.1 eq. 2. A clean image x_0 is mixed with Gaussian noise to give x_t, with a fixed schedule \alpha_t. A network f_\theta takes x_t and t and predicts the noise. Denoising runs the forward steps in reverse §4.1.
x_t = \sqrt{\alpha_t}\, x_0 + \sqrt{1-\alpha_t}\, \epsilon, \qquad \epsilon \sim \mathcal{N}(0, \mathbf{I}) eq. 2
Generated images §4.2 fig. 2. For an image the model generated, the authors have every intermediate state. They take feature maps at one time step and find correspondences between generated images. This works across categories and across domains such as photo to painting fig. 2.
Real images §4.2. Procedure, in order:
- Add noise to the real image to reach level t, using the forward process of eq. 2 §4.2.
- Pass the noised image and t through the network once.
- Keep the output of one upsampling block, the block index n app. C.
- Repeat steps 1 to 3 with several noise draws, and average the feature maps §4.2 app. C.
The result is DIFT. Both the time step and the block index are chosen per task by grid search §4.2 app. C. Larger t and earlier blocks give more semantic features. Smaller t and later blocks keep more low-level detail §4.2.
# Extract DIFT for one real image [§4.2] [app. C]
# Input: image (3, H, W), scaled to [-1, 1]; timestep t; block index n
# Output: features (C, h, w)
def extract_dift(image, t, n, copies):
# Stack copies of the image so each gets its own noise [app. C]
batch = repeat(image, copies) # (K, 3, H, W)
# Noise every copy to level t with the forward process [eq. 2] [§4.2]
noisy = add_noise(batch, t) # (K, 3, H, W)
# One denoiser pass; keep the output of upsampling block n [app. C]
activations = unet_up_blocks(noisy, t)[n] # (K, C, h, w)
# Average over the copies to get one feature map [§4.2]
return mean(activations, axis=0) # (C, h, w)# Match one source pixel to the target image [§3] [eq. 1]
# Input: source_feat (C, h1, w1), target_feat (C, h2, w2), point (x, y)
# Output: matched target pixel (x', y')
def match_point(source_feat, target_feat, point):
# Feature at the source point, bilinearly interpolated [§3]
query = sample_bilinear(source_feat, point) # (C,)
# Cosine similarity with every target location [§3]
scores = cosine(target_feat, query) # (h2 * w2,)
# Nearest neighbour is the best-scoring location [eq. 1]
return pixel_of(argmax(scores), target_feat)Two backbones §5.1. DIFT_{sd} uses Stable Diffusion 2-1, trained on LAION. DIFT_{adm} uses Ablated Diffusion Model, trained on ImageNet without labels §5.1. The baselines are DINO (ViT-B/8, ImageNet without labels) and OpenCLIP (ViT-H/14, LAION), used without fine-tuning §5.1. Each baseline is also grid-searched over block index per task app. C.
Prompts app. C. For Stable Diffusion, SPair-71k uses the text "a photo of a [class]" with the class from the dataset. CUB uses a single bird prompt. HPatches and the video tasks use an empty prompt app. C. The authors report that an empty prompt on SPair-71k costs very little.
Hyperparameters
Values as stated in the paper. Feature map size is the stride relative to the input. Dimension is the channel count of the chosen block.
| Name | Value | Where | Notes |
|---|---|---|---|
| diffusion steps T | 1000 | app. C | both models |
| DIFT_{adm}, semantic | t=101, n=4, 512×512 | app. C | map 1/16, dim 1024 |
| DIFT_{sd}, semantic | t=261, n=1, 768×768 | app. C | map 1/16, dim 1280; prompt "a photo of a [class]" |
| DIFT_{sd}, CUB | same as semantic | §5.2 app. C | prompt "a photo of a bird" |
| DIFT_{adm}, HPatches | t=41, n=11, 768×768 | app. C | map 1/2, dim 512 |
| DIFT_{sd}, HPatches | t=0, n=2, 768×768 | app. C | map 1/8, dim 640; empty prompt |
| DIFT_{adm}, DAVIS-2017 | t=51, n=7, 480p | app. C | map 1/8, dim 512; temperature 0.1; top-k 10; radius 15; 28 previous frames |
| DIFT_{sd}, DAVIS-2017 | t=51, n=2, 480p | app. C | map 1/8, dim 640; temperature 0.2; top-k 15; radius 15; 28 previous frames; empty prompt |
| DIFT_{adm}, JHMDB | t=101, n=5, smaller side 320 | app. C | map 1/8, dim 1024; temperature 0.2; top-k 15; radius 5; 28 previous frames |
| DIFT_{sd}, JHMDB | t=51, n=2, smaller side 320 | app. C | map 1/8, dim 640; temperature 0.1; top-k 15; radius 5; 14 previous frames; empty prompt |
| noise copies (batch) | 8 by default, 4 if memory is short | app. C | features averaged over copies |
| HPatches keypoints | up to 1,000 SuperPoint keypoints | §6.1 | |
| HPatches error thresholds | \epsilon \in \{1, 3, 5\} pixels | §6.1 tab. 4 | mean corner error |
| HPatches matching and fitting | cosine or L2; RANSAC or LMEDS | app. C | best setting reported per method; threshold not stated |
| SPair PCK threshold | \alpha_{bbox} = 0.1 | §5.2 tab. 1 tab. 2 | |
| hyperparameter search | grid search on SPair-71k | §5.2 | reused for PF-WILLOW and CUB |
| feature inversion alternative | DDIM inversion | app. B | similar results, several times slower |
Results
Author-reported. Setups: SPair-71k test split, 12,234 pairs over 18 categories §5.2; PF-WILLOW, 900 pairs §5.2; CUB, 14 splits of 25 images §5.2; HPatches, 116 sequences §6.1; DAVIS-2017 validation videos and JHMDB §6.2. Baselines in the same tables are weakly supervised, supervised, or self-supervised. The paper labels each row by group.
SPair-71k, PCK per image, \alpha_{bbox}=0.1 tab. 1.
| Group | Method | All |
|---|---|---|
| (a) supervised | SCorrSAN | 55.3 |
| (a) supervised | TransforMatcher | 53.7 |
| (c) none | DIFT_{sd} (this paper) | 52.9 |
| (c) none | DIFT_{adm} (this paper) | 46.3 |
| (b) weakly | PWarpC | 35.3 |
| (c) none | OpenCLIP | 38.4 |
| (c) none | DINO | 33.9 |
SPair-71k, PCK per point, \alpha_{bbox}=0.1 tab. 2.
| Method | Mean over categories | All |
|---|---|---|
| ASIC (weak) | 36.9 | not stated |
| DIFT_{adm} (this paper) | 50.2 | 52.0 |
| DIFT_{sd} (this paper) | 57.7 | 59.5 |
| OpenCLIP | 41.0 | 41.4 |
| DINO | 36.0 | 36.7 |
The authors also report that DIFT_{sd} is above the best supervised method in 9 of 18 SPair-71k categories §5.2 tab. 1. Our count from tab. 1 agrees (aeroplane, bicycle, bird, cat, chair, horse, motorbike, plant and sheep). The overall per-image score is 2.4 points below SCorrSAN tab. 1, which the introduction describes as remaining on par §1.
PF-WILLOW and CUB tab. 3.
| Dataset | Metric | Method | Score |
|---|---|---|---|
| PF-WILLOW | PCK per image, \alpha_{bbox}=0.10 | DIFT_{sd} | 81.2 |
| PF-WILLOW | PCK per image, \alpha_{bbox}=0.10 | SCorrSAN (supervised) | 80.0 |
| PF-WILLOW | PCK per image, \alpha_{bbox}=0.10 | DIFT_{adm} | 67.0 |
| PF-WILLOW | PCK per image, \alpha_{bbox}=0.10 | OpenCLIP | 61.3 |
| PF-WILLOW | PCK per image, \alpha_{bbox}=0.10 | DINO | 51.1 |
| CUB | PCK per point, \alpha_{img}=0.1 | DIFT_{sd} | 83.5 |
| CUB | PCK per point, \alpha_{img}=0.1 | DIFT_{adm} | 78.0 |
| CUB | PCK per point, \alpha_{img}=0.1 | OpenCLIP | 67.5 |
| CUB | PCK per point, \alpha_{img}=0.1 | DINO | 66.4 |
HPatches homography accuracy, all sequences tab. 4.
| Method | Geometric supervision | ε=1 | ε=3 | ε=5 |
|---|---|---|---|---|
| CAPS (SuperPoint keypoints) | weak | 44.8 | 76.3 | 85.2 |
| DIFT_{sd} | none | 45.6 | 73.9 | 83.1 |
| DIFT_{adm} | none | 43.7 | 73.1 | 84.8 |
| DINO | none | 38.9 | 70.0 | 81.7 |
| OpenCLIP | none | 33.3 | 67.2 | 78.0 |
DAVIS-2017 and JHMDB tab. 5.
| Method | Trained on video | DAVIS J&F mean | JHMDB PCK@0.1 |
|---|---|---|---|
| DIFT_{adm} | no | 75.7 | 63.4 |
| DINO | no | 71.4 | 57.2 |
| SFC | yes | 71.2 | 61.9 |
| DIFT_{sd} | no | 70.0 | 61.1 |
| OpenCLIP | no | 62.5 | 41.7 |
PF-PASCAL, PCK per image tab. 6. The paper leaves this out of the main results, because 302 of 506 test images also appear in the training set app. D. DIFT_{sd} scores 69.4 at α=0.05 and 84.6 at α=0.10. PWarpC scores 64.2 and 84.4.
Cost app. B. One denoiser pass per copy. On one A6000 GPU, DIFT_{sd} takes 203 ms per 768×768 image and OpenCLIP 231 ms. DIFT_{adm} takes 110 ms per 512×512 image and DINO 154 ms app. B.
Ablations. Dropping the copy averaging costs DIFT_{sd} 1.6 points of per-point PCK on SPair-71k (59.5 to 57.9), and DIFT_{adm} 0.9 points (52.0 to 51.1) app. B. Switching to an empty prompt costs DIFT_{sd} 1.9 points (59.5 to 57.6) app. C. Features from the VAE encoder of Stable Diffusion are an order of magnitude worse than the U-Net features app. B. Accuracy stays high over a wide range of t §5.2 fig. 5 fig. 11 fig. 12.
Paper vs code
The code is Tsingularity/dift at 9421eb2034396c5b66f1aff37f03e540c264e52f.
The project page links it as the paper's code [project page]. Its LICENSE is
MIT and names Luming Tang, the first author LICENSE.
- Stable Diffusion works in latent space. The paper describes noising the real image §4.2 eq. 2. The code first encodes the image with the VAE and samples the latent, then noises the latent dift_sd.py. ADM works in pixel space dift_adm.py.
- Noise copies are independent. The code repeats the image and draws fresh noise for each copy, then averages the block outputs over the batch dift_sd.py dift_sd.py dift_adm.py. This matches §4.2.
- ADM model size. The network is built with
image_size=256[code: src/models/dift_adm.py#L17], but the paper and README feed 512×512 inputs app. C README.md. The code does not explain this. - "Per image" is per pair. The paper defines PCK per image as the average of per-image values §5.2. The code appends one value per image pair, then averages those eval_spair.py. The paper's table uses the code's version, so compare per-pair numbers, not per-picture numbers.
- HPatches threshold. RANSAC and LMEDS use a reprojection threshold of 3 pixels eval_homography.py. The paper does not state it.
- DAVIS context cap. For the video "shooting", the code caps previous frames at 10 to avoid running out of memory eval_davis.py. The paper's DAVIS setting is 28 frames app. C. The cap is code-only.
- DAVIS copy default. The DAVIS script defaults to 4 copies [code: eval_davis.py#L267], while the paper's default is 8 app. C. The README uses 4 for DIFT_{adm} and 8 for DIFT_{sd} [README.md#L140-L192].
- Missing evaluation code. The repository has scripts for SPair-71k, HPatches, DAVIS-2017 and homography only. JHMDB, PF-WILLOW, CUB and PF-PASCAL have no evaluation script [file listing]. Their numbers cannot be rerun from this code.
- Settings that match. The README commands reproduce the paper's values for SPair-71k (DIFT_{sd} t=261, block 1; DIFT_{adm} t=101, block 4), HPatches (DIFT_{sd} t=0, block 2; DIFT_{adm} t=41, block 11) and DAVIS (both models, with the temperature, top-k, radius and 28-frame settings) [README.md#L74-L195] app. C. The code's block indices run from 0 [code: src/models/dift_sd.py#L127].
- Scripts run on GPUs. The featurizers call
.cuda()directly [code: src/models/dift_sd.py#L197] dift_adm.py. CPU use needs edits.
Pitfalls
- Tuning on the test split. The time step and block index are grid-searched on SPair-71k §5.2. SPair-71k is also the benchmark reported. The same settings are reused for PF-WILLOW and CUB §5.2. Treat the SPair numbers as tuned.
- Best setting per method. For HPatches the authors report, per method, the best of cosine or L2 and RANSAC or LMEDS app. C. The same best-of rule applies to every method in that table app. C. Expect some gain from selection.
- Noise level is the main knob. A small t keeps detail and a large t keeps semantics. The best t depends on the task, so use the table values for that task rather than a single default §4.2 app. C.
- Results change with noise. Each run draws new noise, so features vary. Use the copy average and keep the seed fixed when you need reproducible output app. B dift_sd.py.
- Memory and time. Each copy is a full U-Net pass at 768×768 for DIFT_{sd}. The paper's fallback is 4 copies app. C. It measured the cost of no averaging at all, not of 4 copies app. B.
- Grid resolution. Features are at 1/8 or 1/16 of the input. The code bilinearly upsamples the feature map to image size before matching eval_spair.py, so the match lands on an image-size grid while its features stay as coarse as the native map app. C.
- Keypoint sampling convention. HPatches features are sampled with
grid_sampleafter normalising coordinates with (w-1)/2 [code: eval_hpatches.py#L53-L54] eval_hpatches.py. The call does not setalign_corners, so check your PyTorch default before porting. - Threshold choice in PCK. The SPair tables use the bounding-box threshold eval_spair.py. The PF-PASCAL and some baseline rows use image-size thresholds tab. 6. Do not compare the two columns directly.
- Weights are separate. The Stable Diffusion 2-1 and ADM checkpoints have their own licence terms. This paper's CC BY 4.0 licence covers the paper, not those weights. Not checked here; check before commercial use.
- Compute is fixed. Only one denoiser pass per copy is needed, so no sampling loop runs. Diffusion inversion gives similar results and is several times slower app. B.
- Failures. The authors show failures when the keypoint's semantic definition is ambiguous or the viewpoint change is extreme app. E fig. 19.
- Video is label propagation. The temporal results use a propagation scheme with a softmax temperature, a top-k filter and a spatial radius §6.2 eval_davis.py. These settings are part of the method. Using DIFT features alone does not reproduce the numbers.
Lineage
- Builds on: none stated. It reuses the Stable Diffusion 2-1 and ADM checkpoints as they are §5.1.
- Compared against: DINO and OpenCLIP, which share training data with the diffusion models §5.1 app. B; supervised SPair-71k methods (CATs, MMNet, TransforMatcher, SCorrSAN) tab. 1; weakly supervised methods (CAPS, PWarpC, ASIC, GANgealing) tab. 1 tab. 2 tab. 3 tab. 4; video self-supervised methods tab. 5.
- Superseded by: not known from content already in this wiki.
Source and license
Adapted from “Emergent Correspondence from Image Diffusion” by Luming Tang, Menglin Jia, Qianqian Wang, Cheng Perng Phoo, Bharath Hariharan (arXiv:2306.03881), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/Tsingularity/dift at commit 9421eb203439 (MIT). Any quoted code is shown under that license.