Stable Diffusion Fundamentals

AI/ML Documentation » Stable Diffusion Fundamentals

Stable Diffusion is a family of open-weight latent diffusion models that generate images from text. A diffusion model is trained to remove noise from corrupted images. To generate, it starts from random noise and removes noise step by step, with a text prompt guiding the result. This page explains that mechanism and the three networks that implement it. It then covers what each generation setting does: sampler, scheduler, steps, CFG scale, seed, resolution, and denoising strength. The concepts apply with small changes to every model in the family, from SD 1.5 through SDXL, and to flow-matching successors such as SD3 and FLUX.

Latent Diffusion

Early diffusion models denoised directly in pixel space, which made each step very expensive at useful resolutions. Stable Diffusion, released in August 2022 and based on the latent diffusion paper by Rombach et al., moves the iterative work into a compressed latent space. A variational autoencoder (VAE) encodes an image into a latent roughly 48× smaller. All denoising steps run on that latent, and the result is decoded back to pixels once, at the end.

flowchart LR
    Px["Pixel image<br/>512×512×3<br/>(786,432 values)"] -- "VAE encode" --> Lat["Latent<br/>64×64×4<br/>(16,384 values)"]
    Lat -- "iterative denoising<br/>(all the expensive work)" --> Lat2["Denoised latent"]
    Lat2 -- "VAE decode" --> Px2["Pixel image"]

Text-to-image generation never needs the encoder. It starts from latent noise and uses only the decoder. The encoder is needed only when an input image is involved: img2img, inpainting, and training.

Model Lineage

The table lists Stability AI’s releases, the successors that replaced them, and the newer open models they are commonly compared against.

Model Released Denoiser Training objective Text encoder(s) Native resolution
SD 1.4 / 1.5 Aug / Oct 2022 U-Net, ~0.86B ε-prediction CLIP ViT-L 512²
SD 2.0 / 2.1 Nov / Dec 2022 U-Net, ~0.87B v-prediction (768 model) OpenCLIP ViT-H 768²
SDXL Jul 2023 U-Net, ~2.6B ε-prediction CLIP ViT-L + OpenCLIP ViT-bigG 1024²
SD3 / SD3.5 Jun / Oct 2024 MMDiT transformer, 2-8B Rectified flow CLIP-L + CLIP-G + T5-XXL 1024²
FLUX.1 (Black Forest Labs) Aug 2024 Hybrid MMDiT, 12B Rectified flow CLIP-L + T5-XXL ~1 MP, flexible
Qwen-Image (Alibaba) Aug 2025 MMDiT, 20B Flow matching Qwen2.5-VL ~1 MP+
FLUX.2 (Black Forest Labs) Nov 2025 Flow transformer, 32B (dev) Rectified flow Mistral Small 3.x (24B VLM) up to ~4 MP
Z-Image (Alibaba Tongyi) Nov 2025 Single-stream DiT, 6B Flow matching, distilled Turbo Qwen-family LLM ~1 MP+

The broad trend runs from U-Net to transformer (DiT/MMDiT) denoisers, from noise prediction to flow matching, and from CLIP to large language-model text encoders. The mechanism described on this page is the same across all of them. Model-specific details are covered in the SDXL, SD3, and FLUX guides.

The Diffusion Process

Forward Process (Adding Noise)

The forward process gradually corrupts a clean latent $x_0$ with Gaussian noise over $T$ timesteps (typically $T = 1000$). Because each step adds independent Gaussian noise, any timestep can be sampled directly in closed form:

\[x_t = \sqrt{\bar{\alpha}_t}\, x_0 + \sqrt{1 - \bar{\alpha}_t}\, \epsilon, \qquad \epsilon \sim \mathcal{N}(0, I)\]

The noise schedule $\bar{\alpha}_t$ decreases from close to 1 (almost clean) at $t = 0$ toward 0 (almost pure noise) at $t = T$. Samplers often describe the same thing with the noise level $\sigma_t = \sqrt{(1 - \bar{\alpha}_t)/\bar{\alpha}_t}$, which is why sampler settings talk about “sigmas”.

