☰
图像分类半监督学习实战:从标注匮乏到准确率89%的完整方案
2026/10/19 8:26:58 网站建设 项目流程

做图像分类项目时,最扎心的不是模型选得不够花,而是标注数据根本不够用。我去年接手一个真实业务场景:总共只有不到一千张人工标注图,手里却压着几十万张完全没标注的原始图片。外包标一轮问了下报价,直接放弃了。后来靠半监督学习,硬生生把分类准确率从78%拉到89%,整个过程没额外标过一张图。今天就把这套图像分类半监督学习的完整思路和实操经验整理出来:核心方法怎么拆解、损失函数怎么设、训练时踩过哪些坑、什么情况下别硬上,一条条说清楚,你们可以直接拿着调。

1. 半监督学习的核心思路与方案选型

1.1 为什么要用半监督学习:标注瓶颈才是真问题

很多人一提到图像分类,第一反应就是堆数据、上大模型。但真实项目里,干净、准确、覆盖所有类别分布的标注数据,永远是稀缺资源。标注成本高不只是钱的问题,还有时间成本:医学影像需要专业医生逐张看,工业质检缺陷图需要老师傅确认,电商图片需要熟悉商品体系的人打标。这个过程又慢又贵,而且标注质量不稳定,返工率高。

反过来看,无标注数据几乎遍地都是。监控视频抽帧、服务器上积压的历史图片、爬虫采集的公开图像、生产线自动拍摄的样张,这些数据没有标签,但数量可能是标注数据的几百倍。半监督学习解决的就是这个问题:利用大量无标注数据来提升模型的泛化能力,让模型在没有额外标注的情况下,把分类边界学得更准。

它的适用人群也很明确:手里有少量干净标注数据、同时有大量无标注数据、但预算不足以继续扩标注集的工程师和研究者。如果你已经有十万张完美标注的数据,那直接走监督学习就行,半监督的收益边际不大。反过来,如果标注只有几百张、每类几十张,半监督几乎是你成本最低的提点手段。

1.2 半监督到底在学什么:三个基础假设

要理解半监督学习,必须弄明白它依赖的三个前提假设。这些假设既是方法有效性的来源,也是翻车的原因。

第一个是聚类假设。同类样本在特征空间中应当彼此靠近。如果两个样本的特征表示很接近,那它们的类别大概率相同。模型可以利用无标注数据来感知这种聚集结构,让决策边界更贴合数据分布。

第二个是平滑假设。在数据分布的高密度区域,决策边界应当是平滑的。也就是说,对特征空间中的某个样本做小扰动,其预测结果不应发生剧烈变化。这给了半监督方法一个操作抓手:让模型对“变形后的同一张图”也保持稳定输出。

第三个是低密度分离假设。不同类别之间的决策边界应该穿过数据密度较低的区域。如果模型能把大量无标注样本分到明确的类别簇中,而类别之间的空白地带没有样本,那说明分类边界大概率是对的。

这三个假设用大白话讲就是:长得像的应该归一类、换了个说法意思不变、类别中间最好留出空地。所有半监督方法,本质上都是在用不同方式让模型满足这些假设。

1.3 三条技术路线和我的选型建议

目前图像分类半监督主流有三条技术路线。

第一条是一致性正则,代表思路有 Π-Model、Temporal Ensembling、Mean Teacher。核心做法是对同一个输入做两次不同的随机增强,要求模型输出一致。这种方式不依赖伪标签,但收敛慢,对增强策略敏感。

第二条是伪标签法,也就是自训练。先用标注数据训练一个模型,对无标注数据预测出伪标签,挑高置信度的样本加入训练集,迭代循环。实现简单,但存在确认偏差问题,模型一旦预测错了,错误会反复自我强化。

第三条是混合方案,把两者结合起来,比如 FixMatch 这类思路。弱增强生成伪标签,强增强输入模型训练,两者用同一个模型。现在学术界和工业界的基线基本都锚定这一方向。

