- Published on
Diffusion Model 论文综述:从 DDPM 到 Stable Diffusion、DiT、SDXL,图像生成模型的演进
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 引言
- DDPM:扩散模型的基础
- DDIM:加速采样
- 与 Score-based 模型的关系
- Latent Diffusion Model (Stable Diffusion)
- Classifier-free Guidance (CFG)
- DiT: Diffusion Transformer
- SDXL:Stable Diffusion 的进化
- ControlNet:条件生成控制
- 训练流水线与数据准备
- 推理优化技术
- 模型综合对比
- 运营注意事项
- 故障案例与恢复流程
- 结语
- 参考资料

引言
在图像生成领域,Diffusion Model 已经确立为取代 GAN(Generative Adversarial Network)的新范式。自 2020 年 Ho 等人发表 DDPM(Denoising Diffusion Probabilistic Models) 以来,短短三年内 Stable Diffusion、DALL-E 2、Midjourney 等商用服务相继出现,推动了图像生成的大众化。
Diffusion Model 的核心思路出奇地简单:学习向数据逐步添加噪声的 Forward Process,以及将该噪声反向去除以复原数据的 Reverse Process。在这一过程中,模型会在每个噪声水平上学习"应该朝哪个方向去除噪声"。
本文将按时间顺序综述从 DDPM 的数学基础、DDIM 的加速采样、与 Score-based 模型的关系,到 Latent Diffusion(Stable Diffusion)的架构、Classifier-free Guidance、DiT(Diffusion Transformer)、SDXL、ControlNet 等主要模型的演进。文章将全面涵盖各模型的核心贡献、实现代码、性能对比,以及运营时的注意事项。
DDPM:扩散模型的基础
Forward Process(添加噪声)
DDPM 的 Forward Process 会在 T 个步骤中,向原始数据 x_0 逐步添加高斯噪声。每一步 t 的噪声调度由 beta_t 控制。
利用 Reparameterization trick,可以直接计算任意时间步 t 上的噪声图像。
其中 alpha_t = 1 - beta_t,alpha_bar_t 是从 alpha_1 到 alpha_t 的累积乘积。
import torch
import torch.nn as nn
import numpy as np
class DDPMScheduler:
"""DDPM Forward Process 调度器"""
def __init__(self, num_timesteps=1000, beta_start=1e-4, beta_end=0.02):
self.num_timesteps = num_timesteps
# 线性噪声调度
self.betas = torch.linspace(beta_start, beta_end, num_timesteps)
self.alphas = 1.0 - self.betas
self.alphas_cumprod = torch.cumprod(self.alphas, dim=0)
self.sqrt_alphas_cumprod = torch.sqrt(self.alphas_cumprod)
self.sqrt_one_minus_alphas_cumprod = torch.sqrt(1.0 - self.alphas_cumprod)
def add_noise(self, x_0, t, noise=None):
"""生成任意时间步 t 上的噪声图像"""
if noise is None:
noise = torch.randn_like(x_0)
sqrt_alpha_bar = self.sqrt_alphas_cumprod[t].view(-1, 1, 1, 1)
sqrt_one_minus_alpha_bar = self.sqrt_one_minus_alphas_cumprod[t].view(-1, 1, 1, 1)
# x_t = sqrt(alpha_bar_t) * x_0 + sqrt(1 - alpha_bar_t) * epsilon
x_t = sqrt_alpha_bar * x_0 + sqrt_one_minus_alpha_bar * noise
return x_t
def sample_timesteps(self, batch_size):
"""用于训练的随机时间步采样"""
return torch.randint(0, self.num_timesteps, (batch_size,))
Reverse Process(去除噪声)
在 Reverse Process 中,从 x_T ~ N(0, I) 出发,使用训练好的模型 epsilon_theta 逐步去除噪声。
class DDPMSampler:
"""DDPM Reverse Process 采样器"""
def __init__(self, scheduler):
self.scheduler = scheduler
@torch.no_grad()
def sample(self, model, shape, device):
"""DDPM 逆扩散采样"""
# 从纯噪声开始
x = torch.randn(shape, device=device)
for t in reversed(range(self.scheduler.num_timesteps)):
t_batch = torch.full((shape[0],), t, device=device, dtype=torch.long)
# 预测噪声
predicted_noise = model(x, t_batch)
# 计算均值
alpha = self.scheduler.alphas[t]
alpha_bar = self.scheduler.alphas_cumprod[t]
beta = self.scheduler.betas[t]
mean = (1 / torch.sqrt(alpha)) * (
x - (beta / torch.sqrt(1 - alpha_bar)) * predicted_noise
)
# 仅当 t > 0 时添加噪声
if t > 0:
noise = torch.randn_like(x)
sigma = torch.sqrt(beta)
x = mean + sigma * noise
else:
x = mean
return x
训练目标:Simple Loss
DDPM 的训练目标是最小化模型预测噪声与真实噪声之间的 MSE。
def ddpm_training_step(model, x_0, scheduler, optimizer):
"""DDPM 单步训练"""
batch_size = x_0.shape[0]
device = x_0.device
# 1. 随机采样时间步
t = scheduler.sample_timesteps(batch_size).to(device)
# 2. 生成噪声并生成带噪图像
noise = torch.randn_like(x_0)
x_t = scheduler.add_noise(x_0, t, noise)
# 3. 模型预测噪声
predicted_noise = model(x_t, t)
# 4. 计算 Simple Loss
loss = nn.functional.mse_loss(predicted_noise, noise)
# 5. 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
return loss.item()
DDIM:加速采样
DDPM 需要 1000 步的逆扩散过程,生成速度非常缓慢。Song 等人(2020)提出的 DDIM(Denoising Diffusion Implicit Models) 定义了非马尔可夫(non-Markovian)扩散过程,使得用同一个训练好的模型也能实现快 10~50 倍的采样。
DDIM 的核心在于用 eta 参数控制采样是随机的还是确定性的。eta=0 时完全是确定性(deterministic)采样,eta=1 时则等同于 DDPM。
class DDIMSampler:
"""DDIM 加速采样器"""
def __init__(self, scheduler, ddim_steps=50, eta=0.0):
self.scheduler = scheduler
self.ddim_steps = ddim_steps
self.eta = eta
# 生成时间步子集(例如:1000 -> 50)
self.timesteps = np.linspace(
0, scheduler.num_timesteps - 1, ddim_steps, dtype=int
)[::-1]
@torch.no_grad()
def sample(self, model, shape, device):
"""DDIM 加速采样 - 用 50 步生成高质量结果"""
x = torch.randn(shape, device=device)
for i in range(len(self.timesteps)):
t = self.timesteps[i]
t_prev = self.timesteps[i + 1] if i + 1 < len(self.timesteps) else 0
t_batch = torch.full((shape[0],), t, device=device, dtype=torch.long)
predicted_noise = model(x, t_batch)
alpha_bar_t = self.scheduler.alphas_cumprod[t]
alpha_bar_prev = self.scheduler.alphas_cumprod[t_prev]
# 预测 x_0
x_0_pred = (x - torch.sqrt(1 - alpha_bar_t) * predicted_noise) / torch.sqrt(alpha_bar_t)
x_0_pred = torch.clamp(x_0_pred, -1, 1)
# 计算方向
sigma = self.eta * torch.sqrt(
(1 - alpha_bar_prev) / (1 - alpha_bar_t) * (1 - alpha_bar_t / alpha_bar_prev)
)
direction = torch.sqrt(1 - alpha_bar_prev - sigma**2) * predicted_noise
# 计算 x_{t-1}
x = torch.sqrt(alpha_bar_prev) * x_0_pred + direction
if self.eta > 0 and t > 0:
x = x + sigma * torch.randn_like(x)
return x
与 Score-based 模型的关系
Song 与 Ermon(2019)从 Score Matching 的视角解读了扩散模型。Score function 是数据分布对数密度的梯度。
DDPM 的噪声预测 epsilon_theta 与 Score function 之间具有以下关系。
这一关系被统一到 Score SDE(Stochastic Differential Equation)框架中,用如下方式描述连续时间下的扩散过程。
Latent Diffusion Model (Stable Diffusion)
架构概览
Rombach 等人(2022)提出的 Latent Diffusion Model(LDM) 不在像素空间、而是在 潜在空间(latent space) 中执行扩散过程,从而大幅降低了计算成本。这正是 Stable Diffusion 的核心架构。
LDM 由三个核心组成部分构成。
| 组成部分 | 作用 | 详情 |
|---|---|---|
| VAE Encoder | 将图像编码到潜在空间 | 把 512x512 图像压缩为 64x64x4 的潜在表示 |
| U-Net(Denoiser) | 在潜在空间中预测噪声 | 通过 Cross-attention 反映文本条件 |
| VAE Decoder | 将潜在表示解码为图像 | 把 64x64x4 的潜在表示还原为 512x512 图像 |
| Text Encoder | 编码文本提示词 | 用 CLIP ViT-L/14 生成 77 个 token 的嵌入 |
核心代码结构
import torch
from diffusers import StableDiffusionPipeline, DDIMScheduler
class LatentDiffusionInference:
"""Stable Diffusion 推理流水线(简化版)"""
def __init__(self, model_id="stable-diffusion-v1-5/stable-diffusion-v1-5"):
self.pipe = StableDiffusionPipeline.from_pretrained(
model_id,
torch_dtype=torch.float16,
safety_checker=None
).to("cuda")
# 替换为 DDIM 调度器(加速到 50 步)
self.pipe.scheduler = DDIMScheduler.from_config(
self.pipe.scheduler.config
)
def generate(self, prompt, negative_prompt="", num_steps=50, guidance_scale=7.5):
"""文本-图像生成"""
image = self.pipe(
prompt=prompt,
negative_prompt=negative_prompt,
num_inference_steps=num_steps,
guidance_scale=guidance_scale,
).images[0]
return image
def generate_with_latent_control(self, prompt, seed=42):
"""直接控制潜在空间"""
generator = torch.Generator(device="cuda").manual_seed(seed)
# 直接生成潜在向量
latents = torch.randn(
(1, 4, 64, 64),
generator=generator,
device="cuda",
dtype=torch.float16
)
image = self.pipe(
prompt=prompt,
latents=latents,
num_inference_steps=50,
guidance_scale=7.5,
).images[0]
return image
Cross-Attention 机制
在 Stable Diffusion 的 U-Net 中,通过 Cross-Attention 将文本条件反映到图像生成中。Query 来自图像的潜在表示,Key 与 Value 则来自文本嵌入。
class CrossAttention(nn.Module):
"""Stable Diffusion U-Net 的 Cross-Attention 层"""
def __init__(self, d_model=320, d_context=768, n_heads=8):
super().__init__()
self.n_heads = n_heads
self.d_head = d_model // n_heads
self.to_q = nn.Linear(d_model, d_model, bias=False)
self.to_k = nn.Linear(d_context, d_model, bias=False)
self.to_v = nn.Linear(d_context, d_model, bias=False)
self.to_out = nn.Linear(d_model, d_model)
def forward(self, x, context):
"""
x: 图像潜在表示 (B, H*W, d_model)
context: 文本嵌入 (B, seq_len, d_context)
"""
B, N, C = x.shape
q = self.to_q(x).view(B, N, self.n_heads, self.d_head).transpose(1, 2)
k = self.to_k(context).view(B, -1, self.n_heads, self.d_head).transpose(1, 2)
v = self.to_v(context).view(B, -1, self.n_heads, self.d_head).transpose(1, 2)
# Scaled Dot-Product Attention
scale = self.d_head ** -0.5
attn = torch.matmul(q, k.transpose(-2, -1)) * scale
attn = torch.softmax(attn, dim=-1)
out = torch.matmul(attn, v)
out = out.transpose(1, 2).contiguous().view(B, N, C)
return self.to_out(out)
Classifier-free Guidance (CFG)
Ho 与 Salimans(2022)提出的 Classifier-free Guidance 是无需独立分类器即可控制生成质量的核心技术。
训练时同时训练条件模型与无条件模型(以一定概率将文本条件替换为空字符串)。推理时则使用两个预测的加权平均。
其中 w 是 guidance scale。w=1 时为纯条件生成,w 越大则越强烈地服从文本条件(通常取 7.5~15)。
def classifier_free_guidance_step(model, x_t, t, text_embedding, null_embedding, guidance_scale=7.5):
"""Classifier-free Guidance 单步"""
# 把条件/无条件预测合并为一个批次一次性处理
x_in = torch.cat([x_t, x_t], dim=0)
t_in = torch.cat([t, t], dim=0)
c_in = torch.cat([null_embedding, text_embedding], dim=0)
# 用一次 forward pass 同时生成两个预测
noise_pred = model(x_in, t_in, encoder_hidden_states=c_in)
noise_pred_uncond, noise_pred_cond = noise_pred.chunk(2)
# 应用 CFG
noise_pred_guided = noise_pred_uncond + guidance_scale * (
noise_pred_cond - noise_pred_uncond
)
return noise_pred_guided
DiT: Diffusion Transformer
从 U-Net 到 Transformer
Peebles 与 Xie(2023)提出的 DiT(Diffusion Transformer) 把扩散模型的骨干网络从 U-Net 换成了 Transformer。其核心发现是:增大 Transformer 的规模(GFLOPs),生成质量(FID)会随之持续提升。
| 模型 | 骨干网络 | 参数量 | FID(ImageNet 256) | GFLOPs |
|---|---|---|---|---|
| ADM | U-Net | 554M | 10.94 | 1120 |
| LDM-4 | U-Net | 400M | 10.56 | 103 |
| DiT-S/2 | Transformer | 33M | 68.40 | 6 |
| DiT-B/2 | Transformer | 130M | 43.47 | 23 |
| DiT-L/2 | Transformer | 458M | 9.62 | 80 |
| DiT-XL/2 | Transformer | 675M | 2.27 | 119 |
adaLN-Zero 模块
DiT 的核心创新是 adaLN-Zero 条件化方式:把时间步与类别嵌入注入到 Adaptive Layer Normalization 的 scale/shift 参数中,但在初始化时把门控参数设为 0,使模型在训练初期表现为残差连接(identity function)。
class DiTBlock(nn.Module):
"""DiT 的 adaLN-Zero Transformer Block"""
def __init__(self, d_model, n_heads):
super().__init__()
self.norm1 = nn.LayerNorm(d_model, elementwise_affine=False)
self.attn = nn.MultiheadAttention(d_model, n_heads, batch_first=True)
self.norm2 = nn.LayerNorm(d_model, elementwise_affine=False)
self.mlp = nn.Sequential(
nn.Linear(d_model, d_model * 4),
nn.GELU(),
nn.Linear(d_model * 4, d_model),
)
# adaLN modulation:6 个参数(gamma1, beta1, alpha1, gamma2, beta2, alpha2)
self.adaLN_modulation = nn.Sequential(
nn.SiLU(),
nn.Linear(d_model, 6 * d_model),
)
# Zero 初始化 - 使模型在训练初期表现为 identity
nn.init.zeros_(self.adaLN_modulation[-1].weight)
nn.init.zeros_(self.adaLN_modulation[-1].bias)
def forward(self, x, c):
"""
x: patch token (B, N, D)
c: 条件嵌入 - 时间步 + 类别 (B, D)
"""
# 生成 adaLN 参数
shift1, scale1, gate1, shift2, scale2, gate2 = (
self.adaLN_modulation(c).chunk(6, dim=-1)
)
# Self-Attention with adaLN
h = self.norm1(x)
h = h * (1 + scale1.unsqueeze(1)) + shift1.unsqueeze(1)
h, _ = self.attn(h, h, h)
x = x + gate1.unsqueeze(1) * h
# FFN with adaLN
h = self.norm2(x)
h = h * (1 + scale2.unsqueeze(1)) + shift2.unsqueeze(1)
h = self.mlp(h)
x = x + gate2.unsqueeze(1) * h
return x
Patchify 策略
DiT 把潜在表示切分成 p x p 的 patch,作为 Transformer 的输入 token。patch 尺寸越小,token 数量越多,性能会提升,但计算成本也随之增加。
class PatchEmbed(nn.Module):
"""DiT 的 Patchify 层"""
def __init__(self, patch_size=2, in_channels=4, embed_dim=1152):
super().__init__()
self.patch_size = patch_size
self.proj = nn.Conv2d(
in_channels, embed_dim,
kernel_size=patch_size, stride=patch_size
)
def forward(self, x):
"""(B, C, H, W) -> (B, N, D) patch token 序列"""
x = self.proj(x) # (B, D, H/p, W/p)
x = x.flatten(2).transpose(1, 2) # (B, N, D)
return x
SDXL:Stable Diffusion 的进化
主要改进
Podell 等人(2023)提出的 SDXL 相较于 Stable Diffusion v1.5,引入了以下核心改进。
| 特性 | SD v1.5 | SDXL Base |
|---|---|---|
| U-Net 参数量 | 860M | 2.6B(增加 3 倍) |
| 文本编码器 | CLIP ViT-L/14 | OpenCLIP ViT-bigG + CLIP ViT-L |
| 文本嵌入维度 | 768 | 2048 |
| 默认分辨率 | 512x512 | 1024x1024 |
| Attention 模块数 | 16 | 70 |
| Refiner 模型 | 无 | 内置专用 Refiner |
双文本编码器
SDXL 最大的创新之一,是使用 两个文本编码器。它结合了 OpenCLIP ViT-bigG 丰富的语义表示与 CLIP ViT-L 的互补特征,大幅提升了文本理解能力。
from diffusers import StableDiffusionXLPipeline
import torch
class SDXLInference:
"""SDXL 推理流水线"""
def __init__(self):
self.pipe = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
variant="fp16",
use_safetensors=True,
).to("cuda")
# 内存优化
self.pipe.enable_model_cpu_offload()
self.pipe.enable_vae_tiling()
def generate(self, prompt, negative_prompt="", steps=30):
"""SDXL 基础生成"""
image = self.pipe(
prompt=prompt,
negative_prompt=negative_prompt,
num_inference_steps=steps,
guidance_scale=7.5,
height=1024,
width=1024,
).images[0]
return image
def generate_with_refiner(self, prompt, base_pipe, refiner_pipe):
"""Base + Refiner 两阶段流水线"""
# Base 模型:占全部步数的 80%
high_noise_frac = 0.8
image = base_pipe(
prompt=prompt,
num_inference_steps=40,
denoising_end=high_noise_frac,
output_type="latent",
).images
# Refiner:剩余的 20%(提升细节质量)
image = refiner_pipe(
prompt=prompt,
num_inference_steps=40,
denoising_start=high_noise_frac,
image=image,
).images[0]
return image
尺寸/裁剪条件化
SDXL 在训练时把图像的原始尺寸与裁剪坐标作为条件提供,从而能够有效学习各种宽高比的图像。这一机制是通过 Fourier Feature Encoding 实现的。
def get_sdxl_conditioning(original_size, crop_coords, target_size):
"""生成 SDXL 的尺寸/裁剪条件"""
# 原始尺寸 (height, width)
original_size = torch.tensor(original_size, dtype=torch.float32)
# 裁剪坐标 (top, left)
crop_coords = torch.tensor(crop_coords, dtype=torch.float32)
# 目标尺寸 (height, width)
target_size = torch.tensor(target_size, dtype=torch.float32)
# Fourier Feature Encoding
conditioning = torch.cat([original_size, crop_coords, target_size])
# Sinusoidal embedding
freqs = torch.exp(
-torch.arange(0, 128) * np.log(10000) / 128
)
emb = conditioning.unsqueeze(-1) * freqs.unsqueeze(0)
emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=-1)
return emb.flatten()
ControlNet:条件生成控制
Zhang 等人(2023)提出的 ControlNet,向预训练扩散模型添加边缘、深度、姿态等空间条件。它通过 Zero Convolution 技术,在训练初期保留模型原有能力的同时,逐步学习新的条件。
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
from controlnet_aux import CannyDetector
from PIL import Image
import torch
def controlnet_canny_generation(input_image_path, prompt):
"""基于 ControlNet Canny Edge 的图像生成"""
# 加载 ControlNet 模型
controlnet = ControlNetModel.from_pretrained(
"lllyasviel/control_v11p_sd15_canny",
torch_dtype=torch.float16,
)
pipe = StableDiffusionControlNetPipeline.from_pretrained(
"stable-diffusion-v1-5/stable-diffusion-v1-5",
controlnet=controlnet,
torch_dtype=torch.float16,
).to("cuda")
# 提取 Canny Edge
canny_detector = CannyDetector()
input_image = Image.open(input_image_path)
canny_image = canny_detector(input_image, low_threshold=100, high_threshold=200)
# 基于 ControlNet 生成
output = pipe(
prompt=prompt,
image=canny_image,
num_inference_steps=30,
guidance_scale=7.5,
controlnet_conditioning_scale=1.0,
).images[0]
return output
训练流水线与数据准备
数据集构成
以下是大规模扩散模型训练中常用的主要数据集对比。
| 数据集 | 规模 | 分辨率 | 用途 |
|---|---|---|---|
| LAION-5B | 58 亿图像-文本对 | 多样 | Stable Diffusion 训练 |
| LAION-Aesthetics | 1.2 亿(经过筛选) | 多样 | 高质量微调 |
| ImageNet | 130 万 | 256/512 | DiT 训练(类别条件) |
| COYO-700M | 7 亿 | 多样 | 含韩语的多语言训练 |
微调策略
# LoRA 微调(Stable Diffusion)
accelerate launch train_text_to_image_lora.py \
--pretrained_model_name_or_path="stable-diffusion-v1-5/stable-diffusion-v1-5" \
--dataset_name="custom_dataset" \
--resolution=512 \
--train_batch_size=4 \
--gradient_accumulation_steps=4 \
--learning_rate=1e-4 \
--lr_scheduler="cosine" \
--lr_warmup_steps=500 \
--max_train_steps=10000 \
--rank=64 \
--output_dir="./lora_output" \
--mixed_precision="fp16" \
--enable_xformers_memory_efficient_attention
# DreamBooth 微调(特定对象/风格学习)
accelerate launch train_dreambooth.py \
--pretrained_model_name_or_path="stable-diffusion-v1-5/stable-diffusion-v1-5" \
--instance_data_dir="./my_images" \
--instance_prompt="a photo of sks dog" \
--class_data_dir="./class_images" \
--class_prompt="a photo of dog" \
--with_prior_preservation \
--prior_loss_weight=1.0 \
--num_class_images=200 \
--resolution=512 \
--train_batch_size=1 \
--learning_rate=5e-6 \
--max_train_steps=800
推理优化技术
主要优化技术对比
| 技法 | 速度提升 | 质量影响 | 内存节省 |
|---|---|---|---|
| DDIM(50 steps) | 20x | 轻微 | - |
| DPM-Solver++(20 steps) | 50x | 轻微 | - |
| xFormers Memory Efficient Attention | 1.5x | 无 | 30-40% |
| torch.compile | 1.2-1.5x | 无 | - |
| VAE Tiling | - | 轻微 | 70%+ |
| FP16/BF16 | 1.5-2x | 轻微 | 50% |
| TensorRT | 2-4x | 无 | - |
实战优化代码
import torch
from diffusers import StableDiffusionXLPipeline, DPMSolverMultistepScheduler
def optimized_sdxl_pipeline():
"""经过生产环境优化的 SDXL 流水线"""
pipe = StableDiffusionXLPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
torch_dtype=torch.float16,
variant="fp16",
use_safetensors=True,
).to("cuda")
# 1. 应用高速调度器
pipe.scheduler = DPMSolverMultistepScheduler.from_config(
pipe.scheduler.config,
algorithm_type="dpmsolver++",
use_karras_sigmas=True,
)
# 2. VAE Tiling(高分辨率生成时节省内存)
pipe.enable_vae_tiling()
# 3. Attention Slicing(VRAM 不足时)
pipe.enable_attention_slicing()
# 4. torch.compile(PyTorch 2.0+)
pipe.unet = torch.compile(pipe.unet, mode="reduce-overhead", fullgraph=True)
return pipe
# GPU 内存监控
def monitor_gpu_memory():
"""监控 GPU 内存使用量"""
allocated = torch.cuda.memory_allocated() / 1024**3
reserved = torch.cuda.memory_reserved() / 1024**3
max_allocated = torch.cuda.max_memory_allocated() / 1024**3
print(f"Allocated: {allocated:.2f} GB")
print(f"Reserved: {reserved:.2f} GB")
print(f"Peak: {max_allocated:.2f} GB")
模型综合对比
| 模型 | 年份 | 核心贡献 | 骨干网络 | 条件化方式 | 分辨率 |
|---|---|---|---|---|---|
| DDPM | 2020 | 扩散模型的实用化 | U-Net | 无(无条件) | 256 |
| DDIM | 2020 | 加速采样 | U-Net | 无 | 256 |
| LDM(SD) | 2022 | 潜在空间扩散 | U-Net + VAE | Cross-Attention | 512 |
| DiT | 2023 | Transformer 骨干网络 | Transformer | adaLN-Zero | 256/512 |
| SDXL | 2023 | 大规模 U-Net + 双编码器 | U-Net + VAE | Cross-Attention + CFG | 1024 |
| ControlNet | 2023 | 空间条件控制 | Zero Conv + U-Net | 边缘/深度/姿态 | 512 |
| SD3 | 2024 | MMDiT(多模态 DiT) | Transformer | Flow Matching | 1024 |
运营注意事项
GPU 内存管理
运营基于 Stable Diffusion 的服务时,最常见的问题是 GPU OOM(Out of Memory)。需要检查以下事项。
- 限制批次大小:生成 1024x1024 的 SDXL 图像时,单张图像在 A100 80GB 上约占用 12GB,在 V100 16GB 上则会发生 OOM
- 限制并发请求:必须应用 Rate limiter,防止 GPU 内存超限
- 启用 VAE Tiling:生成高分辨率(2048x2048+)图像时是必需的
- 内存分析:通过定期监控 GPU 内存来发现内存泄漏
故障案例:GPU OOM 恢复
# 检查 GPU 内存状态
nvidia-smi --query-gpu=memory.used,memory.total --format=csv
# 检查 Python 进程的 GPU 内存泄漏
fuser -v /dev/nvidia*
# 强制释放 GPU 内存(无需重启进程)
python -c "
import torch
import gc
gc.collect()
torch.cuda.empty_cache()
print('GPU memory cleared')
print(f'Allocated: {torch.cuda.memory_allocated()/1024**3:.2f} GB')
"
# 发生 OOM 时的服务恢复流程
# 1. 对相应 worker 进程执行 graceful shutdown
# 2. 确认 GPU 内存已释放
# 3. 调整批次大小/并发请求数
# 4. 重启 worker 进程
# 5. 确认健康检查通过后恢复流量
NSFW 过滤
商用服务中必须启用 Safety Checker。如果禁用 Safety Checker,可能会生成 NSFW 内容,从而引发法律问题。
# Safety Checker 设置(生产环境必需)
pipe = StableDiffusionPipeline.from_pretrained(
"stable-diffusion-v1-5/stable-diffusion-v1-5",
safety_checker=None, # 仅在开发环境中禁用
)
# 生产环境中必须启用
from diffusers.pipelines.stable_diffusion import StableDiffusionSafetyChecker
from transformers import CLIPImageProcessor
safety_checker = StableDiffusionSafetyChecker.from_pretrained(
"CompVis/stable-diffusion-safety-checker"
)
feature_extractor = CLIPImageProcessor.from_pretrained(
"openai/clip-vit-base-patch32"
)
故障案例与恢复流程
案例 1:模型加载失败
加载大规模模型时,可能会发生磁盘 I/O 超时或 checkpoint 损坏。
import os
from diffusers import StableDiffusionXLPipeline
def robust_model_loading(model_id, max_retries=3):
"""稳健的模型加载(含重试)"""
for attempt in range(max_retries):
try:
pipe = StableDiffusionXLPipeline.from_pretrained(
model_id,
torch_dtype=torch.float16,
use_safetensors=True,
local_files_only=os.path.exists(
os.path.join(model_id, "model_index.json")
),
)
pipe = pipe.to("cuda")
# 执行 warmup
_ = pipe("test", num_inference_steps=1)
return pipe
except Exception as e:
print(f"Attempt {attempt + 1} failed: {e}")
if attempt < max_retries - 1:
import time
time.sleep(10)
# 清除缓存后重试
torch.cuda.empty_cache()
else:
raise RuntimeError(f"Model loading failed after {max_retries} attempts")
案例 2:图像质量下降(CFG Scale 设置不当)
# CFG Scale 指南
guidance_scale_guidelines:
1.0: '几乎忽略条件 - 接近随机生成'
3.0-5.0: '富有创意且多样的生成'
7.0-8.5: '常规推荐范围 - 质量/多样性平衡'
10.0-15.0: '文本一致性高 - 存在过饱和风险'
20.0+: '过度引导 - 产生伪影'
# 问题诊断清单
troubleshooting:
blurry_output:
- 'num_inference_steps 增加(至少 30 以上)'
- '将调度器切换为 DPM-Solver++'
oversaturated:
- '将 guidance_scale 降低到 7.0 以下'
- "在 negative_prompt 中添加 'oversaturated, vivid'"
wrong_composition:
- '改进提示词结构(明确主语-动词-宾语)'
- '用 ControlNet 控制构图'
结语
Diffusion Model 在 DDPM 的理论基础之上,叠加了 DDIM 的加速采样、Latent Diffusion 的高效架构、Classifier-free Guidance 的质量控制、DiT 的可扩展性、SDXL 的规模化,以及 ControlNet 的精细控制,得以迅速发展。
如今,随着 SD3 的 MMDiT(Multi-Modal Diffusion Transformer)、Flow Matching、Consistency Models 等新范式的出现,更快、更高质量的图像生成正在成为现实。尤其是 DiT 架构已成为 Sora(OpenAI)等视频生成模型的基础,Diffusion Model 的应用范围正从图像扩展到视频、3D、音频等领域。
从工程师的角度来看,理解模型的理论背景是优化与调试的关键。只有准确把握噪声调度、CFG Scale、调度器选择、内存管理等各组成部分的作用,才能在生产环境中稳定地运营服务。
参考资料
- Ho, J., Jain, A., & Abbeel, P. (2020). Denoising Diffusion Probabilistic Models. NeurIPS 2020.
- Song, J., Meng, C., & Ermon, S. (2020). Denoising Diffusion Implicit Models. ICLR 2021.
- Rombach, R., et al. (2022). High-Resolution Image Synthesis with Latent Diffusion Models. CVPR 2022.
- Ho, J. & Salimans, T. (2022). Classifier-Free Diffusion Guidance.
- Peebles, W. & Xie, S. (2023). Scalable Diffusion Models with Transformers. ICCV 2023.
- Podell, D., et al. (2023). SDXL: Improving Latent Diffusion Models for High-Resolution Image Synthesis.
- Zhang, L., Rao, A., & Agrawala, M. (2023). Adding Conditional Control to Text-to-Image Diffusion Models. ICCV 2023.
- Lilian Weng. (2021). What are Diffusion Models?