Training Objective

The denoiser $\epsilon_\theta(x_t, t, c)$ receives the noisy latent, the timestep, and the text conditioning $c$, and predicts the noise that was added. Training minimizes the mean squared error:

\[\mathcal{L} = \mathbb{E}_{x_0,\, \epsilon,\, t}\left[\, \lVert \epsilon - \epsilon_\theta(x_t, t, c) \rVert^2 \,\right]\]
flowchart LR
    Img["Training image"] --> Enc["VAE encode"] --> X0["x0"]
    X0 --> Mix["Mix with noise<br/>at random t"]
    Eps["Sampled noise ε"] --> Mix
    Mix --> XT["xt"]
    XT --> Net["Denoiser ε_θ(xt, t, c)"]
    Cap["Caption"] --> TE["Text encoder"] --> Net
    Net --> Pred["Predicted noise"]
    Pred --> Loss["MSE loss"]
    Eps --> Loss

The network never learns to “draw” directly. It learns one function, given a noisy input, what does the noise look like?, at every noise level. Sampling, guidance, img2img, and inpainting are all built on repeated calls to that function.

Prediction Targets

Predicting the noise is only one way to parameterize the output. The alternatives are mathematically interchangeable but behave differently in practice, and a checkpoint must be run with the parameterization it was trained with.

Target Network predicts Used by Notes
ε-prediction The noise $\epsilon$ SD 1.x, SDXL, most SDXL fine-tunes Poorly conditioned at very high noise; struggles to produce very dark or very bright images
v-prediction $v = \sqrt{\bar\alpha_t}\,\epsilon - \sqrt{1-\bar\alpha_t}\,x_0$ SD 2.x (768), NoobAI XL V-Pred Stable across all noise levels; paired with a zero-terminal-SNR schedule it produces full tonal range
Flow velocity $v = \epsilon - x_0$ along a straight path SD3, FLUX, Qwen-Image, Z-Image See Flow Matching

Loading a v-prediction checkpoint as if it were ε-prediction, or the reverse, gives gray, washed-out, or noisy output. This is a common source of “broken model” reports.

Reverse Process (Generation)

Generation runs the process backwards. It starts from pure noise $x_T$. At each step the denoiser estimates the noise, the sampler uses that estimate to compute a slightly less noisy latent, and the loop repeats until $t = 0$. Early steps, at high noise, determine composition and color layout. Late steps, at low noise, add texture and fine detail. This split is why the SDXL refiner and hires-fix passes work on the low-noise end only.

flowchart LR
    N["Pure noise<br/>t = T"] --> C["Composition<br/>and color blocks"] --> S["Shapes<br/>and structure"] --> D["Texture<br/>and fine detail"] --> F["Clean latent<br/>t = 0"]
    P["Prompt conditioning"] -.-> C
    P -.-> S
    P -.-> D

The Three Networks

A Stable Diffusion checkpoint bundles three separately trained networks.

flowchart LR
    Prompt["Prompt"] --> TE["Text encoder<br/>(CLIP / T5 / LLM)"]
    Seed["Seed"] --> Noise["Initial latent noise"]
    TE -->|"token embeddings<br/>(cross-attention)"| Den
    Noise --> Den["Denoiser<br/>(U-Net or DiT)"]
    Sch["Sampler + scheduler"] <-->|"one call per step"| Den
    Den --> Lat["Clean latent"]
    Lat --> VAE["VAE decoder"] --> Img["Image"]

VAE

The VAE maps between pixels and latents. SD 1.x and SDXL use a KL-regularized autoencoder with 8× spatial downsampling and 4 latent channels. SD3 and FLUX.1 moved to 16-channel latents, and FLUX.2 introduced a new autoencoder, which preserve much more fine detail (small text, faces at a distance) at the cost of a harder denoising task. The VAE sets an upper bound on detail and color fidelity. It is also the usual cause of washed-out colors, color casts, or black images (fp16 overflow in the original SDXL VAE). VAEs are architecture-specific: an SD 1.5 VAE cannot decode SDXL or FLUX latents.

