☰
扩散后验采样DPS:用生成先验求解成像逆问题的通用框架
2026/10/26 4:31:01 网站建设 项目流程

今天这讲是计算成像系列里我很期待的一节,聊的是扩散后验采样(DPS):一种用生成先验来求解成像逆问题的通用框架。成像逆问题,说白了就是从一张缺信息、带噪声的观测图里,把原始干净图像x给猜出来。去模糊、超分辨率、图像修复、相位恢复、压缩感知重建,全都是同一个数学壳子:y = A x + n。这问题天生欠定,直接做最小二乘基本是给噪声做放大器。早些年我们靠手调正则项,后来有人尝试用生成模型当先验,直到扩散模型成熟之后,才有了DPS这类把“数据流形”和“测量一致性”都兼顾的解法。这讲我打算从贝叶斯视角把DPS的每一步拆开,再给出一套可以直接上手的代码骨架和排坑清单,适合正在做计算成像实验、或者准备把生成先验用到自己重建任务里的同学参考。

1. 成像逆问题:为什么难,为什么需要生成先验

1.1 从一个最小二乘问题说起

所有成像系统都在干一件事:把真实场景x经过某个测量过程变成观测y。普通相机是卷积加噪声,手机超分是模糊加下采样,医学MRI是欠采样傅里叶变换,无透镜成像可能是光强级联的非线性算子。把这些统一写成 y = A x + n,n通常假设为高斯白噪声 N(0, σ²I),逆问题就是反解x。

如果不加任何约束,最自然的方法是最小化 ||y - A x||²。但这个优化问题的解在A病态时会非常不稳定。拿去模糊来举例:卷积核在频域里往往有一堆接近零的频率,逆滤波要把这些位置的观测值除以接近零的数,结果就是把噪声放大了无数倍。伪逆解看起来像一张被高频噪声吞噬的图像,毫无实用价值。因此工程上必须引入先验,把问题改写成最大后验估计:

x̂ = argmin ||y - A x||² + λ R(x)

这里的R(x)就是我们塞进去的先验知识。早期最常用总变差,假设干净图像分段平滑,惩罚梯度幅值;后来有各种稀疏变换、低秩约束、非局部自相似约束。这些先验有一个共同特点:它们是人类基于对自然图像的局部统计观察,手写出来的规则。手写规则的问题在于表达力有限,总变差能保住边缘,但会抹平纹理;稀疏先验假设自然图像在某组基下稀疏,但这种假设对复杂场景常常不成立。它们本质上都是“局部规则”,像阅卷标准里的“卷面分”,只看你每段写没写清楚,不管你的论证逻辑是不是真的像一篇好文章。

1.2 传统先验与生成先验的差异

生成先验换了一个思路:与其手写规则,不如让模型从海量自然图像里学“什么是自然图像”。GAN时代有人用生成器G把重建结果限制在隐空间:x = G(z),再优化z让A(G(z))≈y。这条路证明有效,但隐空间优化不稳定,生成器覆盖的分布往往有空洞,遇到复杂测量算子容易陷入局部最优,恢复出来的图像也可能被限制在生成器见过的模式里。

扩散模型的到来改变了这一点。它不是在低维隐空间做生成,而是在像素空间直接建模整个数据分布p(x)。它的先验体现为一个分数函数∇ log p_t(x_t),告诉你当前图像离自然图像流形还有多远、应该往哪个方向修正。这个先验是非线性的、全局的,能捕捉纹理、结构和语义层面的约束。把这种先验接到逆问题求解上,就有了DPS这一类方法。理解这个背景很重要,因为后面DPS的每一个设计选择,本质上都是在回答同一个问题:如何既让结果“像自然图像”,又让结果“和观测吻合”。

注意:生成先验的一个隐藏前提是“数据域匹配”。如果预训练扩散模型在自然图像上训练,而你的观测来自医学影像或工业无损检测,先验会把输出往自然图像分布上拽,可能掩盖真实缺陷。选底座时要先想清楚目标域和训练域是不是同一类数据。

2. 扩散模型基础:DPS的底座

2.1 前向过程与反向过程

