扩散模型定义一个可计算的过程,把数据逐步变成噪声,再训练模型估计有用的逆向转移。采样从噪声开始,反复应用学习到的转移得到结果。它是一类生成模型,并不自动保证写实性、事实性或普遍的质量。
核心要点
- 前向过程由噪声调度固定,反向模型与采样器分别学习或选择。
- 噪声预测 MSE 很常见,但参数化、损失权重、条件输入和调度器会改变目标与行为。
- DDPM 与 DDIM 是采样形式,不是质量保证。
- Flow Matching 为选定概率路径学习速度场;扩散路径只是其中一个子集,因此它不是任意扩散检查点的“更快采样器”。
- 潜在扩散降低工作表示的计算量,但 VAE 会引入重建限制,文本编码器也会限制条件控制。
- Guidance、步数、分辨率、随机种子、调度器、检查点、Prompt 和安全过滤都会影响输出。
- 比较模型时应固定带日期的版本、Prompt、种子、预处理、硬件、指标、人工审阅和许可证检查。
前向扩散过程
令 (x_0) 为数据样本,常见高斯转移为:
[ q(x_t\mid x_{t-1}) = \mathcal{N}(\sqrt{1-\beta_t}x_{t-1}, \beta_t I) ]
噪声调度 (\beta_t) 控制信噪比路径。令 (\alpha_t=1-\beta_t)、(\bar{\alpha}t=\prod{s=1}^{t}\alpha_s),可以直接得到:
[ x_t=\sqrt{\bar{\alpha}_t}x_0+ \sqrt{1-\bar{\alpha}_t}\epsilon,\quad \epsilon\sim\mathcal{N}(0,I) ]
因此训练时可以抽取一个时间步,直接构造 (x_t),不必逐步执行之前的所有转移。
package main
import (
"errors"
"fmt"
"math"
)
func addNoise(x0 []float64, alphaBar float64, noise []float64) ([]float64, error) {
if alphaBar < 0 || alphaBar > 1 {
return nil, errors.New("alphaBar must be in [0, 1]")
}
if len(x0) != len(noise) {
return nil, errors.New("shape mismatch")
}
noisy := make([]float64, len(x0))
signalScale := math.Sqrt(alphaBar)
noiseScale := math.Sqrt(1 - alphaBar)
for index := range x0 {
noisy[index] = signalScale*x0[index] + noiseScale*noise[index]
}
return noisy, nil
}
func main() {
noisy, err := addNoise(
[]float64{0.8, -0.4},
0.72,
[]float64{0.15, -0.20},
)
if err != nil {
panic(err)
}
fmt.Printf("%.6f\n", noisy)
}
这个可运行数值示例校验了标量 Schedule 与向量形状,但不是张量库或完整调度器实现。
学习反向过程
模型接收带噪样本、时间步嵌入和可选条件 (c)。常见目标为:
[ \mathbb{E}{x_0,t,\epsilon} \left[w(t)|\epsilon-\epsilon\theta(x_t,t,c)|^2\right] ]
权重 (w(t))、目标参数化(epsilon、v 或其他形式)、噪声计划和数据归一化都属于模型契约。简化训练步骤如下:
package main
import (
"errors"
"fmt"
"math"
)
type NoisePredictor func(noisy []float64, alphaBar float64) []float64
func addNoise(x0 []float64, alphaBar float64, noise []float64) ([]float64, error) {
if alphaBar <= 0 || alphaBar > 1 || len(x0) != len(noise) {
return nil, errors.New("invalid diffusion inputs")
}
noisy := make([]float64, len(x0))
for index := range x0 {
noisy[index] = math.Sqrt(alphaBar)*x0[index] +
math.Sqrt(1-alphaBar)*noise[index]
}
return noisy, nil
}
func trainingLoss(
x0 []float64,
alphaBar float64,
noise []float64,
predict NoisePredictor,
) (float64, error) {
noisy, err := addNoise(x0, alphaBar, noise)
if err != nil {
return 0, err
}
predicted := predict(noisy, alphaBar)
if len(predicted) != len(noise) {
return 0, errors.New("prediction shape mismatch")
}
var squaredError float64
for index := range noise {
delta := noise[index] - predicted[index]
squaredError += delta * delta
}
return squaredError / float64(len(noise)), nil
}
func main() {
noise := []float64{0.15, -0.20}
loss, err := trainingLoss(
[]float64{0.8, -0.4},
0.72,
noise,
func(_ []float64, _ float64) []float64 {
return []float64{0.10, -0.18}
},
)
if err != nil {
panic(err)
}
fmt.Printf("%.6f\n", loss)
}
真实实现还要处理条件批次、混合精度、参数化、损失权重、EMA、检查点和分布式加载。将示例视为可复现基线前,应锁定框架、调度器、模型修订版和预处理。
采样:DDPM、DDIM 与调度器
推理时,调度器根据时间步 (t) 的模型预测计算前一个状态。DDPM 采样具有随机性,通常需要较多模型评估;DDIM 定义了一族非马尔可夫采样,在减少评估次数时仍可使用确定性设置。
两者都不保证固定加速比或“几乎没有质量损失”。结果取决于检查点、噪声计划、时间步间隔、分辨率、Guidance、硬件和指标。现代管线还提供其他求解器与调度方式,应在固定协议下比较。
至少记录:
- 检查点与调度器修订版;
- Seed、Prompt、负面 Prompt 和条件图片;
- 分辨率、批量、精度和模型评估次数;
- Guidance 与安全设置;
- 设备、驱动、框架和墙钟时间测量方法。
扩散与 Flow Matching 不在同一抽象层
Flow Matching 直接回归选定条件概率路径上的时变速度场,得到 Continuous Normalizing Flow。Gaussian Diffusion Path 可以用于该框架,但 Flow Matching 也可选择 Optimal Transport Displacement Path 等其他路径。因此,把 Flow Matching 描述成任意扩散检查点的另一种 Scheduler 并不准确。
应拆开系统契约:
| 层级 | 示例 | 必须锁定什么 |
|---|---|---|
| 训练目标 | Noise/Score Prediction、x0、v、Flow Velocity |
Target 定义、权重、时间采样 |
| 概率路径 | VP/VE Diffusion、Gaussian Bridge、OT Displacement | Schedule 或 Interpolation 与端点分布 |
| 模型参数化 | Epsilon、Score、x0、v、Velocity |
与 Checkpoint 兼容的输入输出语义 |
| Sampler 或 Solver | Ancestral DDPM、DDIM、ODE/SDE Solver | 算法、Tolerance、时间步间隔 |
| NFE | Neural Function Evaluation 次数 | 实际模型调用,含 Predictor/Corrector 阶段 |
| Distillation | Consistency、Progressive、Adversarial 或任务特定方案 | Teacher、Student、数据、Loss 与质量回归 |
更低 NFE 不自动等于更低端到端延迟或更好质量。Encoder、Denoiser 或 Velocity Field 调用、Guidance 分支、Decoder、安全处理、Batching 和硬件必须一起测量。
潜在扩散与条件控制
潜在扩散在编码表示而非像素上执行去噪:
- 编码器把图像映射为潜在表示;
- 去噪器在该表示上运行;
- 解码器还原像素。
这对许多管线可以降低计算量,但不代表计算免费。编码器/解码器可能损失细节,潜在缩放是模型特定的,尺寸也必须符合检查点契约。
文本条件系统通常通过交叉注意力注入文本特征。Classifier-Free Guidance 可表示为:
[ \epsilon_{\text{guided}} = \epsilon_{\text{uncond}}+ s(\epsilon_{\text{cond}}-\epsilon_{\text{uncond}}) ]
增大 (s) 可能改善部分场景的 Prompt 遵循,也可能降低多样性或产生伪影,不存在通用最佳值。
可运行的确定性 Sampler Step
下面的标准库程序为一个微型数值向量实现 DDIM 风格步骤的确定性部分。它把 Checkpoint Contract 显式化:模型预测必须与 Solver 使用相同的参数化语义和 Cumulative Alpha Schedule。
package main
import (
"errors"
"fmt"
"math"
)
func ddimStep(
current []float64,
predictedNoise []float64,
alphaBarCurrent float64,
alphaBarPrevious float64,
) ([]float64, error) {
if len(current) != len(predictedNoise) {
return nil, errors.New("shape mismatch")
}
if alphaBarCurrent <= 0 || alphaBarCurrent > 1 ||
alphaBarPrevious <= 0 || alphaBarPrevious > 1 ||
alphaBarPrevious < alphaBarCurrent {
return nil, errors.New("invalid reverse schedule")
}
previous := make([]float64, len(current))
for index := range current {
predictedX0 := (current[index] -
math.Sqrt(1-alphaBarCurrent)*predictedNoise[index]) /
math.Sqrt(alphaBarCurrent)
previous[index] = math.Sqrt(alphaBarPrevious)*predictedX0 +
math.Sqrt(1-alphaBarPrevious)*predictedNoise[index]
}
return previous, nil
}
func main() {
previous, err := ddimStep(
[]float64{0.42, -0.31},
[]float64{0.08, -0.12},
0.64,
0.81,
)
if err != nil {
panic(err)
}
fmt.Printf("%.6f\n", previous)
}
这不是图像生成器,也不是可直接用于生产的 Scheduler。真实张量管线必须锁定模型标识与 Revision、目标参数化、调度器实现、精度、预处理和 Seed 语义。不要把未经审阅的模型、受版权保护的 Prompt 集、私人输入或生成结果当作已验证的产品产物。
图生图、局部重绘与 Control
- 图生图从条件图开始,强度/噪声参数决定保留多少输入信息;
- 局部重绘还需要 Mask,但 Mask 极性、边缘处理、分辨率和管线契约可能不同;
- Control 适配器可以使用边缘、姿态、深度等条件,预处理必须符合其训练假设。
这些应作为不同任务分别评测。Prompt-only 分数不能说明身份保持、几何结构、Mask 区域泄漏或控制遵循。
与 GAN、VAE 的比较
| 家族 | 优势 | 重要成本或限制 |
|---|---|---|
| GAN | 许多设计可单次前向快速采样 | 对抗优化、模式覆盖和稳定性问题 |
| VAE | 具有明确编码器/解码器和潜在结构 | 重建/生成权衡与似然假设 |
| 扩散模型 | 条件控制灵活、逐步细化 | 多次模型评估、内存和调度器依赖 |
不要脱离任务、数据集、检查点、指标和日期宣称“扩散质量最高”。选择还应考虑延迟、能耗、隐私、许可证、可控性、失败严重性和运维成本。
评测与可复现
评测集应拆分为:
- Prompt 遵循和构图;
- 身份、几何、文字渲染和细节;
- 多样性与 Seed 敏感性;
- 安全、隐私和记忆化探测;
- 延迟、峰值内存、吞吐和成本;
- 人工偏好与任务效用。
比较时固定 Prompt 和 Seed,但不能把一个 Seed 当作代表。记录样本数、指标定义、可行时的置信区间或方差以及典型失败。FID、基于 CLIP 的分数和人工评分测量的是不同属性,不能互相替代。
安全、许可证与运维
模型权重、训练数据、Prompt、参考图片和输出可能适用不同许可证与隐私义务。商业使用前应审阅模型卡片、数据政策、下游限制、来源要求和适用法律。私人图片不应进入共享遥测;尽量记录元数据而非原始 Prompt,并定义保留和删除策略。
生产控制应包括请求认证、租户隔离、输入/输出上限、队列背压、超时、取消、内容筛查、滥用监控和可回滚模型注册表。生成内容不会自动变得真实、安全或不涉及第三方权利。
常见问题
为什么去噪可以生成新样本?
模型学习的是带噪训练样本上的条件反向过程。从随机噪声状态开始应用该过程,可以从学习到的分布中采样,但结果仍受模型和采样器限制。
DDIM 一定比 DDPM 快或好吗?
不一定。DDIM 可能用更少评估次数,也可以确定性采样,但质量与速度取决于时间步、调度器、检查点、分辨率和硬件。应基准测试准确管线。
Flow Matching 只是另一种扩散采样器吗?
不是。Flow Matching 把训练目标改为选定概率路径上的速度场。它可以使用扩散路径,但任意扩散 Checkpoint 不能只靠更换推理 Scheduler 就变成 Flow Matching 模型。
需要什么硬件?
没有统一显存数字。分辨率、批量、注意力实现、精度、模型架构、卸载和并发共同决定内存。应在目标部署上测量峰值显存和延迟。
步数越多质量越好吗?
不一定。额外评估可能在某个管线中改善结果,也可能很快饱和或产生伪影。应在固定质量与延迟协议下调参。
生成内容自动没有版权风险吗?
不是。权利和义务取决于模型许可证、训练与参考数据、司法辖区、输出相似度和使用场景。高风险商业决策应保留来源记录并咨询合格法律专业人士。
延伸阅读
总结
扩散模型是一类学习去噪系统,其行为由数据、目标、检查点、条件输入、调度器和运行时共同决定。理解公式只是起点;在把图像生成器用于生产前,还要锁定实现、测量完整管线,并治理隐私、许可证、安全和回滚。