做机器学习项目做到后期,我越来越觉得:真正卡住进度的往往不是模型结构,而是标注数据不够。项目拿到手,业务方拍着胸脯说"数据多得很",等你打开文件夹一看——原始样本确实成千上万,但带标签的能用数据可能就几百条。剩下的时间全耗在拉标注、对答案、清洗不一致的标签上。半监督学习(semi-supervised learning)解决的正是这个痛点:它允许我们用少量有标签数据 + 大量无标签数据一起训练模型,让模型自己从无标注样本里挖掘结构信息,把标注成本压下来。
这篇文章不打算堆公式,而是按照"它能解决什么问题 → 主流算法各自什么原理 → 实际训练流水线怎么搭 → 哪些业务场景值得上 → 我踩过的坑"这个顺序来讲。适合正被标注成本折磨、又想搞清楚半监督到底怎么落地的朋友,也适合刚接触这个概念、想系统了解算法全貌的初学者。我会把每个方法的核心逻辑讲透,再补上实际项目里才碰得到的调参细节和翻车经验,保证你能直接拿去用。
1. 标注瓶颈与半监督的破局思路:先搞懂它在解决什么
1.1 一个我亲历的项目:百万张图像,最终只有两百张标注
去年我接了一个工业质检项目,产线拍照设备一天能产出几十万张零件图像,一个月下来上百万张轻松达成。听起来数据量大得吓人,可真正到训练模型时才发现,缺陷样本的标注得靠老师傅人工框选,一个老师傅一天最多处理三五百张。项目拖了一个多月,带精确标注的图片也就两百来张,模型的召回率完全没法看。
这个场景太典型了。有标签数据贵、慢、稀缺,无标签数据便宜、快、泛滥,这中间的落差就是半监督学习的机会。半监督的思路非常直白:既然模型能从有标签数据里学到判别能力,那能不能让它先用这点能力去"看"无标签数据,再把无标签数据反哺回来,形成一个自我强化的循环?答案是可以,但要看清楚它的前提条件。
1.2 三个核心假设:平滑性、聚类结构、低密度分隔
半监督学习之所以能成立,不是因为算法有多玄,而是数据本身存在结构规律。几乎所有半监督方法都建立在三个基本假设上:
- 平滑性假设:特征空间中距离相近的样本,大概率属于同一类别。也就是说,决策边界应该在数据分布上"平滑"地变化,而不是剧烈震荡。
- 聚类假设:同一类别的样本在特征空间里会聚成一团,类与类之间存在天然的低密度区域。无标签数据可以帮助我们更准确地画出这些"团"的边界。
- 流形假设:高维数据其实分布在一个低维流形附近,样本点之间的远近关系应该用流形上的距离来衡量,而不是欧氏距离。
理解这三个假设特别重要,因为后面讲的所有算法,本质上都是在用某种方式利用这些结构。比如伪标签方法是在利用聚类假设:高置信度的无标签样本很可能落在某个类别团内部,所以模型给它打的标签可以当作真实标签用。一致性正则化是在利用平滑性假设:对样本做微小扰动,预测不应该剧烈变化。
如果数据本身不满足这些假设,半监督学习不仅帮不上忙,还会拖垮模型。判断数据是否适用,我习惯做一个小实验:先只用有标签数据训练一个baseline,然后用t-SNE或者UMAP把有标签和无标签数据一起投影到二维,肉眼看类别是不是明显分团、无标签数据是不是穿插在团中间。如果类别边界糊成一锅粥,那后面再怎么调半监督算法都是白费力气。
1.3 半监督与有监督、无监督、弱监督的分工与边界
很多人会把半监督学习和无监督学习、弱监督学习搞混,我在这里把边界理清楚。
有监督学习只使用有标签数据,要求每条样本都有对应标签,成本最高,效果上限也最依赖标签质量。无监督学习完全不用标签,目标是发现数据内在结构,比如聚类、降维、生成模型,它不直接预测类别。半监督学习站在中间:一部分数据有标签,一部分没有,训练时两者都用,目的是利用无标签数据提升有监督任务的性能。
弱监督学习则是另一个维度,指的是标签来源不那么可靠或者不那么精细,比如用规则、远程监督、众包等方式产生的标签,可能有大量噪声,或者只有粗粒度的标注。
做项目时,这几种方法不是互相排斥的。我比较推荐的分层思路是:先看看有没有几条干净的标注,有的话就做半监督的种子;如果完全没有任何标注,那就先做无监督聚类或者自监督预训练,再配合一小部分人工标注来校准类别含义。简单说,半监督解决的问题是"少量标注+大量无标注",而不是"零标注"。
2. 主流半监督算法的技术路线与选型逻辑
半监督学习经过几十年发展,形成了好几条技术路线,各有各的适用场景。这一节我按原理类别拆开讲,最后给出一张对比表帮你选型。
2.1 自训练与伪标签:原理简单,但阈值调节才是灵魂
自训练(self-training)是最经典的半监督方法,思路极其朴素:先用有标签数据训练一个模型,然后用这个模型给无标签数据打预测,把高置信度的预测结果作为伪标签(pseudo-label)加入训练集,再重新训练,不断迭代。
Python
# 伪标签训练的简化流程 labeled_loader = DataLoader(labeled_data, batch_size=32, shuffle=True) unlabeled_loader = DataLoader(unlabeled_data, batch_size=64, shuffle=True) model = init_model() # 第一阶段:有监督热启动 for epoch in range(warmup_epochs): for x, y in labeled_loader: loss = supervised_loss(model(x), y) loss.backward() optimizer.step() # 第二阶段:伪标签迭代 for round in range(ssl_rounds): pseudo_labels = [] model.eval() with torch.no_grad(): for x in unlabeled_loader: logits = model(x) conf, pred = torch.max(torch.softmax(logits, dim=-1), dim=-1) # 只保留置信度超过阈值的样本 mask = conf > threshold pseudo_labels.append((x[mask], pred[mask])) # 合并有标签数据与伪标签数据,继续训练 combined_loader = build_loader(labeled_data, pseudo_labels) train_one_epoch(model, combined_loader)这里最关键的参数是置信度阈值。阈值设得太低,大量错误预测会被当成标签喂给模型,错误信息不断累积;阈值设得太高,能用的无标签样本太少,半监督等于没做。我在实际项目中,一般会从0.8起步,根据验证集效果上下调整。另外,不同的类别建议用不同的阈值——模型对高频类别的置信度普遍偏高,对低频类别普遍偏低,一刀切会加剧类别不平衡。
伪标签方法最大的优点是实现成本低,任何有监督模型都能套上去。但它也是翻车概率最高的方法,因为模型一旦在某个区域犯了系统性错误,伪标签会把这个错误放大,下一轮训练时模型更确信错误答案,形成恶性循环。这个问题在学术界被称为确认偏误(confirmation bias),后面实战部分我还会专门讲。
2.2 协同训练:利用多视角信息的经典方案
协同训练(co-training)是另一个经典思路,它的前提是特征天然可以分成两个或多个视角(view),每个视角都足以单独训练一个分类器。比如网页分类任务中,网页正文是一个视角,页面上的锚文本链接是另一个视角;再比如医疗数据里,影像特征和结构化检验指标也可以看作两个视角。
方法的流程是这样的:用有标签数据分别训练两个分类器A和B。训练完后,A挑出它最有把握的无标签样本并打上预测标签,加入B的训练集;B也挑出它最有把握的样本加入A的训练集。如此交替迭代,两个分类器互相喂数据,像两个交换笔记的学生,各自把自己擅长的知识教给另一个。
这种"双人互教"的设计有个天然的防错机制:如果两个视角确实独立且充分,A的错误和B的错误相关性很低,那么A自信预测且B也认同的样本,标签可信度就比较高。所以在实际使用中,除了把A的可信样本交给B,我还会把A和B预测一致的样本单独筛出来,作为高质量伪标签直接加入联合训练,这种样本的准确率往往比单一模型的伪标签高不少。
不过协同训练的限制也很明显:现实中很多数据并没有真正独立的视角。硬把一个特征向量劈成两半并不能保证独立性,强行拆分反而会让每个分类器变弱。所以协同训练现在的使用频率不如以前,但在多模态数据和图数据的某些场景中依然有不可替代的价值。
2.3 一致性正则化与教师-学生架构:当前效果最好的一类
如果说伪标签是半监督里的"老黄牛",一致性正则化(consistency regularization)就是当下的主力军。它的核心思想特别优雅:同一个样本,经过不同的增强变换后,模型对它的预测应该保持一致。
原理上,这是把前面说的平滑性假设直接转化成了训练目标。比如一张猫的图片,稍微旋转、裁剪、调亮度后依然是猫,模型不应该因为这种无损扰动就改变预测。对无标签数据来说,我们无法要求预测结果等于某个确定的标签,但可以要求它等于"模型自己对增强后样本的预测"。
在这个框架下诞生了几个重要方法。时序集成模型(Temporal Ensemble)会把历史预测做滑动平均作为软标签。Mean Teacher用教师模型和学生模型两个网络,教师网络的权重是学生网络权重的指数移动平均(EMA),学生网络学习教师网络给出的预测。
Python
# Mean Teacher / FixMatch 风格的一致性训练核心逻辑 teacher = copy.deepcopy(model) # 教师模型,权重为EMA ema_decay = 0.999 for batch in loader: labeled_x, y = batch["labeled"] unlabeled_x = batch["unlabeled"] # 有监督损失:只在有标签数据上计算 sup_loss = criterion(student(labeled_x_weak), y) # 一致性损失:弱增强生成伪标签,强增强要求输出一致 pseudo_logits = teacher(unlabeled_x_weak) pseudo_conf, pseudo_label = max_softmax(pseudo_logits) consistency_loss = ( masked_cross_entropy( student(unlabeled_x_strong), pseudo_label, mask=pseudo_conf > threshold ) ) total_loss = sup_loss + lambda_u * consistency_loss # 更新学生权重后用EMA软更新教师 student.step() teacher_weights = ema_decay * teacher_weights + (1 - ema_decay) * student_weights这个方案之所以效果好,是因为它同时用上了两个强大的机制:一是强/弱增强的一致性约束,让模型在扰动下依然稳定;二是伪标签的置信度过滤,保证反馈给模型的信息总体是干净的。FixMatch就把这两个机制结合得很好,弱增强的数据用来生成伪标签,强增强的数据用来计算损失,伪标签只在置信度超过阈值时才生效。UDA则在无标签损失中加入了对数几率比率(logit ratio)的锐化操作,进一步提升标签的确定性。
我自己的使用体感是:在图像分类、文本分类这类任务上,一致性正则化类方法通常比单纯伪标签方法高出5到10个百分点的准确率。代价是训练开销更大,因为每个批次都要对无标签数据做多次增强前向计算,GPU显存和训练时间都要预留余量。
2.4 图标签传播:小样本高维数据的另一种选择
图方法(graph-based methods)是半监督学习里非常独特的一支,它把全部数据(有标签+无标签)看成一张图上的节点,节点之间的边权重衡量样本之间的相似度,然后让标签沿着图的边传播。
最经典的是标签传播算法(Label Propagation)。初始时,有标签节点的标签是已知的,无标签节点的标签是未知的,然后迭代更新:每个节点的标签根据邻居节点的标签按边权重加权平均。这个过程可以理解为信息在图上"扩散",直到收敛。
我记得以前实验室前辈用这个方法做文本分类,当时只有50条标注,但有几万条未标注的新闻语料。他们构建了"句子-词语"二部图,通过词语作为桥梁让标签在相似句子之间传播,效果竟然比当时主流的深度模型还好。这就是图方法的魅力——不需要训练复杂的参数,一张构造得当的图就能高效利用未标注数据。
图方法的缺点是计算复杂度高,一张包含百万节点的图,邻接矩阵存不下,必须用稀疏表示和近似算法。此外它对图的构造方式非常敏感,用什么相似度度量、怎么截断连接、边权重怎么归一化,都需要针对数据反复调试。所以它更适合中小规模数据,或者作为深度模型的辅助正则化手段。
2.5 方法对比表与选型建议
到现在为止,几个主流方向都过了一遍,我把它们的核心特征整理成一张表:
| 方法 | 核心原理 | 主要优势 | 主要限制 | 推荐场景 |
|---|---|---|---|---|
| 自训练/伪标签 | 用模型预测给无标签数据打伪标签 | 实现简单,全模型通用 | 确认偏误,需要精细调阈值 | 标注极少的中低难度任务 |
| 协同训练 | 多视角分类器互相标注 | 双模型互纠,错误相关性低 | 依赖视角独立性,难迁移 | 多模态或多源特征数据 |
| 一致性正则化 | 增强扰动下输出保持一致 | 效果好,上限高,稳定 | 训练开销大,实现复杂 | 图像/文本分类的主流选择 |
| 图标签传播 | 标签沿样本相似图扩散 | 无需复杂训练,可解释 | 计算量大,图构造敏感 | 中小规模高维数据 |
| 生成式方法 | 用生成模型建模联合分布 | 理论优美,可生成样本 | 训练不稳定,收敛慢 | 有强生成先验的领域 |
我选型时的决策逻辑很简单:先看数据规模,如果无标签数据超过10万条,我倾向于用一致性正则化类方法,因为它对结构的利用效率最高;如果数据规模在几千到几万,图方法或者伪标签往往更省事;如果特征天然多视角,协同训练值得一试;如果标注少得可怜(几十条),任何半监督方法都可能不稳定,我会先做有监督baseline再考虑是否硬上半监督。
3. 半监督训练的标准流水线:从数据准备到模型评估
选好算法只是第一步,真正让项目跑起来的是工程流水线。这一节我把自己的标准做法完整复盘一遍,每个环节都附上需要注意的细节。
3.1 数据划分:有标签集、无标签池、验证集怎么切
很多人做半监督项目时,随手把少量标注划成训练集,剩下的标注全拿去当验证集,这种做法在数据量小的时候没什么大问题,但一旦标注数量过少,验证集就失去统计意义。
我的划分原则是:
- 有标签数据必须再拆成训练子集和验证子集,验证子集只能用于观察训练状态和选择超参,绝不能直接进入训练。
- 如果想评估半监督算法相对纯监督baseline的真实提升,还要从标注数据里预留一个"最终测试集",这个集合从头到尾不参与任何训练和调参,只在最后跑一次。
- 无标签池要有意识地和标注数据从同一时间窗口、同一来源渠道采集。如果无标签数据来自另一个渠道,分布差异会让半监督方法失效,这一点在第四节会展开讲。
具体比例方面,我习惯把标注数据按照70%训练、15%验证、15%测试来切。如果标注总数只有200条,那测试集30条确实有点少,这种情况下宁可牺牲一些训练数据,也要保证测试集至少有50条,否则模型的评估结果方差太大,根本无法判断半监督有没有带来真实提升。
3.2 先有监督热启动,再进入半监督循环
半监督训练不是一个从零开始的过程。绝大多数半监督方法都要求一个还不错的初始化模型,如果直接用随机初始化的模型去给无标签数据打伪标签,打出来的标签基本等于随机噪声,整个训练过程只会原地打转。
所以我的流程是:先用有标签训练子集做充分的有监督训练,直到验证集准确率不再明显提升。这个阶段的目标不是达到最终效果,而是让模型先学会最基本的判别能力,比如至少能把高频类别和低频类别区分开。热启动完成后,再把无标签数据接入训练,半监督损失的比例(即lambda_u)从0逐步增大,给模型一个适应期。
关于学习率,我有一个经验值:进入半监督阶段后,学习率应该比热启动阶段降低一到两个数量级。因为此时无标签数据的损失会对参数产生大量梯度信号,学习率太高会导致loss震荡甚至崩溃。我见过不少团队直接把有监督阶段的学习率沿用到半监督阶段,结果伪标签损失把模型权重推飞了。
3.3 伪标签筛选与课程式学习的调参要点
伪标签不是拿来就用的,筛选策略直接决定训练质量。除了前面说的置信度阈值,还有几个细节值得注意:
- 课程式伪标签:训练早期使用较高的置信度阈值,确保加入的伪标签高度可靠;随着训练进行,模型能力增强,再逐步降低阈值,让更多样本参与进来。这个思路很像教小孩做题,先练一定会做的题建立信心,再逐步增加难度。
- 类别均衡采样:如果无标签数据里某个类别的样本特别多,伪标签也会集中在那个类别,导致训练集类别比例严重失衡。解决办法是每个类别单独设阈值,或者对伪标签样本按类别做上限控制。
- 软化标签 vs 硬标签:硬标签(one-hot)训练效率高,但错误一旦发生就是完全错误;软化标签(soft label,直接使用概率分布)能保留不确定性,梯度更平滑。我通常在训练初期用软标签,后期切换为硬标签,这样兼顾稳定性和收敛速度。
Python
# 课程式阈值调整 def get_current_threshold(epoch, max_epochs, start_threshold=0.9, end_threshold=0.7): progress = epoch / max_epochs # 线性退火 return start_threshold - (start_threshold - end_threshold) * progress3.4 评估陷阱:验证集选择与"半监督是否真的有效"的判断方法
半监督项目最大的评估陷阱,是用有标签训练子集反复迭代模型,然后看模型在训练子集上的loss——这么做没有任何意义,因为伪标签和模型预测高度相关,loss下降可能只说明模型在自我确认。
正确做法有两个铁律:第一,所有超参选择都只看独立验证子集的指标;第二,最终的结论必须由从未参与训练的测试子集给出。如果测试子集上,半监督模型相对纯监督baseline的提升超过2个百分点,我才认为这个方法真的起作用了;如果只是持平甚至下降,我会停下来排查数据分布问题和伪标签质量,而不是简单地去调更大的lambda_u。
另外我建议做一个"无监督baseline"对照:直接用无标签数据做自监督预训练(比如对比学习),下游再在有标签数据上微调。这个baseline能帮你分清楚性能提升到底是来自"无标签数据的表示学习",还是来自"半监督的标签传播机制"。如果自监督预训练+baseline就已经追平了半监督模型,说明你的任务本质上是表示学习问题,半监督标签这部分只是锦上添花,不值得为此投入更多工程成本。
4. 真实场景应用:哪些业务适合上、哪些不适合硬上
半监督不是万能药,落地前一定要认清楚业务场景。我总结了几类天然适合半监督的行业场景,也列出了一些不适合硬上的情况。
4.1 医疗影像:稀缺的是专家标注,不缺的是历史影像
医疗影像是最典型的半监督场景之一。某三甲医院的影像科一天产生几千张CT、MRI片,但能给出像素级标注的专家时间极其有限。更麻烦的是,医疗标注还涉及隐私保护和多专家一致性校验,一条高质量标注的成本高得惊人。
这类场景中,无标签影像数据天然是现成的,模型可以先从有标签的数据学会病灶的基本形态,再通过一致性正则化在海量无标签影像中确认"这个区域看起来像不像病灶"。比较成熟的应用包括肺结节检测、眼底图像分类、病理切片辅助判读。我做过的某医疗AI团队项目里,通过半监督把需要标注的样本量压到了原来的十分之一,模型在独立测试集上的AUC还能稳住不降。
4.2 工业质检与安防视觉:用海量无标注产线数据压低误检率
开头我提的工业质检项目就是很好的例子。产线上拍下来的图片大部分是良品,带缺陷的样本本来就少,加上缺陷种类多、形态差异大,标注成本很高。如果把无标签产线图像一股脑全扔进有监督模型,模型只会学到"这些全是良品",然后漏掉所有缺陷。
半监督的玩法是:先让模型在有标签数据上学会"正常-异常"的基本区分,然后利用无标签产线图的预测置信度做异常分数估计。如果一个无标签样本的预测概率离决策边界很近,就说明这是模型知识盲区,优先安排人工复核。这样产线只需要标注模型"看不懂"的样本,标注量能少一个数量级。安防场景里,陌生人脸聚类、行为识别也可以走同样的思路:海量监控视频没有标注,但模型可以先学"这个小区的常见人脸长什么样",再挑出偏离的样本交给安保人工判断。
4.3 风控反欺诈与异常交易识别
风控场景有个特点:欺诈样本极度稀缺,正常样本多到爆炸,而且欺诈模式不断演变,旧标签很快就过时了。这里半监督的用法和图像不太一样,更常用的是图的标签传播思路。把用户、交易、设备、IP等实体建成异构图,欺诈标签从少数已确认的黑样本出发,沿着交易关系、设备关联传播到可疑账户。
这套做法的原理是:欺诈行为通常有聚集性,一个已确认欺诈的账户,它高频交易的另一个账户大概率也有问题。半监督图传播可以快速找出这种"危险邻居"。当然,图传播出的结果只能作为风控候选名单,最终还需要人工核实,但它能把排查范围从百万级缩小到几千级,效率提升非常明显。
4.4 文本意图分类与企业知识库
NLP领域里,半监督的应用同样广泛。客服机器人需要识别用户意图,但每次上线新的业务线,能用的历史对话标注往往只有几十条。这时候可以把历史海量对话当作无标签数据,先用带标注的对话训练一个意图分类器,再对无标签对话打伪标签,让模型自行扩充理解范围。
我做过一个企业知识库问答项目,当时只有120条高意图标注数据,再加上两万多条历史咨询记录。用一致性正则化训练了一个轻量级文本分类器,最终在测试集上准确率达到88%,而只使用120条标注训练的模型只有71%。有意思的是,这两万条无标签数据里其实混着大量噪声(广告、闲聊、乱码),但一致性正则化方法天然对这类噪声有韧性,因为每个样本都要经过两次不同增强并保持输出一致,偶发的乱码不会形成稳定梯度。
4.5 语音与音视频内容理解
语音识别和音视频理解也有半监督的一席之地。语音识别里,大量音视频只有语音没有转写文本,用无监督/半监督方式先从有标注语音学会声学模型,再对无标注语音做伪转写并筛选高置信度片段加入训练,可以显著降低转写成本。视频内容理解中,大量监控视频没有动作标签,通过半监督方式先学会通用的时空特征,再在少量标注上做动作分类,也是成熟的落地路径。
这些场景和图像分类的思路一样,核心是"无标签数据多到用不完、有标签数据贵到标不起",半监督的杠杆效应非常明显。
4.6 不太适合半监督的几种情况
不是所有场景都值得硬上。我总结了几种慎用半监督的情况:
一是无标签数据与有标签数据分布严重不一致。比如有标签是网上的公开数据集,无标签来自公司内部,特征分布差异很大,模型从有标签学到的边界很可能不适用于无标签数据。
二是任务本身对低概率事件极度敏感。比如极端稀有缺陷检测,如果某个缺陷类别在无标签池里几乎没有出现,半监督方法不但发现不了它,还可能把现有的有监督边界推偏。
三是冷启动阶段没有任何可用的预训练模型。半监督要求初始化模型有能力给出还不算离谱的预测,如果此时模型性能接近随机,所有伪标签和一致性信号都是噪声,训练只会浪费时间。
四是实时性和成本约束极强。一致性正则化类方法训练开销是有监督的几倍,如果业务要求每天更新模型且算力有限,需要慎重评估投入产出比。
5. 实战中的坑:伪标签噪声、分布漂移与模型崩溃
最后分享一些我在实操中反复踩过的坑,这些内容通常不会写在算法论文里,但对项目成败影响非常大。
5.1 确认偏误:模型把自己的错误越滚越大
确认偏误是伪标签方法最危险的坑。模型在某个样本上预测错误,但它很自信,于是这个错误预测被当作伪标签进入训练集,下一轮训练模型会更确信这个错误答案,然后错误继续扩散。
我的应对手段有三个层次:第一,严格控制伪标签阈值,宁可少用也不要用错,我一般宁可让半监督只覆盖30%的无标签数据,也不愿意为了覆盖80%而塞进大量噪声标签。第二,给伪标签设置一个损失权重上限,即使某个伪标签被加入了训练集,它的梯度贡献也要受限,防止个别错误样本主导训练方向。第三,定期用有监督验证集检查模型在哪个类别上掉点了,如果某个类别的伪标签噪声明显,就把该类别的阈值上调或直接关闭该类别伪标签。
5.2 有标签与无标签数据分布不一致导致的失效
这是最隐蔽的一个坑。有一次我拿到一批有标签数据是历史三月的,无标签数据是最近一周刚采集的,产品外观发生了变化,结果半监督训练后模型性能反而明显下降。原因就是分布漂移:模型在有标签上学到的模式已经不能解释新数据的形态了,此时让模型去给新数据打伪标签,等于让过时的老师教新学生,教出来的全是错的。
解决方式有两个:一是尽量保证无标签池与有标签数据同源、同时段、同采集流程;二是在训练过程中加入分布监控,定期比较无标签样本的预测置信度分布和特征分布,如果漂移过大,说明无标签池不能继续用了,需要重新采集或者重新标注部分新样本。
5.3 类别不平衡在伪标签上的放大效应
大多数实际数据集中,高频类别和低频类别比例悬殊。伪标签机制会天然放大这种不平衡:模型对高频类别更加自信,于是更多高频类别的伪标签被选中进入训练集;低频类别因为本身置信度低,更难获得伪标签,于是低频类别在训练中越来越被边缘化。
我常用的对策是按类别设定伪标签配额的思路:每个类别的伪标签数量在本轮训练中设一个上限,低频类别即使置信度稍低也允许少量进入,高频类别即使置信度很高也不超过配额。这样训练集的类别比例不会因为伪标签过程进一步恶化,低频类别的召回率能得到保护。
5.4 半监督基线怎么建:别盲目追求复杂算法
很多团队一上来就上当前最先进的半监督算法,结果调参调了两个月,效果不如一个简单伪标签baseline。我强烈建议,在任何半监督项目开始时,先搭三组基线:纯有监督baseline(只有少量标注训练)、伪标签baseline(最简单)、有监督+自监督预训练baseline。三组基线跑完,你才能知道复杂算法的性能天花板到底在哪里,也才能判断你的数据到底适不适合半监督。
这三组基线跑起来通常只需要半天时间,却能帮你省下后面几周的无意义调参。我遇到过太多团队,做了大量复杂的半监督实验,最后测试集性能其实和最朴素的伪标签持平——他们把大量时间花在了追求算法新意上,而数据本身的瓶颈根本没有解决。
5.5 我的实操经验与最终建议
做了这么多半监督项目,我最大的体感是:半监督是一项"工程技术"多于"算法创新"的工作。决定项目成败的往往是数据划分策略、伪标签筛选制度、验证方案的严谨性,而不是跑了哪个最新模型。
如果让我给一个最精简的实操清单,我会写这几条:
- 先做纯有监督baseline,确认标注数据确实不够用,再引入半监督。
- 无标签池要与有标签数据同分布,并有意识地定期做分布监控。
- 伪标签质量比数量重要,阈值宁高勿低,权重宁小勿大。
- 一切超参选择以独立验证集为准,最终结论以从未参与训练的测试集为准。
- 优先从简单的伪标签或一致性正则化方案起步,复杂方法只有在简单方法效果已见顶时才考虑。
我之前在工业质检项目里,就是用"有监督热启动+伪标签课程式阈值+一致性正则化"这套组合,把有效标注需求从几万条降到了一两千条,模型漏检率反而比全量标注时更低。原因也简单:老师傅标注时难免疲劳出错,而半监督模型通过大量无标签数据学到了更稳定的特征结构,对个别错误标签的敏感度反而降低了。
最后再分享一个小技巧:如果无标签数据里混入了大量垃圾样本,不要在一开始就全部丢进去训练。先用模型跑一遍,把置信度极低(比如低于0.3)的样本视为"可疑噪声"过滤掉,常常发现这些恰好就是图像模糊、文本乱码、语音残缺的坏数据。这一步过滤做完,半监督训练的收敛速度和最终精度都会明显提升。这个做法几乎不花成本,但收益稳定,我每次都会先做这一步。