我的实际选型建议是:如果无标注数据量很大、但标注数据每类只有几十张,优先尝试混合方案,性价比最高。如果标注数据稍微充足一些但计算资源有限,一致性正则也够用。伪标签法最容易实现,但必须要配高置信度阈值和较强的数据增强,否则很容易训练崩。

2. 关键方法拆解:一致性正则与伪标签是怎么干活的

2.1 一致性正则的直观理解与损失设计

一致性正则的思想非常朴素。你给模型看一张猫的照片,模型说这是猫;你把照片水平翻转、轻微裁剪、调一下亮度,再让模型看,模型还是应该说这是猫。对无标注数据来说,我们不知道它到底是什么类别,但我们知道:同一张图的不同增强版本,类别一定相同。

这个约束落到损失函数上,就是让模型对两个增强版本的预测分布尽量一致。常见的做法是算两个预测分布之间的 KL 散度或交叉熵。以 Mean Teacher 思路为例,一个学生模型做梯度更新,一个教师模型用学生权重的指数移动平均来维护,训练时让学生模型的预测去逼近教师模型的预测,同时学生模型也接受有标注数据的监督损失。教师模型的输出比单次预测更稳定,相当于给学生提供了更可靠的学习目标。

实操中有一个需要注意的点:一致性正则的损失权重不能从一开始就拉满,否则模型还没学好特征就先被“一致性”给僵住了。我常用的做法是前若干个 epoch 让监督损失主导,无监督损失权重从一个很小的值逐渐上升到目标值,类似一个升温过程。

2.2 伪标签的流程、阈值与确认偏差

伪标签法就更好理解了。模型先在标注数据上学出初始能力,然后对无标注数据做预测,把置信度高的预测结果当作“伪标签”加入训练。听上去很简单,但这里有个致命的坑:确认偏差。

模型对某个样本如果第一次就预测错了,而且置信度还很高,那么把它当伪标签训练,等于把错误再教一遍。等到下一轮迭代,模型对这类样本的错误倾向会更强。几轮下来,模型就彻底被自己带偏了。

应对确认偏差的手段主要是两个方向。一是设置高置信度阈值,比如只有 max 概率超过 0.95 的伪标签才参与训练。阈值高,虽然会丢掉很多候选样本,但留下的伪标签整体可靠性更高。二是增加伪标签的噪声容忍度,比如把硬标签改成软标签,用模型预测的概率分布直接做监督信号,这样即使预测不完全正确,梯度也不至于太“狠”。我在实际操作中通常先用高阈值跑通一个版本,再考虑软标签变体。

2.3 为什么最终选 FixMatch 思路而不是 Mean Teacher 或 MixMatch

我在项目里最终采用的是 FixMatch 这一类混合思路。它的关键设计是:对无标注图片打两次增强,一个弱增强、一个强增强。弱增强版本送入模型,得到预测分布,取 argmax 和对应的置信度;如果置信度超过阈值,就把这个 argmax 当作伪标签;然后用强增强版本作为输入,让模型预测去拟合这个伪标签。整个过程只有一个模型、一份无监督损失,实现起来非常干净。

这里弱增强和强增强的分工特别关键。弱增强的目的是生成相对可靠的伪标签,所以扰动幅度要小,不能让模型“看花了眼”。强增强的目的是让模型在更大的数据扰动范围内保持稳定,所以要足够“狠”,逼模型去学习真正的语义特征而不是浅层的像素模式。我测试下来,弱增强通常用随机水平翻转和裁剪,强增强用 RandAugment 或 AutoAugment 加 CutOut,效果比较稳。

为什么不选 Mean Teacher?因为双模型结构训练成本高,且 EMA 更新需要额外调参,收敛速度慢。为什么不选 MixMatch?它用了多个增强分支和标签锐化,性能不错但复杂度高,工程上维护成本偏高。FixMatch 思路在效果和实现复杂度之间最平衡,特别适合这类“标注少、无标注多”的真实场景。

方法思路核心机制优点代价
一致性正则(Mean Teacher)学生模型逼近 EMA 教师输出目标稳定,无需伪标签训练慢,双模型成本高
伪标签(Self-training)高置信度伪标签自举实现简单,直接确认偏差风险高
混合方案(FixMatch)弱增强生成标签,强增强训练效果好,实现干净对增强策略和阈值敏感

