共计 1409 个字符,预计需要花费 4 分钟才能阅读完成。
背景:从 Classifier Guidance 到 Classifier-Free
传统 classifier guidance 方法通过预训练分类器的梯度(gradient)来引导扩散过程,但存在两个致命缺陷:

- 梯度冲突 :分类器训练目标与生成质量目标不一致,导致梯度方向出现偏差
- 计算代价 :需要额外的前向 - 后向传播计算,显存占用增加 30% 以上
而 classifier-free guidance 通过联合训练条件 / 无条件扩散模型,直接学习条件嵌入(conditional embedding)的语义控制能力。其优势在于:
- 统一的目标函数避免梯度冲突
- 单次前向传播完成条件生成
- 条件强度可通过 guidance scale 连续调节
核心实现
1. 联合训练策略
class ConditionalDiffusion(nn.Module):
def __init__(self, unet_dim=512, cond_dim=128):
super().__init__()
# 共享主干网络
self.unet = UNet(dim=unet_dim) # [B,C,H,W]->[B,C,H,W]
# 条件嵌入层
self.cond_proj = nn.Linear(cond_dim, unet_dim) # [B,D_cond]->[B,D_model]
def forward(self, x, t, cond=None):
# 无条件分支
if cond is None:
return self.unet(x, t) # [B,C,H,W]
# 条件分支
cond_emb = self.cond_proj(cond) # [B,D_model]
return self.unet(x, t, cond_emb) # 需修改 UNet 支持条件输入
训练时交替使用两种输入:
- 50% 概率使用真实条件文本
- 50% 概率将 cond 设为 None
2. Guidance Scale 公式推导
定义条件预测 ε_c 和无条件预测 ε_u,最终噪声预测为:
ε_θ = ε_u + w(ε_c - ε_u)
其中 w(guidance weight)控制条件强度:
- w= 1 时退化为普通条件模型
- w>1 时增强条件控制
- w<1 时降低条件影响
3. 条件嵌入实现
# 文本编码器输出形状 [B, seq_len, D_text]
text_emb = clip_model.encode_text(prompts)
# 均值池化获得全局条件向量 [B, D_text]
cond = text_emb.mean(dim=1)
# 调节条件强度
noise_pred = (1 + guidance_scale) * cond_pred - guidance_scale * uncond_pred
性能分析
质量指标变化
| guidance weight | FID↓ | CLIP↑ |
|---|---|---|
| 1.0 | 28.7 | 0.72 |
| 3.0 | 19.2 | 0.81 |
| 7.0 | 15.4 | 0.85 |
| 10.0 | 18.9 | 0.83 |
注:w>7 时出现质量下降,建议范围 3 -7
显存占用
| batch_size | 显存 (GB) |
|---|---|
| 16 | 10.2 |
| 32 | 18.7 |
| 64 | OOM |
避坑指南
- 条件维度平衡 :
- cond_dim 建议取 model_dim 的 1 / 4 到 1 /2
-
过大会导致无条件生成质量下降
-
梯度爆炸预防 :
- 初始化 cond_proj 权重为小随机值
- 添加梯度裁剪(gradient clipping)
- 使用 AdamW 优化器(lr=3e-5)
开放问题
如何将 classifier-free guidance 扩展到视频生成?可能的思路:
- 时间维度条件嵌入
- 3D UNet 架构改造
- 跨帧注意力机制
期待读者在实践中探索更多可能性。
正文完
发表至: 未分类
近两天内
