wikillm

Paper · 2023-08-11 · cs.CV

Diverse Data Augmentation with Diffusions for Effective Test-time Prompt Tuning

DiffTPT tunes four CLIP context tokens per unlabeled test image. It adds 63 Stable Diffusion image variations to the usual crop and flip views, keeps the 80% most cosine-similar views and then the 30% lowest-entropy ones. Author-reported zero-shot gains over TPT on ImageNet variants and 10 fine-grained datasets are 0.7 to 2.9 points on the averages printed in the tables.

Test-time trainingSoft prompt tuningEntropy minimizationDiffusion modelstest-time-adaptationprompt-tuningdiffusiondata-augmentation

arXivPDFCodeMarkdown12 min read

AI-compiled by claude-haiku-5-5 on 2026-10-19, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.

In plain words

CLIP can label pictures it was never trained on, but accuracy drops when the pictures look unlike its training data. Test-time prompt tuning adjusts the text prompt for each picture on the fly, with no labels, by checking how confident the model is across several versions of that one picture.

The earlier method makes those versions by cropping and flipping, and the versions end up looking much alike. DiffTPT adds versions drawn by an image generator, which vary more in appearance but keep the same object. It then drops generated versions that look too different from the original and versions the model is unsure about. On the averages the paper prints, it beats the earlier method, though by less than its headline number suggests.

TL;DR

DiffTPT is test-time prompt tuning for CLIP. For each unlabeled test image it builds 128 views: the original, 64 crop-and-flip views, and 63 Stable Diffusion image variations. It keeps the 80% of generated views most similar to the original, then the 30% lowest-entropy views, and tunes four context tokens for four optimizer steps at learning rate 5e-3. The paper reports gains of 0.7 to 2.9 points over TPT on the averages in its own tables (author-reported); the 5.13% headline figure cannot be reproduced from them. The code is public but has no LICENSE file.

Problem

Zero-shot CLIP degrades under distribution shift. Prompt tuning fixes this only with labelled data from the target domain, so the paper studies the setting where a model sees one unlabeled test image at a time and must adapt to it §1 §3.1. The earlier test-time method (TPT) makes its views with cheap transforms, so the views vary little, and it filters them only by prediction entropy, which does not guarantee that a kept view still shows the same class §1 §3.2. Generating views with a diffusion model gives more variety, but the generated images can drift to other classes, so the paper pairs diffusion views with a similarity filter §3.2 §3.4.

Method

Setting and TPT baseline §3.1. A CLIP image encoder f and text encoder g score an image x against K class prompts with a temperature-scaled cosine similarity eq. 1. The generic objective in the paper is a loss L over a prompt v and one test image eq. 2. TPT's concrete objective minimizes the entropy of a mean prediction taken over the confident augmented views, where confidence is judged by each view's own entropy eq. 3 eq. 4.

Diffusion views §3.3. The paper uses Stable Diffusion V2. Its usual text-conditioning is replaced by the CLIP image embedding of the test image f(x), because no label is available at test time. Each generated view is D_n(x) = G(f(x), n_n), where n_n is fresh Gaussian noise eq. 5. Equation 6 swaps the standard views for these diffusion views in the TPT sum. The paper then uses both sources together, to combine the standard view's variety with the diffusion views' variety §3.3.

Cosine filter §3.4. Each generated view is compared with the test image by cosine similarity. The paper keeps views whose similarity is above a threshold ε chosen so that a fraction ρ_C of the views survives §3.4. The combined objective keeps the entropy indicator and adds the cosine indicator, normalized by ρ_H ρ_C N eq. 7. The paper does not state which representation the cosine uses; see Paper vs code.

Per-image procedure. The loop below condenses §3.1 to §3.4 and the released code. The paper has no algorithm box, so this is our reading.

Pseudocode
# Per-image loop, condensed from §3.1-§3.4 and eq. 4-7.
# Inputs: one unlabeled test image and its 63 pre-generated SD views.

