工厂数据少能训动AI吗:小样本+预训练+增量微调组合方案
TL;DR 速览
- 缺陷样本为零:走无监督异常检测(PatchCore / EfficientAD / FastFlow),只用良品图建模,良品 50–500 张即可冷启动,只判「像不像正常」,不分类。
- 缺陷样本每类 100–200 张:若业务需要知道缺陷类别与位置,走两阶段串联(异常检测预筛 + 监督细分类),兼顾低漏检与低误检。
- 缺陷样本每类 200–500 张:直接冻结 backbone 微调检测头(YOLO / RT-DETR 系),输出类别与位置,可量化。
- 选型判断:先数缺陷样本,再问「要不要输出缺陷类别」;三条路线最终都汇入样本回流池,攒够一批触发增量微调,让模型随产线一起长大。
目录
- 一、问题场景:缺陷样本为什么天然稀缺
- 二、技术原理:小样本能成立,靠的是三个前提
- 三、方案拆解:按数据家底选路线
- 四、数据验证:这条路线在真实产线上跑通过吗
- 五、小结
- 常见问题
先说结论:能,而且路径很成熟。 工厂数据少不是「训不训得动」的问题,而是「选哪条路线」的问题。当前工业视觉场景下有三条被反复验证的路线:预训练 backbone 迁移(几百张良品就能起步的异常检测)、参数高效微调(只训万分之一的参数)、以及产线运行中的增量迭代。缺陷样本少不是拦路虎,拦路虎是没有把「缺陷少」这个事实设计进方案里。
一、问题场景:缺陷样本为什么天然稀缺
产线质检数据的分布是极度偏斜的。一条正常运行的产线良品率往往在 98% 以上,一天十万件产品里,某一类缺陷可能只出现几十件,还未必都能被抓拍留存。如果按传统监督学习的思路「每类缺陷准备几千张标注图再开工」,很多工厂的数据攒一年都不够。
更现实的问题是:缺陷类型不封闭。今天训好的模型只能认它见过的缺陷,明天工艺波动冒出一个新缺陷形态,监督模型对它就是零检出。这就是为什么「数据少」在工业场景不是边缘案例,而是常态——中国信通院在 2026 年 10 月的行业大会上就指出,近一半「人工智能+」应用场景停留在试点阶段未放量推广,数据底子薄是主要卡点之一(信通院,2026-10-15 济南人工智能产业大会)。
二、技术原理:小样本能成立,靠的是三个前提
前提一:预训练 backbone 已经把「看图能力」学完了。
在 ImageNet 等大规模数据集上预训练过的骨干网络,已经学会了边缘、纹理、形状这些通用视觉表征。工厂的任务不是从零学「怎么看图」,只是在这个表征之上学「什么算异常」。这就是为什么迁移学习下,缺陷检测所需的样本量比从零训练低一到两个数量级。
前提二:异常检测把问题从「认缺陷」换成「认良品」。
无监督异常检测(Unsupervised Anomaly Detection)只用良品图片建模「正常长什么样」,推理时输出与正常模式的偏离度。缺陷样本一张都不需要——这直接绕开了缺陷稀缺的死结。代表作 PatchCore(Roth et al., CVPR 2022)在工业异常检测标准基准 MVTec AD 上拿到图像级 AUROC 最高 99.6%,论文还专门验证了 few-sample(每类仅 1–16 张良品图)场景下依然有竞争力的表现(来源:CVPR 2022 论文《Towards Total Recall in Industrial Anomaly Detection》,Amazon/AWS)。
前提三:参数高效微调把「训得起」的门槛拉低了。
全量微调一个大模型要更新全部参数,显存和算力都扛不住。LoRA(Hu et al., 2021,微软)的做法是冻结预训练权重、只注入低秩矩阵参与训练——以 GPT-3 175B 为例,可训练参数量比全量微调减少一万倍、GPU 显存需求降低约 3 倍,且效果持平甚至略优(来源:arXiv:2106.09685)。同一思想在视觉模型微调上同样成立:冻结 backbone、只训检测头或少量适配层,几百张样本就能收敛。
三、方案拆解:按数据家底选路线
| 无监督异常检测(PatchCore / EfficientAD / FastFlow) | 0 张 | 几十到几百张 | 检出「不像正常」的区域,不分类 | 冷启动,缺陷图还没攒够 |
| 监督检测微调(YOLO / RT-DETR 系,冻结 backbone 微调检测头) | 每类 200–500 张有效标注 | 搭配数百张 | 输出缺陷类别与位置,可量化 | 缺陷图已有一定积累 |
| 两阶段串联(异常检测预筛 + 监督细分类) | 每类 100–200 张起步 | 数百张 | 低漏检 + 低误检平衡 | 产线稳定运行期 |
表中样本量为多篇工程实践文章的共识区间(CSDN 工程实践专栏 2025–2026 年多篇落地复盘交叉一致:监督方案每类缺陷 200–500 张收敛到可用水平,异常检测方案良品样本 50–500 张即可起步),不是标准,具体还要看缺陷形态复杂度和成像一致性。
把这张表翻译成决策路径更直观——先看手里有多少缺陷样本,再看业务上要不要输出缺陷类别,两条判断就能落到具体路线:
#mermaid-svg-5IRqy1gld1OpJe4m{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5IRqy1gld1OpJe4m .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5IRqy1gld1OpJe4m .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5IRqy1gld1OpJe4m .error-icon{fill:#552222;}#mermaid-svg-5IRqy1gld1OpJe4m .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5IRqy1gld1OpJe4m .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5IRqy1gld1OpJe4m .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5IRqy1gld1OpJe4m .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5IRqy1gld1OpJe4m .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5IRqy1gld1OpJe4m .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5IRqy1gld1OpJe4m .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5IRqy1gld1OpJe4m .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5IRqy1gld1OpJe4m .marker.cross{stroke:#333333;}#mermaid-svg-5IRqy1gld1OpJe4m svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5IRqy1gld1OpJe4m p{margin:0;}#mermaid-svg-5IRqy1gld1OpJe4m .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-5IRqy1gld1OpJe4m .cluster-label text{fill:#333;}#mermaid-svg-5IRqy1gld1OpJe4m .cluster-label span{color:#333;}#mermaid-svg-5IRqy1gld1OpJe4m .cluster-label span p{background-color:transparent;}#mermaid-svg-5IRqy1gld1OpJe4m .label text,#mermaid-svg-5IRqy1gld1OpJe4m span{fill:#333;color:#333;}#mermaid-svg-5IRqy1gld1OpJe4m .node rect,#mermaid-svg-5IRqy1gld1OpJe4m .node circle,#mermaid-svg-5IRqy1gld1OpJe4m .node ellipse,#mermaid-svg-5IRqy1gld1OpJe4m .node polygon,#mermaid-svg-5IRqy1gld1OpJe4m .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5IRqy1gld1OpJe4m .rough-node .label text,#mermaid-svg-5IRqy1gld1OpJe4m .node .label text,#mermaid-svg-5IRqy1gld1OpJe4m .image-shape .label,#mermaid-svg-5IRqy1gld1OpJe4m .icon-shape .label{text-anchor:middle;}#mermaid-svg-5IRqy1gld1OpJe4m .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5IRqy1gld1OpJe4m .rough-node .label,#mermaid-svg-5IRqy1gld1OpJe4m .node .label,#mermaid-svg-5IRqy1gld1OpJe4m .image-shape .label,#mermaid-svg-5IRqy1gld1OpJe4m .icon-shape .label{text-align:center;}#mermaid-svg-5IRqy1gld1OpJe4m .node.clickable{cursor:pointer;}#mermaid-svg-5IRqy1gld1OpJe4m .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5IRqy1gld1OpJe4m .arrowheadPath{fill:#333333;}#mermaid-svg-5IRqy1gld1OpJe4m .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5IRqy1gld1OpJe4m .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5IRqy1gld1OpJe4m .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5IRqy1gld1OpJe4m .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5IRqy1gld1OpJe4m .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5IRqy1gld1OpJe4m .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5IRqy1gld1OpJe4m .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5IRqy1gld1OpJe4m .cluster text{fill:#333;}#mermaid-svg-5IRqy1gld1OpJe4m .cluster span{color:#333;}#mermaid-svg-5IRqy1gld1OpJe4m div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5IRqy1gld1OpJe4m .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5IRqy1gld1OpJe4m rect.text{fill:none;stroke-width:0;}#mermaid-svg-5IRqy1gld1OpJe4m .icon-shape,#mermaid-svg-5IRqy1gld1OpJe4m .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5IRqy1gld1OpJe4m .icon-shape p,#mermaid-svg-5IRqy1gld1OpJe4m .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5IRqy1gld1OpJe4m .icon-shape .label rect,#mermaid-svg-5IRqy1gld1OpJe4m .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5IRqy1gld1OpJe4m .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5IRqy1gld1OpJe4m .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5IRqy1gld1OpJe4m :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
0 张(只有良品)
每类 100–200 张
每类 200–500 张
需要分类与定位
只需判良/NG
开始:盘点数据家底
缺陷样本数量
无监督异常检测PatchCore / EfficientAD / FastFlow
是否需要输出缺陷类别
监督检测微调YOLO / RT-DETR 冻结 backbone 训检测头
两阶段串联异常检测预筛 + 监督细分类
样本量:良品 50–500 张适用阶段:冷启动,缺陷图还没攒够
样本量:每类缺陷 200–500 张有效标注适用阶段:缺陷图已有一定积累
样本量:每类缺陷 100–200 张起步 + 良品数百张适用阶段:产线稳定运行期
样本回流池:误报/漏报人工确认后回灌
攒够一批触发增量微调冻结主干、只训检测头
读图要点:缺陷样本为零时不必纠结分类能力,先让异常检测跑起来挡漏检;样本攒到每类一两百张时,再问一句「业务要不要知道这是哪类缺陷」——要,就走两阶段串联;只要判良/NG,继续用异常检测即可;每类攒到两三百张以上,才值得上监督检测微调,直接输出类别与位置。三条分支最终都汇入样本回流池,这也是路线能随产线一起进化的原因。
落到工程上,一个典型的组合流水线长这样:
[产线相机] → [图像预处理/畸变校正]
│
├─→ [异常检测引擎: PatchCore] ← 只用良品建模
│ │ 异常分数 > 阈值?
│ ├─ 否 → 判良品, 放行
│ └─ 是 → 送第二级
│
└─→ [监督细分类: 微调检测头] ← 少量缺陷样本微调
│ 输出缺陷类别 + 位置
└─→ [样本回流池] ← 误报/漏报人工确认后回灌
其中「样本回流池」是增量微调的弹药库:产线每天跑,误报和漏报经人工确认后自动沉淀为新的标注样本,攒够一个批次(比如每类新增 50 张)就触发一轮增量微调——冻结主干、只训检测头,一次微调在单张消费级显卡上通常几十分钟到几小时就能完成,不用停产重训。
一个最小化的参数高效微调骨架(PyTorch 风格伪代码):
# 冻结预训练 backbone,只训练检测头 + 低秩适配层
model = build_detector(pretrained=True)
for name, p in model.named_parameters():
p.requires_grad = ("head" in name) or ("lora" in name)
# 实际参与训练的参数量通常只占全模型的 0.5%–2%
trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
total = sum(p.numel() for p in model.parameters())
print(f"trainable ratio: {trainable / total:.4%}")
# 增量微调: 新批次缺陷样本 + 少量旧样本回放(防灾难性遗忘)
loader = mix_loader(new_defects, replay_ratio=0.2)
train(model, loader, epochs=30, lr=1e-4)
回放(replay)这一步不能省——只拿新缺陷图训,模型会把旧缺陷忘干净,这就是持续学习里的「灾难性遗忘」问题。混 20% 左右的旧样本回放是经验上比较稳的做法。
上面是「有缺陷样本之后」的微调骨架。如果缺陷样本还是零,先跑下面这段基于 PatchCore 思路的无监督异常检测最小实现——只用良品图建模,三步走完:良品建模 → 异常分数计算 → 阈值判定。
import torch
import torch.nn.functional as F
from torchvision.models import wide_resnet50_2, Wide_ResNet50_2_Weights
# ========== 第 0 步:准备特征提取器(冻结的预训练 backbone) ==========
# 用 ImageNet 预训练的 WideResNet50 做特征提取,权重全程冻结,不参与训练
backbone = wide_resnet50_2(weights=Wide_ResNet50_2_Weights.IMAGENET1K_V1).eval()
for p in backbone.parameters():
p.requires_grad = False
def extract_features(x):
"""取 layer2 / layer3 的中层特征,兼顾纹理细节与语义信息"""
feats = []
for name, module in backbone.named_children():
x = module(x)
if name in ("layer2", "layer3"):
feats.append(x)
# 统一上采样到同一分辨率后拼接
target_size = feats[0].shape[–2:]
feats = [F.interpolate(f, size=target_size, mode="bilinear", align_corners=False) for f in feats]
return torch.cat(feats, dim=1) # [B, C, H, W]
# ========== 第 1 步:良品建模(只用正常样本,构建特征记忆库) ==========
def build_memory_bank(good_loader, coreset_ratio=0.1):
"""把良品图的 patch 特征压成一个记忆库,coreset 采样降低冗余"""
bank = []
with torch.no_grad():
for imgs in good_loader:
feat = extract_features(imgs) # [B, C, H, W]
patches = feat.permute(0, 2, 3, 1).reshape(–1, feat.shape[1]) # [B*H*W, C]
bank.append(patches)
bank = torch.cat(bank, dim=0)
# 随机 coreset 采样:保留 coreset_ratio 比例的特征点,控制显存与推理耗时
idx = torch.randperm(bank.shape[0])[: max(1, int(bank.shape[0] * coreset_ratio))]
return bank[idx] # [M, C],M 为记忆库大小
memory_bank = build_memory_bank(good_loader) # 几十到几百张良品图即可
# ========== 第 2 步:异常分数计算(每个 patch 找最近邻,取最大距离) ==========
def anomaly_score(img, k=1):
"""返回图像级异常分数与像素级异常热力图"""
with torch.no_grad():
feat = extract_features(img) # [1, C, H, W]
patches = feat.permute(0, 2, 3, 1).reshape(–1, feat.shape[1]) # [H*W, C]
# 计算每个 patch 到记忆库所有特征的欧氏距离
dist = torch.cdist(patches, memory_bank) # [H*W, M]
# 取最近的 k 个邻居距离求均值,作为该 patch 的异常分数
patch_scores = dist.topk(k, largest=False).values.mean(dim=1)
score_map = patch_scores.reshape(1, 1, *feat.shape[–2:])
# 图像级分数 = 最异常 patch 的分数(局部缺陷不会被平均掉)
img_score = patch_scores.max().item()
return img_score, score_map
# ========== 第 3 步:阈值判定(用良品验证集定阈值,避免拍脑袋) ==========
def calibrate_threshold(good_val_loader, sigma=3.0):
"""在纯良品验证集上跑一遍,取 均值 + sigma*标准差 作为阈值"""
scores = [anomaly_score(img)[0] for img in good_val_loader]
scores = torch.tensor(scores)
return (scores.mean() + sigma * scores.std()).item()
threshold = calibrate_threshold(good_val_loader)
def predict(img):
"""产线推理入口:分数超阈值判 NG,并返回热力图供人工复核"""
score, heatmap = anomaly_score(img)
is_ng = score > threshold
return {"score": score, "threshold": threshold, "is_ng": is_ng, "heatmap": heatmap}
三步的分工很明确:良品建模把「正常长什么样」固化成记忆库,缺陷样本一张都不用;异常分数计算用最近邻距离衡量每个 patch 偏离正常的程度,取最大值作为图像级分数,保证小面积缺陷不被稀释;阈值判定在良品验证集上按 3σ 原则自动标定,比人工拍一个固定值稳得多。实际落地时把 coreset_ratio 调到 1%–10%、k 取 1–9,就能在单张消费级显卡上做到毫秒级推理。
关键参数怎么调
上面这段代码能跑通,但真正决定产线效果的是四个参数。它们不是各自独立的旋钮,而是有先后顺序的——顺序错了,调一天也调不出稳定结果。
| coreset_ratio(记忆库采样比例) | 1%–10%(良品图少于 100 张时可放到 20%–30%) | 比例过低会丢掉稀有正常形态,漏检上升 | 比例过高记忆库冗余,误检略降但推理变慢 | 第 1 步:先定记忆库规模 |
| k(近邻数) | 1–9(小面积缺陷取 1–3,噪声大的成像取 5–9) | k 偏大时小缺陷被邻居平均掉,漏检上升 | k 偏小对成像噪声敏感,误检上升 | 第 2 步:固定阈值前先定 k |
| 阈值 sigma(3σ 系数) | 2.5–4.0(漏检代价高取 2.5,误检代价高取 4.0) | sigma 越大阈值越高,漏检上升 | sigma 越小阈值越低,误检上升 | 第 3 步:前两个参数定完再标定 |
| 输入分辨率 | 短边 256–512(缺陷小于 5 像素时必须 ≥ 512) | 分辨率不足时小缺陷特征被抹平,漏检上升 | 分辨率过高引入纹理噪声,误检上升 | 第 0 步:最先定,且定完不再改 |
三条工程经验:
四、数据验证:这条路线在真实产线上跑通过吗
几组可交叉验证的事实:
五、小结
「工厂数据少能不能做 AI」这个问题的答案分三层:
- 缺陷样本为零 → 用无监督异常检测,良品图几十到几百张就能冷启动;
- 缺陷样本有几百张/类 → 冻结 backbone 微调检测头,或异常检测预筛 + 监督细分类两级串联;
- 数据会持续积累 → 把样本回流池和增量微调机制设计进系统,让模型随产线一起长大。
真正的门槛不是样本数量,是有没有把「缺陷天然稀缺」设计进架构。先让异常检测跑起来挡漏检,再让回流机制把每一天的生产变成训练数据——数据少,就这样一点点变多。
常见问题
Q:我们厂数据很少,能训得动 AI 吗? 能。缺陷样本一张都没有也能起步:无监督异常检测只需要良品图,几十到几百张就能建模「正常长什么样」。PatchCore 这类方法在工业标准基准上只用良品训练就做到了 99.6% 的图像级 AUROC。缺陷样本后续通过产线回流慢慢攒,攒够一批做一次增量微调。
Q:做 AI 质检到底需要多少张样本? 看路线。监督检测方案的经验区间是每类缺陷 200–500 张有效标注才能收敛到可用水平;无监督异常检测只需要良品,50–500 张起步;两阶段串联方案每类缺陷 100–200 张起步。注意样本多样性比数量重要——同一产线同一角度拍两千张,不如覆盖不同光照、不同批次的几百张。
Q:增量微调会不会把模型训坏,越训越差? 会有这个风险,叫「灾难性遗忘」——只喂新缺陷样本,模型会忘掉旧的。工程对策有两个:一是训练时混入 20% 左右的旧样本回放;二是冻结预训练主干、只微调检测头或低秩适配层,主干表征不动,遗忘就有限。每次增量微调后用固定的回归测试集验证旧缺陷检出率,不达标就回滚。
参考资料
关于作者:云湃智算(VASTIQ),专注制造业 AI 落地的技术团队,持续分享工业视觉检测、设备数据采集中踩过的坑和填坑方法。



