news 2026/10/22 3:49:36

从得分函数到生成模型:Score-based Model 原理、训练与调参实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从得分函数到生成模型:Score-based Model 原理、训练与调参实战

最近几年生成模型的研究基本被扩散模型和 Score-based Model 这两条线霸屏了。如果你翻过一些顶会论文,会发现大量工作都挂着一个叫“Score”的词,从图像生成到分子构象采样,再到科学计算里的反问题求解,到处都能看到它的影子。很多人第一次接触这个概念时容易被“得分”这个翻译带偏,以为是个打分机制,其实它和“打分”没有半点关系。Score-based Model 指的是对数据分布的对数密度梯度进行建模,换句话说,模型不直接学习分布本身,而是学习分布指向高概率区域的“方向场”。这个思路绕开了概率密度归一化难题,让生成这件事变得异常优雅。

这篇内容适合谁看?如果你已经在用扩散模型做生成任务,但对其中的数学原理还停留在“去噪”这种直观理解层面,想真正搞懂 Score-based Model 为什么能工作、采样时那些参数为什么这样设置,那你来对地方了。如果你是刚入门生成模型的研究生或工程师,想知道除了扩散模型之外还有没有其他等价视角,这篇也能帮你把两套框架打通。文章会从原理逐步拆到实操细节,再到训练时踩过的坑和调参经验,全程用大白话,遇到数学尽量用直觉解释清楚。

1. 为什么要把分布的学习转成“得分”的学习

1.1 从归一化难题说起

任何一个概率模型的核心任务都是刻画数据分布 p(x)。最直接的做法是把这个密度函数显式写出来,比如高斯混合模型就是一堆高斯分布的加权和。但现实数据往往是高维空间里极其复杂的流形,比如一张 256x256 的彩色图像,其本质是 196608 维空间里的一个低维流形。直接估计这个密度函数的解析形式几乎不可能,因为密度函数必须满足两个条件:处处非负,且在整个空间上积分等于 1。第二个条件也就是归一化约束,是所有显式概率模型最头疼的事。

考虑一个常见的能量模型形式:

p(x) = exp(-E(x)) / Z

其中 Z 是配分函数,也就是 exp(-E(x)) 在全空间的积分。在高维空间里,这个积分没有解析解,数值积分也会随着维度增加指数级崩溃。于是 Score-based Model 换了一个思路:我不估计 p(x),我估计 ∇x log p(x)。这个量叫得分函数(Score Function)。关键的一点是,求导操作自动消掉了归一化常数 Z,因为 Z 对 x 的导数是零。用直觉理解就是:归一化常数只负责把整个分布“压”到积分面积为 1,它不改变分布形状的“走向”,所以求梯度时它就自动消失了。

这个思路等价于:你不需要知道一座山每个点的绝对海拔(密度值),只需要知道每个点往哪个方向走是上坡,以及坡有多陡。而爬山路线完全由梯度决定,海拔绝对值不影响你到达山顶。

1.2 得分函数到底长什么样

直观一点想,如果数据点集中在一个区域的中心,得分函数就是这个区域边缘指向中心的箭头场。如果数据分布有几个簇,得分函数就会在每个簇周围形成一个“指向簇心”的向量场,而簇与簇之间的鞍点处向量会趋于零。训练 Score-based Model,就是训练一个神经网络 sθ(x),让它逼近真实的得分函数 ∇x log p(x)。

有了得分函数,生成新样本的过程就变成了 Langevin 动力学采样。这个采样方法本质上是带噪的梯度上升:每次沿得分方向走一小步,同时加入一点高斯噪声,防止模型收敛到同一个点。迭代若干步之后,初始的随机噪声点就会被“搬运”到数据分布的高概率区域,也就是生成出逼真样本。整个生成过程没有显式密度计算,没有归一化常数,所有困难一步到位绕开了。

1.3 与扩散模型的关系澄清

