扩散模型定义一个可计算的过程,把数据逐步变成噪声,再训练模型估计有用的逆向转移。采样从噪声开始,反复应用学习到的转移得到结果。它是一类生成模型,并不自动保证写实性、事实性或普遍的质量。

核心要点

  • 前向过程由噪声调度固定,反向模型与采样器分别学习或选择。
  • 噪声预测 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),不必逐步执行之前的所有转移。

go
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 或其他形式)、噪声计划和数据归一化都属于模型契约。简化训练步骤如下:

go
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 和硬件必须一起测量。

潜在扩散与条件控制

潜在扩散在编码表示而非像素上执行去噪:

  1. 编码器把图像映射为潜在表示;
  2. 去噪器在该表示上运行;
  3. 解码器还原像素。

这对许多管线可以降低计算量,但不代表计算免费。编码器/解码器可能损失细节,潜在缩放是模型特定的,尺寸也必须符合检查点契约。

文本条件系统通常通过交叉注意力注入文本特征。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。

go
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 模型。

需要什么硬件?

没有统一显存数字。分辨率、批量、注意力实现、精度、模型架构、卸载和并发共同决定内存。应在目标部署上测量峰值显存和延迟。

步数越多质量越好吗?

不一定。额外评估可能在某个管线中改善结果,也可能很快饱和或产生伪影。应在固定质量与延迟协议下调参。

生成内容自动没有版权风险吗?

不是。权利和义务取决于模型许可证、训练与参考数据、司法辖区、输出相似度和使用场景。高风险商业决策应保留来源记录并咨询合格法律专业人士。

延伸阅读

总结

扩散模型是一类学习去噪系统,其行为由数据、目标、检查点、条件输入、调度器和运行时共同决定。理解公式只是起点;在把图像生成器用于生产前,还要锁定实现、测量完整管线,并治理隐私、许可证、安全和回滚。

一手来源