DPS不是要单独训练一个条件扩散模型,它利用的是无条件扩散模型。先简单回顾扩散模型在做什么。给一张干净图像x0,前向过程逐步加噪:

x_t = √ᾱ_t · x0 + √(1−ᾱ_t) · ε,ε ~ N(0, I)

这里ᾱ_t是一个随t递减的常数,t越大ᾱ_t越接近0,x_t就越接近纯噪声。一个很好的性质是:从x0到任意时刻t的加噪结果都能一步算出来,不用真的迭代T次。训练时,神经网络ε_θ(x_t, t)的任务是预测混进去的噪声ε,损失就是简单的 ||ε − ε_θ(x_t,t)||²。

这个看似简单的目标有一个深层含义:网络实际在估计条件期望,并隐式学会了当前噪声图像的分数。具体关系是:

∇ log p_t(x_t) ≈ −ε_θ(x_t,t) / √(1−ᾱ_t)

也就是说,只要有一个噪声预测器,就等于拿到了图像分布的分数。生成时,从x_T ~ N(0,I)出发,按反向过程一步步去噪,每步相当于“先猜一个x0,再往更可信的状态挪一步”。DDPM采样通常要几百到上千步;DDIM通过确定性的轨迹可以压缩到几十步,代价是生成多样性略降。对DPS来说,这个底座是预先训练好的,不需要为每个逆问题重新训练,这是它能成为通用求解器的前提。

2.2 从无条件生成到条件采样

无条件扩散模型只能采样p(x),也就是生成一张看起来自然的图像,但完全不受观测y约束。要让采样结果满足y,最朴素的想法是给每个任务都训练一个条件扩散模型p(x|y)。可逆问题的退化方式五花八门,卷积核不同、超分倍率不同、采样mask不同,都算一个新任务。每个任务都重新训练,成本完全不可接受。

DPS的思路是在采样阶段做零训练引导。它把后验分布写成:

p(x_t|y) ∝ p(x_t) · p(y|x_t)

对应到反向采样的每一步,我们可以先按无条件扩散模型走一步,再根据“当前状态和观测y的匹配程度”去修正这一步的方向。这个修正量来自似然项的梯度,也就是DPS名字里的“后验采样”:采样过程不再只是沿着先验分数走,而是沿着条件分数走。这样,同一个预训练扩散模型,可以通用于一批逆问题,只需要换测量算子A和观测y,接入一条梯度即可。

3. DPS核心推导:测量一致性如何注入扩散采样

3.1 目标分布:条件分数分解

如果能在每一步都计算出条件分数的解析式,问题就解决了。条件分数可以分解为:

∇ log p_t(x_t|y) = ∇ log p_t(x_t) + ∇ log p_t(y|x_t)

第一项是扩散模型的先验分数,可以直接用噪声预测网络代入。第二项是“给定x_t时观测y的似然”,它是DPS整个方法的核心难点。难点在于p_t(y|x_t)不是一个可以直接写出来的分布,原因是x_t是加了大量噪声的中间状态,它和观测y之间隔着未知的x0。严格写的话:

p_t(y|x_t) = ∫ p(y|x0) p(x0|x_t) dx0

这里p(y|x0)很简单,就是一个以A x0为均值的高斯分布;但p(x0|x_t)是“从噪声图像反推干净图像”的后验,没有解析形式。这个积分把测量一致性和先验耦合在一起,必须想办法近似。

3.2 关键近似:用x̂0替换不可解积分

一个自然的想法是用期望值或众数来近似这个积分。扩散模型领域有一个Tweedie公式:给定x_t,对干净图像x0的最优估计是:

x̂0 = (x_t − √(1−ᾱ_t) · ε_θ(x_t,t)) / √ᾱ_t

这个x̂0其实就是去噪网络做一次去噪得到的结果,它在采样过程中本来就会反复出现。DPS的关键近似是:直接把这个x̂0当成x0的代表,把不可解积分替换成一个点估计:

p_t(y|x_t) ≈ p(y|x̂0(x_t)) = exp( −||y − A x̂0(x_t)||² / (2σ²) )