def difftpt_adapt(clip, x_test, sd_views):
    # Original, 64 crop/flip views, 63 SD views: 128 in total
    # [§4.1] [code: tpt_classification.py#L177-L178]
    views = [x_test] + augment(x_test, count=64) + sd_views
    # Context starts from "a photo of a", 4 tokens, reset per image
    # [§4.1] [code: tpt_classification.py#L279-L283]
    ctx = init_context("a photo of a", n_ctx=4)
    # Paper says Adam; released code uses AdamW at lr 5e-3
    # [§4.1] [code: tpt_classification.py#L146]
    optimizer = AdamW([ctx], lr=5e-3)
    keep = None
    # Four optimization steps  [§4.1] [code: scripts/do_tpt_difftpt.sh#L6]
    for step in range(4):
        # Class logits for every view  # (128, K)
        logits = clip.logits(views, ctx)
        if keep is None:
            # Filter once at step 1, then reuse the indices
            # [code: difftpt_utils.py#L133-L138]
            keep = select_views(logits)
        # Entropy of the mean probability over kept views  [eq. 4] [eq. 7]
        loss = avg_entropy(logits[keep])
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    # Predict the original image with the tuned context
    return clip.logits(x_test, ctx)


def select_views(logits):
    # Cosine of each view's logits with the original view's logits
    # [§3.4] [code: difftpt_utils.py#L99-L102]
    sims = [cosine(logits[0], logits[i]) for i in range(1, 128)]
    # Keep the top 80% most similar views: floor(127 * 0.8) = 101
    # [§4.1] [code: difftpt_utils.py#L102]
    kept = top_k(sims, floor(127 * 0.8))
    # Original plus the kept views, mapped back to view indices
    # [code: difftpt_utils.py#L107]
    candidates = [0] + [i + 1 for i in kept]
    # Keep the 30% lowest-entropy candidates: floor(102 * 0.3) = 30
    # [§4.1] [code: difftpt_utils.py#L109-L110]
    entropies = [entropy(logits[i]) for i in candidates]
    lowest = lowest_k(entropies, floor(102 * 0.3))
    return [candidates[j] for j in lowest]

Key equations, as written in the paper with its numbering:

\tilde{p}_v = \frac{1}{\rho_H N} \sum_{n=1}^{N} \mathbb{1}[H(p_n) \le \tau]\, p_n(y \mid \mathcal{A}_n(x_{test})) eq. 4

\mathcal{D}_n(x_{test}) = \mathcal{G}(f(x_{test}), \mathbf{n}_n) eq. 5

\tilde{p}_v = \frac{1}{\rho_H \rho_C N} \sum_{n=1}^{N} \mathbb{1}[H(p_n) \le \tau]\, \mathbb{1}[\mathcal{M}_n]\, p_n(y \mid \mathcal{D}_n(x_{test})) eq. 7

Here M_n is the similarity mask from §3.4. Equation 6 is the same sum with D_n in place of A_n. The paper writes H(p_i) in eq. 6 and eq. 7 but sums over n; we read it as H(p_n).

Hyperparameters

NameValueWhereNotes
BackboneCLIP RN50 (scripts); CLIP ViT-B/16 (tables)§4.1 tab. 1 tab. 2 do_tpt_difftpt.shThe ViT-B/16 run command is not in the scripts
Prompt init"a photo of a"§4.1 do_tpt_difftpt.sh--ctx_init a_photo_of_a
Learnable tokens4§4.1 tpt_classification.py--n_ctx default 4
OptimizerAdam (paper); AdamW (code)§4.1 tpt_classification.pyNo weight decay passed in code
Learning rate5e-3§4.1 tpt_classification.pyPaper and code default agree
Optimization steps4§4.1 §4.3 do_tpt_difftpt.shargparse default is 1 tpt_classification.py
Test batch1 test image per step§4.1 tpt_classification.py
Views per image1 original + 64 augmented + 63 SD = 128§4.1 tpt_classification.py difftpt_utils.pyAugmented count is batch_size
SD views used63§4.1 difftpt_utils.pyGenerator writes 65 per image image_generator_R.py
Cosine keep ratio ρ_C0.8§4.1 §4.3 tpt_classification.pyApplied to 127 views, floored to 101
Entropy keep ratio ρ_H0.3§4.1 §4.3 tpt_classification.pyApplied to 102 candidates, floored to 30
GeneratorStable Diffusion V2 (image-variation checkpoint)§3.3 image_generator_R.pylambdalabs/sd-image-variations-diffusers, revision v2.0
Generator guidancenot stated§3.3 §4.1Code uses 3 image_generator_R.py
Generator sampler and stepsnot stated§3.3 §4.1Pipeline default; no value set in code
Precisionnot stated§4.1Autocast and GradScaler with init scale 1000 tpt_classification.py
Seednot stated§4.1Code default 0 tpt_classification.py
Test set1000 random images across classes§4.1Generator sampling is unseeded (Pitfalls)
Few-shot baselines16-shot, 4 tokens, trained on ImageNet§4.1Weights not in repository
Hardware1 × NVIDIA Tesla V100, 32 GB§4.1