经常会有人问:Score-based Model 和扩散模型到底是不是一回事?答案是:是同一类方法的不同视角。扩散模型的前向过程是逐步加噪,把数据破坏成纯噪声;反向过程学习的是“去噪”,从纯噪声逐步还原出数据。Score-based Model 则直接定义了一个随机微分方程(SDE):前向过程把数据分布逐渐变成噪声分布,反向过程则依赖得分函数来逆转这个过程。DDPM、DDIM、Score SDE 这些算法都能统一在同一个 SDE 框架下。

用大白话解释:扩散模型是从“图像被噪声毁掉”的角度学怎么修复,Score-based Model 是从“知道每个像素怎么调整更像真实数据”的角度去生成。两套视角描述的是同一个物理过程,只是解释起来一个像视频倒放,一个像地图导航。

2. 核心技术拆解:从得分匹配到 SDE 统一框架

2.1 训练目标为什么不能直接用 L2 距离

你可能会想:既然要逼近真实的得分函数,那我直接用均方误差让 sθ(x) 去拟合 ∇x log p(x) 不就行了?理论上没问题,但实操中会撞上一堵墙:真实得分函数我们根本不知道。我们手里只有一堆样本数据,p(x) 本身是未知的。这就陷入“没有参考答案怎么对答案”的困境。

于是有了 Score Matching 这一系列方法。它巧妙的地方在于,可以把这个未知目标转成一个只依赖样本的优化目标。核心思想是通过分部积分把目标函数里的未知项换掉,最终得到的形式只包括模型输出对输入的雅可比矩阵的迹以及模型本身。这个目标不需要知道真实 p(x),只需要对训练样本做前向传播就可以计算。

其中一种最常用的变体是 Denoising Score Matching(DSM)。它的做法更直观:给数据点加上高斯噪声得到扰动后的样本,然后训练模型去预测这个噪声。等等,这不就是扩散模型的噪声预测目标吗?对,完全一样。这也从目标函数层面印证了两个框架殊途同归。

2.2 单一噪声尺度为什么搞不定

早期 Score-based Model 最简单的版本就是训练一个模型去匹配某个固定噪声水平下的得分函数。但实际跑起来会发现效果很差。原因在高维空间里,数据流形只占据极小的体积,噪声稍微小一点,采样点落在流形附近的概率极低,得分函数在那里几乎没有信号;噪声稍微大一点,数据细节全被抹掉了,生成的样本模糊不清。单一噪声尺度就像用一把固定焦距的镜头拍微距,对不上焦。

所以后来的方法都采用多尺度噪声策略:训练一个网络同时接受噪声尺度作为条件输入。低噪声水平负责捕捉细节纹理,高噪声水平负责把握整体结构。采样时从大噪声开始逐步退火到小噪声,这个过程本质上和扩散模型的“从纯噪声逐步去噪”完全对应。梯度场从“粗略的轮廓指引”逐步细化到“精确的细节修正”,生成质量有了质的飞跃。

2.3 SDE 框架把几套方法统一了

我真正觉得 Score-based Model 体系漂亮的点是它的 SDE 统一视角。论文里的核心结论可以概括成这样:前向过程可以用一个随机微分方程来描述:

dx = f(x, t)dt + g(t)dw

其中 f 是漂移项,g 是扩散系数,dw 是维纳过程的增量。这个 SDE 的作用是把复杂的数据分布 p_data(x) 随时间演化成一个简单的先验分布 p_prior(x)。而神奇的是,任何 SDE 都存在一个对应的反向 SDE,反向过程同样可以用 SDE 表示,但里面的未知项恰好就是得分函数 ∇x log p_t(x)。

这意味着什么?意味着只要你学会了所有时间点上的得分函数,就能从先验分布开始,一步步逆向演化回到数据分布。不同论文之间的区别只是 f 和 g 的取法不同。取特定的 f 和 g,退出来就是 DDPM 的离散加噪过程;取另一种形式就是连续时间扩散模型;再换一种,就是经典的郎之万动力学采样方式。这种统一视角不仅让理论更优雅,还带来一个实际好处:可以借用 SDE 求解器的各种数值技巧来加速采样,比如后来很火的 SDE 快速求解器,本质就是高阶数值解法。

2.4 概率流 ODE:一条确定性的生成捷径

