跳转至

01 - 概率论基础

学习时间: 3小时 重要性: ⭐⭐⭐⭐⭐ 扩散模型的数学基石


🎯 学习目标

完成本章后,你将能够: - 理解高斯分布及其在扩散模型中的核心作用 - 掌握条件概率和贝叶斯定理的直观意义 - 理解KL散度的含义及其在训练目标中的作用 - 用代码验证概率论概念


1. 高斯分布(正态分布)

1.1 直观理解

高斯分布是扩散模型中最重要的概率分布,没有之一。

为什么重要? - 扩散模型的前向过程就是不断添加高斯噪声 - 反向过程学习的是去噪分布,也是高斯分布 - 数学上易于处理,有闭合形式的解

直观理解: 想象你向靶心射箭,大多数箭会集中在靶心附近,少数会偏离。这种"中间多、两边少"的分布就是高斯分布。

1.2 数学定义

一维高斯分布的概率密度函数:

\[p(x) = \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left(-\frac{(x-\mu)^2}{2\sigma^2}\right)\]

其中: - \(\mu\):均值(分布的中心位置) - \(\sigma\):标准差(分布的"宽度") - \(\sigma^2\):方差

1.3 多维高斯分布

对于 \(d\) 维向量 \(\mathbf{x}\)

\[p(\mathbf{x}) = \frac{1}{(2\pi)^{d/2}|\Sigma|^{1/2}} \exp\left(-\frac{1}{2}(\mathbf{x}-\boldsymbol{\mu})^T\Sigma^{-1}(\mathbf{x}-\boldsymbol{\mu})\right)\]

其中: - \(\boldsymbol{\mu}\)\(d\) 维均值向量 - \(\Sigma\)\(d \times d\) 协方差矩阵

扩散模型中:图像可以看作是高维向量(例如 \(32 \times 32 \times 3 = 3072\) 维),每个像素值服从高斯分布。

1.4 代码实践

Python
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

# 设置随机种子,保证可重复
np.random.seed(42)

# ========== 1. 一维高斯分布 ==========
print("=" * 50)
print("一维高斯分布")
print("=" * 50)

# 定义参数
mu = 0      # 均值
sigma = 1   # 标准差

# 采样
samples = np.random.normal(mu, sigma, 10000)

# 绘制直方图和理论曲线
plt.figure(figsize=(12, 4))

plt.subplot(1, 3, 1)
plt.hist(samples, bins=50, density=True, alpha=0.7, label='Samples')

# 理论曲线
x = np.linspace(-4, 4, 100)
y = stats.norm.pdf(x, mu, sigma)
plt.plot(x, y, 'r-', linewidth=2, label='Theory')
plt.title(f'Gaussian: μ={mu}, σ={sigma}')
plt.xlabel('x')
plt.ylabel('Probability Density')
plt.legend()
plt.grid(True, alpha=0.3)

# ========== 2. 不同参数的比较 ==========
plt.subplot(1, 3, 2)
params = [(0, 0.5), (0, 1), (0, 2), (2, 1)]
colors = ['blue', 'red', 'green', 'orange']

for (mu, sigma), color in zip(params, colors):  # zip按位置配对
    y = stats.norm.pdf(x, mu, sigma)
    plt.plot(x, y, color=color, linewidth=2,
             label=f'μ={mu}, σ={sigma}')

plt.title('Different Parameters')
plt.xlabel('x')
plt.ylabel('Probability Density')
plt.legend()
plt.grid(True, alpha=0.3)

# ========== 3. 二维高斯分布 ==========
plt.subplot(1, 3, 3)

# 生成二维高斯样本
mean = [0, 0]
cov = [[1, 0.5], [0.5, 1]]  # 协方差矩阵
samples_2d = np.random.multivariate_normal(mean, cov, 1000)

