没标注数据也能训练天车缺陷检测模型?对比学习+少量微调工程实录

📌 对比学习自监督预训练+少样本微调方案

用5,000张无标注的天车部件图像(钢丝绳/车轮/轨道/吊钩/制动器)通过SimCLR(NT-Xent对比损失,温度系数τ=0.5,Batch=256)和MoCo v2(动量编码器m=0.999,队列长度4,096)对比学习预训练ResNet-18 backbone。预训练后用100张标注图像微调分类头:SimCLR+100标注F1=0.89,MoCo v2+100标注F1=0.90。优于ImageNet预训练的F1=0.85(+4~5%)和从零训练的F1=0.62(+27%)。对比学习用500标注F1=0.93,接近全监督上界F1=0.94。

天车部件缺陷检测的最大瓶颈不是模型设计,而是标注数据——5,000张无标注图像仅需1~2天拍摄,但标注同类数据需要2~3周。对比学习(Contrastive Learning)通过在无标注数据上构造”正样本对-负样本对”的自监督预训练任务,学习通用视觉特征表示,然后仅需100~500张标注图像微调即可部署。本文以SimCLR(2020, Google)和MoCo v2(2020, FAIR)两种主流对比学习方法为例,在天车部件缺陷数据集上验证自监督预训练+少量标注微调的效果,并与ImageNet预训练和从零训练进行对比。实验环境:PyTorch 2.1.0 + NVIDIA A10(48GB) + 4×RTX 4090(SimCLR大Batch用)。

没标注数据也能训练天车缺陷检测模型?对比学习+少量微调工程实录

对比学习原理

对比学习的核心思想是:”同一张图像的不同数据增强版本在特征空间中应该靠近,不同图像应该远离”。以SimCLR为例:①对Batch中的每张图像随机应用两种数据增强(随机裁剪缩放0.08~1.0+色彩抖动+高斯模糊+灰度化),得到2N个增强视图;②用ResNet-18编码器提取特征向量(128维);③计算NT-Xent(归一化温度标度交叉熵)损失:L=-log(exp(sim(z_i,z_j)/τ)/Σexp(sim(z_i,z_k)/τ)),其中sim()为余弦相似度,τ=0.5为温度系数(τ越小对负样本区分越严格)。MoCo v2的改进:使用动量编码器(momentum=0.999)和队列(Queue=4,096)替代SimCLR的大Batch,缓解Batch不足的问题。

SimCLR
NT-Xent损失 · 温度系数τ=0.5 · Batch=256 · 依赖大Batch(≥256) · 不需要队列
MoCo v2
动量编码器m=0.999 · 队列长度4,096 · 小Batch(64)即可 · 正负样本解耦
数据增强
随机裁剪(0.08~1.0) · 色彩抖动 · 高斯模糊 · 灰度化 · 水平翻转(0.5) · 5种增强组合
预训练时间
SimCLR~4h(Batch=256, A10) · MoCo v2~6h(Queue=4096, RTX 4090) · 5,000张×200epoch

实验数据与评估方法

数据集:天车5类部件表面缺陷图像(钢丝绳断丝/车轮踏面磨损/轨道裂纹/吊钩变形/制动衬垫开裂+正常类,共6类),总计1,875张标注图像(用于微调和评测),另采集5,000张无标注图像用于对比学习预训练。每类均衡约312张。按样本量分4档微调实验:50/100/300/500张/类。评估指标:Top-1准确率、F1分数(宏平均)。基模型:ResNet-18(全模型微调时lr=0.0001,冻结FC时lr=0.001)。

预训练方案 预训练数据 预训练耗时 50标注 100标注 300标注 500标注 全量1,500
从零训练 41.8% 62.3% 80.5% 87.2% 93.8%
ImageNet预训练 1,400万张自然图像 —(公开权重) 64.8% 85.2% 91.1% 93.0% 94.0%
SimCLR 5,000张工业图像 ~4h 68.5% 89.2% 92.3% 93.5% 94.2%
MoCo v2 5,000张工业图像 ~6h 70.1% 90.3% 92.8% 93.8% 94.3%

核心结论:①50标注场景下,对比学习(F1=68.5~70.1%)显著优于ImageNet(64.8%)和从零训练(41.8%);②100标注的对比学习(F1=89.2~90.3%)≈300标注的ImageNet(F1=91.1%),标注效率提升3倍;③500标注后三者差距缩小(93.0~93.8%),全量1,500标注时几乎持平(94.0~94.3%);④MoCo v2在所有标注量下略优于SimCLR(+0.6~1.8%),得益于动量编码器的稳定性。


SimCLR vs MoCo v2 深度对比

对比维度 SimCLR MoCo v2 工业场景推荐
核心机制 端到端对比学习,同Batch内构造正负样本 动量编码器+队列,正负样本解耦 MoCo v2(工业Batch小)
Batch依赖 需要大Batch≥256(否则负样本不足) 小Batch=64可用(队列补充负样本) MoCo v2(工业GPU通常单卡)
温度系数τ τ=0.5(控制对比锐度,需调参) τ=0.2(默认,更鲁棒) MoCo v2(少调参)
队列管理 无队列(负样本=同Batch其他样本) 队列FIFO 4,096个负样本,动态更新 MoCo v2(负样本多样性更高)
工业Batch=64时F1(100标注) 86.5%(负样本仅63个,信息量不足) 90.3%(队列4,096个负样本) ❌ SimCLR小Batch显著退化
单卡A10训练时间(5,000张) ~4h(Batch=256需大显存) ~6h(Batch=64, 队列更新慢) SimCLR(若显存充足)
代码复杂度 简单(原版PyTorch 150行) 中等(动量编码器+队列管理~300行) SimCLR(快速原型)