除了反向 SDE,这个框架还推出了一个确定性过程叫 Probability Flow ODE。直觉解释是:SDE 的反向过程中,除了一个确定性的漂移项,还有一个随机噪声项把样本往不同方向推。如果你把随机噪声项去掉,只保留确定性部分,得到的 ODE 轨迹仍然能把先验分布映射回数据分布,只是每条轨迹是确定性的。好处是采样时可以大步长跳跃,不用像 SDE 那样小心翼翼小步走。

这个 ODE 还带来了额外红利:因为它确定了从噪声到数据的可逆映射,可以在潜在空间做插值、编辑,比如在两张图的隐变量之间做线性插值生成过渡帧。这为生成模型做语义编辑和控制打开了大门。

3. 实操过程:自己训练一个 Score-based Model

3.1 环境与数据准备

动手实践时不需要太夸张的硬件,我自己的经验是单张 24GB 显存的显卡足够跑通 CIFAR-10 级别的实验,如果你只有 12GB 显存,把 batch size 调小、模型宽度减少一些也能跑,只是效果差点。代码框架建议直接用 PyTorch,生态成熟,调试方便。

数据集先用简单的,MNIST 或 CIFAR-10 都是好选择。MNIST 分辨率低、结构简单,能快速验证 pipeline 是否正确;CIFAR-10 的彩色图像和复杂纹理能检验模型是否真的学到了分布结构。我建议首次实验用 CIFAR-10,因为 MNIST 太简单,指标好看但掩盖了实现细节问题,容易让你误以为代码写对了。

模型结构推荐 U-Net,这和扩散模型社区的经验一致。U-Net 的编码器-解码器结构配合跳跃连接,能在不同尺度上同时捕捉全局结构和局部纹理。关键是要把噪声尺度 t 作为条件输入到网络中,常见做法是做正弦位置编码后加到每个残差块上。

3.2 损失函数与训练循环的关键代码

训练目标用 Denoising Score Matching 的变体。给定数据点 x,随机采样一个噪声尺度 σ,加噪得到 x̃ = x + σ·ε,其中 ε 是标准高斯噪声。模型的输出用于预测 ε 或者等价地预测得分,损失函数如下:

L(θ) = E[ λ(σ) · || sθ(x̃, σ) - (-ε/σ) ||² ]

这里 sθ 的监督目标是 -ε/σ,也就是真实得分的蒙特卡洛近似。为什么该目标有效?因为 x̃ 的条件分布是已知的高斯分布,它的得分函数有闭式解就是 -ε/σ,不需要知道 p(x) 就能构造监督信号。权重 λ(σ) 常见取 σ²,用来平衡不同噪声尺度下损失的尺度差异。

实际代码里有个容易踩的坑:如果没有做损失加权,高噪声尺度的损失天然就大,模型会偏向优化这些大尺度而忽略细节。加上 σ² 加权后相当于给低噪声尺度更大的相对权重,能明显改善生成纹理的锐利度。

训练循环本身并不复杂:前向传播得到预测噪声,计算加权 MSE,反向传播更新参数。但要注意不要把噪声采样和加噪写进 DataLoader 的预处理里,而是在每次迭代时随机采样。这样每个 epoch 中同一个图像会被不同强度的噪声扰动,数据增强效果等于无限倍,模型泛化性会好很多。

3.3 采样过程参数怎么设

训练完成后采样,最经典的方式是 annealed Langevin dynamics。每次迭代分两步:先沿得分方向更新,再加噪声随机扰动:

x_{i+1} = x_i + α · sθ(x_i, σ_i) + √(2α) · z_i

其中 α 是步长,z_i 是标准高斯噪声。步长与噪声尺度的平方成正比,因为大噪声水平下得分场的尺度大,步子要相应变大。整个采样过程从最大的噪声尺度出发,逐步减小噪声,每一轮噪声尺度下迭代若干步。

关键参数有三组。第一是噪声尺度序列的长度,常用等差或者几何序列,长度从 10 到上百都有。第二是每个尺度下的迭代步数,一般 50 到 100 步足够,多了边际收益很小。第三是初始噪声尺度,必须大到能把数据完全淹没,否则采样链永远无法从噪声区“登陆”到数据流形上。

