
1. 工业AI质检的冷启动困局为什么“没有不良品样本”是常态而非意外但凡在制造业产线上摸爬滚打过几年的人大概率都听过或者亲身经历过这样一个场景老板或者项目负责人拍板要上AI质检目标很明确——用视觉算法替代人工目检提升检出率、降低人力成本。项目启动会开得热火朝天等到真正要动手训练模型的时候问题来了翻遍产线几个月的存图良品图片几十万张不良品图片可能连一百张都凑不齐有些缺陷类型甚至一张都没有。这不是个别现象而是工业质检领域最普遍的冷启动难题。很多人第一反应是“那就多收集一些不良品图片呗”但实际产线上的情况是第一有些缺陷本身就是小概率事件良品率99.5%意味着每1000个产品里才5个不良品你要攒够训练模型所需的最低样本量可能要等几个月甚至半年第二有些缺陷一旦出现产线会立刻停机调整等你反应过来去拍照不良品已经被处理掉了第三新产品导入阶段连良品长什么样都还在摸索更别提不良品了。所以“没有不良品样本怎么做AI质检”这个问题本质上不是一个技术问题而是一个工程策略问题。它考验的不是你会不会调参、会不会选backbone而是你能不能在数据极度匮乏的条件下用一套组合拳把模型从零到一地搭起来并且让它真正在产线上跑起来、稳下来。这篇文章面向的是正在或者即将面对这个问题的算法工程师、机器视觉从业者、制造业数字化转型的推动者以及对这个领域感兴趣的技术管理者。我会从整体思路、核心技术方案、实操落地步骤、常见坑与排查技巧几个维度把这件事掰开揉碎了讲清楚。不敢说看完就能直接上手干但至少能让你少走几个月的弯路。2. 整体方案设计没有坏样本时模型到底在学什么2.1 核心思路转换从“认识坏”到“认识好”传统监督式分类或检测模型的逻辑是给模型看大量良品和不良品的标注样本让它学会区分两者的边界。这条路在没有不良品样本时显然走不通。但如果我们换一个角度想——模型不一定非要“认识坏”它只需要“认识好”然后对任何不像好的东西发出警报就行了。这就是异常检测Anomaly Detection的核心思想。在工业质检场景下我们把它叫做“缺陷检测的无监督范式”。模型在训练阶段只接触良品样本学习良品的数据分布。推理阶段任何偏离这个分布的输入都会被判定为异常。这个思路的好处非常直接你不需要收集不良品样本只需要足够多的良品样本就能启动。但这里有一个关键前提需要说清楚无监督异常检测假设“良品是高度一致的不良品是偏离良品的”。如果你的产线本身波动就很大——光照不稳定、产品位置偏移、来料批次差异明显——那模型学到的“良品分布”会非常宽泛导致真正的缺陷也被当成正常波动放过。所以选择这条路之前先评估一下你的产线稳定性。2.2 方案选型对比三条路各自的适用边界在实际项目中面对“没有不良品样本”的约束通常有三条技术路线可选它们并不是互斥的很多时候是组合使用。方案核心原理最低数据要求适用场景主要局限无监督异常检测仅学习良品分布偏离即异常200-500张良品图缺陷形态未知、良品一致性高对光照和位置敏感误报率偏高合成缺陷增强在良品图上人工生成缺陷100张以上良品图缺陷类型大致已知合成缺陷与真实缺陷存在域差距迁移学习少样本预训练模型少量标注样本微调10-50张不良品图已有少量不良品样本需要一定量的标注成本我个人的经验是优先走无监督异常检测路线做冷启动同时并行推进合成缺陷增强等产线跑一段时间积累了一定真实不良品样本后再逐步过渡到半监督或少样本微调。这个渐进式策略的好处是你不需要等数据齐了才开工而是边跑边迭代。2.3 为什么不能直接上大模型或者通用视觉API有些朋友可能会想现在多模态大模型这么强直接拿通用视觉能力去判断产品好坏不就行了这个想法在demo阶段可能看起来可行但落到产线上基本行不通。原因有三第一通用模型没有见过你的产品它不知道什么是“这个产品的正常状态”第二产线节拍要求推理时间通常在几十毫秒级别大模型的推理成本根本扛不住第三工业场景对误报率和漏报率有严格的量化要求通用模型无法给出可控的置信度阈值。所以工业质检的AI方案最终一定要落到针对具体产品、具体工位定制的轻量级模型上。无监督异常检测恰好满足这个需求模型小、推理快、只需要良品数据就能训练。3. 核心技术方案拆解从良品数据到可用模型的完整链路3.1 数据采集良品样本的“质”比“量”更重要很多人以为无监督方法对数据要求低就随便拍几百张良品图丢进去训练。我踩过这个坑结果就是模型在验证集上表现还行一到产线上就疯狂误报。后来复盘发现问题出在数据采集环节。良品样本的采集有几个硬性要求。第一覆盖所有正常波动。你的产线在一天之内可能经历光照变化早晚光线不同、产品位置微移、来料批次差异这些“正常的变化”都必须出现在训练数据里否则模型会把它们当成异常。第二排除隐性缺陷。有些产品表面看起来是良品但实际上存在微小的瑕疵如果这些图片被当作良品训练模型会学到错误的分布。建议采集时由经验丰富的质检员复核一遍。第三数量不是越多越好。对于无监督异常检测500到1000张高质量良品图通常就足够了关键是多样性而非绝对数量。实操中我通常这样操作在产线稳定运行的一个完整班次内每隔一段时间采集一批图片覆盖早中晚不同时段、不同批次来料。采集完成后做一次去重和筛选把明显模糊、过曝、欠曝的图片剔除。3.2 图像预处理让模型只关注“产品本身”原始产线图片里包含大量与缺陷无关的信息背景、夹具、传送带、光照不均。如果直接拿这些图去训练模型会学到一堆无关特征。预处理的目标就是把这些干扰因素去掉让模型聚焦在产品区域。标准流程是这样的首先做ROI裁剪根据产品在图像中的固定位置裁出只包含产品表面的区域。如果产品位置有偏移可以用模板匹配或者简单的目标检测模型先定位产品。然后做光照归一化常用的方法包括直方图均衡化、自适应直方图均衡化CLAHE或者更简单粗暴的——在采集阶段就把光照环境固定死。最后做尺寸统一把所有图片缩放到模型输入尺寸比如256x256或512x512。注意预处理阶段做的任何变换在推理阶段必须完全一致地执行。我见过不止一个项目训练时用了CLAHE推理时忘了加结果模型表现断崖式下降。3.3 模型选择PatchCore、PaDiM还是FastFlow无监督异常检测领域这几年发展很快工业场景下常用的模型有PatchCore、PaDiM、FastFlow、STPM等。它们各有特点选择哪个取决于你的具体需求。PatchCore的核心思路是用预训练CNN提取良品图片的特征构建一个特征记忆库推理时计算测试图片特征与记忆库的最近邻距离距离超过阈值就判为异常。它的优势是不需要训练直接拿预训练模型提特征就行部署极快。缺点是推理时需要遍历记忆库速度受记忆库大小影响。PaDiM则是用高斯分布建模每个位置的特征分布推理时计算马氏距离。它比PatchCore快但对齐要求更高。FastFlow用归一化流做密度估计训练和推理都比较快适合产线节拍要求高的场景。我的建议是如果项目周期紧、产线节拍要求不苛刻优先用PatchCore快速验证可行性。如果验证通过但速度不够再考虑换成FastFlow或者对PatchCore做记忆库压缩。3.4 阈值设定没有不良品样本怎么定判定边界这是无监督异常检测落地时最棘手的问题之一。模型输出的是一个异常分数你需要定一个阈值来决定多少分以上算不良。没有不良品样本就没法用传统的ROC曲线来选阈值。实践中我通常用以下几种方法组合确定第一种是统计法。假设良品图片的异常分数服从某种分布通常是高斯分布或Gamma分布取良品分数的99.5%分位数作为初始阈值。这意味着在良品上误报率大约0.5%。第二种是人工复核法。用初始阈值跑一批产线图片把被判为异常的图片拿出来人工看如果大部分确实是误报就适当提高阈值如果发现有些确实是缺陷但没被判出来就降低阈值。第三种是合成缺陷验证法。在良品图上人工合成一些缺陷看模型给这些合成缺陷打多少分以此校准阈值的下限。实际操作中我会先用统计法给出一个初始值然后产线试运行一周每天收集误报和漏报情况逐步微调。这个过程通常需要一到两周才能稳定下来。4. 实操落地全流程从零搭建一个可用的质检原型4.1 环境搭建与依赖安装先说一下我常用的技术栈Python 3.9、PyTorch 1.13、OpenCV、scikit-learn、FAISS用于PatchCore的最近邻搜索。如果你用Anomalib这个开源库很多模型已经封装好了省去不少重复劳动。# 创建虚拟环境 python -m venv venv source venv/bin/activate # Windows下用 venv\Scripts\activate # 安装核心依赖 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install opencv-python scikit-learn faiss-cpu pip install anomalib # 可选封装了多种异常检测模型提示如果你的产线工控机没有GPU用CPU推理PatchCore也是可以的只是速度会慢一些。512x512输入下CPU单张推理大约200-500ms看具体CPU性能。4.2 数据准备与目录结构Anomalib对数据目录有固定要求我一般按下面的结构组织dataset/ ├── train/ │ └── good/ │ ├── 001.png │ ├── 002.png │ └── ... ├── validation/ │ └── good/ │ └── ... └── test/ ├── good/ │ └── ... └── defect/ └── ... # 如果有的话训练集只放良品图验证集也放良品图用于确定阈值测试集如果有不良品图就放进去评估没有的话就只放良品图看误报率。4.3 模型训练与阈值确定以PatchCore为例用Anomalib训练的核心代码如下from anomalib.data import Folder from anomalib.models import Patchcore from anomalib.engine import Engine # 数据模块 datamodule Folder( rootdataset/, normal_dirtrain/good, normal_test_dirtest/good, taskclassification, image_size(256, 256), ) # 模型 model Patchcore( backbonewide_resnet50_2, layers[layer2, layer3], coreset_sampling_ratio0.1, # 记忆库压缩比例 ) # 训练 engine Engine(max_epochs1) engine.fit(modelmodel, datamoduledatamodule) engine.test(modelmodel, datamoduledatamodule)PatchCore的“训练”实际上只是构建特征记忆库所以epoch设为1就够了。coreset_sampling_ratio控制记忆库的压缩比例0.1表示保留10%的特征点既能保证精度又能控制推理速度。这个参数需要根据你的数据量和精度要求调我一般从0.1开始试如果精度不够就提高到0.2或0.3。训练完成后用验证集上的良品图片计算异常分数分布取99.5%分位数作为初始阈值import numpy as np # 假设 scores 是验证集所有良品图片的异常分数 threshold np.percentile(scores, 99.5) print(f初始阈值: {threshold:.4f})4.4 产线部署与推理服务模型训练好之后部署到产线上通常有两种方式一种是直接集成到现有的视觉系统里用Python调用模型做推理另一种是封装成HTTP服务产线PLC通过接口调用。我倾向于后者因为解耦之后维护和更新都更方便。from fastapi import FastAPI, UploadFile import cv2 import numpy as np app FastAPI() app.post(/predict) async def predict(file: UploadFile): img cv2.imdecode(np.frombuffer(await file.read(), np.uint8), cv2.IMREAD_COLOR) # 预处理 img preprocess(img) # 推理 score model.predict(img) # 判定 is_defect score threshold return {score: float(score), is_defect: bool(is_defect)}推理服务的响应时间要控制在产线节拍以内。如果单张推理超过节拍时间可以考虑批量推理或者模型量化加速。4.5 合成缺陷增强让模型“见过”缺陷虽然无监督方法不需要不良品样本但如果你能合成一些缺陷图片对模型调优和阈值校准都有帮助。合成缺陷的方法有很多简单一点的可以用OpenCV在良品图上画随机形状、加噪声、做局部亮度变化复杂一点的可以用GAN或者扩散模型生成更逼真的缺陷。import cv2 import numpy as np def synthesize_defect(img, num_defects3): 在良品图上合成随机缺陷 h, w img.shape[:2] result img.copy() for _ in range(num_defects): # 随机位置 x np.random.randint(0, w - 30) y np.random.randint(0, h - 30) # 随机大小 rw np.random.randint(10, 30) rh np.random.randint(10, 30) # 随机颜色模拟划痕、污点等 color tuple(np.random.randint(0, 100, 3).tolist()) cv2.rectangle(result, (x, y), (x rw, y rh), color, -1) return result合成缺陷的用途主要是验证模型对缺陷的敏感度、辅助确定阈值下限、在缺少真实不良品时做初步的模型评估。但要注意合成缺陷和真实缺陷之间存在域差距不能完全依赖合成数据来评估模型性能。5. 常见问题与排查技巧实录5.1 误报率居高不下怎么办这是无监督异常检测落地时最常见的抱怨。产线跑了一天模型报了上百个异常结果人工复核发现全是误报。遇到这种情况按下面的顺序排查先看训练数据是否覆盖了所有正常波动。如果训练集只有白天的图片晚上的光照变化就会被当成异常。解决办法是补充不同时段、不同批次的良品图片重新训练。再看预处理是否一致。训练和推理的预处理流程必须完全一致任何差异都会导致误报。最后看阈值是否偏低。适当提高阈值可以降低误报但要注意别把真正的缺陷也放过了。5.2 漏报模型对某些缺陷不敏感漏报比误报更危险因为不良品流出去了。如果发现模型对某类缺陷不敏感首先确认这类缺陷在异常分数上是否确实偏低。如果是说明模型学到的良品分布太宽泛把这类缺陷也覆盖进去了。解决办法包括收紧良品数据的采集标准排除隐性缺陷、增加合成缺陷样本做微调、或者针对这类缺陷单独训练一个检测模型。5.3 产线环境变化导致模型失效产线不是实验室光照、温度、设备状态都在变化。我遇到过换了一批来料之后模型误报率突然飙升的情况。排查后发现是新来料的表面纹理和之前有细微差异模型把它当成了异常。这种问题的根本解法是建立模型持续迭代的机制定期用新的良品数据更新记忆库或者用产线积累的真实数据做增量训练。5.4 常见问题速查表问题现象可能原因排查方向解决措施误报率高训练数据覆盖不足检查训练集是否包含各种正常波动补充多时段、多批次良品图误报率高预处理不一致对比训练和推理的预处理代码统一预处理流程误报率高阈值偏低查看良品分数分布提高阈值至99.5%分位以上漏报良品分布过宽检查训练集是否有隐性缺陷清洗训练数据收紧良品标准漏报缺陷类型未见过分析漏报缺陷的特征合成类似缺陷做微调推理速度慢记忆库过大查看coreset_sampling_ratio降低采样比例或换FastFlow模型突然失效产线环境变化对比新旧来料、光照条件更新记忆库或增量训练5.5 几个我踩过的坑第一个坑是过度依赖合成缺陷。早期项目里我用合成缺陷做了大量调优结果模型对合成缺陷很敏感对真实缺陷反而反应迟钝。后来才明白合成缺陷和真实缺陷的纹理、边缘、对比度都有差异不能混为一谈。第二个坑是忽略推理时的图像质量。训练时用的都是高清工业相机拍的图推理时换了一个便宜相机图像噪声大、对比度低模型表现直接崩了。所以训练和推理的硬件条件要尽量一致。第三个坑是阈值设完就不管了。产线运行一段时间后设备磨损、来料变化都会导致数据分布漂移固定阈值慢慢就不适用了。后来我加了一个自动监控机制每周统计一次误报率和漏报率超过阈值就触发告警提醒更新模型。6. 从冷启动到持续迭代一条务实的落地路径如果你现在正面对“没有不良品样本”的困境我建议的落地路径是这样的第一周采集500-1000张高质量良品图做好预处理用PatchCore快速搭一个原型确定初始阈值。第二到四周产线试运行每天收集误报和漏报案例人工复核后微调阈值和预处理参数。第二个月开始如果积累了少量真实不良品样本用它们做少样本微调或者训练一个专门的缺陷分类器做二级判定。第三个月之后建立定期更新机制每月用新数据更新一次记忆库或做增量训练。这条路走下来你会发现最大的挑战不是算法本身而是数据工程和产线配合。算法方案是成熟的开源工具是现成的真正花时间的是跟产线沟通采集数据、跟质检员确认判定标准、跟设备工程师协调相机和光照。这些事没有捷径只能一步一步来。最后分享一个小技巧如果你实在连良品样本都很少可以考虑用预训练模型的特征提取能力做零样本异常检测。比如用CLIP这类视觉语言模型通过文本描述“正常产品”和“缺陷产品”来做分类。这个方法精度不如专门训练的模型但在项目极早期用来验证可行性是够用的。等验证通过再投入资源采集数据、训练专用模型风险会小很多。