
第一次在采样器下拉列表里看到 EDM 这个词我以为是又一个新出的求解器名字缩写难记、面板上除了步数几乎没有别的可调项扫了两眼就划过去了。后来做一组需要反复复现的对比测试时才发现EDM 压根不是某一个采样器的名字——它是一整套把 Stable Diffusion 的加噪、去噪、采样全部重新参数化的框架。你在界面里看到的 euler、heun、dpm_2 这些求解器以及调度器里那个 Karras 选项追根溯源都能挂到这套框架上。换句话说很多人天天在用的EDM 采样器其实是这套框架被切碎之后散落在界面各处的零件。这篇内容我打算把 EDM 从头拆一遍它的 sigma 参数化在干什么、Euler 和 Heun 的两个公式怎么写、s_churn 这几个旋钮拧错了会出什么画面、以及在 Stable Diffusion 的实际工作流里怎么把它们用对。适合已经能跑通出图、但对着采样器列表一脑袋问号的中级用户也适合想搞清楚换采样器为什么出图完全变样的调试型玩家。1. EDM 那篇论文真正改掉的三件事1.1 把时间步 t 换成噪声强度 sigma传统扩散模型的写法里采样过程跟着离散时间步 t 0,1,2,…,T 走每一步对应一个加了多少噪声的隐含状态。这种写法有个麻烦t 只是一个序号它本身不带物理意义不同模型、不同 schedule 下同一个 t 对应的噪声水平天差地别你想横向比较两个模型的采样难度都做不到。EDM 的做法是把这层抽象直接撕掉用一个连续的噪声标准差 sigma 来描述状态。干净图像对应 sigma 0纯噪声对应 sigma 接近 sigma_max。整条采样轨迹就是从 sigma_max 平滑降到 0 的一条曲线每个点 x 都是干净图加上 sigma 倍标准高斯噪声的混合体。这个换轴带来的直接影响是步数 N 变成了对这条曲线的离散采点数而不绑定某个固定的训练时刻表。你可以用 20 步采也可以用 50 步采采的始终是同一条连续曲线只是疏密不同。Stable Diffusion 里那些看起来步数改了构图就变了的玄学现象很大一部分就来自这种离散化误差——采点位置变了浮点误差累积路径就变了。论文里给出的三个基准常数值得记一下它们几乎出现在所有后续实现的默认值里参数默认值含义sigma_data0.5训练数据的标准差归一化后的经验值sigma_max80采样起点纯噪声端的最大噪声强度sigma_min0.002采样终点视为几乎干净的噪声下限rho7采点分布曲线的弯曲程度sigma_max 取 80 而不是 1是因为这套框架把图像归一化到零均值、单位方差之后还需要很高的噪声水平才能彻底覆盖数据分布。你在实现里如果看到输入张量被乘了 0.5 之类的系数大概率就是在对齐 sigma_data。1.2 预条件让网络在每个噪声等级下都手感一致这套框架里我认为最值得细看的是预条件preconditioning。原始扩散训练有个隐藏问题在 sigma 极大时网络输入几乎全是噪声预测目标和输入的量级差了几十倍在 sigma 极小时输入几乎就是干净图网络只需要学一个接近恒等的映射梯度又太小。同一个网络要在这两个极端之间切换训练非常难受。EDM 用四个系数把输入、输出、训练目标、噪声标签全部重新缩放c_skip(sigma) sigma_data^2 / (sigma^2 sigma_data^2) c_out(sigma) sigma * sigma_data / sqrt(sigma^2 sigma_data^2) c_in(sigma) 1 / sqrt(sigma^2 sigma_data^2) c_noise(sigma) 0.25 * ln(sigma) D(x; sigma) c_skip * x c_out * F(c_in * x; c_noise)这四个式子的作用可以这样理解c_in 把输入缩放回单位量级c_noise 把跨度巨大的 sigma 压成对数尺度喂给网络否则网络对 sigma 的感知分辨率太粗c_out 把输出缩放回来而 c_skip 是一个捷径——当 sigma 很小时c_skip 趋近 1网络输出直接等于输入加上一个小修正学起来轻松当 sigma 很大时c_skip 趋近 0全部依赖网络 F 自己预测。训练时的噪声采样也不再是均匀的。论文用对数正态分布ln(sigma) ~ N(-1.2, 1.2²)再配一个损失权重 lambda(sigma) (sigma² sigma_data²) / (sigma · sigma_data)²把各个噪声等级的损失拉回同一量级。这两处设计合起来的效果是训练不再需要按课程从易到难这类技巧一次跑完就在整个 sigma 区间上均匀收敛。注意预条件是训练阶段的产物它和网络权重是绑定的。你在推理时把一套 EDM 采样参数套到用 epsilon 预测训练的模型上等于让网络在错误的输入尺度下工作出图必然发灰或过曝。这一点后面第 3 章会专门展开。1.3 采样器只是这套框架里的一个可替换插槽框架把整个设计空间拆成三块训练目标、网络预条件、采样器。前两块决定模型本身长什么样第三块才是推理时你能换的东西。采样器这一块又被细化成两个独立组件一是确定性求解器Euler、Heun 这类积分方法决定怎么沿着轨迹走二是噪声调度sigma 的离散采点方案决定每一步踩在哪。这两个组件在实现里是解耦的所以你才能看到同一个 euler 求解器配合 karras 调度和配合 normal 调度出图差别不小这种组合玩法。把采样器当插槽这件事直接解释了 Stable Diffusion 生态里的一个现象界面上的采样器列表之所以长到让人不想看是因为它把求解器 × 噪声调度 × 是否加入随机性三个维度摊平成了一个扁平列表。真正需要理解的维度只有三个剩下都是排列组合。2. Euler 与 Heun 的推导每一步到底在往哪走2.1 漂移项 (x - D)/sigma 的几何含义先看最朴素的 Euler。给定当前状态 x 和噪声等级 sigma网络输出 D(x; sigma)也就是对干净图像的估计。定义漂移项d (x - D(x; sigma)) / sigma这个方向有两个读法。从概率角度看扩散模型学到的得分函数满足 score (D - x) / sigma²所以 d -sigma · score它指向概率密度上升的方向也就是往更像真实图像的地方走。从几何角度看更直观x - D 是当前带噪图减去估计的干净图正好是残留在里面的那部分噪声除以 sigma 做归一化就得到一个单位尺度的噪声方向。Euler 一步的更新式是x_{next} x (sigma_next - sigma) * d因为 sigma 一直在下降sigma_next - sigma 是负数所以实际效果是沿着 d 的反方向减去一部分噪声。整个过程就是标准的欧拉法解一个常微分方程只不过这个 ODE 的时间变量是 sigma。Euler 是一阶方法局部截断误差是 O(h²)。落到画面上步数偏少时你会看到两种情况一是纹理细节被抹平毛发、织物这类高频结构先崩二是大色块边缘出现轻微的方向性偏移因为一阶方法在一次大步长里没法修正曲率。20 步以内用 euler 出图鼻子、眼睛这种小结构最容易翻车。2.2 Heun 的半步修正为什么值一次额外前向Heun 是二阶方法思路是先用 Euler 迈出一步拿到预测点再在预测点上重新问一次网络把两次的斜率取平均。伪代码如下d1 (x - D(x; sigma)) / sigma x_pred x (sigma_next - sigma) * d1 if sigma_next ! 0: d2 (x_pred - D(x_pred; sigma_next)) / sigma_next x_next x (sigma_next - sigma) * (0.5 * d1 0.5 * d2) else: x_next x_pred代价很明确每一步要跑两次网络前向。所以同样标称 20 步Heun 的实际计算量约等于 Euler 的 40 次前向出图时间接近翻倍。收益是局部误差从 O(h²) 降到 O(h³)在步数不足时对结构的保持明显更好。我实测下来的经验区间如果你手上只有 12 到 18 步的预算Heun 相对 Euler 的提升是能看出来的尤其是人脸和手部的结构稳定性但一旦步数上到 30 以上Euler 和 Heun 的差距就缩到需要并排放大看才能分辨的程度这时候多花的那一倍时间就不太值了。还有一个容易忽略的点Heun 在最后一步sigma_next 0会跳过第二次前向。这是必须的因为 sigma 0 时漂移项要除以 sigma会直接炸成 inf。你自己写采样脚本时如果忘了这个判断出图会满屏噪点或者干脆全黑。2.3 rho 7 的采点曲线把步数堆在了低噪声区噪声调度解决的是这 N 步踩在哪的问题。EDM 用的是多项式曲线sigma_i ( sigma_max^(1/rho) i/(N-1) * (sigma_min^(1/rho) - sigma_max^(1/rho)) )^rhorho 7 时这条曲线的形状是在高噪声端步子迈得很大在低噪声端步子迈得很密。为什么会这样设计因为在 sigma 很大时图像基本被噪声淹没网络输出对细节的影响很小大步走不心疼而在 sigma 很小时每一点细微扰动都会直接反映成画面上的细节变化必须小步慢磨。界面里那个 Karras 调度选项本质就是这条 rho 7 曲线。和它并列的 normal、exponential、sgm_uniform 是别的采点方案区别只在曲线形状调度方案采点特征常见表现karras高噪端稀疏、低噪端密集细节保留好20 步就能出较锐利的图exponential按指数衰减分配中低噪段过渡平缓风格化模型更稳normal相对均匀通用没明显偏好sgm_uniform均匀分配步数少时高噪段太密容易浪费预算simple线性只在特定模型上有味道同一个 euler 求解器配 karras 和配 normal20 步的成图差异可以大到换了一个提示词的程度。这不是玄学是采点位置变了导致的轨迹偏差。2.4 s_churn 那四个旋钮随机性到底加在哪EDM 的随机采样版本对应界面里带 ancestral 或 sde 后缀的那些多了一层加噪操作用四个参数控制if s_tmin sigma s_tmax: gamma min(s_churn / N, sqrt(2) - 1) else: gamma 0 sigma_hat sigma * (1 gamma) x_hat x sqrt(sigma_hat^2 - sigma^2) * s_noise * epsilon逐项解释s_churn 是加噪强度总开关0 表示完全确定性数值越大每一步注入的随机量越多。上限被 sqrt(2) - 1 卡住是防止单步噪声超过信号本身。s_tmin / s_tmax 划定生效的噪声区间。默认 s_tmin 0.05、s_tmax 50意思是只在中间段加噪极高噪声端和极低噪声端都不碰。低噪声端不加噪是为了避免最后关头把已经成型的细节重新打散。s_noise 是噪声幅度系数默认 1.003略大于 1 的取值来自论文的实测调优不是什么神秘常数。gamma 里除以 N 是因为加噪是按步分摊的步数越多每步加得越少总噪声量大致不变。这几个参数在界面里通常藏在高级采样器节点里用默认值就能跑。但如果你追求某种微颗粒质感或者想让画面在多次采样中产生微妙变化把 s_churn 从 0 提到 10 到 20 是个可玩的方向代价是同一提示词同一种子出图不再完全一致。3. 界面里的名字对照表与模型匹配的坑3.1 求解器名字与 EDM 谱系的对应关系节点式工作流界面里那串采样器名字按 EDM 谱系归类大致是这样界面名称类型是否随机相对耗时适配步数区间euler一阶 Euler否1x20-40euler_ancestral一阶 Euler 加噪是1x20-40heun二阶 Heun否2x12-25heunpp2二阶 Heun 改进否2x12-25dpm_2二阶多步否1x15-30dpm_2_ancestral二阶多步 加噪是1x15-30lms线性多步否1x25-50这里要提醒一句界面把求解器和调度器拆成两个下拉框时上表说的是否随机和阶数只由第一个下拉框决定第二个下拉框只管采点位置。有些整合包把它们合并成一个列表名字里带 Karras 字样的就是在求解器后面挂了 rho 7 的调度。dpm_2 这类多步方法严格说不完全属于 EDM 原始论文的算法清单它来自另一支 DPM-Solver 的工作但落地实现时复用了同样的 sigma 离散化思路和预条件形式所以放在同一张表里比较是合理的。3.2 模型预条件不匹配出图发灰、过曝、糊成一团的头号原因这是我最想强调的一节。EDM 的采样公式里(x - D)/sigma 这个漂移项的正确性依赖于模型输出 D 确实是对干净图像的估计。而 Stable Diffusion 主流的模型权重大多是 epsilon 预测或 v 预测训练的它们输出的东西不是 x0。数学上两者可以互相转换。如果模型输出 epsilon那么干净图像的估计是 x0 x - sigma * epsilon在信号系数归一化的约定下。实现里通常会在模型包装层做一次转换把 epsilon 预测翻译成 x0 预测再喂给 EDM 的采样循环。转换做对了一切正常转换缺失或重复就会出现输出整体偏灰、对比度上不来因为尺度被压了一次。高光区域过曝成纯白因为低噪声段的残差没被正确扣除。画面糊成一团、纹理完全消失因为等价于在错误的 sigma 上求值。现在很多界面提供专门的模型采样类型节点用来声明这个权重是 epsilon 预测、那个是 v 预测、这两个是连续 sigma 训练。这个声明不是形式主义它直接决定了采样循环里的转换分支。你加载一个社区权重后如果出图明显不对第一件事就是确认这个声明和权重的实际训练方式是否一致而不是急着去调 CFG。注意EDM 原论文的预条件c_skip / c_out 那套是训练时就嵌进权重的。对于没有用这套预条件训练的模型你只能用数学等价的转换而不能指望它自动获得 EDM 的训练收益。有些界面里那个把采样方式切成 EDM 的开关只对确实用连续 sigma 训练的权重有意义对普通 epsilon 权重套上去反而会出问题。3.3 一套可以复现的对比测试流程想搞清楚这些采样器在自己常用模型上的差别别靠记忆和感觉做一次受控对比比看十篇帖子都管用。我自己用的流程是固定提示词、固定种子、固定分辨率建议 768×768避开 SDXL 原生的分桶干扰、固定 CFG先用 5.0、固定步数先用 20。先把模型采样类型节点设成与权重匹配的正确值跑一张基线图存档。只换采样器下拉框euler → heun → dpm_2 → lms 依次跑其余全部不动。再把调度器固定成 karras重复第 3 步。把四张图拼在一起对比重点看三处皮肤和毛发的微纹理、文字或线条的边缘锐度、暗部有没有色块堆积。这套流程跑下来大概十分钟你能得到一份只属于自己模型和提示词组合的经验表比任何通用推荐都准。记录的时候把步数和耗时也写进去因为 heun 的 20 步实际等于 euler 的 40 次前向不看耗时对比是不公平的。4. 步数、CFG 与随机性的联动调参4.1 步数的收益拐点在哪里步数不是越多越好这话说起来像常识但拐点在哪是有数据可循的。以 karras 调度的 euler 为例我在几组不同风格的提示词上做过阶梯测试步数观察结果8-12大结构能对五官和手指容易崩画面偏软15-20大部分人像和场景的可用区间细节基本到位25-30微小纹理继续改善改善幅度已经不明显35-50除非是极精细的材质或大尺寸出图否则纯属浪费50 以上可能出现细节过度锐化、皮肤出现不自然的颗粒二阶方法heun、dpm_2的可用步数下限能往前提 5 步左右因为每次更新用的信息更多。反过来说二阶方法在 40 步以上的边际收益比一阶方法更早归零。还有一个反直觉的点步数增加不总是让画面更正确。有些模型在极低步数下会产生一种结构松散但构图有趣的图加步数之后反而收敛到一个更平庸的解。如果你在做创意探索8 到 12 步配随机采样器euler_ancestral批量出图然后再挑一张用高步数精修是效率很高的玩法。4.2 CFG 和采样器的交互比想象中大CFG 控制的是条件引导强度理论上和采样器正交但实际体验里两者搅在一起。原因在于随机采样器带 ancestral 的那些每一步都在注入噪声而 CFG 的引导是在每次前向里完成的两者叠加会放大高 CFG 下的过饱和现象。我的一般建议是确定性采样器euler、heun、dpm_2配 CFG 5.0 到 7.0 比较舒服随机采样器euler_ancestral、dpm_2_ancestral配 4.0 到 6.0因为它们自带的那点随机扰动本身就起到了轻微的多样性提升作用不需要太强的引导去硬拉。CFG 超过 9 之后无论配哪个采样器都会出现明显的边缘发亮和色彩断层这时候应该去改提示词而不是继续拧 CFG。另外带 s_churn 的那套随机机制和 ancestral 系列并不是一回事。前者是在 sigma 上加扰动再减回去后者是在每一步注入新的噪声样本。功能上有重叠但实现路径不同同一个界面里一般不会同时开启。4.3 高分辨率和局部重绘时的参数修正出图尺寸一上去EDM 系采样器的表现会变。1024 以上的分辨率同样的提示词和步数画面容易出现整体锐、局部平的情况因为采点在像素空间上的相对密度被稀释了。我的做法是分辨率翻倍时步数增加 20% 到 30%或者干脆换成二阶方法。如果做局部重绘inpaint把重绘区域当成独立的一张图来处理步数按区域尺寸重新算而不是沿用整图步数。局部重绘时用确定性采样器更稳随机采样器会让重绘区和原图之间出现接缝处的质感差异。还有一个实用技巧局部重绘的最后几步如果关掉 s_churn或者干脆换 euler接缝会明显更干净。原理和第 2.4 节说的一样低噪声段不该再引入扰动。5. 踩坑记录从画面症状反推参数问题5.1 三种典型画面症状的归因路径我把自己遇到过和帮别人排查过的问题整理成一张对照表按症状倒推原因比盲调参数快得多画面症状优先怀疑验证方法整体发灰、对比度低模型输出转换缺失尺度错位换回常规采样器看是否恢复高光死白、暗部死黑CFG 过高叠加随机采样器CFG 降到 5 试一次满屏细密噪点步数过少 ancestral 系列步数翻倍或换确定性采样器规则网格状纹理低噪声段采点太稀换 karras 调度边缘方向性拖影一阶方法步长过大换 heun 或增加步数同一组参数两次出图不同s_churn 或 ancestral 的随机性检查 seed 与采样器类型这张表里最容易被误判的是第一行。很多人看到图发灰第一反应是模型坏了或者这个采样器不行其实是模型采样类型的声明没对上导致 EDM 循环里多做或少做了一次尺度转换。换回他平时用的采样器立刻就正常反过来验证了这个判断。5.2 一次完整的排查链路实录说个具体的。某次我在一个新品类的权重上试 euler karras20 步出图整体偏灰、细节全糊第一眼像是噪声没降干净。当时的排查顺序是这样的第一步把采样器换成平时最常用的那个非 EDM 谱系的其余不动。结果依然偏灰。这一步排除了采样器本身的问题把矛头指向模型或参数。第二步检查模型采样类型节点的声明值发现默认停在了一个和该权重训练方式不匹配的选项上。改成匹配的值之后重跑灰度消失但细节仍然偏软。第三步怀疑步数。把 20 步提到 30 步细节有改善但没到满意程度。再看调度器当前是 normal。第四步把调度器换成 karras步数回落 22 步细节锐度明显上来了。到这里问题基本解决。第五步为了确认不是运气把种子换三个重复跑结果稳定。结论根因是模型声明不匹配 调度器选错两个问题叠加只改一个都只能解决一半。这个链路里我特意把换采样器放在第一步因为它是最快的排除手段成本只有一次前向。很多人喜欢从调 CFG 开始那是效率最低的路径因为 CFG 对灰度这种系统性偏差几乎没有作用。5.3 参数改动的记录习惯EDM 系采样器的参数互相纠缠步数影响 gamma、gamma 影响加噪量、加噪量影响最终纹理单靠脑子记不住哪次改动起了作用。我的习惯是每次实验都存一份节点图快照文件名里带上采样器名、步数、调度器和一句提示词摘要比如euler_22_karras_人像A。一周之后回头看哪些组合稳定好用一目了然。另一个小技巧是把常用的几组采样器配置做成独立的预设节点组用的时候整体切换而不是逐个改下拉框。这样做能避免改了采样器忘了改调度器这类低级错误我在早期没少因为这种疏忽得出错误结论。最后分享一个我自己反复验证过的结论在这套框架里调度器采点位置对出图的影响往往比求解器的阶数更大。与其纠结选 euler 还是 heun不如先把调度器在 karras 和 normal 之间对比一遍那一步的收益通常更直接。