plt.scatter(samples_2d[:, 0], samples_2d[:, 1], alpha=0.5, s=10)
plt.title('2D Gaussian Distribution')
plt.xlabel('x1')
plt.ylabel('x2')
plt.axis('equal')
plt.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('gaussian_distribution.png', dpi=150)
plt.show()

# 打印统计信息
print(f"样本均值: {np.mean(samples):.4f} (理论: {mu})")
print(f"样本标准差: {np.std(samples):.4f} (理论: {sigma})")

运行结果分析: - 样本均值接近理论均值 \(\mu=0\) - 样本标准差接近理论标准差 \(\sigma=1\) - 直方图形状与理论曲线吻合

1.5 高斯分布的性质

性质1:线性变换 如果 \(X \sim \mathcal{N}(\mu, \sigma^2)\),那么 \(aX + b \sim \mathcal{N}(a\mu + b, a^2\sigma^2)\)

性质2:独立高斯变量的和 如果 \(X \sim \mathcal{N}(\mu_1, \sigma_1^2)\)\(Y \sim \mathcal{N}(\mu_2, \sigma_2^2)\),且独立,那么: $\(X + Y \sim \mathcal{N}(\mu_1 + \mu_2, \sigma_1^2 + \sigma_2^2)\)$

扩散模型中的应用

Python
# 在扩散模型中,加噪过程就是不断添加高斯噪声
x_0 = np.random.normal(0, 1, 1000)  # 原始数据
epsilon = np.random.normal(0, 1, 1000)  # 噪声

# x_t = sqrt(1-beta) * x_{t-1} + sqrt(beta) * epsilon
beta = 0.1
x_t = np.sqrt(1-beta) * x_0 + np.sqrt(beta) * epsilon

print(f"x_0: mean={np.mean(x_0):.4f}, std={np.std(x_0):.4f}")
print(f"x_t: mean={np.mean(x_t):.4f}, std={np.std(x_t):.4f}")
# x_t 仍然是高斯分布!


2. 条件概率与贝叶斯定理

2.1 条件概率

定义:在事件 \(B\) 发生的条件下,事件 \(A\) 发生的概率:

\[P(A|B) = \frac{P(A, B)}{P(B)}\]

扩散模型中的应用: - \(p(x_t | x_{t-1})\):已知上一步 \(x_{t-1}\),当前步 \(x_t\) 的概率 - \(p(x_{t-1} | x_t)\):已知当前步 \(x_t\),上一步 \(x_{t-1}\) 的概率(反向过程)

2.2 贝叶斯定理

\[P(A \mid B) = \frac{P(B \mid A)P(A)}{P(B)}\]

直观理解: 贝叶斯定理告诉我们如何"反转"条件概率。在扩散模型中,我们需要从 \(p(x_t | x_{t-1})\) 推导出 \(p(x_{t-1} | x_t)\)

2.3 代码示例

Python
# 用简单的例子理解条件概率

# 假设有两个盒子
# 盒子A:3红球,2蓝球
# 盒子B:1红球,4蓝球

# 随机选择一个盒子,然后抽一个球
P_A = 0.5  # 选择盒子A的概率
P_B = 0.5  # 选择盒子B的概率

# 条件概率:P(红|A) = 3/5, P(蓝|A) = 2/5
P_red_given_A = 3/5
P_blue_given_A = 2/5

# 条件概率:P(红|B) = 1/5, P(蓝|B) = 4/5
P_red_given_B = 1/5
P_blue_given_B = 4/5

# 联合概率:P(红, A) = P(红|A) * P(A)
P_red_and_A = P_red_given_A * P_A
P_red_and_B = P_red_given_B * P_B

# 边缘概率:P(红) = P(红, A) + P(红, B)
P_red = P_red_and_A + P_red_and_B

print(f"P(红) = {P_red:.4f}")

# 贝叶斯定理:P(A|红) = P(红|A) * P(A) / P(红)
P_A_given_red = P_red_given_A * P_A / P_red
print(f"P(A|红) = {P_A_given_red:.4f}")

