首页 / 资讯中心 / 文章详情

工业异常检测新思路:解耦扩散模型DeCo-Diff的原理与实战

工业异常检测新思路:解耦扩散模型DeCo-Diff的原理与实战 ★ FEATURED ARTICLE
异常检测这个方向说起来简单做起来是真的磨人。工业质检里最常见的场景就是产线上跑过去几千张图片大部分都是好的偶尔出现一个划痕、一块脏污、一个异形焊点你需要在运行中把它挑出来。传统分类思路直接糊掉因为异常形态你根本没法提前枚举纯靠重建误差也不行因为“正常”本身的分布很宽泛化能力稍微强一点的重建模型会把异常区域也当成正常内容给补齐了。这套矛盾我踩了很多次坑所以看到今年CVPR上的DeCo-Diff论文时一下就来了兴趣。它的思路不是让模型去学“完整图像长什么样”而是先把图像里的正常模式拆成几个可控的部件再靠扩散生成过程去重建每个部件最后用局部重建误差来锁定异常位置。这篇解读我会按方法设计、核心模块、复现实验和避坑实录来展开适合正在做工业异常检测、或者准备把扩散模型落到实际场景的同学参考。1. 为什么异常检测需要DeCo-Diff从痛点说起1.1 工业异常检测的两难困局我见过不少刚接触异常检测的朋友第一反应都是“直接用分类器不就行了”但实际上真实场景首先就不满足分类的前提你拿不到足够多的异常样本。更麻烦的是异常不是一两类固定模式而是“anything that looks different from normal”。一块R角上的毛刺、一根线路上的刮痕、一个气泡内部的阴影都可能算异常但你没法把每类都标注出来。这就逼着大家把目标转成无监督或自监督只用正常样本训练期望模型在测试时能对异常产生“不适应”。然而“不适应”的表达方式很讲究。早期方案用autoencoder重建图像计算重建误差。这套方案在异常和正常差异足够大的时候挺有效可一旦正常样本本身的纹理、光照、位姿存在多样性重建模型就会越学越聪明把一些特殊区域也解释成正常变化。比如我把一个正常的零件表面学得很好测试时来一个同样位置的印记它照样能重建得像模像样漏检就这么来的。另一个痛点在于定位整图的MSE只能告诉你“这图有毛病”却说不出毛病在哪在产线上这几乎没法用。所以这两难困局其实是两个问题叠加一是表征学习的分寸——既要学会正常模式又不能过拟合到所有像素级的“正常”二是决策空间的设计——异常分数最好能在空间上对齐到具体异常区域这样后续的人工复检和定位才有意义。前者属于表征学习的问题后者属于决策与度量学习的问题两者不是简单串联而是互相耦合的如果表征太泛异常会被当成正常如果决策空间太粗就算找到了异常也不知道位置在哪里。DeCo-Diff本质上就是在同时回答这两件事并把它们统一到一个可训练的网络框架里。1.2 扩散模型如何在异常检测中落地在聊DeCo-Diff之前得先说说它踩在前人肩膀上的那步——用扩散模型做异常检测。扩散模型的基本玩法你肯定不陌生训练时往干净图像上逐步叠加高斯噪声直到图像变成纯噪声推理时再从纯噪声出发一步步去噪还原出干净图像。直觉上如果模型只见过正常样本那它应该“会”重建正常图而遇到异常输入时去噪过程就会纠结甚至编出离谱的内容于是重建误差或者梯度信息就能当异常分数。这个想法听起来很顺但实际落地有坑。坑之一在于扩散模型太能“补”了。它学到的是数据的整体分布对于一张带有局部异常的图它大概率会把异常区域当作一种“低概率的正常变化”给修掉导致重建结果和原图几乎一样异常分数算出来也没多少区别。坑之二在于计算开销一张图要来回采样几十步除非你上蒸馏或者加速采样否则在产线在线检测里完全扛不住。所以单纯地把扩散模型套进异常检测并不是一个好主意需要更结构化的设计来约束它。DeCo-Diff的聪明之处就在这儿它没有拿扩散模型去重建整张图而是先引入了解耦操作把图像里面的“正常变化”拆到不同子空间里然后让扩散模型只在每个子空间内部去做信息补偿。这样一来扩散模型被关进笼子里想去弥补异常区域的时候没有全局自由度重建阶段被迫更诚实异常自然就暴露出来了。1.3 DeCo-Diff的核心定位现在可以给DeCo-Diff一个比较清晰的定位了。按名字拆DeCo代表Decomposition也就是解耦或解构Diff代表Diffusion也就是扩散生成。它的核心主张是异常检测不应该在完整图像的像素空间中做端到端重建而应该先学习一组可解释、可组合的正常模式表征再用扩散机制对这些模式做细粒度的重建与对比。这样做的好处很实际。首先是检测粒度变细因为异常分数是逐位置对比解耦后的重建结果与输入而来的所以天然具备像素级定位能力不用额外训练分割头。其次是对正常多样性的容忍度更高解耦模块把“一个表面有其纹理分布”和“一个表面有其颜色分布”分开建模模型不会因为某个属性略微偏移就把整张图判为异常。最后是训练数据压力小核心模块都可以在单类正常数据上完成自监督训练不需要异常样本参与。所以它解决的并不是“我能不能用扩散模型”的问题而是“扩散模型在异常检测里到底应该承担什么角色”的问题。换句话讲它把扩散模型从主角变成了配角真正起决定作用的是前面的解耦表征扩散模块负责提供精细化重建和概率度量两者配合才能又准又稳。这个定位在我看来是比具体网络结构更重要的贡献。2. 方法拆解解耦分解与扩散生成如何协同2.1 整体架构从输入到异常分数我按自己理解DeCo-Diff的视角来画这个流程。输入一张图像先过一个特征提取主干论文里用的是带预训练权重的卷积或Transformer骨干目的是拿到多尺度的特征图。随后在特征层面上做解耦而不是在RGB像素层上盲目拆分。解耦模块会输出几组特征分量每组对应一种语义维度比如粗略地说有的分量专门刻画局部纹理细节有的分量刻画语义结构还有的刻画颜色与材质统计。这些分量会被分别送入扩散模块做条件重建。扩散模块接收到的是被遮罩或扰动过的当前分量任务是恢复出对应的正常版本。最后把每个分量的重建误差按空间位置聚合就得到异常分数图再对整图分数做池化得到图像级判断。这个流程跟以往“整图进重建图出算MSE”的方案有一个结构性的区别重建不发生在同一尺度上。在DeCo-Diff里每一支扩散重建都是针对解耦后的分量做的过程中的信息瓶颈被刻意放大逼着模型必须依赖“该部位正常模式”的先验来补全而不是仗着全图信息把所有东西都一笔带过。从工程上看主干部分可以替换成任意成熟backbone扩散模块也可以按显存预算做轻量版本所以整体复现门槛不算特别高很适合拿来二次开发。2.2 解耦模块把“正常”拆成可学习的部件解耦模块是DeCo-Diff真正决定上限的地方。我个人的理解是它本质上是一个带约束的特征分解器输入特征图经过若干分支每个分支通过一个注意力机制或掩码机制输出一个分量同时约定所有分量之间尽可能正交、且合起来能够覆盖原始特征的主要信息。用数学点的话说它在优化一个类似于重构加正交化加稀疏性约束的目标最终让每个分量只对特定的语义结构敏感。为什么要做正交化约束我打个比方。正常的苹果表面有颜色和纹理两种属性如果模型没有约束某个分量可能同时把颜色和纹理都编码了那么测试时一个异常的颜色变化会被纹理分量顺带解释掉异常信号被稀释。正交化就是逼着不同分量各管一摊让颜色异常只能在颜色分量里产生大的重建差异纹理异常只能在纹理分量里产生差异。这样一来异常不仅能被检出连类型都能初步区分出来对后续人工处置非常有价值。实际实现时解耦模块的复杂度需要控制。如果每个分支都套一个大网络参数量会爆炸。DeCo-Diff里用的是轻量级的多层感知机加通道注意力只在特征图的通道维度上做分解而不是在空间上切块。空间位置信息被完整保留到下一步扩散模块中这保证了解耦精度和定位精度不会因为压缩而损失。我在复现时一开始把分支数设成5结果其中两个分支学出来高度相似正交性很差后来把分支数降到3同时把正交损失权重调高才真正解耦开。2.3 扩散模块用重建误差精准定位异常解耦完事之后扩散模块才登场。扩散模块的输入不是完整图像而是把解耦后的分量随机做一次mask或加噪然后交给条件扩散模型去恢复原始分量。训练时模型需要学习在给定部分信息的条件下把缺失的正常模式补全。测试时我们不mask而是直接让扩散模型对完整分量做重建由于模型没有见过异常模式在重建过程中遇到异常的局部区域时补全出来的结果就会和输入产生偏差这个偏差就是异常信号。这个设计有一个很明显的好处扩散模型的任务被简化了。整图重建时模型要同时协调全局结构和局部细节哪个地方出问题都可能掩盖真正异常。而现在分量内部的模式相对单一扩散模型只需要处理该分量对应语义域的正常变化重建难度下降重建质量反而更容易做到极致对异常的敏感度也就更纯粹。另一个细节是扩散模型采用的条件方式。DeCo-Diff用的是交叉注意力注入把已知部分作为条件让去噪网络每一步都参考当前分量的上下文而不是像标准扩散模型那样只靠时间步嵌入。这样做的效果是正常的区域在去噪过程中被逐步加固异常区域则因为与已学分布不匹配而被拒绝这种拒绝行为反映在重建误差图上往往呈现为一块连通的、边缘清晰的区域非常利于阈值化处理。2.4 训练损失与推理流程训练阶段的损失函数不是单一的重建损失而是三部分叠加。第一个是解耦阶段的重建损失保证多个分量合起来还能还原出原始特征。第二个是正交化损失强制不同分量对应的特征向量彼此独立。第三个是扩散模型的标准降噪损失要求给定条件下网络预测噪声的误差尽可能小。三个损失被加权到一起权重之间需要小心平衡根据我复现时参考的常见配置默认权重大致在0.5比0.1比1.0附近实际复现时还要根据数据集微调。推理流程则分两步。第一步把所有分量的重建误差逐像素取L2距离并按通道加权求和得到一个初始的异常响应图。第二步为了抑制噪声会对响应图做一次基于多尺度的高斯平滑然后再用固定阈值或自适应阈值生成二值mask。图像级分数则是响应图的全局最大响应值。在工业场景里最异常的那个点有多大往往就决定了这块产品要不要被拦下来最大池化比平均池化更符合质检逻辑。损失设计上的另一个关键点是感知损失的引入。如果只用像素级L2距离扩散模型可能会倾向于输出模糊的结果模糊也会带来高误差但这并不是我们想要的“锐利异常”。DeCo-Diff在扩散重建输出之后会再接入一个预训练的特征网络进行比较在语义层面对齐重建图和输入图这让异常响应更集中而不是整片糊在一起。这一点我在实验里对比过加了感知损失之后像素级AUROC大概能涨3到5个点。3. 复现路上的关键实验与调参心得3.1 数据准备与预处理复现这类方法数据整备往往是第一个隐形门槛。我建议先别急着上完整的多类数据集挑一个相对可控的工业异常基准数据集取其中一类开始比如某种电子元件表面的纹理类缺陷训练集里只放正常样本测试集里混入异常样本。这样你的评估迭代闭环最短调参时能快速判断模型改动的效果。预处理环节我踩过的坑主要在尺寸和归一化上。扩散模型对输入分辨率非常敏感分辨率太低会把细小的划痕直接抹掉分辨率太高又会让训练显存爆炸。我实测下来训练和推理统一使用256乘256是性价比最高的选择既能保住多数工业缺陷的细粒度特征又能在单卡上跑得动。归一化方面不要直接用自然图像数据集上统计出来的均值和方差因为工业图像的色彩分布跟自然图像差别很大用数据集的真实统计来做标准化收敛速度会有可见的提升。如果数据量不够可以考虑在解耦特征层面做增强对输入图做小幅旋转、色阶抖动、高斯模糊而不是直接对像素做大量裁剪这样能保持异常区域的空间完整性。数据加载用多进程预读把图像解码和预处理放到后台否则扩散模型的训练GPU利用率会掉得很惨。3.2 核心训练配置与超参选择有了数据之后第一个问题是训练分几阶段。DeCo-Diff的官方做法是两阶段第一阶段先单独训练主干和解耦模块把特征分量训得稳定第二阶段冻结主干再训练扩散模块。我一开始直接端到端训练结果两个模块互相拉扯loss怎么都压不下去。后面改成两阶段才顺起来。这个思路放之四海皆准先让表征稳定再让生成任务去适配表征比同时学两个高复杂度任务要稳得多。超参方面我记录一份可供参考的配置优化器用AdamW主干学习率2e-5解耦模块3e-4扩散模块1e-4扩散步数训练时1000步推理时可以压到50步配合DDIM采样批次大小8在单张GPU上显存占用大约16GB左右。这里要强调主干学习率一定要比新增模块低一个量级因为预训练权重已经被训得很好了学习率太大会把主干里的通用表征破坏掉后面解耦和扩散学到的东西都会建立在坏地基上。此外扩散模型的噪声调度我用的是线性调度beta从0.0001线性增到0.02跟原论文保持一致尝试过cosine调度收敛更快但重建细节稍差还是线性调度更稳。3.3 评估指标怎么看工业异常检测的评估指标最常用的还不是简单准确率而是像素级和图像级的AUROC以及F1最大值。像素级AUROC看的是每个像素被判为异常的置信度排序能力图像级AUROC看的是整张图能不能被正确区分成正常和异常。DeCo-Diff这类方法由于天然输出像素级异常分数两者通常都比较高但你要小心一个陷阱图像级分数如果直接取最大池化容易让一个很小的噪声点把整张图带崩所以更推荐用P99也就是99分位数来代替最大值稳定很多。另一个绕不开的坑是阈值选择。AUROC只评估排序不评估绝对分数所以在实际产线上你还需要一个固定的判断阈值。我个人做法是在验证集上画出PR曲线选F1最大的那个点作为默认阈值同时留一个安全系数宁可误杀一点也不能漏检毕竟产线的漏检代价远高于误检。评估时还要分缺陷类型来看结果。纹理类缺陷通常容易细小、低对比度的缺陷往往是被漏检的重灾区。我建议把测试集按缺陷类别拆分分别报告AUROC而不是只看总体数字。否则某一类缺陷指标高另一类低平均一下会掩盖真实问题后面调整方向也会跑偏。4. 常见训练问题与排查实录4.1 重建效果很好检测效果却崩了我第一个遇到的大问题就是扩散模块的重建图像看着完美无瑕连异常区域都被修得干干净净但异常分数反而很低。原因其实很朴素模型在训练时见过大量正常样本同时又靠预训练主干提供了很强的先验到了推理阶段它实际上脑补出了异常区域应该长什么样把异常也当正常给重建了。说白了重建模型太强反而是劣势。解决办法有三个方向。第一从信息瓶颈下手把解耦分量的通道数或者分辨率压缩一些逼着模型没有足够容量去对异常区域做精细补充。第二在训练时故意给正常样本加一些随机的局部扰动让模型学会遇到没见过的东西宁可拒绝也不要强行补齐。第三在损失上给扩散模块加一条惩罚重建过于平滑的约束比如提高感知损失的权重让重建结果更贴近正常样本的真实特征而不是变成一个平均模糊图。我踩坑过程中的体会不要一上来就猛堆扩散模块的容量先跑通最简结构确认异常分数能随缺陷出现明显响应再逐步加容量、加精度。很多人一上来就把UNet通道数拉到256结果显存不够、训练还慢最后发现瓶颈根本不在容量上。4.2 损失不下降或震荡训练DeCo-Diff经常会遇到两类症状一类是总loss不降一类是前面降得好好的中途开始来回震荡。如果遇上第一种先检查是不是解耦模块和扩散模块之间的尺度不匹配。扩散模块输出的特征值域往往很大而解耦模块的分量被约束在相对小的值域里两者相加时梯度容易失衡。我的做法是给扩散模块的输入做一次LayerNorm让每个分量的均值和方差对齐loss瞬间就稳定不少。如果是训练后程震荡多半是学习率踩到底了。建议把学习率调成余弦退火前10%的步数做warmup后面平滑衰减。另一个常见元凶是批量大小和梯度累积不一致如果你的代码里改了batch size却忘了同步调整学习率也会导致后期震荡。经验公式是batch size翻倍学习率大约乘根号2具体值还是以验证集为准。还有一个容易被忽略的点多个loss之间的权重不要一成不变。尤其是在前500步解耦模块还没稳定此时把扩散损失权重拉满会让优化方向被带偏。我用的策略是前500步只训练解耦模块之后再把三个损失一起开效果比从头到尾三损失联动要好不少。这个细节官方文档里不会写但实际影响非常大。4.3 推理速度太慢怎么办扩散模型的老大难问题就是推理慢。DeCo-Diff因为只对解耦后的分量做扩散已经比整图扩散快了几倍但如果要在产线上用50步的DDIM还是捉襟见肘。我试过几个方案按加速收益排列第一换成更小的扩散UNet结构把通道数从128降到64参数量下降一半质量损失很小第二把步数压到25步配合DDIM的eta参数调成0基本上速度翻倍检测指标只有一到两个点的下降第三把多个分量的采样过程并行化因为不同分量之间是相互独立的推理时可以用多卡或单卡多流并行总耗时最多能降到原来的三分之一。如果连单张28毫秒这种级别都达不到那就需要换思路了。可以考虑把扩散模块蒸成一个单步映射也就是训练一个教师-学生网络让学生一步就预测出扩散多步的恢复结果。这一步会牺牲一些理论上的可解释性但工程落地往往更需要确定性的延迟。务实的做法是保留扩散模块做周期性的离线校准在线部署用蒸馏模型两者结果差异可以做监控。5. 我的一点延伸思考5.1 扩散类异常检测的下一步DeCo-Diff给我的一个启发是扩散模型在异常检测里的价值不在于重建能力而在于它对概率密度的建模能力。未来的方向很可能不再执着于把扩散过程直接跑完而是把扩散模型的中间状态当成一种特征分布的距离度量或者把扩散模型和多尺度特征金字塔结合去检测那些多尺度性质很强的缺陷。此外实时性会越来越重要扩散蒸馏和跨场景的域适应会是两个并行推进的发力点。5.2 实操体会和建议最后说点很实际的话。我复现DeCo-Diff最大的体会是读论文别急着上代码先想清楚每个模块解决哪个环节的问题。DeCo-Diff的成功在于把什么是正常和什么是异常的边界从整图下放到了解耦分量的粒度上这个思路在很多工业场景都能套用。如果你的数据里正常样本差异很大可以先试解耦分支的数量从3增加到5看异常分数的背景噪声是否下降如果你的缺陷对比度很低重点调扩散模块的感知损失权重它往往比单纯调阈值更管用。这些调整我都踩过坑也希望能省下你几个晚上的调试时间。
阅读完成 · 觉得有帮助?
咨询建站