这样一来,测量一致性的量度完全落在一个平方误差上。我们需要修正x_t,使得当前去噪估计再经过测量算子之后,尽可能接近观测y。注意,这里x̂0是x_t的函数,所以对x_t求梯度时必须把ε_θ的参数也纳进来,靠自动微分完成。这个近似看起来简单,但把“先验推断”和“数据拟合”之间最难解的积分绕过去了,这是DPS能在工程里落地的关键一步。

3.3 更新公式与实现细节

把上面几步组合起来,DPS的采样循环可以写成:

x_T ~ N(0, I) for t = T, T−1, ..., 1: 1) 先执行一步无条件反向采样,得到 x_{t−1}^{uncond} 2) 计算 x̂0 = (x_t − √(1−ᾱ_t) ε_θ(x_t,t)) / √ᾱ_t 3) 计算引导梯度 g = ∇_{x_t} ||y − A(x̂0)||² 4) 令 x_{t−1} = x_{t−1}^{uncond} − ζ_t · g / (||g|| + ε)

这里ζ_t是引导步长,ε是防止除零的小常数。在实践中,最稳的做法是对梯度做归一化后再乘步长,这样可以避免不同t时刻梯度范数差异太大导致的震荡。有些人会问,为什么不直接用带权重的梯度1/(2σ²)·g?可以,但权重会和σ耦合在一起,调参时比较痛苦;归一化之后,ζ的语义更单纯,就是一个“测量约束强度”的旋钮。

还有两个值得注意的细节。第一,在自动微分框架里,计算g时x_t必须是requires_grad的叶子节点,损失用的是A(x̂0)与y的平方误差,这样g会自然包含x̂0对x_t的依赖。第二,在t很大的时候x_t几乎全是噪声,x̂0非常模糊,引导梯度的方向并不精确,所以有些实现会给ζ乘一个随t变化的系数,早期弱引导、后期强引导。我个人复现时,全程固定ζ=1.0在很多线性问题上也能跑通,但要做精细实验还是建议加一个动态系数。

4. 实操指南:从代码到实验设置的完整流程

4.1 一个能跑起来的DPS代码骨架

纸上谈兵没用,直接看代码。假设你已经有一个训练好的无条件扩散模型denoiser,测量算子A是一个可微的映射,alpha_bar[i]存放第i步的噪声调度值。下面是单步引导梯度的实现思路:

import torch def dps_guidance(x_t, t, y, A, denoiser, alpha_bar, zeta=1.0): # 关键:让 x_t 成为计算图的叶子节点 x_t = x_t.clone().requires_grad_(True) eps_pred = denoiser(x_t, t) x0_hat = (x_t - torch.sqrt(1 - alpha_bar[t]) * eps_pred) / torch.sqrt(alpha_bar[t]) loss = torch.sum((y - A(x0_hat)) ** 2) grad = torch.autograd.grad(loss, x_t)[0] # 梯度归一化后乘步长,更稳 grad = grad / (grad.norm() + 1e-6) * zeta return grad

在采样循环里,每一轮的顺序是:先用DDPM或DDIM的无条件更新规则得到x_next_uncond,然后调用上面的函数拿到引导梯度,最后让x_next = x_next_uncond - guidance。注意整个引导计算单独立出来,避免污染无条件更新里的梯度状态。

我实际跑下来,有几个容易踩的坑:

  • 输入尺度必须和训练扩散模型时一致。如果扩散模型是在[-1,1]范围内训练的,y和A的输出也要统一到这个尺度,否则引导梯度的量级会偏移。
  • A(x0_hat)的输出和y的shape要保持一致。超分辨里A往往包含下采样,如果你的下采样算子不是可微的,要换成“模糊+可微采样”的近似。
  • 不要对x_t本身做detach后再计算引导,否则你拿不到∂x̂0/∂x_t这一项,引导会退化成一种粗糙的“测量匹配”,效果明显变差。

4.2 关键超参数选择

DPS的超参数不多,但每个都值得花时间调。

引导步长ζ是最敏感的一个。太小,测量一致性不足,结果模糊;太大,图像结构被强行扭曲,出现彩色噪点或振铃。一个比较合理的起始点是1.0,然后观察结果:如果数据保真项下降但感知质量变差,就往小调;如果重建结果和观测始终差得远,就往大调。在DDPM采样下0.5到1.5是一个常见区间;改成DDIM加速时,步数减少会让每一步的“信息密度”变大,我认为把ζ比经典设置略微下调更安全。