# 验证:P(A|红) + P(B|红) = 1
P_B_given_red = P_red_given_B * P_B / P_red
print(f"P(B|红) = {P_B_given_red:.4f}")
print(f"Sum = {P_A_given_red + P_B_given_red:.4f}")

3. KL散度(Kullback-Leibler Divergence)

3.1 直观理解

KL散度衡量两个概率分布之间的"差异"。

扩散模型中的应用: - 训练目标是最小化模型分布与真实分布之间的KL散度 - 用于衡量生成的图像分布与真实图像分布的差异

注意:KL散度不是距离,因为它不对称:\(D_{KL}(P||Q) \neq D_{KL}(Q||P)\)

3.2 数学定义

对于离散分布: $\(D_{KL}(P||Q) = \sum_i P(i) \log\frac{P(i)}{Q(i)}\)$

对于连续分布: $\(D_{KL}(P \Vert Q) = \int p(x) \log\frac{p(x)}{q(x)} dx\)$

3.3 代码实践

Python
import numpy as np
import matplotlib.pyplot as plt

# ========== KL散度计算 ==========
def kl_divergence(p, q):
    """
    计算KL散度 D_KL(P||Q)
    p, q: 概率分布(已归一化)
    """
    # 避免log(0),添加小量
    epsilon = 1e-10
    p = np.clip(p, epsilon, 1)
    q = np.clip(q, epsilon, 1)

    return np.sum(p * np.log(p / q))

# 创建两个高斯分布
x = np.linspace(-5, 5, 1000)

# 分布P:标准正态
mu_p, sigma_p = 0, 1
p = stats.norm.pdf(x, mu_p, sigma_p)
p = p / np.sum(p)  # 归一化

# 分布Q:不同的均值
mu_q, sigma_q = 1, 1
q = stats.norm.pdf(x, mu_q, sigma_q)
q = q / np.sum(q)

# 计算KL散度
kl_pq = kl_divergence(p, q)
kl_qp = kl_divergence(q, p)

print(f"D_KL(P||Q) = {kl_pq:.6f}")
print(f"D_KL(Q||P) = {kl_qp:.6f}")
print(f"不对称!D_KL(P||Q) != D_KL(Q||P)")

# 可视化
plt.figure(figsize=(12, 4))

plt.subplot(1, 2, 1)
plt.plot(x, p, 'b-', linewidth=2, label=f'P: μ={mu_p}, σ={sigma_p}')
plt.plot(x, q, 'r-', linewidth=2, label=f'Q: μ={mu_q}, σ={sigma_q}')
plt.fill_between(x, p, alpha=0.3)
plt.fill_between(x, q, alpha=0.3)
plt.title(f'KL(P||Q) = {kl_pq:.4f}')
plt.xlabel('x')
plt.ylabel('Probability')
plt.legend()
plt.grid(True, alpha=0.3)

# 比较不同差异程度的KL散度
plt.subplot(1, 2, 2)
mu_q_values = np.linspace(-3, 3, 50)
kl_values = []

for mu_q in mu_q_values:
    q = stats.norm.pdf(x, mu_q, sigma_q)
    q = q / np.sum(q)
    kl = kl_divergence(p, q)
    kl_values.append(kl)

plt.plot(mu_q_values, kl_values, 'g-', linewidth=2)
plt.axvline(x=0, color='r', linestyle='--', alpha=0.5, label='P=Q')
plt.xlabel('μ_Q (Q的均值)')
plt.ylabel('KL Divergence')
plt.title('KL散度随分布差异的变化')
plt.legend()
plt.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('kl_divergence.png', dpi=150)
plt.show()

print("\n观察:当两个分布越接近时,KL散度越小")
print("当P=Q时,KL散度为0")

3.4 高斯分布的KL散度(闭合形式)

对于两个高斯分布 \(P = \mathcal{N}(\mu_1, \sigma_1^2)\)\(Q = \mathcal{N}(\mu_2, \sigma_2^2)\)