如果你生成出来的图片全是模糊一片没有结构,多半是初始噪声不够大或步数太少。如果你生成的图有形状但细节很脏,通常是低噪声尺度迭代不足或者模型对低频噪声拟合还不够精细。这些都需要反复调参,没有万能公式,但上面的排查方向基本能覆盖 90% 的问题。

3.4 采样加速的实用技巧

SDE 采样器虽然稳定,但速度确实慢,需要的步数多。实际使用中有几个提升效率的手段。第一是换成 DDIM 式的确定性采样器,步数能直接从几百降到 50 甚至更少,代价是多样性略微下降。第二是使用高阶 SDE 求解器,比如基于指数积分器的方法,能在同样的步数下获得更小的离散化误差,细节保留更好。

第三种技巧和模型本身配合:蒸馏。用训练好的教师模型生成一批高质量的噪声-数据对,再用学生模型直接学习从大噪声到小噪声的跳跃映射,一步完成原来几十步做的事情。这个方案在减少生成成本上成效显著,许多生产环境部署用的就是这个思路。

4. 训练中的常见问题与排查心得

4.1 损失曲线看着很漂亮但生成效果差

这是我见过最多的一个坑。训练损失一路下降,但采样出来的图像像打了马赛克,甚至完全是噪声。问题通常出在“训练和采样之间的噪声尺度分布错配”。训练时模型见过的噪声分布比较宽,但采样时你给的初始噪声超出了训练覆盖范围,模型对没见过的噪声水平只能瞎猜。

解决办法:检查你训练时采样的 σ 范围是否覆盖了采样时所有可能用到的值,尤其是最大值。我习惯在训练结束时多采样几个超大噪声尺度的样本放进验证集里看模型输出是否合理。另一个常见原因是训练和采样时对 σ 的条件编码方式不一致,比如训练时用了 log 尺度而采样时用了线性尺度,这种细节容易被忽略但破坏力极大。

4.2 模型对噪声尺度条件不敏感

条件注入应该是 Score-based Model 训练里最容易被忽视的步骤。如果你把 σ 编码后和图像特征直接拼接或简单相加,模型很容易忽略这个条件,导致所有尺度共用一套特征。正确的做法是参考 DDPM 的 AdaGN 机制:把 σ 编码后生成每个残差块的缩放和偏移参数,和批归一化的做法类似。

判断模型是否真正“理解”了条件,有个笨办法:固定一张输入图,连续改变 σ 输入,观察输出变化是否平滑。如果输出几乎不变,说明条件注入失效;如果变化是渐变而非突变,说明注入方式基本正确。

4.3 显存溢出与 Batch Size 的平衡

固定噪声尺度的 Score-based Model 前向传播不需要通过太多中间变量反传,显存压力主要来自 U-Net 本身的深度和大通道数。训练时如果 OOM,我一般先降 batch size 而不是降模型尺寸,因为模型尺寸直接影响生成质量上限,batch size 可以通过梯度累积补偿。梯度累积每 k 步做一次参数更新,效果等价于用更大的 batch size,代价只是训练时间线性增加。

另一个节省显存的实用手段是混合精度训练。score 本身是浮点梯度,误差对精度不那么敏感,用 FP16 训练损失很少出问题,但注意损失缩放策略要设置对,否则前期容易出现 NaN。

4.4 生成样本多样性不足

有时候你发现生成出来的图虽然质量不错,但像是在复制训练集里的样本,多样性明显不足。这个现象通常和采样温度或者噪声退火策略有关。如果最终噪声水平降得太低,采样链就被“钉死”在单个数据点附近,失去多样性。解决办法是让最终噪声尺度不要小到完全消失,留一点点噪声作为“探索温度”,同时增大中低噪声段的迭代步数。

还有一种情况是模型容量太高而训练数据太少,模型直接把训练集记住了。这种时候调参没用,得换更正则化的训练策略,或者扩充数据增强方法。Score-based Model 同样受困于过拟合,只是表现形态比较隐蔽。

4.5 数值不稳定的处理