Results

Author-reported. Setup: CLIP RN50 and ViT-B/16 backbones; top-1 accuracy (%) on 1000 randomly selected test images §4.1; baselines are zero-shot CLIP with the default prompt and with an 80-prompt ensemble, TPT, and CoOp and CoCoOp trained on ImageNet with 16 shots §4.1. Arrows against each group's baseline are omitted here; they can be recomputed from the values.

Scenario 1, natural distribution shift tab. 1. Columns are ImageNet (IN), ImageNet-A, ImageNet-V2, ImageNet-R, ImageNet-Sketch, the 5-dataset average, and the 4-dataset OOD average.

BackboneMethodININ-AIN-V2IN-RIN-SkAvgOOD Avg
RN50CLIP (default prompt)58.1022.8153.0053.9033.5042.26 *40.80
RN50Ensemble59.9024.1253.5058.0035.2046.1442.70
RN50TPT59.4027.3455.2056.8034.5046.6543.46
RN50DiffTPT60.8031.0655.8058.8037.1048.7145.69
RN50CoOp63.3024.5257.9055.1034.8047.1243.08
RN50TPT&CoOp63.7029.7560.9057.8036.5049.7346.24
RN50DiffTPT&CoOp64.7032.9661.7058.2036.8050.8747.42
RN50CoCoOp61.5025.7354.8056.0035.5046.7143.01
RN50TPT&CoCoOp62.4026.4356.1056.5035.6047.4143.66
RN50DiffTPT&CoCoOp63.5030.4557.7058.5037.9049.6146.14
ViT-B/16CLIP (default prompt)67.3047.1459.9071.2043.0057.7155.31
ViT-B/16Ensemble68.5048.4462.7073.5045.5059.7357.53
ViT-B/16TPT69.7053.6764.3073.9046.4061.5959.57
ViT-B/16DiffTPT70.3055.6865.1075.0046.8062.2860.52
ViT-B/16CoOp72.3049.2565.7071.5047.6061.2758.51
ViT-B/16TPT&CoOp73.3056.8866.6073.8049.4064.0061.67
ViT-B/16DiffTPT&CoOp75.0058.0966.8073.9049.5064.1261.97
ViT-B/16CoCoOp71.4050.0563.8073.1046.7061.0158.41
ViT-B/16TPT&CoCoOp67.3050.2562.3073.9047.1060.1758.39
ViT-B/16DiffTPT&CoCoOp69.3052.5663.2075.3047.5061.5759.64

* Printed as 42.26. The five printed values average to 44.26 (see Pitfalls).

Scenario 2, cross-dataset generalization tab. 2. Each row lists the five datasets of its half of the table, then the 10-dataset average. The averages are over all 10 datasets, which is how the printed values reconcile. Baselines CoOp and CoCoOp are trained on ImageNet with 16 shots.

