Stable Diffusion 稳定扩散
五层读懂一个词。这次拆的是:Stable Diffusion--让文生图从「实验室的炫技」变成「每个人的玩具」。核心创新不是扩散模型本身,而是 Latent Diffusion(在压缩隐空间而非像素空间做扩散)——把生成一张 512×512 图片的计算量从 100 GPU-hour 降到 10 秒。开源 + 消费级 GPU + ControlNet 可控,让 SD 成为 2022-2025 年最具影响力的 AI 项目之一。
L1 · 一句话点破
Stable Diffusion = VAE 压缩 + 隐空间扩散 + CLIP 文本条件。不在像素空间(512×512×3=786k 维)直接做扩散,而是先用 VAE 把图像压缩到隐空间(64×64×4=16k 维,48x 压缩),在隐空间做扩散模型的去噪,最后用 VAE 解码回像素。配合 CLIP 文本编码器做条件控制——比像素空间扩散快 50x,消费级 GPU 也能跑。
L2 · 通俗类比
像素空间扩散 = 在 4K 巨幕上逐点作画:
- 每步去噪要处理 512×512 个像素
- 一个点一个点改,太慢了
- 需要数据中心级别的 GPU
Stable Diffusion = 先画缩略图,再放大:
- VAE 编码器:把 4K 巨幕压成一张便签(16k 维 latent)
- 扩散模型:在便签上作画——便签虽小,但包含了画的关键信息
- VAE 解码器:把便签还原成 4K 巨幕
- 快 50x,因为大部分工作在便签上完成
VAE 压缩像「图片的 DNA」:
猫的照片 (512×512×3 = 786,432 像素)
↓ VAE Encoder
latent (64×64×4 = 16,384 个浮点数) ← "猫的DNA"
↓ Diffusion 在 latent 上做去噪
denoised latent
↓ VAE Decoder
猫的图片 (512×512×3) ← "从DNA重建猫"三组件分工:
| 组件 | 作用 | 类比 |
|---|---|---|
| VAE Encoder | 图像→latent | 压缩成 DNA |
| U-Net (扩散模型) | latent 去噪 | 在 DNA 上创作 |
| VAE Decoder | latent→图像 | 从 DNA 重建 |
| CLIP Text Encoder | 文本→条件 | "画一只猫" → 条件信号 |
代价:
- VAE 压缩有信息损失(极细细节可能丢失)
- 文生图的 prompt 需要技巧(prompt engineering)
- 生成结果有随机性
- 版权/伦理争议
适用:
- 文生图(最经典)
- 图生图(Image-to-Image)
- Inpainting(局部重绘)
- ControlNet 可控生成(姿势/草图/深度图控制)
- 视频生成(SVD / AnimateDiff)
L3 · 正经定义
Stable Diffusion:由 Rombach et al. 2022(LMU Munich + Stability AI)提出的基于 Latent Diffusion 的文生图模型。开源发布后成为最广泛使用的图像生成模型。
架构:
文本: "a cat sitting on a sofa"
↓
CLIP Text Encoder → text_embedding [77, 768]
↓
随机噪声 latent [64, 64, 4] + text_embedding + timestep t
↓
U-Net (以 text_embedding 为条件,每层注入 timestep)
↓
去噪后的 latent [64, 64, 4]
↓
VAE Decoder
↓
图像 [512, 512, 3]版本演进:
| 版本 | 时间 | 分辨率 | 关键更新 |
|---|---|---|---|
| SD 1.5 | 2022-10 | 512×512 | 经典的 1.5 |
| SD 2.1 | 2022-12 | 768×768 | 更好 CLIP,去掉 NSFW |
| SDXL | 2023-07 | 1024×1024 | 双文本编码器 + 更大 U-Net |
| SD3 | 2024-03 | 1024×1024 | DiT 架构 + MMDiT (多模态) |
| SD3.5 | 2024-10 | 1024×1024 | 改进版,三种尺寸 |
参考资料:
- 📄 Rombach et al., High-Resolution Image Synthesis with Latent Diffusion Models, CVPR 2022
- 📄 Podell et al., SDXL: Improving Latent Diffusion Models for High-Resolution Image Synthesis, 2023
- 📄 Esser et al., Scaling Rectified Flow Transformers for High-Resolution Image Synthesis (SD3), 2024
- 🔧 GitHub:https://github.com/Stability-AI/stablediffusion
- 🎨 WebUI (AUTOMATIC1111):https://github.com/AUTOMATIC1111/stable-diffusion-webui
- 🎨 ComfyUI:https://github.com/comfyanonymous/ComfyUI
L4 · 原理深挖
4.1 Latent Diffusion 的设计
为什么压缩到 latent:
| 空间 | 维度 | 相对计算量 |
|---|---|---|
| 像素 (512×512) | 786,432 | 1x |
| Latent (64×64×4) | 16,384 | 1/48x |
| 像素 (1024×1024) | 3,145,728 | 4x |
| Latent (128×128×4) | 65,536 | 1/12x |
VAE 的训练:
- VAE 和扩散模型分开训练
- VAE 在大量图像上预训练(重建 + KL 正则)
- 扩散模型在冻住 VAE 的情况下训练
- 推理时也是冻住的 VAE
VAE 的下采样因子:
- SD 1.5/2.1: f=8(512→64)
- SDXL: f=8(1024→128)
- 更激进的下采样(f=16/32)可进一步压缩但重建质量下降
4.2 U-Net 的条件注入
文本条件的注入方式(Cross-Attention):
# U-Net 中的 Cross-Attention 层
class CrossAttention(nn.Module):
def forward(self, x, context):
# x: [B, C, H, W] 图像特征
# context: [B, 77, 768] 文本 embedding
q = self.to_q(x) # 图像特征 → query
k = self.to_k(context) # 文本 → key
v = self.to_v(context) # 文本 → value
# Q·K^T: 图像特征根据文本做注意力
attn = softmax(q @ k.T / sqrt(d))
out = attn @ v
return out时间步注入:
# 时间步 t → 编码 → 加到每一层
t_emb = sinusoidal_embedding(t) # [B, D]
t_emb = Linear(D, D*2)(t_emb) # scale + shift
# 在每层的 GroupNorm 之后
x = norm(x) * (1 + scale) + shift4.3 推理流程(文生图)
from diffusers import StableDiffusionPipeline
pipe = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")
# 1. 文本编码
text_emb = pipe.text_encoder(prompt)
# 2. 从噪声开始
latents = torch.randn(1, 4, 64, 64)
# 3. 逐步去噪(DDIM 50 步)
for t in pipe.scheduler.timesteps:
# 预测噪声
noise_pred = pipe.unet(latents, t, encoder_hidden_states=text_emb)
# 更新 latents
latents = pipe.scheduler.step(noise_pred, t, latents).prev_sample
# 4. 解码到像素
image = pipe.vae.decode(latents).sample关键参数:
| 参数 | 典型值 | 作用 |
|---|---|---|
| guidance_scale | 7.5 | 文本条件强度 |
| num_inference_steps | 30-50 | 去噪步数 |
| seed | 任意 int | 固定可复现 |
| negative_prompt | "blurry, low quality" | 抑制不要的特征 |
| width/height | 512-1024 | 输出分辨率 |
4.4 图生图(Image-to-Image)
# 不是从纯噪声开始,而是从加了部分噪声的原图开始
init_image = load_image("sketch.png")
init_latent = vae.encode(init_image)
# 加 noise(strength 控制保留多少原图)
# strength=0.8 → 加 80% 噪声,保留 20% 原图
# strength=0.3 → 加 30% 噪声,保留 70% 原图
# 从 init_latent 开始去噪 → 得到和图相关但不完全相同的新图应用:
- 草图→成图
- 低分辨率→超分辨率
- 风格迁移(原图结构 + 新风格 prompt)
4.5 Inpainting(局部重绘)
# 只重新生成 mask 遮住的区域
# mask 外保留原图
image = load_image("photo.jpg")
mask = load_mask("mask.png") # 白色=重绘区域,黑色=保留
# U-Net 输入额外通道: latent + mask + masked_image_latent
pipe = StableDiffusionInpaintPipeline(...)
result = pipe(prompt="a cute dog", image=image, mask_image=mask)4.6 ControlNet
问题:prompt 只能控制「内容」,不能精确控制「布局/姿势/深度」。
ControlNet(Zhang et al. 2023):
- 额外训练一个网络,接受控制信号(姿态图、深度图、Canny 边缘、线稿等)
- 控制信号加到 U-Net 的侧边
- 不改变原始 SD 权重
姿态骨骼 → ControlNet → 注入 U-Net skip connections
文本 prompt → Cross-Attention → U-Net
噪声 latent → U-Net → 去噪 latent支持的 ControlNet 类型:
| ControlNet | 控制什么 |
|---|---|
| OpenPose | 人体姿态 |
| Canny | 边缘(线稿) |
| Depth | 深度图 |
| Scribble | 涂鸦 |
| Segmentation | 语义分割 |
| Normal | 法线贴图 |
| IP-Adapter | 参考图风格 |
4.7 SD 的局限
局限 1: 自然度不够。即使 SD3,某些场景仍有 AI 感(过度平滑、细节不自然)。
局限 2: 手指/文字/复杂结构。手指出错率仍高,文字生成不可靠,多人场景容易错乱。
局限 3: Prompt 理解有限。CLIP 对复杂组合("三只猫中有一只戴帽子一只打伞")理解力弱。
局限 4: 分辨率和长宽比。固定训练分辨率(如 1024×1024),极端长宽比(如 banner)效果差。
局限 5: 版权和伦理。训练数据来源争议,deepfake 风险,NSFW 内容。
局限 6: 推理速度。消费级 GPU 上 10-30s 一张图,不够实时。
局限 7: 一致性。同 seed+同 prompt 复现,但跨 session 或微小 prompt 改动结果不同。
局限 8: 无法做精确编辑。不能「把领带从蓝色改成红色」,需要配合 inpainting 或特殊工具。
L5 · 沿革与坑
5.1 沿革
- 2022-08:Stable Diffusion 开源(v1.4),引爆社区
- 2022-10:SD 1.5(最广泛使用的版本)
- 2022-11:SD 2.0/2.1(768×768,去 NSFW)
- 2023-02:ControlNet 发布
- 2023-07:SDXL 1.0(1024×1024,更好文本理解)
- 2024-03:SD3(DiT 架构,MMDiT)
- 2024-08:Flux(SD 原团队新作,部分超越 SD3)
- 2024-2025:视频生成(SVD/AnimateDiff/ComfyUI 生态蓬勃发展)
5.2 常见坑
坑 1: SD 1.5 和 SDXL checkpoint 互不兼容。控制网络/VAE/调度器都不一样。版本要统一。
坑 2: VAE 没选对。SD 1.5 的 VAE 和 SDXL 的 VAE 不通用。用了错 VAE → 图像模糊或颜色错。
坑 3: guidance_scale 和 CFG rescale 不配合。SDXL 引入了 CFG rescale,如果不调可能过饱和。
坑 4: 长 prompt 被 CLIP 截断到 77 token。超长 prompt 无效果或效果偏差。
坑 5: 负向 prompt 过度使用。大量负向 prompt 降低生成多样性。
坑 6: 分辨率不是 64 的倍数。VAE 下采样 8x,分辨率必须是 8 的倍数。512/768/1024 OK;600×400 不 OK。
坑 7: seed 固定但 scheduler 不同。不同 scheduler(DDIM/DPM-Solver/Euler)在相同 seed 下结果不同。
坑 8: 微调模型和基础模型的 prompt 格式不同。DreamBooth/LoRA 模型可能改变了 trigger word。用错 prompt 格式无效果。
坑 9: 大量生成时显存泄漏。每次 pipe() 不清理缓存,显存逐渐涨。要定期 torch.cuda.empty_cache()。
坑 10: NSFW filter 误杀。SD 内置安全过滤器可能把正常图标记为 NSFW。生产环境要测试。
5.3 面试怎么考
- Stable Diffusion 为什么快? 答:在 VAE 压缩的隐空间(64×64×4)做扩散,而非像素空间(512×512×3)。计算量降低约 48x,消费级 GPU 可跑。
- SD 的三个核心组件? 答:VAE(图像↔latent 压缩/解压)、U-Net(在 latent 上做去噪扩散)、CLIP Text Encoder(文本→条件信号)。
- SDXL 比 SD 1.5 改进了什么? 答:双文本编码器(CLIP-L + OpenCLIP)、更大 U-Net、原生 1024×1024、CFG rescale、更好的文本理解和构图。
- ControlNet 怎么做到可控生成的? 答:额外训练控制网络,接受姿态/深度/边缘等控制信号,注入 U-Net 的 skip connection。不改变原始 SD 权重。
- guidance_scale 和 negative prompt 怎么配合? 答:guidance_scale 控制条件强度(越高越遵 prompt),negative prompt 抑制不想要的属性。两者叠加:正 prompt 吸引 + 负 prompt 排斥。
速记卡
架构:
CLIP Text Encoder → text_emb [77, 768]
↓
Noise latent [64,64,4] → U-Net + timestep → denoised latent → VAE Decoder → Image [512,512,3]核心创新:
| 创新 | 作用 |
|---|---|
| Latent Diffusion | 在压缩空间做扩散(48x 加速) |
| Cross-Attention | 文本条件注入 U-Net |
| Classifier-free Guidance | 条件强度控制 |
版本对比:
| 版本 | 分辨率 | U-Net | Text Encoder |
|---|---|---|---|
| SD 1.5 | 512 | 860M | CLIP-L |
| SDXL | 1024 | 2.6B | CLIP-L + OpenCLIP |
| SD3 | 1024 | DiT | T5-XXL + CLIP |
推理参数:
| 参数 | 典型值 |
|---|---|
| guidance_scale | 7.5 |
| steps | 30 (DDIM) |
| seed | 任意 |
| negative_prompt | "low quality, blurry" |
一句话记忆:Stable Diffusion = VAE 压缩(图像→latent)+ Latent Diffusion(在 latent 上做去噪)+ CLIP 编码(文本→条件)的三合一架构。核心创新不在扩散而在 Latent——把工作从像素空间搬到压缩空间,计算量降 48x,消费级 GPU 文生图从此普及。SD 1.5(512²/经典)、SDXL(1024²/双编码器)、SD3(DiT+MMDiT)。配合 ControlNet 做到精确可控(姿态/深度/草图)。局限:手指/文字细节差、复杂组合 prompt 理解弱、一致性不足。
*上一篇:扩散模型原理 -- 扩散模型是原理,Stable Diffusion 是把它搬到压缩空间实现文生图。 下一篇:多模态 LLM -- ViT 看懂图 + LLM 理解文字 = 多模态大模型的诞生。