训练偶尔会遇到 loss 突然变成 NaN。这个问题的来源通常有两个:一是学习率过高导致梯度爆炸,这个最好排查,直接降学习率或加梯度裁剪就能解决;二是数据里存在极端离群值,加噪后得到的 x̃ 过于极端,前向传播经过深层网络时激活值溢出。我习惯在数据预处理时做一次 z-score 标准化,让像素分布零均值单位方差,同时把梯度裁剪阈值设在 1.0 左右,基本能挡住 99% 的数值崩溃问题。

5. 更进一步:Score-based Model 的扩展应用思路

5.1 从图像生成到科学计算

Score-based Model 最迷人的地方可能不在图像,而在任意高维分布建模场景。比如分子构象生成,难点在于分子在三维空间中的分布高度多模态,传统方法难以采样到所有能量低谷。用 Score-based Model 对分子构象分布建模,能从随机坐标出发逐步演化出合理构象,而且天然处理多模态性质。

类似思路也被用在蛋白质结构预测、材料设计、逆分子设计等领域。这些场景的共同特点是:数据分布极其复杂、显式密度不可得、但可以拿到大量样本。这正是 Score-based Model 最擅长的设定。

5.2 与强化学习的结合

最近有个比较热的方向是把 Score-based Model 和学习策略结合。传统强化学习需要策略分布输出具体动作,但高维动作空间的策略分布同样存在归一化难题。Score-based Model 可以绕开显式策略密度,直接在动作空间上学习得分函数,然后通过郎之万采样输出最优动作。这种范式在机器人控制中被造了个词叫 “Diffusion Policy”,已经在不少物理仿真任务中刷新了效果榜。

这类工作的工程坑往往不在策略本身,而在采样延迟。郎之万采样几十步对实时控制来说太慢,所以实践里大多用蒸馏或者确定性 ODE 采样器把推理压到一步以内。把生成模型的采样效率和决策频率做匹配,是落地这类系统真正要面对的难题。

5.3 条件生成与可控编辑

如果你想让 Score-based Model 生成特定类别的图像,最简单的方式是类别条件注入,也就是把类别标签作为额外的条件输入网络。复杂一点的场景是文本引导生成,这时得分函数要改写为条件得分 ∇x log p(x|c),根据贝叶斯公式,它等于无条件得分 ∇x log p(x) 加上条件对数似然的梯度 ∇x log p(c|x)。后者通常用另一个分类器或 CLIP 模型提供,这就是所谓分类器引导(Classifier Guidance)的原理。

这种合成梯度的方法让编辑和可控生成变得非常灵活:你想让图像更偏向某个属性,就在得分场上叠加一个指向属性方向的偏置场。不用重新训练生成模型,只需要额外训练一个轻量级分类器,这也是 Score-based Model 生态能迅速扩展的原因之一。

5.4 与潜在空间方法的区别

很多人喜欢拿 VAE、GAN 和 Score-based Model 做比较。VAE 的问题在于用高斯分布作为潜在空间的先验太弱,学到的隐变量往往没有充分解耦语义,生成质量上限受限。GAN 的问题在于训练不稳定,判别器和生成器的博弈很容易坍缩。Score-based Model 绕开这些困难的方式是:不做显式的潜在空间建模,而是直接在数据空间上定义概率路径。代价是推理时需要迭代采样,计算成本更高。

这个取舍在离线生成场景下完全值得,因为你换来了两个显著优势:一是训练过程稳定,没有对抗博弈那种极度敏感的超参数;二是生成的多样性有保障,不会像 GAN 那样模型崩塌后只剩几张图轮流转。如果你需要快速推理且对多样性要求不高,GAN 仍然有它的位置;如果你要覆盖复杂数据分布且追求训练稳定性,Score-based Model 显然是更稳妥的选择。

6. 实操后的经验与建议

跑了一整轮 Score-based Model 的实验之后,我想分享几条朴素但管用的经验。第一条是先跑通小规模实验再上大模型。我在 CIFAR-10 上先把噪声尺度序列长度设成 10,模型通道数减半,用一个非常小的配置把损失曲线和采样流程全部跑通,确保从训练到采样整条链路没问题,再逐步加到完整配置。这个习惯帮我避开了很多“训练了一天发现采样代码有 bug”的惨剧。