3. 实操过程:从数据准备到训练收敛

3.1 数据划分与增强策略

我拿一个公开的十类图像数据集举例,类别数不多,比较典型。假设每类只有 40 张标注图,总共 400 张标注数据,另有 4 万张无标注数据。先把标注集按 8:2 切出训练子集和验证子集,无标注数据不参与验证和测试集划分,因为它的分布和标注集可能有偏移,拿它做评估会虚高。

数据加载时,我把一个 batch 设计成两部分:一部分是标注样本,另一部分是无标注样本。比如每个 batch 包含 64 张标注图和 64 张无标注图,无标注图又同时生成两个版本:弱增强版本和强增强版本。这样一次前向计算就能同时拿到监督损失和无监督损失所需的全部输入。

弱增强我用随机水平翻转加随机裁剪后缩放回原尺寸,这是图像分类里最常见的组合。强增强我用 RandAugment,配合 CutOut。RandAugment 的幅度和操作数可以调整,我常用幅度 10、操作数 2 起步,如果发现无监督损失下降困难,再把幅度调小。CutOut 遮蔽的像素块大小在 16 到 32 之间,具体看图像分辨率。

3.2 损失函数、采样配置与训练超参

整体损失函数就是三部分相加:监督交叉熵损失、无监督伪标签交叉熵损失和一个权重系数 λ。无监督损失只在高置信度 mask 为真的样本上计算,这样做的本质是对伪标签做了一次筛选。

参数设置方面,我给出一套经过多次实验验证的初始配置:

  • 优化器:SGD,momentum 0.9,权重衰减 5e-4
  • 学习率:0.03,带 5 个 epoch 的线性 warmup,之后 cosine 衰减
  • 总训练轮数:200 epoch
  • 无监督损失权重 λ:前 20 个 epoch 从 0 线性升到 1,之后保持 1
  • 高置信度阈值:0.95
  • batch 构成:64 张标注图 + 64 张无标注图(含强弱两个版本)
  • EMA:对模型参数做指数移动平均,decay 0.999,用于最终评估

这里有个容易忽略的点:无标注样本的批次大小不要太少。半监督的效果依赖无标注数据的多样性,batch 太小会导致伪标签分布不稳定,训练震荡。如果有显存余量,我建议无标注部分至少和标注部分一样大。

3.3 核心训练伪代码

我按 PyTorch 风格整理一份核心训练逻辑,把关键部分做了精简,方便理解整体流程:

for step, batch in enumerate(loader): # batch 包含:标注图像、标注标签、无标注弱增强、无标注强增强 x_l, y_l, x_u_w, x_u_s = batch # 1. 监督损失 logits_l = model(x_l) loss_s = ce_loss(logits_l, y_l) # 2. 无监督损失,先获取弱增强的预测结果 logits_u_w = model(x_u_w) probs_u_w = softmax(logits_u_w, dim=1) conf, pseudo_label = torch.max(probs_u_w, dim=1) # 3. 高置信度样本的 mask mask = (conf >= threshold).float() # 4. 强增强版本的预测与伪标签做交叉熵 logits_u_s = model(x_u_s) loss_u = ce_loss(logits_u_s, pseudo_label, reduction="none") loss_u = (loss_u * mask).sum() / mask.sum().clamp(min=1.0) # 5. 总损失 loss = loss_s + lambda_u * loss_u optimizer.zero_grad() loss.backward() optimizer.step()

这条逻辑里最关键的就是 mask 的操作,它直接决定了无监督哪些样本的反向传播是激活的。我见过有人直接把所有样本的无监督损失都算进去,结果低置信度样本的噪声把模型带崩了。mask 的作用等价于只让模型在“自己比较有把握”的样本上吸收信息,其余样本干脆忽略。

3.4 评估、模型保存与监控指标

训练过程中我保留一份单独的标注验证集,每个 epoch 结束后用 EMA 模型跑一次验证集准确率。EMA 模型的作用是平滑震荡,它的准确率通常比原始模型稳定不少,也更适合作为最终的预测版本。