Denoiser (U-Net or DiT)

The denoiser is the large network that predicts noise or velocity at every step, and it holds most of the parameters.

  • U-Net (SD 1.x, 2.x, SDXL): a convolutional encoder-decoder with skip connections. Transformer blocks inside it apply self-attention (image regions attend to each other) and cross-attention (image regions attend to prompt tokens).
  • Diffusion Transformer, DiT / MMDiT (SD3, FLUX, and newer models): the latent is cut into patches and processed as a token sequence. MMDiT processes text and image tokens jointly, with information flowing both ways, instead of injecting text only through cross-attention. Transformers scale more predictably with parameters and data, which is why every new flagship model uses one.

LoRAs, and most other fine-tuning, modify the denoiser’s attention and projection weights. Some LoRAs also modify the text encoder.

Text Encoder

The text encoder turns the prompt into a sequence of embeddings that condition the denoiser. Its capacity largely determines how well the model follows prompts.

Model Text encoder Token window Practical effect
SD 1.5 CLIP ViT-L 77 Keyword-style prompts; weak at relations and counting
SDXL CLIP ViT-L + OpenCLIP ViT-bigG 77 each (front-ends chunk longer prompts) Better composition; short sentences work
SD3 / SD3.5 CLIP-L + CLIP-G + T5-XXL 77 (CLIP), up to 256 by default (T5) Long natural-language prompts, legible short text
FLUX.1 CLIP-L (pooled) + T5-XXL 256 (schnell) / 512 (dev) Strong prompt adherence and text rendering
FLUX.2, Qwen-Image, Z-Image LLM or VLM encoder Long Multi-subject scenes, layout instructions, multilingual text

CLIP was trained to match images with short captions, so it encodes a loose set of concepts. T5 and LLM encoders encode syntax, which is why “a red cube on top of a blue sphere” works reliably only on the newer models.

Samplers and Schedulers

Two settings control how the reverse process is integrated. They are chosen independently.

  • Sampler (solver): the numerical method that turns each noise prediction into the next latent, such as Euler, DPM++ 2M, or UniPC.
  • Scheduler (sigma schedule): which noise levels the N steps visit, and how they are spaced.
flowchart LR
    Steps["Step count N"] --> Sched["Scheduler<br/>chooses N+1 sigma levels"]
    Sched --> Loop
    subgraph Loop["Sampling loop (per step)"]
        direction LR
        Den["Denoiser predicts<br/>noise at sigma_i"] --> Solv["Sampler computes<br/>latent at sigma_(i+1)"]
    end
    Loop --> Out["Clean latent"]

Samplers

Sampler Type Behavior Typical use
Euler Deterministic, 1st order Simple and robust Previews; the default for flow models (SD3, FLUX)
Euler a (ancestral) Stochastic Injects fresh noise each step, so the image keeps changing as steps increase Anime fine-tunes, exploration
DDIM Deterministic The original fast sampler; supports exact inversion Legacy workflows, inversion-based editing
DPM++ 2M Deterministic, 2nd-order multistep Sharp results in 20-30 steps; converges as steps increase General default for U-Net models
DPM++ 2M SDE / 3M SDE Stochastic More texture and detail; needs a few more steps Photographic final renders
UniPC Deterministic, predictor-corrector Good quality at 10-20 steps Low step counts
LCM Consistency sampler Only for LCM-distilled models or LoRAs 4-8 step generation

Two properties matter more than the name of the sampler:

  • Deterministic vs stochastic. With a fixed seed, every sampler is reproducible on the same hardware and software. Only deterministic samplers converge, though: adding steps refines the same image. Ancestral and SDE samplers inject new noise, so 30 steps and 50 steps give noticeably different images.
  • Order. Higher-order and multistep solvers (DPM++ 2M, UniPC) reach a given quality in fewer steps than Euler, but can overshoot at very low step counts or very high CFG.

Schedulers

Common options in ComfyUI and A1111/Forge:

Scheduler Spacing Notes
normal / simple Follows the model’s training schedule Safe default; simple is the usual choice for flow models
karras Denser steps at low noise (Karras et al., 2022) Better detail per step for U-Net models; pairs well with DPM++
exponential Evenly spaced in log-sigma Good for SDE samplers and some distilled models
sgm_uniform Uniform over training timesteps Recommended for SDXL Turbo and Lightning
beta Concentrates steps at both ends Popular with FLUX and flow models
Align Your Steps (AYS) Schedules optimized per model (NVIDIA, 2024) Better results at 10-20 steps; separate node in ComfyUI

The scheduler used in training (for example linear or cosine $\bar\alpha_t$) is fixed by the checkpoint. The sampling scheduler only chooses which points on that curve to visit.

Classifier-Free Guidance (CFG)

A conditional model’s prediction alone follows the prompt only weakly. Classifier-free guidance runs the denoiser twice per step, once with the prompt ($\epsilon_{\text{cond}}$) and once with an empty or negative prompt ($\epsilon_{\text{uncond}}$), and extrapolates away from the unconditional prediction:

\[\hat{\epsilon} = \epsilon_{\text{uncond}} + w \left(\epsilon_{\text{cond}} - \epsilon_{\text{uncond}}\right)\]

At $w = 1$ this is simply the conditional prediction, with no extrapolation. Larger $w$ pushes the sample further toward what distinguishes the prompt from “anything”. Prompt adherence and contrast increase until colors oversaturate and details burn.

sequenceDiagram
    participant S as Sampler
    participant D as Denoiser
    S->>D: latent + prompt embedding
    D-->>S: eps_cond
    S->>D: latent + negative (or empty) embedding
    D-->>S: eps_uncond
    Note over S: eps = eps_uncond + w * (eps_cond - eps_uncond)
    S->>S: step to next sigma

Practical consequences:

  • The negative prompt replaces the unconditional branch. This is how negative prompts work, and why they have no effect at CFG 1.
  • CFG roughly doubles compute per step, because it runs two forward passes. This is why distilled models that run at CFG 1 are twice as fast per step.
  • Guidance-distilled models (FLUX.1-dev, FLUX.2-dev) learned the guided output directly. They run at CFG 1 with a separate guidance value (about 2.5-4) passed as model input. Raising real CFG on them mostly degrades output.
Model family Typical CFG
SD 1.5 6-9
SDXL and fine-tunes 4-7 (Pony and Illustrious: 5-7)
SD3.5 3.5-5
FLUX.1-dev / FLUX.2-dev CFG 1, guidance ≈ 2.5-4
Turbo, Lightning, LCM, schnell 1-2

Several techniques reduce the side effects of high CFG: CFG rescale (introduced for zero-terminal-SNR models), dynamic thresholding, and APG (adaptive projected guidance). Perturbed-attention guidance (PAG) takes a different approach. It adds structure by contrasting against a deliberately degraded prediction instead of relying only on a high $w$. See Advanced Techniques.

Generation Parameters

Resolution

Generate at or near the pixel count the model was trained on. The model learned composition at that scale. Much larger canvases produce duplicated subjects and repeated limbs, and much smaller ones look soft.

Model Native pixel budget Example sizes
SD 1.5 ~0.26 MP 512×512, 512×768
SDXL / Pony / Illustrious ~1 MP 1024×1024, 832×1216, 1344×768
SD3.5, FLUX.1 ~1 MP (FLUX tolerates 0.5-2 MP) 1024×1024, 1152×896
FLUX.2, Qwen-Image ~1-4 MP Model-card dependent

For larger output, generate at native size and then upscale in a second pass: latent or pixel upscale, then img2img at about 0.3-0.5 denoise, optionally tiled with a tile ControlNet.

Steps

Steps Use
1-8 Distilled models only (Turbo, Lightning, LCM, Hyper, DMD2, FLUX schnell, Z-Image Turbo)
15-25 Previews; flow models often look finished by about 20-28
25-35 Standard for SD 1.5 and SDXL with DPM++ samplers
40+ Rarely worth it with deterministic samplers; SDE samplers benefit slightly

Seed

