之前整体探索了SD稳定扩散模型的理论基础。
https://blog.csdn.net/liliang199/article/details/156280004
这里尝试进一步详细推导DDPM的前向加噪过程,逐步展示从基本定义到闭式解的完整数学推导。
DDPM前向过程理解扩散模型的基础,也是反向去噪过程推导的前提,关键结论整理如下。
1)闭式解:可以直接从
采样任意
,无需逐步计算
2)可调节性:通过
调度控制噪声添加速度
3)理论保证:当
时,
收敛到标准高斯分布
4)计算高效:训练时可以随机采样t,直接计算
1. 前向过程定义
1.1 马尔可夫链定义
前向过程是一个马尔可夫链,逐步向数据添加高斯噪声:
其中每一步的转移概率为:
参数说明:
-
:噪声调度参数,满足
-
:保留的信号比例
-:单位矩阵
1.2 重参数化表示
使用重参数化技巧,可以从采样
:
或者用表示:
2 递归展开推导
第一步:展开
从定义出发:
第二步:代入
将的表达式代入:
代入得:
第三步:展开括号
第四步:合并噪声项
现在有两个独立的噪声项和
,它们都服从
。
令:
则A + B是两个独立高斯随机变量的和。
3 高斯分布的性质
性质1:独立高斯变量的线性组合
若 ,
,且独立,则:
性质2:重参数化
若,则:
应用到我们的情况
对于A + B:
-
A的方差系数:
-
B 的方差系数:
总方差系数:
化简:
因此:
用重参数化表示:
其中是一个新的标准高斯噪声。
4 得到递推关系**
将合并的噪声代回的表达式:
其中 \(\epsilon \sim \mathcal{N}(0, I)\)。
4 完全归纳推导
继续之前的到
的推理过程。
第一步:从到
,经过2步
代入得:
第二步:合并噪声项
两个独立噪声项的方差和为:
因此:
这里的关键是:系数应该是,而不是从1到t的所有α的乘积。
第三步:推广到从到
如果要得到从到
的闭式解,需要归纳推导:
归纳假设:假设对于从到
有:
验证k=1:
成立,其中。
归纳步骤:假设对k成立,证明对k+1成立:
合并噪声项:
所以:
正确结论:
从直接到
的闭式解:
其中,
。
但是,如果只从到
(经过k步),则:
5 闭式解
概率分布形式
前向过程的闭式解为:
重参数化采样
要采样 \(x_t\),可以直接使用:
6 性质分析
6.1 信号衰减
-
当t=0时,
,
(原始数据)
-
当t增加时,
单调递减
-
当
时,
,
6.2 方差变化
-
方差
从 0 单调增加到 1
-
当
时,信号和噪声的权重相等
6.3 噪声调度设计
通常选择:
或
例如线性调度:
7 代码示例
以下是噪声调度过程中保留信号比例变化的代码示例。
import torch
import numpy as np
def linear_beta_schedule(timesteps, beta_start=1e-4, beta_end=0.02):
"""线性噪声调度"""
return torch.linspace(beta_start, beta_end, timesteps)
def cosine_beta_schedule(timesteps, s=0.008):
"""余弦噪声调度"""
steps = timesteps + 1
x = torch.linspace(0, timesteps, steps)
alphas_cumprod = torch.cos(((x / timesteps) + s) / (1 + s) * torch.pi * 0.5) ** 2
alphas_cumprod = alphas_cumprod / alphas_cumprod[0]
betas = 1 - (alphas_cumprod[1:] / alphas_cumprod[:-1])
return torch.clip(betas, 0.0001, 0.9999)
def forward_diffusion(x0, t, betas):
"""前向扩散过程采样"""
# 计算累积参数
alphas = 1 - betas
alphas_cumprod = torch.cumprod(alphas, dim=0)
# 采样噪声
epsilon = torch.randn_like(x0)
# 提取对应时间步的参数
sqrt_alpha_bar_t = torch.sqrt(alphas_cumprod[t]).reshape(-1, 1, 1, 1)
sqrt_one_minus_alpha_bar_t = torch.sqrt(1 - alphas_cumprod[t]).reshape(-1, 1, 1, 1)
# 计算加噪后的图像
xt = sqrt_alpha_bar_t * x0 + sqrt_one_minus_alpha_bar_t * epsilon
return xt, epsilon
# 示例使用
timesteps = 1000
betas = linear_beta_schedule(timesteps)
alphas = 1 - betas
alphas_cumprod = torch.cumprod(alphas, dim=0)
# 可视化alpha_bar的变化
import matplotlib.pyplot as plt
plt.plot(alphas_cumprod.numpy())
plt.xlabel('Timestep')
plt.ylabel('ᾱ_t')
plt.title('Signal Preservation Schedule')
plt.show()
8 数学验证
验证1:均值正确性
这与分布的均值一致。
验证2:方差正确性
假设(已标准化),则:
这确保了方差保持为单位矩阵。
reference
DDPM前向加噪过程详细推导