Skip to content

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 Decoderlatent→图像从 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.52022-10512×512经典的 1.5
SD 2.12022-12768×768更好 CLIP,去掉 NSFW
SDXL2023-071024×1024双文本编码器 + 更大 U-Net
SD32024-031024×1024DiT 架构 + MMDiT (多模态)
SD3.52024-101024×1024改进版,三种尺寸

参考资料


L4 · 原理深挖

4.1 Latent Diffusion 的设计

为什么压缩到 latent

空间维度相对计算量
像素 (512×512)786,4321x
Latent (64×64×4)16,3841/48x
像素 (1024×1024)3,145,7284x
Latent (128×128×4)65,5361/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):

python
# 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

时间步注入

python
# 时间步 t → 编码 → 加到每一层
t_emb = sinusoidal_embedding(t)       # [B, D]
t_emb = Linear(D, D*2)(t_emb)        # scale + shift

# 在每层的 GroupNorm 之后
x = norm(x) * (1 + scale) + shift

4.3 推理流程(文生图)

python
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_scale7.5文本条件强度
num_inference_steps30-50去噪步数
seed任意 int固定可复现
negative_prompt"blurry, low quality"抑制不要的特征
width/height512-1024输出分辨率

4.4 图生图(Image-to-Image)

python
# 不是从纯噪声开始,而是从加了部分噪声的原图开始

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(局部重绘)

python
# 只重新生成 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 面试怎么考

  1. Stable Diffusion 为什么快? 答:在 VAE 压缩的隐空间(64×64×4)做扩散,而非像素空间(512×512×3)。计算量降低约 48x,消费级 GPU 可跑。
  2. SD 的三个核心组件? 答:VAE(图像↔latent 压缩/解压)、U-Net(在 latent 上做去噪扩散)、CLIP Text Encoder(文本→条件信号)。
  3. SDXL 比 SD 1.5 改进了什么? 答:双文本编码器(CLIP-L + OpenCLIP)、更大 U-Net、原生 1024×1024、CFG rescale、更好的文本理解和构图。
  4. ControlNet 怎么做到可控生成的? 答:额外训练控制网络,接受姿态/深度/边缘等控制信号,注入 U-Net 的 skip connection。不改变原始 SD 权重。
  5. 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-NetText Encoder
SD 1.5512860MCLIP-L
SDXL10242.6BCLIP-L + OpenCLIP
SD31024DiTT5-XXL + CLIP

推理参数

参数典型值
guidance_scale7.5
steps30 (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 理解文字 = 多模态大模型的诞生。

内容采用 CC BY-SA 4.0,代码采用 MIT。