Paper · 2023-02-16 · cs.CV, cs.AI, cs.LG, cs.MM
T2I-Adapter: Learning Adapters to Dig out More Controllable Ability for Text-to-Image Diffusion Models
T2I-Adapter trains small adapter networks that read a control map (sketch, segmentation, keypose, depth, colour) and add multi-scale features to the encoder of a frozen Stable Diffusion UNet. Adapters can be composed with weights and run once per sample. Author-reported COCO val FID 16.78 with text plus segmentation, against 24.68 for Stable Diffusion with text only.
Diffusion modelsLatent diffusionText-to-image generationParameter-efficient fine-tuningcontrollable-generationadapterstext-to-imagestable-diffusion
arXivPDFCodeMarkdown13 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
Text-to-image models can draw a lot, but a text prompt is a loose way to say where things go or what shape they take. This paper adds a small helper network, called an adapter, to a large pretrained image generator. The big generator stays frozen. The adapter reads a simple guide image, such as a sketch, a colour blob layout, a pose skeleton or a depth map, and turns it into hints that steer the generator's internal features.
The adapter is cheap to train because it only has to learn how to line up the guide with what the generator already knows. Several adapters can be trained for different guides and mixed together with a weight for each. The authors report that the generated images follow the guide more closely and look better than the plain generator with text alone.
TL;DR
T2I-Adapter is a set of small convolutional adapters trained on top of a frozen Stable Diffusion model (paper version: SD 1.4). Each adapter reads one control map and adds four multi-scale features to the UNet encoder. Adapters for colour, sketch, segmentation, keypose and depth are described; multiple adapters are composed by a weighted sum with no extra training. Author-reported COCO validation FID is 16.78 (text plus segmentation) and 17.36 (text plus sketch), against 24.68 for Stable Diffusion with text only tab. 1. Check the Pitfalls before implementing: the cubic timestep formula, the sketch threshold, the learning rate and the composition weights differ between paper and code.
Problem
Text prompts alone give unstable structure in complex prompts. The paper's examples are unusual compositions the base model renders inconsistently, and it attributes this to the text not carrying enough spatial guidance rather than to missing generation ability §1 fig. 3. Earlier controllable methods either retrain the whole generator, which is costly, or steer through cross-attention manipulation or gradients, which the authors describe as impractical for complex scenes §2.2. The goal is a low-cost, plug-in network that aligns the control signal with the generator's internal knowledge without changing the frozen model §1.
Method
The base model is Stable Diffusion, a latent diffusion model with an autoencoder and a text-conditioned UNet denoiser §3.1 eq. 1 eq. 2. Adapters are trained with the base model frozen §3.4. At generation time the adapter's features are added to the UNet encoder features at each scale §3.3 eq. 4. The four stages of the method are:
- Condition encoding. The control map (sketch, segmentation, keypose, depth, or a spatial colour map) is passed through the adapter. The adapter is a convolution followed by residual blocks, organised in four scales, with a downsampling step between scales §3.3 fig. 2. It returns one feature map per scale, with the same channel dimension as the UNet encoder at that scale eq. 3.
- Feature injection. Each adapter feature is added to the matching encoder feature of the UNet. The paper injects into all four encoder scales; injecting into the decoder as well was tested and gave worse FID §3.3 §4.4.1 tab. 2.
- Multi-adapter composition. Several adapters can be combined as a weighted sum of their features, with no retraining. The weights are set by hand §3.3 eq. 5 §5.
- Adapter training with non-uniform timesteps. Only the adapter is optimised with a standard noise-prediction loss eq. 6. Training timesteps are drawn from a cubic distribution that favours early (high-noise) steps, because the authors found that guidance added in late steps has little effect §3.4 fig. 4 fig. 5.
Pseudocode for the adapter forward pass. The paper gives the layout in words and in its architecture figure; the code shows the same layout for its released model adapters.py.
# T2I-Adapter forward pass for one condition map [§3.3] [fig. 2]
# Input: condition (1 or 3 channels, 512 x 512 in the paper)
# Output: four feature maps, one per UNet encoder scale [eq. 3]
def adapter_forward(condition):
# Pixel-unshuffle down to 64 x 64; 512 -> 64 implies factor 8 [§3.3]
features = pixel_unshuffle(condition, factor=8) # (C*64, 64, 64)
# One convolution to the first scale's channel count [§3.3]
features = conv3x3(features)
outputs = []
for scale in range(4): # four scales [§3.3]
for block in range(2): # two residual blocks per scale [§3.3]
# First block of scales 2 to 4 also halves the resolution [§3.3]
is_first = block == 0
features = residual_block(
features, downsample=(scale > 0 and is_first))
outputs.append(features)
return outputsPseudocode for injection and for the adapter-only training step. Both use the cubic timestep rule from §3.4.
# Cubic timestep sampling for one training sample [§3.4]
# Input: num_steps (T, the number of diffusion steps; not stated in paper)
# Output: integer timestep t in [0, T]
def sample_cubic_timestep(num_steps):
# Draw u uniformly from [0, 1) [§3.4]
u = uniform(0.0, 1.0)
# t = (1 - u^3) * T, so most mass sits near high-noise steps [§3.4]
return int((1.0 - u ** 3) * num_steps)# One adapter training step; the base model stays frozen [§3.4] [eq. 6]
# Input: images X0, condition maps C, captions y
# Output: scalar loss; only adapter parameters receive gradients
def adapter_training_step(images, conditions, captions, adapter, sd):
# Encode the image to latent Z0 with the frozen autoencoder [§3.4]
latents = sd.autoencoder.encode(images) # (B, 4, 64, 64)
# One timestep per sample from the cubic rule [§3.4]
timesteps = [sample_cubic_timestep(T) for _ in images]
# Gaussian noise epsilon and the noised latent Z_t [§3.1] [§3.4]
noise = sample_gaussian_noise(latents.shape)
noisy_latents = add_noise(latents, noise, timesteps)
# Text states tau(y) from the frozen text encoder [§3.1]
text_states = sd.text_encoder(captions)
# Adapter runs on every training sample, unlike at inference [§3.4]
guidance = adapter_forward(conditions) # list of four maps [eq. 3]
predicted = sd.unet(noisy_latents, timesteps, text_states, guidance)
# Noise-prediction loss on the adapter only [eq. 6]
loss = mean_squared_error(predicted, noise)
return loss# Generation with one or more adapters [§3.2] [§3.3] [eq. 5]
# Input: prompt, list of condition maps, list of weights omega
# Output: image
def generate(prompt, conditions, weights, steps):
text_states = sd.text_encoder(prompt)
# Run each adapter once; its features are reused at every step [§1]
guidance = compose_adapters(conditions, weights) # F_c [eq. 5]
latent = sample_gaussian_noise((4, 64, 64)) # Z_T [§3.1]
# Sampling schedule: DDIM with 50 steps is the setting in [fig. 4]
for t in schedule(steps):
predicted = sd.unet(latent, t, text_states, guidance)
latent = scheduler_step(predicted, t, latent)
return sd.decoder(latent)Key equations, in the paper's notation:
Diffusion loss of Stable Diffusion, with \mathbf{Z}_t the noised latent and \mathbf{C} the conditioning eq. 1:
\mathcal{L} = \mathbb{E}\left[\lVert \epsilon - \epsilon_\theta(\mathbf{Z}_t, \mathbf{C})\rVert_2^2\right] eq. 1
Cross-attention used by the UNet to read the text, with \phi and \tau learnable embeddings eq. 2:
\mathbf{Q} = \mathbf{W}_Q \phi(\mathbf{Z}_t);\quad \mathbf{K} = \mathbf{W}_K \tau(\mathbf{y});\quad \mathbf{V} = \mathbf{W}_V \tau(\mathbf{y})
\mathrm{Attention}(\mathbf{Q}, \mathbf{K}, \mathbf{V}) = \mathrm{softmax}\left(\frac{\mathbf{Q}\mathbf{K}^T}{\sqrt{d}}\right)\cdot \mathbf{V} eq. 2
Adapter features and their addition to the UNet encoder, for scale i \in \{1,2,3,4\} eq. 3 eq. 4:
\mathbf{F}_c = \mathcal{F}_{AD}(\mathbf{C}) eq. 3
\hat{\mathbf{F}}_{enc}^{i} = \mathbf{F}_{enc}^{i} + \mathbf{F}_c^{i} eq. 4
Composition of K adapters with weights \omega_k eq. 5:
\mathbf{F}_c = \sum_{k=1}^{K} \omega_k\, \mathcal{F}_{AD}^{k}(\mathbf{C}_k) eq. 5
Adapter training objective, with the base model frozen eq. 6:
\mathcal{L}_{AD} = \mathbb{E}_{\mathbf{Z}_0, t, \mathbf{F}_c, \epsilon \sim \mathcal{N}(0,1)}\left[\lVert \epsilon - \epsilon_\theta(\mathbf{Z}_t, t, \tau(\mathbf{y}), \mathbf{F}_c)\rVert_2^2\right] eq. 6
Hyperparameters
Values stated in the paper. Code values are from the official repository at code_commit, which targets SDXL; the paper's SD 1.4 experiments are in the SD branch (see Paper vs code).
| Name | Value | Where | Notes |
|---|---|---|---|
| base model | Stable Diffusion v1.4 | §4.1 | weights frozen during adapter training §3.4 |
| optimizer | Adam | §4.1 | betas, epsilon and weight decay not stated |
| learning rate | 1e-5 | §4.1 | no schedule or warmup stated |
| batch size | 8 | §4.1 | per device or total not stated |
| epochs | 10 | §4.1 | |
| training resolution | 512 x 512 | §4.1 | images and condition maps resized |
| hardware | 4 x NVIDIA Tesla V100 32 GB | §4.1 | completed within 3 days (stated) |
| sketch training data | COCO 2017, 164K images | §4.1 | sketch from edge model [edge] |
| sketch threshold | 0.5 | §4.1 | applied to the edge model output |
| segmentation training data | COCO-Stuff, 164K images | §4.1 | 80 thing, 91 stuff, 1 unlabelled class |
| keypose, colour, depth data | LAION-Aesthetics, 600K image-text pairs | §4.1 | keypose from MMPose, depth from MiDaS |
| colour downsampling | 64x bicubic, then nearest upsampling | §3.3 | empirical value |
| pixel-unshuffle | 512 to 64 | §3.3 | factor 8 implied; not written in the paper |
| adapter scales and blocks | 4 scales, 2 residual blocks each, 3 downsamples | §3.3 | one convolution before the blocks |
| base adapter size | about 77M parameters, about 300M storage | §1 | |
| small adapter size | 18M parameters | §4.4.2 | used for the colour palette |
| tiny adapter size | 5M parameters | §4.4.2 | |
| timestep distribution | t = (1 - (t/T)^3) T, t uniform | §3.4 | see Pitfalls for the notation |
| inference sampler in figure | DDIM, 50 steps | fig. 4 | used for the guidance-stage study only |
| composition weights | adjustable, values not stated | §3.3 §5 | set by hand |
| classifier-free guidance scale | not stated | ||
| evaluation set | COCO validation, 5,000 images | §4.2 | one sample per image; FID reference set not stated |
Results
Author-reported. Setup: COCO validation set, 5,000 images, one generation per image per method; CLIP score with ViT-L/14; base model Stable Diffusion for the SD row §4.2 tab. 1. Whether baseline numbers were re-run or copied from prior papers is not stated.
Quantitative comparison tab. 1; lower FID and higher CLIP score are better. Bold marks the best result in the paper.
| Method | Condition | FID (lower is better) | CLIP score (higher is better) | Source |
|---|---|---|---|---|
| SPADE | segmentation | 23.44 | 0.2314 | tab. 1 |
| OASIS | segmentation | 18.71 | 0.2274 | tab. 1 |
| PITI | segmentation | 19.36 | 0.2287 | tab. 1 |
| PITI | sketch | 21.21 | 0.2129 | tab. 1 |
| Stable Diffusion | text only | 24.68 | 0.2648 | tab. 1 |
| T2I-Adapter | text plus segmentation | 16.78 | 0.2652 | tab. 1 |
| T2I-Adapter | text plus sketch | 17.36 | 0.2666 | tab. 1 |
Guidance-injection ablation tab. 2. FID only; dataset and metric setup are not stated for this table.
| Mode | Scales | Encoder | Decoder | FID |
|---|---|---|---|---|
| 1 | 4 | yes | no | 17.36 |
| 2 | 4 | no | yes | 18.32 |
| 3 | 4 | yes | yes | 18.08 |
| 4 | 3 | yes | no | 17.86 |
| 5 | 2 | yes | no | 18.77 |
| 6 | 1 | yes | no | 22.66 |
Other results are qualitative only: visual comparisons fig. 6, single-adapter examples for colour, sketch, depth, segmentation and keypose fig. 7, image editing with sketch in inpainting mode fig. 8, composition of depth with keypose and sketch with colour fig. 9, transfer to SD 1.5 and a custom model fig. 10, and adapter size variants fig. 11. The paper reports no numbers for composition, generalisation, or the cubic timestep rule beyond the figures §4.3 §4.4.2.
Paper vs code
The official repository is github.com/TencentARC/T2I-Adapter. Its README links the paper and says the main branch is the SDXL release, while the SD branch is the SD 1.4/1.5 release README.md. The commit recorded here is main at c408b05, which has no LICENSE file. The SD branch has an Apache-2.0 LICENSE. The SD branch was read through a web view, not cloned at a pinned commit, so its statements below are summaries without line numbers and are unverified against a commit.
Discrepancies found in main (SDXL), which are the cited lines:
- Input size and pixel-unshuffle: paper uses 512 x 512 with factor 8 §4.1 §3.3.
mainuses 1024 x 1024 withPixelUnshuffle(16)(the sketch config setscin: 256, which is one channel times 16 times 16) adapters.py Adapter-XL-sketch.yaml. Both give a 64 x 64 grid. - Adapter channels and blocks: paper gives no channel counts §3.3.
mainuses channels 320, 640, 1280 and 1280 with two residual blocks per scale and average-pooling downsampling (use_conv: false) Adapter-XL-sketch.yaml adapters.py. - Injection: paper adds features to four encoder scales eq. 4 §4.4.1.
mainadds one adapter feature after each of the three UNet down blocks and once after the mid block, with the adapter list consumed in order unet.py unet.py. The SDXL layout has three down blocks, so the four-scale mapping is not one-to-one. - Learning rate: paper states 1e-5 §4.1.
mainargparse default is 5e-6 train_sketch.py; the README training command passes 1e-5. Themainoptimiser is AdamW with PyTorch defaults for betas and weight decay, and the scheduler defaults to constant train_sketch.py train_sketch.py. - Batch size and steps: paper: batch 8, 10 epochs §4.1.
mainconfig: batch 2 Adapter-XL-sketch.yaml; README command: batch 1 with 4-step gradient accumulation, 60,000 steps. The README says it uses 4 A100 GPUs in FP16, not the paper's V100s. - Training data: paper uses COCO for sketch and LAION-Aesthetics for colour, keypose and depth §4.1.
maintrains on LAION_6plus and Lexica web datasets sampled 70/30 at 1024 px Adapter-XL-sketch.yaml. - Sketch threshold: paper thresholds the edge map at 0.5 §4.1.
maindraws a threshold uniformly between 0.3 and 0.8, rounded to one decimal, for each batch train_sketch.py train_sketch.py. The SD branch summary reports a fixed 0.5 threshold on the PiDiNet output, which would match the paper. - Edge model: paper cites [edge], which is Pixel Difference Networks [bib: edge].
mainloads PiDiNet and takes its last output train_sketch.py train_sketch.py. - Timestep sampling: paper formula §3.4.
maindraws u uniformly in [0, 1), computes (1 - u^3) times the scheduler's number of training steps, and truncates to an integer train_sketch.py. This is the same distribution as the paper's formula with u mapped to [0, 1). - Inference sampler: Figure 4 uses DDIM with 50 steps fig. 4.
mainsampling usesDDPMSchedulerwith 50 steps by default and classifier-free guidance with scale 7.5 Sampling.py Sampling.py. The paper states neither a guidance scale nor the CFG setup for Table 1. - Adapter application at inference: the paper says the adapter runs once per sample §1.
maincomputes the adapter outputs once and passes the same copy to every UNet call Sampling.py.
Pitfalls
- Cubic timestep formula. The paper writes t = (1 - (t/T)^3) T with t uniform on [0, T] §3.4. The symbol t is used on both sides. The code reads it as u uniform on [0, 1) and computes (1 - u^3) times the step count, with integer truncation train_sketch.py. Use the code's reading, and state which convention the step count uses: the paper does not give the number of training steps T.
- Which steps are early. The paper says the cubic rule raises the probability of the early sampling stage §3.4. Early means high noise, so the rule must map to the large-t end of the schedule. Check that the scheduler's indexing matches this before training.
- Adapter once at inference, every step in training. During training the adapter runs on every sample train_sketch.py; at inference it runs once and its output is reused §1 Sampling.py. Running it inside the denoising loop at inference is wasteful and not what the paper describes.
- Fusion is plain addition. Equation 4 adds the adapter feature to the encoder feature without a learned gate or scale eq. 4. Any extra scale is the composition weight or the caller's conditioning scale, not stated in the paper.
- Composition weights are manual. The paper gives no default and says the weights need manual tuning §3.3 §5. The released diffusers example uses adapter_conditioning_scale 0.8 for a single adapter test.py. Treat that as a starting point, not a paper value.
- Colour adapter size. The colour palette uses the small (18M) adapter, while the others use the base (77M) one §4.4.2. The parameter count therefore depends on the condition.
- Colour downsampling. The paper states 64x downsampling and nearest upsampling §3.3. The code reads this as resizing to width/64 and height/64 with bicubic interpolation, then nearest-neighbour resizing back to full size api.py. At 512 px this is an 8 x 8 map.
- Guidance stage. Guidance added in middle and late steps has little effect §3.4 fig. 4. This is a qualitative finding from figures; no numbers are given.
- Decoder injection hurts. Mode 2 (decoder only) and mode 3 (encoder and decoder) are worse than encoder-only injection tab. 2. For the both-sides case the paper says control becomes too strong and limits texture richness §4.4.1; it gives no reason for the decoder-only result.
- Ablation scale drop. When fewer than four scales are used, the paper says it discards the feature at the small scale §4.4.1. "Small" is not defined: the lowest-resolution map is the likely meaning, but this is inferred.
- Ablation setup not stated. Table 2 shows FID with no dataset or sampler given tab. 2. Its encoder-only row (17.36) equals Table 1's text-plus-sketch FID, which suggests the same setup, but the paper does not say so.
- Baseline setup not stated. Whether SPADE, OASIS and PITI were re-run or copied, and what sampler SD used in Table 1, is not stated §4.2.
- Generalisation is qualitative. Transfer to SD 1.5 and a custom model is shown only in figures §4.3.3 fig. 10.
- Missing figure label. The introduction refers to a teaser figure whose label does not exist in the source. The figure number for that example cannot be matched from the source §1.
- Learning rate and schedule. The paper gives a learning rate but no schedule, warmup or optimiser betas §4.1. The code's constant schedule is the default train_sketch.py.
- Attribution and licence. The paper is CC BY 4.0 [raw metadata]. The code repository at the recorded commit has no LICENSE file, so no code is quoted; only pseudocode in our own words and citations are used.
Lineage
- Builds on: Stable Diffusion, referred to as [ldm] in the paper; the arXiv id is not in the source. Adapter-style modules from NLP are cited as [adapter] §2.3.
- Compared against: SPADE [spade], OASIS [oasis], PITI [piti] and Stable Diffusion alone tab. 1.
- Concurrent work: ControlNet [controlnet] learns task-specific control networks, and composer [composer] retrains a diffusion model conditioned on control factors §2.2.
Source and license
Adapted from “T2I-Adapter: Learning Adapters to Dig out More Controllable Ability for Text-to-Image Diffusion Models” by Chong Mou, Xintao Wang, Liangbin Xie, Yanze Wu, Jian Zhang, Zhongang Qi, Ying Shan, Xiaohu Qie (arXiv:2302.08453), 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/TencentARC/T2I-Adapter at commit c408b059c36e (none at code_commit (no LICENSE file); the SD branch LICENSE is Apache-2.0). Any quoted code is shown under that license.