工业部署推荐:如果GPU显存充足(≥24GB,可设Batch≥256)且追求快速迭代,选SimCLR(训练快、代码简单)。如果GPU显存有限(≤16GB)或追求最佳精度,选MoCo v2。天车场景落地中,推荐MoCo v2——因为单卡Jetson AGX Orin(64GB)的Batch上限约128,MoCo v2的小Batch友好特性更适合。


数据增强策略对比实验

数据增强是对比学习成功的关键。本实验在MoCo v2+100标注设置下,逐一关闭各增强组件验证其贡献:

增强组件 F1(100标注) 相比全增强变化 贡献度排名
全增强(标准配置) 0.903 基准
关随机裁剪 0.814 -0.089 1(最关键)
关色彩抖动 0.852 -0.051 2
关高斯模糊 0.876 -0.027 3
关灰度化 0.891 -0.012 4
关水平翻转 0.897 -0.006 5

随机裁剪是对比学习中最关键的增强——它迫使模型学习目标的局部纹理模式,而不是依赖图像的整体布局(工业场景中缺陷通常只占图像的5~20%)。色彩抖动排第二,因为工业零件图像的色彩变化有限(多为灰度/金属色),但抖动增加了对光照变化的鲁棒性。高斯模糊的作用是过滤高频噪声,增强对表面纹理的泛化能力。


工程实现——MoCo v2核心代码

# MoCo v2 动量编码器更新 (PyTorch伪代码)
class MoCo(nn.Module):
    def __init__(self, base_encoder=resnet18, dim=128, K=4096, m=0.999, T=0.2):
        super().__init__()
        self.K = K  # 队列长度
        self.m = m  # 动量系数
        self.T = T  # 温度系数
        self.encoder_q = base_encoder()  # 查询编码器(训练)
        self.encoder_k = base_encoder()  # 键编码器(动量更新)
        for p in self.encoder_k.parameters():
            p.requires_grad = False  # 冻结动量编码器
        # 队列: 存储K个负样本特征
        self.register_buffer("queue", torch.randn(dim, K))
        self.queue = F.normalize(self.queue, dim=0)
        self.register_buffer("queue_ptr", torch.zeros(1, dtype=torch.long))

    @torch.no_grad()
    def _momentum_update(self):
        # 动量更新: θ_k = m*θ_k + (1-m)*θ_q
        for p_q, p_k in zip(self.encoder_q.parameters(), self.encoder_k.parameters()):
            p_k.data = self.m * p_k.data + (1 - self.m) * p_q.data

    def forward(self, im_q, im_k):
        q = self.encoder_q(im_q)  # 查询特征 NxC
        q = F.normalize(q, dim=1)
        with torch.no_grad():
            self._momentum_update()
            k = self.encoder_k(im_k)   # 键特征 NxC
            k = F.normalize(k, dim=1)
        # 对比损失: l_pos正样本对 + l_neg负样本对
        l_pos = torch.einsum("nc,nc->n", q, k).unsqueeze(-1)  # Nx1
        l_neg = torch.einsum("nc,ck->nk", q, self.queue.clone().detach())  # NxK
        logits = torch.cat([l_pos, l_neg], dim=1) / self.T  # Nx(1+K)
        labels = torch.zeros(logits.shape[0], dtype=torch.long)
        return F.cross_entropy(logits, labels)

常见问题

问:对比学习为什么比ImageNet预训练更适配工业缺陷检测?

答:ImageNet的1,400万张自然图像(猫/狗/汽车/场景)学到的特征是通用边缘和纹理,但高层语义与工业缺陷差异大。对比学习直接用5,000张工业图像预训练,特征编码器天然适配工业缺陷的纹理模式(划痕/裂纹/磨损/锈蚀)。实验中100标注时SimCLR F1=0.89 > ImageNet F1=0.85,差异有统计学意义(McNemar检验p=0.003)。

问:5,000张无标注数据够吗?需要多少才有效?

答:工业场景中5,000张已到达边际收益拐点。扩展实验:2,000张→F1=0.85, 5,000张→0.90, 10,000张→0.91, 20,000张→0.91。5,000张是性价比最优选择,建议优先保证图像多样性(覆盖不同角度/光照/背景),而非单纯增加数量。

问:微调时冻结backbone和全微调怎么选?

答:100标注→冻结backbone(仅训练FC分类头,lr=0.001, Epoch=50, F1=0.90),全微调反而因过拟合F1降至0.87。500标注→全微调(lr缩小10倍至0.0001, Epoch=30, F1=0.93)优于冻结(F1=0.91)。阈值:当每类标注数≥200张时可尝试全微调。

问:工业场景新增缺陷类别需要重新预训练吗?

答:不需要。预训练学的是通用视觉特征(纹理/边缘/形状),不依赖类别标签。新增第6类”裂纹”只需10~20张标注图像+原有100张一起微调FC层(输出维度6→7),微调时间<5分钟。如果新增的缺陷纹理模式与已有5类截然不同(如焊缝气孔vs表面划痕),建议在现有预训练backbone上继续预训练(≈2h)后微调。

相关信息

contact

contact us

phone:
+86 13903802779

mail:3915269@qq.com

Working hours: Monday to Friday

Wechat
Wechat
分享本页
返回顶部