\[D_{KL}(P||Q) = \log\frac{\sigma_2}{\sigma_1} + \frac{\sigma_1^2 + (\mu_1 - \mu_2)^2}{2\sigma_2^2} - \frac{1}{2}\]

扩散模型中的重要性: 扩散模型的训练目标可以转化为计算高斯分布之间的KL散度,而高斯分布的KL散度有闭合形式,这使得计算变得可行!

Python
def kl_gaussian(mu1, sigma1, mu2, sigma2):
    """
    计算两个高斯分布之间的KL散度 D_KL(N1||N2)
    """
    return (np.log(sigma2 / sigma1) +
            (sigma1**2 + (mu1 - mu2)**2) / (2 * sigma2**2) - 0.5)

# 验证
mu1, sigma1 = 0, 1
mu2, sigma2 = 1, 2

kl_closed = kl_gaussian(mu1, sigma1, mu2, sigma2)
print(f"闭合形式计算: D_KL = {kl_closed:.6f}")

# 数值计算验证
x = np.linspace(-10, 10, 10000)
p = stats.norm.pdf(x, mu1, sigma1)
q = stats.norm.pdf(x, mu2, sigma2)
p = p / np.sum(p)
q = q / np.sum(q)
kl_numerical = kl_divergence(p, q)
print(f"数值计算: D_KL = {kl_numerical:.6f}")

4. 重参数化技巧(Reparameterization Trick)

4.1 问题背景

在扩散模型中,我们需要从条件分布 \(p(x_t | x_0)\) 中采样。直接采样需要计算复杂的积分,但重参数化技巧可以让我们用标准高斯噪声来表示。

4.2 核心思想

如果 \(x \sim \mathcal{N}(\mu, \sigma^2)\),那么: $\(x = \mu + \sigma \cdot \epsilon, \quad \epsilon \sim \mathcal{N}(0, 1)\)$

好处: - 将随机性从参数中分离出来 - 可以使用梯度下降优化 - 扩散模型前向过程的核心技巧

4.3 代码验证

Python
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)

# 目标分布参数
mu = 2.0
sigma = 1.5

# 方法1:直接从目标分布采样
samples_direct = np.random.normal(mu, sigma, 10000)

# 方法2:重参数化技巧
epsilon = np.random.normal(0, 1, 10000)
samples_reparam = mu + sigma * epsilon

# 比较两种方法
plt.figure(figsize=(12, 4))

plt.subplot(1, 2, 1)
plt.hist(samples_direct, bins=50, density=True, alpha=0.5,
         label='Direct Sampling', color='blue')
plt.hist(samples_reparam, bins=50, density=True, alpha=0.5,
         label='Reparameterization', color='red')
plt.title('Sampling Comparison')
plt.xlabel('x')
plt.ylabel('Density')
plt.legend()
plt.grid(True, alpha=0.3)

# 统计比较
plt.subplot(1, 2, 2)
stats_data = {
    'Direct': [np.mean(samples_direct), np.std(samples_direct)],
    'Reparam': [np.mean(samples_reparam), np.std(samples_reparam)],
    'Theory': [mu, sigma]
}

x_pos = np.arange(2)
width = 0.25

for i, (method, values) in enumerate(stats_data.items()):  # enumerate同时获取索引和元素
    plt.bar(x_pos + i*width, values, width, label=method)

plt.xlabel('Statistic')
plt.ylabel('Value')
plt.title('Mean and Std Comparison')
plt.xticks(x_pos + width, ['Mean', 'Std'])
plt.legend()
plt.grid(True, alpha=0.3, axis='y')

plt.tight_layout()
plt.savefig('reparameterization.png', dpi=150)
plt.show()

print("统计比较:")
print(f"直接采样: mean={np.mean(samples_direct):.4f}, std={np.std(samples_direct):.4f}")
print(f"重参数化: mean={np.mean(samples_reparam):.4f}, std={np.std(samples_reparam):.4f}")
print(f"理论值: mean={mu:.4f}, std={sigma:.4f}")