第二条是保存模型时同时保存一份采样配置。不同模型用的最优噪声尺度序列、迭代步数可能都不同,把参数和模型绑定存档能省掉大量重复调参时间。我踩过因为采样配置和训练配置不一致导致结果暴涨暴跌的坑,后来就养成了每次跑实验都写配置文件的习惯。

第三条是可视化得分场的分布。很多人只看生成的最终图像,但中间过程的诊断信息同样重要。我习惯在每个 epoch 结束后从测试集挑几张图,把真实加噪样本的得分场可视化出来,看模型预测的箭头是否指向数据聚集区域。这个可视化比损失数值直观得多,能提早发现梯度方向混乱、条件注入失效这类深层问题。

第四条是学习率要根据模型规模动态调整。Score-based Model 对学习率没有 GAN 那么敏感,但仍然有明显的适用区间。模型小时学习率大一点没事,模型加深加宽后,需要适当降低学习率,否则后期会出现 loss 震荡不减的现象。我通常先用线性学习率扫描找出量级,再配合余弦退火获得更平滑的收敛过程。

最后一条可能听起来有些反直觉:不要迷信论文里的超参数。论文里的配置是在特定数据集、特定计算资源下调出来的,直接复制到你的场景很可能不是最优,甚至会出现训练不稳定。理解每个参数的作用,然后用你的数据去做小规模搜索,远比照抄参数清单更有效率。Score-based Model 的理论框架很优雅,但它能发挥多大效果,最终还是由你在工程细节上的处理水平决定。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 3:48:26

POCSAG解码器:嵌入式低功耗无线协议解析硬核实践

简介:本资源是一套面向无线电通信、嵌入式开发及复古寻呼技术爱好者POCSAG编码解码实践工具集,聚焦低带宽数字寻呼协议的原理理解与工程实现。压缩包含29个文件,以C语言源码(3个.c、2个.h、2个.s)、编译中间产物&#…

作者头像 李华
网站建设 2026/10/22 3:48:19

POWER9+三卡V100并行跑LLM:AC922网络安装与实战记录

说实话,接到这个任务的时候我下意识先问了一句:这年头还有人折腾 POWER9 跑 LLM?然后我看了眼手边这台正在嗡嗡作响的机器——AC922,双路 POWER9,三张 V100 挂着 NVLink,心里那点抵触瞬间变成了“真香”。这…

作者头像 李华
网站建设 2026/10/22 3:47:43

交通事故检测数据集实战:VOC/YOLO格式1741张图像训练YOLOv8全流程指南

1. 这套交通事故数据集到底解决了什么问题先交代一下背景。前阵子我一直在做一个城市道路异常事件检测的项目,说白了就是让路侧摄像头学会“看到”交通事故,而不是等人工盯监控屏。跑了一段时间后,最让我头疼的不是模型结构,而是数…

作者头像 李华
网站建设 2026/10/22 3:46:27

事故检测数据集实战:1741张图训练避坑与部署经验

智慧交通这块儿,我这两年接触最多的就是监控视频里的目标检测。车、人、交通标志都好办,公开数据集一抓一大把,卷到飞起。但有一个场景,做的人相对少,数据也最难搞——交通事故检测。事故这个东西,本身是小…

作者头像 李华
网站建设 2026/10/22 3:45:41

对外接口别用枚举?五类线上事故与字符串替代方案全解析

1. 对外接口不用枚举:这不是偏好,是线上事故教出来的求你了,真的不要在对外接口中使用枚举类型了。这句话不是标题党,而是我维护一个订单状态查询接口半年之后,从线上告警和凌晨排查电话里总结出来的教训。那个接口的s…

作者头像 李华
网站建设 2026/10/22 3:45:40

一致性算法解决直流微电网均流、电压补偿与恒功率负荷平衡点唯一性

从事直流微电网控制研究的同行,对“均流”和“电压偏差”这对矛盾应该都不陌生。下垂控制虽然能实现基本不依赖通信的功率分配,但负载变化时母线电压跌落、各变换器输出电流分配不均的问题总是如影随形。我接触这个方向时,最头疼的还不是控制…

作者头像 李华