噪声水平σ也不能乱设。DPS的似然项里1/(2σ²)承担着“我该多信任观测”的权重。如果你直接把σ设成0,就是把观测当成无噪声,在低质量观测下容易过拟合噪声;设得过大,则引导太软。如果退化噪声未知,可以先做一个粗重建,从观测残差里估计σ² ≈ ||y − A x_recon||² / m,其中m是y的元素个数。把这个估计值放进DPS,比拍脑袋定σ要靠谱得多。

总采样步数T也需要平衡。理论上DPS遵循DDPM反向过程,1000步是黄金标准;实际工程里我用DDIM把步数压到50到100步,效果依然可以,只是需要重新调一下ζ。如果你发现步数减少后图像出现“半成品感”,大概率是引导太强,每一步都企图把当前状态强行拉向某个测量一致的点。

4.3 不同逆问题怎么快速适配

DPS最大的吸引力在于“通用”。换问题基本就是换一个A函数。下面这张表是我做过的几种常见适配:

逆问题测量算子A需要注意的点
高斯去模糊卷积核要padding正确,梯度在边界处收敛慢
超分辨率模糊+下采样下采样算子要可微,用面积平均近似较多
图像修复二进制掩膜掩膜区域直接置零即可,引导梯度天然只在已知区域生效
压缩感知随机投影矩阵大矩阵时用分块计算,避免显存爆掉
相位恢复傅里叶幅度非线性观测,损失改成y与幅度之间的误差
医学MRI重建欠采样傅里叶用FFT算子,梯度计算方便,重点调σ

拿相位恢复举例,观测模型变成y = |F(x)|²,不再写成y = Ax。这时候DPS的推导几乎不用改,只要把数据保真项从||y − A(x̂0)||²换成||y − |F(x̂0)||²,并且对x_t重新求梯度就行。这恰恰是DPS比很多依赖线性观测模型的方法更通用的原因:只要你的测量过程可微,它就能作为损失函数接入。

5. 实验结果解读:DPS效果与局限

5.1 定性定量的表现

在常见基准上,DPS的表现在中等噪声和复杂先验场景下通常明显优于传统TV正则化。去模糊和超分这类任务中,TV解出来的图边缘是干净的,但纹理和材质会被磨平;DPS能恢复比较自然的高频细节,尤其在人脸、毛发这类强语义结构上,差距肉眼可见。定量指标上,PSNR提升几dB的情况不少见,在感知指标LPIPS上的提升通常更明显,有时能差出0.1以上。

这背后的原因是:像素级指标PSNR更关注“平均误差”,而DPS的先验约束在感知层面,生成结果可能和真实图像不是逐像素一致的,但视觉上非常真实。这也是所有生成先验方法的双刃剑:指标好看、观感自然,但你没法保证恢复出来的细节是“真实发生过”的细节。在做图像质量评价时,不能只看单张最好看的图,还要看多random seed下的稳定性和最终应用能不能接受这种不确定性。

5.2 和其他生成先验路线的对比

把DPS放进生成先验的谱系里看会更清楚:

方法路线先验形式主要限制DPS的相对优势
GAN生成先验隐空间流形分布覆盖率有限、隐空间优化不稳像素空间采样更完整
能量模型/归一化流显式密度高维图像建模难度大扩散模型训练成熟稳定
需要SVD的扩散后验方法子空间分解需要测量算子可分解只需要可微算子
DPS分数先验+逐像素梯度每步一次反向传播通用、零训练

如果你手里的测量算子结构很规整,比如周期采样、对角化的模糊核,那些需要SVD的方法可能更快更准;但一旦算子是非线性、耦合复杂、没有漂亮分解的,DPS往往是更省事的选择。这也是我在实际课题里选择DPS的主要原因。

5.3 典型的失败模式和边界

