
最近在调研半监督分类方向把几篇“对比学习 半监督分类”相关的论文翻来覆去读了几遍又动手复现了小半个月有些想法想记下来。这类论文的思路用一个句子概括就是先用大量无标签数据把特征空间拉得足够规整再用少量有标签数据做分类边界校正对比学习在这里面充当了“无监督特征学习”的发动机。很多初学者一上来就被对比损失那一串公式吓住其实抓住三个关键词就能理顺投影头、InfoNCE损失、温度系数。这篇笔记我不打算逐段翻译论文而是从“为什么要这么设计”出发把整体流程、关键公式、训练配置和踩过的坑串一遍希望能给正在入门对比学习和半监督分类的朋友一个比较完整的参考。1. 论文速览核心思路与解决场景1.1 半监督分类的老问题和老思路半监督分类解决的是这么一个问题手里只有几百张带标签的图剩下几万张图都没有标签怎么把分类模型训好。这在真实场景里太常见了标注成本高、专家难找很多医院的影像数据、工厂的缺陷图片能用上的标签往往只占很小一部分。过去几年的主流方案可以分成两派。一派是做伪标签先用有标签数据训练一个模型拿这个模型去给无标签数据打预测挑置信度高的样本当成标签加进训练集。另一派是做一致性正则对同一张无标签图片做不同的数据增强要求模型在两种扰动下的输出保持一致。这两条路线的共同瓶颈在于伪标签本身有噪声噪声会随着训练累积模型的表征能力又不够强一旦早期学歪了后面就很难绕回来。我复现过经典的伪标签方法效果很不稳定同一个数据集换一次随机种子最终精度能差两三个点这就是确认偏差在作怪。1.2 对比学习为什么能补位对比学习这波热潮自SimCLR和MoCo之后就没停过它的核心目标是让模型学会“什么是相似、什么是不相似”而且完全不需要标签。具体做法是同一张图做两次不同的数据增强得到一正一正的两个样本对再拿其他图片当负样本学一个嵌入空间让正样本对在这个空间里靠近负样本对远离。这类方法有一个很吸引人的特性它能在完全没有标签的情况下把特征空间训练得具备“类聚”性质。如果对比学习学得好同一个类别的图片在特征空间里会自然靠在一起这等于给后续的半监督分类打下了一个特别好的基础。有标签数据只需要做一件事把簇和类别对应起来而不是从零去学特征。我之前做过一个小实验随机初始化网络直接半监督训练PCA降维后的特征是糊成一团的。但如果先用对比学习在无标签数据上预训练一轮再只用10%的标签去微调特征空间会清楚得多分类精度也明显高一截。这其实就是这类论文最核心的设计动机用无监督方式解决特征学习把有监督信号留给决策边界。1.3 论文整体框架的一句话版本我这篇笔记重点梳理的方法框架大致可以拆成三个步骤第一步用全部数据重点是大量无标签数据做对比预训练把特征空间拉好第二步用少量有标签数据做一次有监督微调让模型学会把特征对应到类别第三步联合训练阶段对无标签数据生成伪标签或做一致性约束同时保留对比损失让特征空间在训练过程中不会退化。这三个步骤不是这篇论文独有的很多对比学习加半监督的方案都遵循类似的节奏。但不同论文在第三步的细节上差别很大有的用伪标签做“人为的正样本对齐”有的用不同增强视角算对比损失还有的把对比学习放到特征空间的聚类结构上。读论文的时候不用纠结哪一篇更好抓住“特征空间怎么被约束住”这条主线就够了。2. 方法细节拆解从对比损失到半监督训练的三段式结构2.1 基础InfoNCE损失与投影头先把这个损失函数的真实含义说清楚。InfoNCE损失的基本形式是L -log(exp(sim(z_i, z_j)/τ) / Σ_{k1}^{N} exp(sim(z_i, z_k)/τ))这里的sim通常是余弦相似度z_i和z_j是同一个样本两个增强视角经过编码器之后得到的向量分母里的z_k是一批样本里所有其他特征。直观理解就是我要在N个候选里找出那个真正和我配对的样本这是个N分类问题温度系数τ控制着分布的平滑程度。τ这个超参在实践中特别敏感。τ越小softmax的分布越尖模型越倾向把正例和所有负例拉得非常开特征容易崩塌τ太大正负例的区分度又会变弱。我复现时的经验是τ在0.07到0.2这个区间比较稳常用的初始值从0.1开始调。再说投影头。编码器输出的特征向量不直接进入对比损失而是先过一个两层的MLP把特征映射到一个更小的空间比如128维在这个映射空间里算相似度。一开始我也觉得这步多余后来想明白了分类任务需要保留的语义信息和对比任务需要区分的实例信息不完全一样投影头相当于给对比学习一个独立的工作空间。训练完之后真正用于分类的还是编码器的输出投影头会被扔掉。2.2 无标签数据如何参与训练很多刚开始读这类论文的人都卡在这里无标签数据到底是怎么“参与”训练的对比学习和半监督分类似乎各说各话怎么能揉到一个损失函数里在我看的这几篇论文里无标签数据的参与方式主要有两种。第一种是直接算无监督对比损失。对任意一张无标签图随机做两次增强分别过编码器和投影头算InfoNCE损失让这两个增强视角在特征空间里靠近。这种方式不产生任何伪标签避免了一部分确认偏差的风险。它的问题在于对比损失只是在拉近同一样本的不同视角没有显式告诉模型某个区域应该属于哪个类分类边界的形成主要靠分类损失来完成。第二种是伪标签加对比约束。先用有标签数据训一个分类头让它对无标签数据预测出一个伪标签再在对比学习的框架里把同一张图的预测结果和历史预测结果做一致性约束。有些工作还会维护一个特征队列或者动量编码器让伪标签的生成和特征更新交替进行相当于一边给无标签数据“起名”、一边用“起名”的结果反过来约束特征空间。我复现的时候更倾向于先跑通第一种再试试第二种。第一种方法代码简单不容易出问题。第二种方法如果伪标签质量把控不好训练过程中很容易出现某个类被吞掉的情况尤其当数据类别不平衡时置信度高的那几类会占据主导低置信度类别的梯度几乎为0整个特征空间崩塌。碰到这种情况先把伪标签阈值调高或者对伪标签做类别重加权都能明显改善。2.3 损失函数如何组合这类方法的损失函数一般长这个样子L L_sup λ_1 * L_unsup_con λ_2 * L_pseudoL_sup是有标签数据的交叉熵损失。L_unsup_con是无标签数据的对比损失。L_pseudo是伪标签或者一致性损失。λ_1和λ_2是权重系数有的论文还会加一个ramp-up曲线训练初期权重接近0随着训练推进逐步加大。这里有个容易忽略的细节有标签数据也可以同时算对比损失。同一张有标签图做两次增强它的对比损失和分类损失是两个不同的监督信号一个拉近特征一个约束类别。实际操作中很多代码是直接把有标签数据也丢进对比损失的batch里同时参与两种损失的计算。权重怎么调我踩过几次坑之后得出的经验是对比损失的权重初始值不用太大0.1到1之间先试重点看验证集上的表现。λ_2如果指伪标签的交叉熵权重可以跟着置信度阈值动态调阈值高的样本权重大一点低置信度的样本要么丢掉、要么给一个很小的权重。伪标签模型最怕的是把错误标签的梯度放大宁可少用一些无标签样本也不要让噪声混进来。为了把训练流程说清楚我贴一段自己整理过的核心训练伪代码框架和论文基本一致for step, (img_l, label_l), (img_u, _) in zip(label_loader, unlabel_loader): # 有标签分支 feat_l encoder(img_l) logits_l classifier(feat_l) loss_sup cross_entropy(logits_l, label_l) # 无标签分支两次随机增强 img_u1, img_u2 aug(img_u), aug(img_u) feat_u1 encoder(img_u1) feat_u2 encoder(img_u2) # 对比损失计算两个增强视角之间的InfoNCE loss_con info_nce_loss(feat_u1, feat_u2, temperature0.1) # 伪标签分支可选 with torch.no_grad(): pseudo_label classifier(encoder(img_u)).argmax(dim1) conf torch.softmax(classifier(encoder(img_u)), dim1).max(dim1).values mask conf threshold logits_u classifier(feat_u1) loss_pseudo cross_entropy(logits_u[mask], pseudo_label[mask]) loss loss_sup lambda1 * loss_con lambda2 * loss_pseudo loss.backward() optimizer.step()这段代码只是一个粗略骨架真正跑的时候还要处理多卡同步、梯度累积、指数滑动平均之类的问题。但先把这段跑通后面再往细调会顺利很多。3. 复现流程与关键配置3.1 数据集与数据增强策略论文里最常用CIFAR-10、CIFAR-100、SVHN、STL-10这几个数据集。主要原因就是它们足够小能快速迭代验证方法有效性。CIFAR-10有60000张32x32的图分成10类STL-10的图片分辨率高一些而且专门为了半监督设计只有1000张有标签样本剩下13000张无标签图片来自一个宽泛的分布代表性很强。用在这类方法上的标签数量一般取400、1000、2500、4000这几个档。400张标签的CIFAR-10是最挑战的设置每个类别平均只有40张这个数量下模型很容易过拟合也最能体现对比学习的增益。数据增强在这里的作用比普通分类任务重要得多。对比学习依赖不同的增强视角来构造正样本对增强策略直接决定正样本对的质量。我在复现时用的是弱增强加强增强的组合弱增强包括随机裁剪和水平翻转强增强在弱增强基础上叠加颜色抖动、灰度化、高斯模糊和Cutout。颜色抖动的作用是让模型学会不依赖颜色分布强制它去关注形状和结构这在CIFAR这类小数据集上尤其有用。补充一句颜色抖动幅度不能拉太猛否则正样本对会变得过于困难对比损失怎么都降不下去。我一开始用的幅度参数是0.5训练到中期损失纹丝不动降到0.25之后情况马上好转。3.2 网络结构与优化器选择网络结构我用的是ResNet-18打底对比分支再加上一个两层MLP投影头。投影头第一层把特征从512维映射到256维第二层映射到128维中间用ReLU激活。这个128维是在论文中反复出现的一个值128维的投影空间对CIFAR规模的数据集已经足够再高只增加开销效果提升很小。优化器方面SGD配momentum 0.9、weight decay 5e-4是最稳妥的组合。AdamW这类适应性优化器在对比学习里不是不能用但效果通常不如SGD尤其在大batch训练时SGD的泛化性更好。初始学习率开0.03到0.1配合cosine schedule递减。有个细节是学习率需要随batch size线性缩放batch size翻倍学习率也翻倍这样可以稳定对比学习的训练。投影头这一层最好不给它初始学习率衰减或者用更大的权重衰减因为投影头是额外加上的结构它拟合的是对比任务权重更新太慢会导致对比损失拖后腿。我试过给投影头单独设一个学习率乘子设置为1.0而backbone设置为0.3训练速度略慢但最终精度更稳。3.3 两阶段训练流程与详细参数表我在复现里采用了论文中常见的两阶段流程。阶段一是对比预训练。在全部无标签数据上跑对比学习这一步和半监督标签完全无关只看对比损失是否收敛训练大约200到300个epoch。这个阶段结束之后把编码器保存下来作为第二阶段的初始化权重。如果预训练效果理想模型此时已经能够在特征空间里把相同类别的样本聚成一个个簇虽然还没有类别标签。阶段二是联合训练。加载预训练好的编码器随机初始化分类头然后用有标签数据和无标签数据一起训练。这个阶段的核心是分类损失教会模型怎么把簇对应到具体的类别对比损失继续约束特征空间让新加入的类别信息不会破坏已有的聚簇结构。联合训练大约100到200个epoch学习率从0.01开始cosine schedule衰减到接近0。我把整理好的关键配置列成一个表方便对照复现配置项参数设置备注数据集CIFAR-10 / STL-10标签数量 400、1000、4000骨干网络ResNet-18不使用预训练权重投影头512-256-128 MLP ReLU只在对比分支使用优化器SGDmomentum 0.9wd 5e-4比AdamW稳定基础学习率0.03batch size 256随batch线性缩放学习率调度cosine schedule阶段二从0.01起步batch size256有标签和无标签混在同一个batch温度系数 τ0.1太大会崩太小会退化对比损失权重 λ_10.5可根据数据集微调伪标签阈值0.95以上才用于交叉熵训练轮数预训练200 联合训练100 ~ 200小数据量可减少一半这张表不是一个死的标准但按它去跑至少能出一个不差的结果。后续要优化再针对具体数据集的特性做调整。4. 实验结果与我的调参记录4.1 不同标注比例下的效果对比在CIFAR-10上400张标签的极端低标注条件下这类方法比传统半监督方法提升非常明显。我记得早期只用ReMixMatch这类一致性正则方法的准确率大约在86%到88%之间而对比学习加半监督的方案在同样条件下可以冲到90%以上不同论文的报数是90%到92%不等。我复现时的结果是90.6%虽然没到论文里那么高但考虑到训练轮数和超参没有完全对齐这个差距可以理解。把标签数提高到4000张之后所有方法都趋近于饱和差异缩小到两三个点以内。这说明对比学习的主要增益集中在小标注规模标注充足时它的优势没那么明显毕竟有监督信号已经足够强了特征空间长什么样反而不那么关键。STL-10上我验证的感受更深。STL-10的无标签集分布比CIFAR更杂传统半监督方法在这类数据上翻车概率很高。但对比预训练阶段能把无标签数据里的结构先理顺联合训练阶段的稳定性会高很多最终准确率比直接用半监督方法高接近5个百分点。4.2 温度系数和对比损失权重怎么影响收敛温度系数是我花时间最多调的一个参数。最开始我设置的τ是0.5训练了20个epoch之后发现对比损失在0.6附近徘徊不降把投影头的输出统计出来看了下特征的模长分布已经严重偏向某一侧其实就是退化现象。把τ降到0.1之后对比损失开始正常下降。后来又试了τ0.05训练前期确实更快但到了联合训练阶段无监督特征空间的过度分散导致分类头的决策边界很难学最终效果反而变差。对比损失权重λ_1也类似。λ_1设为0时就是纯半监督分类但特征质量随着训练退化验证集精度后期会掉。λ_1设得太大比如超过2分类损失的影响被稀释模型对类别的判别力不足。我最终在CIFAR上用的是0.5在STL-10上用了0.3因为STL-10的数据分布更杂对比损失过强会让模型过度关注无标签样本的细节差异。4.3 与其他半监督方法融合的公平性问题复现论文时最需要警惕的是对比基准的公平性。很多论文与baseline对比时会加入额外的数据增强、更长的训练轮数或者更大的batch size这导致最终的精度差距未必全来自对比学习本身。我自己复现时会把所有方法放在同一个训练框架里数据增强、优化器、学习率全部保持一致只改变核心算法模块这样对比出来的结果才有意义。聊一个实用的对比思路把对比学习当作一个插件接入已有的半监督方法。比如在两个经典的一致性正则方法之上把对比损失加到总损失里看能不能涨点。我在CIFAR-10上试过插到其中一个方法之后低标注比例下提升了1到2个百分点高标注比例下基本持平。这说明对比学习的增益主要体现在特征层面当标注足够时特征质量的边际贡献会递减。5. 常见问题与排查技巧5.1 特征崩塌与损失爆掉的检查方法特征崩塌是对比学习最经典的问题训练过程中如果发现对比损失突然掉到很低不要高兴得太早大概率是模型找到了一个“捷径”把所有样本映射到同一个特征。这时候投影头输出向量的方差会变得极小或者不同样本特征之间的余弦相似度都接近1。排查方法很简单训练过程中定期把投影头输出的128维特征保存下来算一下全batch的均值和方差如果均值接近0但方差也接近0那就是特征崩塌了。或者直接看特征矩阵的秩秩远小于batch size说明有效的特征维度在缩减。解决特征崩塌的思路主要有几个调低温度系数、增大batch size提高负样本数量、引入负样本队列缓存历史特征、或者采用动量编码器稳定特征更新节奏。我试过最简单有效的还是调τ和加大batchbatch size从128调到512之后正负样本的比例一下子就正常了。5.2 伪标签噪声累积的问题怎么办联合训练阶段伪标签的质量决定上限。最低级的错误是直接用训练中的模型预测无标签样本并当真实标签这样早期错误会一路放大。我的解决办法是双重保险第一低于阈值的样本直接丢弃阈值设0.95宁可少用无标签样本也要保证进入训练的标签足够可靠第二对伪标签做类别均衡重采样统计每个类被选中进入训练的样本数凑出一个均匀的分布防止高置信度类别霸占训练集。另一个细节是伪标签生成时用的是一个单独的特征表示不是当前模型的最新状态。我在复现中给伪标签分支加了指数移动平均的模型副本每轮更新EMA在生成伪标签时用EMA模型的输出这样伪标签比实时模型的预测稳定得多噪声明显降低。5.3 显存和训练速度的取舍对比学习对显存的消耗比普通分类大不少因为同一个batch里要同时算两次增强的梯度。ResNet-50加batch size 512在单张24GB显卡上勉强够跑如果换更大的模型就必须想办法减负。几个可落地的措施降低batch size同时开梯度累积对比损失本身对batch规模敏感梯度累积可以模拟更大的batch但注意batch norm的统计量变化会影响最终效果第二专职学生模型减半投影头参数量少但也要占显存可以设置它为半精度训练第三减少强增强在训练初期的频率前几个epoch弱增强让模型先稳定下来再用强增强增加难度。我这边资源有限时采用的是梯度累积加混合精度训练速度大概提升30%精度损失控制在0.3个点以内。5.4 问题速查表现象可能原因排查方向对比损失不降温度系数太大或太小正样本对太困难先试τ0.1减弱颜色抖动强度特征全部坍缩到一点负样本不足τ过小增大batch引入特征队列无标签部分完全没贡献伪标签阈值过高λ权重太小调低阈值到0.9加大权重有标签过拟合标注太少加大无标签对比损失权重提前结束阶段一分类头训完特征又乱了联合训练对比损失被过度削减保持λ_1在0.3以上让特征空间持续被约束训练到后半段突然震荡学习率过大cosine schedule末段不平滑改小初始学习率加EMA权重平均这张表涵盖了大部分我在复现过程中遇到的实际问题如果训练结果异常先对着表排查一轮能省去很多盲目调参的时间。6. 一点经验与延伸想法跑了小半个月最大的体会是这类方法真正的价值不在于某一个组件有多厉害而在于把几种不同性质的监督信号放在一个f框架里各司其职。对比损失管特征空间的结构交叉熵损失管类别判别伪标签的一致性约束管无标签样本的类别一致性——每个模块单独看都不稀奇组合起来才能在小标注条件下取得好结果。我在实际动手过程中养成的一个习惯是先别上完整结果把代码裁剪到一个小规模数据集上只跑几十个epoch确认损失曲线正常、特征不崩塌、伪标签噪声可控再切换到完整方案。这样每次改动都能快速看出是正向还是负向调参效率会高很多。论文里那些最终结果看起来是一步到位背后其实都经历了大量的中间实验。如果继续往深走有几个方向我觉得值得延伸一是把对比学习中间的特征表示和聚类反馈结合起来让无监督信号更贴近数据结构二是把这个框架迁移到更复杂的多标签场景半监督多标签分类目前还是很难做三是和当前的大模型对齐思路结合对比学习的本质其实就是在做表征对齐它和CLIP那套思路有很强的亲缘性。半监督这个方向短期之内还会一直热下去而对比学习作为无监督表征学习的一个强有力工具在这条路上肯定还会继续发挥重要作用。