The seed initializes the random number generator that produces the starting noise. The same seed, prompt, settings, model, and software stack reproduce the same image. Results can still differ across GPU vendors, precisions, or attention backends, and between CPU- and GPU-generated noise (A1111 generates on the GPU by default, ComfyUI on the CPU). Keeping the seed fixed while changing one parameter is the standard way to see what that parameter does.

Denoising Strength (img2img and Inpainting)

Image-to-image starts from an existing image instead of pure noise. The image is encoded, noised to an intermediate timestep, and the loop runs from there. Denoising strength (0-1) chooses how far into the schedule to start, which is the same as how much of the original the model may change.

flowchart LR
    In["Input image"] --> E["VAE encode"] --> Add["Add noise to level s<br/>(denoising strength)"]
    Add --> Loop["Run the remaining<br/>fraction s of steps"] --> Dec["VAE decode"] --> Out["Output"]
Strength Effect Typical use
0.2-0.4 Keeps structure and colors; refines texture Hires-fix detailing, cleanup
0.5-0.65 Keeps layout; changes content and style Restyling, variations
0.7-0.85 Loose reinterpretation Sketch-to-image
0.9-1.0 Almost text-to-image Input used as a vague color hint

With 30 steps and strength 0.4, only the last 12 steps run. Inpainting applies the same process inside a mask. Dedicated inpainting checkpoints, or models with native editing such as FLUX.1 Kontext, blend the edges better. For structural control that img2img cannot give, see ControlNet and Inpainting & Editing.

Prompting Mechanics

The prompt is split into tokens, the text encoder produces embeddings, and the denoiser attends to them through attention. Some consequences follow from that:

  • Earlier tokens tend to carry more weight in CLIP-based models. CLIP’s causal attention and training on short captions favor the start of the prompt. Put the subject first, then details, style, and lighting. This matters less with T5 or LLM encoders.
  • Cross-attention is local. Each image region attends to the tokens most relevant to it, which is why concepts “bleed” (a “red hat” also turns the shirt red). Regional prompting and attention masking address this. See Advanced Techniques.
  • Negative prompts take the place of the unconditional branch in CFG (see above). Short, specific negatives work better than long boilerplate lists, especially on SDXL and newer models.
  • Prompt style depends on the training captions. SD 1.5 anime fine-tunes and Pony, Illustrious, and NoobAI expect danbooru tags. Base SDXL accepts short sentences. SD3, FLUX, and LLM-encoder models expect full descriptive prose and can render quoted text.

Weighting Syntax

A1111, Forge, and ComfyUI scale a token’s embedding with the following syntax:

Syntax Effect Supported by
(word) ×1.1 A1111, Forge, ComfyUI
(word:1.4) ×1.4 A1111, Forge, ComfyUI
[word] ×0.9 (de-emphasis) A1111 and Forge only; ComfyUI treats brackets literally
[a:b:0.5] Prompt editing: switch from a to b halfway through the steps A1111 and Forge (ComfyUI uses conditioning nodes)

Weights above about 1.5 usually cause artifacts. On T5 and LLM-encoded models, weighting is less effective and often unsupported. Rephrase instead.

Memory and Performance

Approximate VRAM needed to generate at native resolution with a single model loaded:

Model fp16 / bf16 With fp8 or GGUF quantization, or offload
SD 1.5 4 GB 2-3 GB
SDXL 8 GB (fp16-fix VAE) 6 GB
SD3.5 Large (8B) ~18-20 GB ~10-12 GB
FLUX.1-dev (12B) ~24 GB ~8-12 GB (fp8 or GGUF Q4-Q8)
FLUX.2-dev (32B + 24B encoder) Datacenter-class ~16-24 GB with 4-bit weights and offload
Z-Image Turbo (6B) ~16 GB Less with quantization

In order of cost, the main levers are:

  1. Memory-efficient attention. PyTorch SDPA (the default in current front-ends), xFormers, or FlashAttention.
  2. Lower-precision weights. fp16/bf16, then fp8, then GGUF or NF4 4-bit quantization. Quality loss is small down to about 8 bits and noticeable below 5.
  3. Offloading. Keep only the active network on the GPU. ComfyUI and Forge do this automatically, and diffusers exposes enable_model_cpu_offload().
  4. Tiled VAE decode for large images, where the decode alone can exceed VRAM.