4.4 在扩散模型中的应用

Python
# 扩散模型中的前向过程
# x_t = sqrt(alpha_t) * x_0 + sqrt(1 - alpha_t) * epsilon

def q_sample(x_0, t, alphas):
    """
    从 q(x_t | x_0) 采样
    使用重参数化技巧

    参数:
        x_0: 原始数据
        t: 时间步
        alphas: 累积alpha值
    """
    # 计算均值和方差
    alpha_t = alphas[t]
    mean = np.sqrt(alpha_t) * x_0
    std = np.sqrt(1 - alpha_t)

    # 重参数化采样
    epsilon = np.random.normal(0, 1, x_0.shape)
    x_t = mean + std * epsilon

    return x_t, epsilon

# 示例
x_0 = np.array([1.0, 2.0, 3.0])  # 原始数据
alphas = np.linspace(0.99, 0.01, 1000)  # 随时间递减的alpha
alphas_cumprod = np.cumprod(alphas)

# 在不同时间步采样
for t in [0, 250, 500, 750, 999]:
    x_t, eps = q_sample(x_0, t, alphas_cumprod)
    noise_level = np.sqrt(1 - alphas_cumprod[t])
    print(f"t={t:4d}: x_t={x_t}, noise_level={noise_level:.4f}")

5. 本章总结

核心概念回顾

  1. 高斯分布
  2. 扩散模型的基础分布
  3. 线性变换后仍是高斯分布
  4. 便于数学处理

  5. 条件概率与贝叶斯定理

  6. 理解前向和反向过程的关键
  7. \(p(x_t|x_{t-1})\) 推导 \(p(x_{t-1}|x_t)\)

  8. KL散度

  9. 训练目标的数学基础
  10. 衡量两个分布的差异
  11. 高斯分布有闭合形式

  12. 重参数化技巧

  13. 使梯度下降成为可能
  14. 扩散模型前向过程的核心

关键公式

概念 公式
高斯分布 \(p(x) = \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left(-\frac{(x-\mu)^2}{2\sigma^2}\right)\)
贝叶斯定理 \(P(A \mid B) = \frac{P(B \mid A)P(A)}{P(B)}\)
KL散度 \(D_{KL}(P \Vert Q) = \int p(x) \log\frac{p(x)}{q(x)} dx\)
重参数化 \(x = \mu + \sigma \cdot \epsilon, \quad \epsilon \sim \mathcal{N}(0, 1)\)

📝 自测问题

基础问题

  1. 高斯分布
  2. 为什么扩散模型选择高斯噪声而不是其他分布?
  3. 如果 \(X \sim \mathcal{N}(0, 1)\)\(Y = 2X + 3\)\(Y\) 服从什么分布?

  4. 条件概率

  5. 解释 \(p(x_t | x_{t-1})\)\(p(x_{t-1} | x_t)\) 的区别
  6. 在扩散模型中,哪个是前向过程,哪个是反向过程?

  7. KL散度

  8. KL散度为0意味着什么?
  9. 为什么KL散度不对称?这在实际中有什么影响?

  10. 重参数化

  11. 重参数化技巧解决了什么问题?
  12. 写出扩散模型中 \(x_t\) 的重参数化形式

编程练习

  1. 实现一个函数,计算两个任意分布的KL散度
  2. 用重参数化技巧从多元高斯分布中采样
  3. 可视化扩散过程中噪声水平的变化

思考题

  1. 如果扩散模型使用均匀分布作为噪声,会有什么不同?
  2. 为什么高斯分布的KL散度有闭合形式很重要?
  3. 重参数化技巧对梯度计算有什么帮助?

🔗 下一步

你已经掌握了概率论的基础知识,接下来我们将学习随机过程与马尔可夫链,这是理解扩散模型动态过程的关键。

→ 下一步:02-随机过程与马尔可夫链.md