跳转至

扩散模型原理


一句话说明

扩散模型是 2020 年后最强大的生成模型,核心思路是"先把数据逐步加噪声变成纯噪声,再训练神经网络逐步去噪还原数据"——Stable Diffusion、DALL-E 2 都基于此原理,生信中用于蛋白质结构生成、分子设计。


核心知识点

两个过程

前向过程(加噪):数据 x₀ → 逐步加高斯噪声 → xT(纯噪声)

q(xₜ|xₜ₋₁) = N(xₜ; √(1-βₜ)xₜ₋₁, βₜI)
β 是每步加噪的程度(噪声调度)

反向过程(去噪):训练神经网络预测并去除噪声

pθ(xₜ₋₁|xₜ) = N(xₜ₋₁; μθ(xₜ,t), Σθ(xₜ,t))

训练目标

训练噪声预测网络 εθ,预测第 t 步加的噪声:

L = E[||ε - εθ(xₜ, t)||²]
ε 是真实噪声,εθ 是模型预测的噪声

关键技术点

概念作用
噪声调度控制每步加噪的幅度(线性/余弦/平方根)
U-Net 骨干图像扩散模型的主流架构
条件引导 CFG用文本/条件控制生成方向
DDIM 采样跳步采样,大幅加速推断
潜扩散 LDM在潜空间而非像素空间扩散(Stable Diffusion)

生信应用

工具应用
RFdiffusion蛋白质骨架设计(Baker Lab, 2023)
DiffSBDD基于靶点的药物分子生成
FrameDiff蛋白质骨架扩散
DiffRNARNA 结构生成
DiMA分子动力学轨迹生成

实战代码

import torch
import torch.nn as nn
import numpy as np

# ===== 1. 噪声调度(线性 β 调度)=====
def linear_beta_schedule(timesteps=1000, beta_start=1e-4, beta_end=0.02):
    """
    定义每步加噪的幅度 β
    timesteps: 总扩散步数(通常 1000)
    """
    return torch.linspace(beta_start, beta_end, timesteps)  # 从小到大线性增加

# 预计算扩散过程的参数
timesteps = 1000
betas = linear_beta_schedule(timesteps)      # β: 每步噪声幅度 [T]
alphas = 1.0 - betas                          # α = 1 - β
alphas_cumprod = torch.cumprod(alphas, dim=0) # ᾱ = ∏α,累积乘积

# ===== 2. 前向过程:给数据加噪 =====
def q_sample(x_0, t, noise=None):
    """
    一步到位地给 x_0 加 t 步的噪声(利用数学推导的解析式)
    x_0: 原始数据 [batch, dim]
    t: 时间步索引 [batch]
    返回: x_t,即加了 t 步噪声后的数据
    """
    if noise is None:
        noise = torch.randn_like(x_0)  # 从标准正态分布采样噪声

    # 根据时间步 t 提取对应的 ᾱ
    alpha_t = alphas_cumprod[t].unsqueeze(-1)  # [batch, 1]

    # 解析式:x_t = √ᾱ * x_0 + √(1-ᾱ) * ε
    x_t = torch.sqrt(alpha_t) * x_0 + torch.sqrt(1 - alpha_t) * noise
    return x_t, noise

# ===== 3. 噪声预测网络(简化版 MLP,实际用 U-Net)=====
class SimpleNoisePredictor(nn.Module):
    """
    预测给定 x_t 和时间步 t 时加入的噪声
    实际应用中替换为 U-Net 或 Transformer
    """
    def __init__(self, data_dim, time_dim=64):
        super().__init__()
        # 时间步嵌入:把整数 t 转化为向量
        self.time_embed = nn.Embedding(1000, time_dim)

        self.net = nn.Sequential(
            nn.Linear(data_dim + time_dim, 256),  # 数据 + 时间步
            nn.SiLU(),                              # SiLU 激活(扩散模型常用)
            nn.Linear(256, 256),
            nn.SiLU(),
            nn.Linear(256, data_dim)               # 输出预测的噪声
        )

    def forward(self, x_t, t):
        t_emb = self.time_embed(t)              # 时间嵌入 [batch, time_dim]
        x_in = torch.cat([x_t, t_emb], dim=-1) # 拼接数据和时间信息
        return self.net(x_in)                   # 预测噪声

# ===== 4. 训练循环 =====
data_dim = 512    # 假设是蛋白质特征维度
model = SimpleNoisePredictor(data_dim)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)

# 模拟训练数据(实际替换为蛋白质坐标等)
fake_proteins = torch.randn(1000, data_dim)

for step in range(200):
    # 随机采样批次和时间步
    idx = torch.randint(0, 1000, (32,))
    x_0 = fake_proteins[idx]                           # 原始数据
    t = torch.randint(0, timesteps, (32,))             # 随机时间步

    # 前向:添加噪声
    x_t, true_noise = q_sample(x_0, t)

    # 预测噪声
    pred_noise = model(x_t, t)

    # 损失:预测噪声 vs 真实噪声(L2 损失)
    loss = nn.MSELoss()(pred_noise, true_noise)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if step % 50 == 0:
        print(f'Step {step}, Loss: {loss.item():.4f}')

# ===== 5. 反向过程(DDPM 采样)=====
@torch.no_grad()
def ddpm_sample(model, shape, device='cpu'):
    """从纯噪声逐步去噪生成数据"""
    x = torch.randn(shape).to(device)  # 从标准正态开始(纯噪声)

    for t in reversed(range(timesteps)):  # 从 T=999 逐步到 t=0
        t_batch = torch.full((shape[0],), t, dtype=torch.long)

        pred_noise = model(x, t_batch)  # 预测当前步的噪声

        # 计算去噪后的 x_{t-1}(简化版,实际包含方差项)
        alpha = alphas[t]
        alpha_bar = alphas_cumprod[t]
        x = (x - (1 - alpha) / torch.sqrt(1 - alpha_bar) * pred_noise) / torch.sqrt(alpha)

        if t > 0:  # 最后一步不加噪声
            x += torch.sqrt(betas[t]) * torch.randn_like(x)

    return x  # 生成的数据

generated = ddpm_sample(model, shape=(5, data_dim))
print(f'生成的蛋白质特征形状: {generated.shape}')

面试常问点

Q: 扩散模型和 GAN 的主要区别? A: 扩散模型训练更稳定(没有对抗博弈),生成多样性更好,但推断速度慢(需要几百步去噪)。GAN 推断快但容易模式崩溃。

Q: DDPM 和 DDIM 的区别? A: DDPM 是随机采样(每步有噪声),需要 1000 步;DDIM 是确定性采样,可以跳步(50-200步),速度提升 10x+。

Q: RFdiffusion 怎么用于蛋白质设计? A: 在蛋白质骨架坐标空间做扩散,给定结合口袋约束条件,从噪声生成满足约束的蛋白质骨架,再用 ProteinMPNN 设计序列。

Q: 潜扩散模型(LDM)的优势? A: 在低维潜空间(而非像素/坐标空间)做扩散,计算量大幅减少,且 VAE 的潜空间已经学到了语义表示。


速查表

术语解释
前向过程数据 → 加噪声 → 纯噪声
反向过程纯噪声 → 去噪 → 数据
β 调度每步加噪幅度的安排
DDPM去噪扩散概率模型(原版)
DDIM确定性采样加速版本
CFG分类器自由引导(条件生成)
RFdiffusion蛋白质骨架设计扩散模型
SiLUSwish 激活函数,扩散模型常用