See the Optimization Guide for details.

Flow Matching

SD3, FLUX, and most models since 2024 are trained with rectified flow, a form of flow matching, instead of the DDPM noise objective. The noisy sample is a straight-line interpolation between data $x_0$ and noise $\epsilon$:

\[x_t = (1 - t)\, x_0 + t\, \epsilon, \qquad t \in [0, 1]\]

The network $v_\theta$ is trained to predict the constant velocity along that line:

\[\mathcal{L} = \mathbb{E}_{x_0,\, \epsilon,\, t}\left[\, \lVert (\epsilon - x_0) - v_\theta(x_t, t, c) \rVert^2 \,\right]\]

Generation integrates the ordinary differential equation $\mathrm{d}x/\mathrm{d}t = v_\theta$ from $t = 1$ (noise) to $t = 0$ (data). Because the training paths are straight, even a plain Euler solver with 20-30 steps follows them accurately. Distillation can reduce this to 1-8 steps.

  DDPM-style diffusion Rectified flow
Noisy sample $\sqrt{\bar\alpha_t}\,x_0 + \sqrt{1-\bar\alpha_t}\,\epsilon$ $(1-t)\,x_0 + t\,\epsilon$
Network predicts Noise $\epsilon$ (or $v$) Velocity $\epsilon - x_0$
Sampling paths Curved Nearly straight
Typical sampler DPM++ 2M, Karras Euler, simple or beta schedule
Models SD 1.x, 2.x, SDXL SD3, FLUX, Qwen-Image, Z-Image

Flow models also use timestep shift. More sampling steps are spent at high noise for larger images, because a high-resolution image keeps its coarse structure visible at noise levels that would erase a small one. ComfyUI exposes this as ModelSamplingSD3 or ModelSamplingFlux (shift).

Few-Step Generation

Distillation trains a student model to match what the full model produces over many steps, but in only a few steps:

Technique Year Idea Steps
Latent Consistency Models (LCM) 2023 Map any point on the trajectory directly to its endpoint 4-8
Adversarial Diffusion Distillation (SDXL Turbo, SD3 Turbo) 2023-24 Distillation plus a GAN discriminator 1-4
Progressive / adversarial (SDXL Lightning) 2024 Halve the step count repeatedly, with adversarial loss 1-8
Distribution Matching Distillation (DMD2) 2024 Match output distributions rather than individual trajectories 1-4
Guidance and timestep distillation (FLUX.1-schnell, Z-Image Turbo) 2024-25 Bake CFG and few-step sampling into the weights 1-8

Distilled models run at CFG ≈ 1, ignore or weaken negative prompts, and usually need a specific sampler and scheduler, which the model card gives. See the Optimization Guide for the speed trade-offs.

Troubleshooting

Symptom Likely cause Fix
Solid black image fp16 VAE overflow (SDXL) or NaNs Use the fp16-fix VAE, or decode in bf16/fp32
Gray, low-contrast, noisy output ε/v-prediction mismatch; wrong VAE Set the model’s prediction type; use the matching VAE
Oversaturated, “fried” colors CFG too high for the model Lower CFG (see the table above), or use CFG rescale
Duplicated subjects, extra heads Resolution far above the native pixel budget Generate at native size, then upscale
Soft, blurry result Too few steps, resolution too low, distilled LoRA at full CFG Raise steps, use a native bucket, match CFG to the model
Image keeps changing as steps increase Ancestral or SDE sampler Expected behavior; use DPM++ 2M or Euler for convergence
Prompt partly ignored Token limit, concept bleed, CLIP’s weak syntax Shorten or reorder the prompt; regional prompting; a T5 or LLM-encoder model
LoRA has no effect or errors LoRA built for a different architecture Match the LoRA to the base (SD 1.5 vs SDXL vs FLUX)

See Also