BackboneMethodFlowerDTDPetsCarsUCF101Caltech101Food101SUN397AircraftEuroSATAvg (10)
RN50CLIP (default prompt)62.4539.6580.5057.4856.7381.5874.8557.4316.2024.3055.12
RN50Ensemble63.1441.6880.7958.3355.7483.6874.9559.5317.4027.6956.29
RN50CoOp62.2537.3386.0056.2959.0182.3878.8157.1815.4026.9956.16
RN50CoCoOp63.5338.4986.2955.7060.4083.3877.4359.2815.7027.3956.76
RN50TPT62.2540.0482.8260.5460.7984.5877.2361.8017.5022.2156.98
RN50DiffTPT63.5340.7283.4060.7162.6786.8979.2162.7217.6041.0459.85
ViT-B/16CLIP (default prompt)67.9444.1085.7166.5863.3790.2985.0561.8824.7040.6463.03
ViT-B/16Ensemble67.6544.8786.2067.6064.3690.8985.3564.6524.4047.0164.30
ViT-B/16CoOp66.0842.1789.0063.4466.0491.6985.1561.5418.0035.3661.85
ViT-B/16CoCoOp70.8844.7888.7165.2268.4292.4986.5364.6524.2046.2265.21
ViT-B/16TPT69.3146.2386.4966.5066.4492.4986.9363.4824.9037.1563.99
ViT-B/16DiffTPT70.1047.0088.2267.0168.2292.4987.2365.7425.6043.1365.47

Differences against TPT, computed from the printed averages above (not printed by the paper): Scenario 1, RN50 +2.06 and ViT-B/16 +0.69; Scenario 2, RN50 +2.87 and ViT-B/16 +1.48. The appendix gives full-dataset averages of 54.42 → 57.52 for RN50 and 62.21 → 63.27 for ViT-B/16 app. A.

Ablations (author-reported; read from text, plots not reproduced) §4.3. ρ_H = 0.3 and ρ_C = 0.8 give the best result, and ρ_H above 0.5 lowers accuracy fig. 5. Accuracy rises with the number of views up to about N = 64 and holds at N = 128 fig. 6. Going from one to four optimization steps lifts Scenario 2 from 56.6 to 58.8, and further steps slightly reduce it fig. 7. Mixing standard and diffusion views is studied on a grid fig. 4.

Inference cost §4.3. The paper gives timings for TPT and for stable diffusion without a shared setting (see Pitfalls).

Paper vs code

Code paths are relative to the repository root at commit 03f11696ccc793888a2cac303a8cbf643ea171d5. The repository is github.com/chunmeifeng/DiffTPT, linked from the paper's author block. The repository owner is the paper's first author.

  • Cosine space. The paper computes cos(D_n(x), x) between the generated view and the test image §3.4. The paper does not name the embedding. The code takes the model's per-class logits for each view and compares them with the logits of the original view difftpt_utils.py.
  • Selection timing. The paper's objective uses the indicators in every step eq. 7. The code computes the cosine and entropy selection once, at the first step, and reuses the indices afterwards difftpt_utils.py.
  • Optimizer. The paper says Adam §4.1. The code uses AdamW and passes no weight decay tpt_classification.py.
  • Integer rounding. The paper gives ratios §4.1. The code floors them: 101 of 127 views survive the cosine step and 30 of 102 survive the entropy step difftpt_utils.py difftpt_utils.py.
  • Diffusion model. The paper calls SD V2 a text-to-image model and swaps the text embedding for the CLIP image embedding §3.3. The code uses the image-variation checkpoint lambdalabs/sd-image-variations-diffusers, revision v2.0, with guidance 3 and the pipeline's default sampler image_generator_R.py image_generator_R.py.
  • Augmented views. The paper says TPT's standard augmentation uses random resized crops §4.2. The code adds AugMix operations only when the dataset name is longer than one character tpt_classification.py tpt_classification.py. For the ImageNet family the augmented views are crop and flip only datautils.py.
  • Scripts. Only RN50 runs appear in scripts/do_tpt_difftpt.sh do_tpt_difftpt.sh. The ViT-B/16 numbers in tables 1 and 2 have no command in the repository. A comment in the code still names a ViT-L/14 model tpt_classification.py.
  • Few-shot baselines. The TPT&CoOp and TPT&CoCoOp rows need the CoOp or CoCoOp weights, passed with --load tpt_classification.py. The repository does not contain those weights.
  • Diffusion views are precomputed. The paper's inference-cost discussion includes generation time §4.3. The released test loop only reads the precomputed _<i> images listed in selected_data_list.txt difftpt_utils.py image_generator_R.py.
  • Unused generated views. The generator writes 65 variants per image image_generator_R.py and the loader reads 63 difftpt_utils.py.