DPS不是万能的。第一个典型失败是高噪声场景。观测噪声很大时,x̂0在采样早期非常不可靠,引导梯度可能把一个合理的去噪方向带偏,结果出现各种不存在的结构。第二个是测量信息严重不足时,生成先验会“脑补”细节。这在医学图像里尤其需要警惕,因为“看起来合理”不等于“诊断正确”。第三个是逐像素平方损失带来的过平滑,有时对细节敏感的任务,DPS不如专门设计的结构化损失版本。

针对这些边界,后续有不少改进思路。一类是在更新时限制x̂0不要偏离x_t的邻域太远,相当于给引导梯度加一个信任区域;另一类是改成在潜在扩散模型的潜空间里做DPS,速度和显存都友好很多;还有一类是把逐像素MSE换成特征域损失,让测量一致性约束在感知空间里生效。这些都是在DPS框架上打补丁,核心的后验采样思想没有变。

6. 常见问题与排查技巧实录

6.1 样本崩坏:引导步长过大还是过小

我在复现时遇到的第一个问题是结果出现大量彩色噪点和结构性伪影。第一反应是引导步长太大了,把每次采样都推出合理流形。后来我把ζ从1.0降到0.5,伪影立刻缓解,但细节也少了一些。最终在0.8左右找到一个平衡点。反过来的症状是结果模糊、观测残差居高不下,多半是ζ太小或引导启动太晚。

建议做法:固定其他参数,对ζ做一组小扫描,比如0.3、0.5、1.0、1.5。同时监控两个数值:数据保真项||y − A(x̂0)||²和x̂0的感知质量。保真项下降但感知质量变差,说明过拟合观测;保真项降不下去,说明引导不足。这种“保真和感知互搏”的现象,在生成先验方法里几乎必然出现,要学会接受并找到平衡点。

6.2 噪声水平设置不匹配

如果你发现DPS在低噪声数据上表现反而不如高噪声数据,不用奇怪,很可能是σ值设大了。σ在这个方法里直接控制似然项的锐度,设太大,引导就变成“蜻蜓点水”;设太小,引导变成“钻牛角尖”。比较稳妥的方式是直接用上一节说的经验估计法,从残差里估σ。如果想让结果更稳一点,可以略微把估出来的σ调大10%~20%,牺牲一点保真换稳定。

6.3 梯度爆炸与数值不稳定

虽然我对梯度做了归一化,但不幸的是,在某些病态严重的算子下,A(x̂0)的梯度依然可能在某几步出现尖峰。原因通常是A本身条件数太差,或者x̂0在t较小时出现了极值。我的应对办法有几个:一是对引导梯度做clip,限制每一步修正量不要超过图像像素值范围的一定比例;二是给A(x̂0)先做一个很小的空间平滑再算损失,相当于给梯度穿过一个低通滤波;三是检查输入尺度,如果图像像素值在[-1,1]但y是[0,255],梯度方向可能没问题,但幅度会被尺度差带着跑。

6.4 内存占用与采样加速

DPS每一步都要通过A(x̂0)反传,显存开销比普通扩散采样高出一截。在高分辨率任务里,我一般这样优化:优先用DDIM把总步数压到100以内;对大图像按重叠patch切块,分别计算引导梯度再拼回去,注意重叠区域做加权平均;对线性算子的矩阵直接用自定义的线性算子实现,不要显式构造大矩阵;最后,如果你发现瓶颈在x̂0的反向上,可以对x̂0做一次detach再算一部分解析梯度,但这会损失精度,我一般只在显存实在不够时用。

6.5 怎么判断DPS该停了

我个人的习惯是每20步打印一个数据保真项和x̂0的LPIPS值。DPS采样的过程中,保真项一般是单调下降然后趋于稳定,感知质量则可能在某个点之后开始反弹变差。当你看到这两个指标开始“互搏”的时候,就是ζ该调小、或者采样总步数可以截断的信号。这个习惯帮我避过很多次“生成结果好看但不保真”的坑。

另有一个小技巧:如果某个任务的测量模型特别复杂,先用一个低分辨率或降采样的版本跑一轮DPS,观察引导梯度的量级和稳定性,再放大到完整分辨率。这样调参的成本会低很多。计算成像里大部分DPS翻车,都是直接上高分辨率,结果发现噪声估计、步长、显存三个问题搅在一起,很难定位。先降维排查,再回全分辨率,效率要高不少。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询