监控指标我会同时记录四类信息:监督损失值、无监督损失值、伪标签启用比例(即 mask 的平均值)、验证集准确率。伪标签启用比例是一个特别有用的早期预警信号。如果阈值设得太高,可能大部分无标注样本都被过滤掉了,导致无监督损失几乎不更新,整个半监督分支形同虚设。如果这个比例长期在 90% 以上,说明阈值设得太低,伪标签噪声已经被大量注入。

模型保存方面,我一般不只存最后一轮权重,而是存验证集准确率最高的 EMA 权重快照。这比“跑到最后一个 epoch 就收工”要稳得多,因为训练后期往往有些震荡,峰值往往在最后几轮之前。

4. 常见问题与排查技巧实录

4.1 无监督损失不下降,模型根本不收敛

这个现象通常有两种表现。一种是无监督损失持续停在某个固定值附近波动,另一种是验证集准确率反而比纯监督基线还低。我排查的顺序如下。

先看伪标签启用比例。如果低于 10%,说明高置信度阈值挡住了绝大多数样本。原因可能是模型本身还没学到足够强的特征,或者强增强太猛导致预测分布普遍低置信度。解决方法是把阈值从 0.95 降到 0.9 甚至 0.8 试一下,同时把 RandAugment 的幅度调低。

再看学习率。半监督训练对学习率比纯监督更敏感,学习率过大时模型很快震荡,过小时无监督信息根本推不动模型。我在实际项目中碰到的多数情况是学习率偏大,SGD 配 0.03 只是一个起点,如果你用的是 Adam,建议从 1e-3 往下调。

最后确认无监督数据分布是否和标注数据差距太大。如果无标注数据里混入了大量不属于任何目标类别的图片,伪标签无论怎么筛选都学不到有效信息。这时候需要先对无标注数据做一轮清洗或聚类,把离群部分剔除。

4.2 伪标签噪声太大,模型被自己带偏

这里说的噪声大,不是指置信度阈值低,而是即使置信度很高,预测结果依然是错的。高频类别尤其容易出现这种现象:模型对“狗”这类样本见得多了,把一些背景相似但不属于狗的图片也高置信度地标成狗。伪标签和真实标签不一致,又互相强化,就是典型的确认偏差。

我的处理策略有三层。第一层是提升数据增强强度,让强增强真正制造出足够的扰动,逼模型必须依赖语义特征而非纹理背景。第二层是临时冻结监督分支:先用纯监督损失训练 10 到 20 个 epoch,让模型初步收敛,再打开无监督分支。不要一开始就让两个分支同时优化,否则噪声会污染早期特征学习。第三层是把硬伪标签换成软标签,即用模型的预测概率分布作为监督目标,而不是只取 argmax,这样可以在一定程度上缓解错误标签的“过度自信”。

如果上述手段都不理想,还可以试试改变伪标签的产生方式:用一个 EMA 模型的输出来生成伪标签,而不是用当前快速更新的模型。EMA 模型变化慢,输出目标更稳定,能明显降低噪声波动。

4.3 显存翻倍与训练时间变长的问题

半监督训练相比纯监督训练,最直接的工程代价就是多了一路强增强输入。每个 batch 里无标注数据需要同时保存弱增强和强增强的中间特征,显存占用几乎翻倍。训练时间也会因此变长。

我的处理经验是分三步优化。第一步是混精度训练,模型前向和反向用 FP16 计算,损失计算保留 FP32,显存和速度都能明显改善。第二步是调整 batch 构成,不一定非得标注和无标注各 64,可以把标注压到 32、无标注保持 64,这样显存压力小一些,整体效果损失不大。第三步是如果实在显存不够,就把无监督损失改成每隔一个 step 计算一次,相当于把无监督更新的频率减半,虽然训练速度会变慢,但至少能跑起来。