Pitfalls

  • Printed average does not match its parts. In Table 1 the CLIP RN50 average is printed as 42.26, but its five values (58.10, 22.81, 53.00, 53.90, 33.50) average to 44.26. The OOD average (40.80) does match. Recompute averages from the per-dataset values before comparing.
  • Headline gain not reproduced. The abstract and conclusion state an average gain of 5.13% over TPT. §4.2 gives 5.1% (RN50) and 2.3% (ViT-B/16) for Scenario 2. The printed Scenario 2 averages give 2.87 and 1.48 over TPT, and 4.73 and 2.44 over zero-shot CLIP. The paper does not say how the 5.13% figure is computed. Treat it as unverified.
  • Backbone attribution in §4.2. The sentence on ViT-B/16 gains gives the pair 61.27 → 64.12 and 61.01 → 61.57 as ResNet-50 results. Those values are the ViT-B/16 rows of Table 1, and the RN50 rows show 47.12 → 50.87 and 46.71 → 49.61 §4.2 tab. 1.
  • Subset versus full data. The main tables use 1000 sampled images per dataset §4.1. Appendix A reports full-dataset numbers; its text gives CLIP-RN50 ImageNet-V2 as 51.41, while Table 1 prints 53.00 app. A tab. 1. Do not compare across the two.
  • Inference-cost figures conflict. §4.3 gives 6 s for 10 images with TPT, 36 min for standard SD, and 70 s for the original SD to generate 10 images, with the consistency model at 0.5 s §4.3. No hardware or step count is given for these figures, so they cannot be compared directly.
  • Selection is not reproducible from code alone. The generator shuffles the candidate images without a seed image_generator_R.py, and its diffusion calls set no seed. The generated images are not in the repository, so the exact 1000-image set and its views must be regenerated.
  • Safety checker disabled. The generator replaces the pipeline's safety checker with a pass-through image_generator_R.py. Stated for transparency; the paper does not mention it.
  • Model terms not stated. The paper does not state the license or terms of the Stable Diffusion checkpoint used for generation. Check them before redistributing any generated images.
  • Entropy term index. Equations 6 and 7 write H(p_i) inside a sum over n. Read it as H(p_n) eq. 4 eq. 7.
  • Precision. The code runs under autocast with a gradient scaler at initial scale 1000 tpt_classification.py. The paper does not state a precision.
  • Argparse defaults are not the paper's. --tta_steps defaults to 1 and --selection_p to 0.1 tpt_classification.py. Use the script values: 4 steps, ρ_H 0.3, ρ_C 0.8.
  • No license file. The repository has no LICENSE file, so code_license is not stated. Do not quote code from it. Read the code and reimplement.
  • Other method in the same repository. The IT3A/ folder holds code for a different method, IT3A (its README links arXiv 2412.09706). It is not covered by this card.

Lineage

  • Builds on: Test-time prompt tuning (TPT), Shu et al., 2022 ("Test-time prompt tuning for zero-shot generalization"). Its arXiv id is not stated in the paper's source, so no link is given. DiffTPT keeps TPT's augmented views, adds diffusion views next to them, and adds a cosine filter on top of TPT's entropy filter §3.3 §3.4.
  • Also uses: CLIP §3.1; CoOp and CoCoOp (Zhou et al., 2022) as baselines and as starting points for TPT&CoOp and TPT&CoCoOp §4.1; Stable Diffusion V2 §3.3.
  • Compared against: TPT, CoOp, CoCoOp, zero-shot CLIP with the default prompt and with an 80-prompt ensemble §4.1.
  • Superseded by: not stated.

Source and license

Adapted from “Diverse Data Augmentation with Diffusions for Effective Test-time Prompt Tuning” by Chun-Mei Feng, Kai Yu, Yong Liu, Salman Khan, Wangmeng Zuo (arXiv:2308.06038), 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/chunmeifeng/DiffTPT at commit 03f11696ccc7 (not stated (no LICENSE file in repository)). Any quoted code is shown under that license.