这里还要提醒一句:不要把无标注数据全部一股脑塞进内存再预处理。最好用在线增强,让 GPU 边训练边处理,否则数据 IO 会成为新的瓶颈。我头几次实验时直接在磁盘上预生成全部强增强版本,结果磁盘读写把训练速度拖垮了一半。

4.4 类别不平衡时半监督反而拖后腿

如果你标注数据里的类别分布不是均匀的,比如 A 类有 200 张、B 类只有 20 张,半监督的收益会明显下降,甚至比纯监督还差。原因是模型会在高频类别上先形成高置信度的伪标签,这些伪标签数量多,在无监督损失里占比大,导致模型向高频类偏移,低频类几乎学不到。

针对这种情况,我采取两个办法。一是对每个类别单独计算置信度阈值,而不是用全局同一个阈值。高频类可以设 0.95,低频类降到 0.8,让低频类也有机会产生伪标签参与训练。二是无监督损失按类别做重加权,计算每一类的样本数,用类频率的倒数对损失加权,避免高频类主导梯度更新。

还有一个比较取巧的做法:先统计无标注数据在所有类别上的预测分布,如果发现某些类几乎没有无标注样本被选中,直接手动对那些类别的伪标签阈值做退火,从 0.95 阶梯降到 0.7。这样虽然会引入一部分噪声,但至少让低频类别在训练中“有存在感”。我试过之后,低频类的单类准确率提升明显,整体平均准确率也涨了。

5. 几个工程上的心得判断

5.1 半监督不是万能药,什么时候用它收益最大

经过这个项目,我对半监督学习的适用边界有了更清晰的认识。它最适用的场景是:标注数据极度稀缺,每类几十张甚至更少,同时无标注数据量大且分布与标注集基本一致。在这种情况下,半监督能带来从 70% 到 85% 量级的提升,几乎等于免费标注。

但如果标注数据已经比较充足,比如每类超过几百张,半监督的提升就明显减弱。这时候与其花时间调半监督参数,不如把算力留给数据清洗或更强的网络结构。另外,如果无标注数据本身噪声极大,包含大量无关类别或重复图片,收益也会缩水,需要先做一轮去重和过滤。

从资源分配角度看,我现在的习惯是先跑一个纯监督基线,如果准确率已经超过 90%,半监督基本不用碰。如果准确率只有 75% 以下,半监督就值得全力投入。在标注和无标注的比例上,我一般要求无标注量至少达到标注量的 50 倍以上,不然收益不明显。

5.2 如果还想再进一步,值得尝试的方向

这套流程稳定跑通之后,有几条扩展路径可以明显再拔高效果。

一条是把半监督和预训练特征结合。现在很多图像模型都用大规模无监督预训练初始化,把初始化权重换成预训练模型,再叠加伪标签训练,收敛速度更快,最终准确率也更高。我测试过用预训练初始化的半监督训练,相比随机初始化,最终准确率能再涨两到三个点。

另一条是引入更强的数据增强策略。RandAugment 的幅度调参范围很宽,如果进一步搜索幅度和操作数的组合,或者在强增强里加入更激进的裁剪策略,无监督损失能提供更强的正则化信号。

还有一条是和主动学习结合。先用半监督模型对无标注数据打分,挑出置信度最低、模型最“不确定”的样本去做人工标注,再把新标注的样本加入标注集继续训练。这样标注人力极少,但标注的目标样本价值非常高,形成了一个小成本高收益的闭环。

结尾

我个人在实际操作中的体会是:半监督不应该被当成一个花哨的学术技巧,而是当作一种免费的“数据扩充”手段。先用小规模数据快速跑通纯监督基线,确认模型架构和增强策略没有大问题,再启动半监督分支,按照三件事来检查:监督损失是否正常下降、无监督损失是否有效更新、伪标签启用比例是否维持在一个健康的区间。

最后再分享一个小技巧:训练过程中每 100 步打印一次无标注样本的置信度均值,也就是所有无标注样本 max 概率的平均值。它比 loss 值更能反映训练动态。如果这个均值一直低于 0.7,说明增强太强或阈值太高,模型根本没有从无标注数据里学到任何东西,趁早调整,别等训完一轮再回头看。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询