☰
对比学习实战指南:无监督表征训练的组件、参数与评估方法
2026/10/21 3:17:46 网站建设 项目流程

数据科学这个圈子有个很现实的问题:大多数团队不缺数据,缺的是"能用起来的数据"。标注成本一年比一年高,业务方又不愿意等三个月等一批高质量标注,于是很多人开始盯上无监督方案。我大概在一年多以前开始认真研究对比学习,当时纯粹是被逼的——项目组拿不到足够的标注样本,又希望做一个通用的商品表征服务,能够同时支撑检索、聚类、相似推荐好几个下游任务。试了一圈之后,我确认对比学习确实是当下无监督大数据表征里最值得投入的方向之一,它不依赖标签,不需要针对某个细分任务单独调模型,训练完之后可以直接迁移到多个场景。

这篇文章我不打算从原理教科书的角度来写,而是按照我实际落地一个对比学习项目的过程来拆:核心思想、关键组件、训练参数、评估方法、踩过的坑,一条线讲下来。如果你正准备在团队里引入对比学习,或者已经在跑但效果不理想,这篇多少能帮你少走一点弯路。内容会比较长,重点部分我会尽量展开。

1. 对比学习到底在学什么:从一个"没有标签"的困局说起

1.1 表征学习的前提:让数据自己说话

先聊一个最基本的背景。过去我们做有监督训练,本质上是让模型通过"输入x对应标签y"的映射来学到特征。这种学法的上限很高,代价也很大。一张图要不要打标、一段文本要不要分类,都需要人在前面把语义定好。如果样本量是百万级,标注成本和时间成本很快就失控了。于是大家开始琢磨一个更根本的问题:模型能不能不依赖标签,直接从数据本身的结构里学到一种"通用表示"?

这种通用表示就是"表征"。理想情况下,一个训练好的编码器应该做到:语义上相似的内容,在表征空间里距离近;语义上不相似的内容,距离远。一旦得到这样的表征,下游任务就变得很简单——加一个线性分类头就能做分类,算一下向量距离就能做检索和聚类,完全不需要为每个任务重新训练一个深度模型。

对比学习的核心思路就是这么来的:不告诉模型"这张图是猫",而是告诉模型"这张图和另一张图是同一类,跟其他图不是同一类"。让模型在大量的"相似/不相似"配对中,自己去刻画数据的语义结构。听起来像是降级版的监督学习,但在实际实验里,只要数据量够大、增强方式设计得好,学出来的表征甚至可以逼近有监督的预训练模型。

1.2 一个类比:从脸盲到人脸识别

我经常跟团队里的新同学用一个类比:对比学习有点像你刚到一个新城市,谁也不认识,但你能慢慢认出"同一个小区的邻居"和"完全陌生的路人"。区分熟悉的邻居并不需要你知道每个人的名字,你只需要知道"见过这个人""这个人跟那个人一起走""这两个人看起来有关系"。

模型也是一样。给它一批图片,它不知道里面谁是"猫"谁是"狗",但如果构造出一种规则,让模型知道"同一只猫的两个不同角度的照片应该接近",模型就会逼着自己去学习"猫"背后那些稳定的视觉因素——毛发纹理、姿态、颜色分布——而不是盯着某一个像素。这个去除细枝末节、抓住核心语义的过程,其实就是特征提取器逐渐变强的过程。

有监督学习给的是"标准答案",对比学习给的则是"关系线索"。线索虽然没有答案那么直接,但只要线索足够多、设计得足够细,模型照样能把底层结构学出来。

1.3 对比学习解决的核心问题

展开来看,对比学习解决的是三个层面的问题。

第一,冷启动问题。新业务积累不了标注数据,但原始数据往往早就躺在那了。对比学习可以直接用这些原始数据预训练一个底座,等后续有少量标注之后再加微调,启动成本非常低。

第二,通用性问题。传统有监督模型往往是"一任务一模型",换个分类目标就要重新训练。对比学习学的是通用表征,任何一个需要向量表示的下游任务都可以直接复用,省掉了大量的重复训练开销。

第三,语义连续性问题。现实中很多业务场景的语义并不是几个离散类别能概括的,比如电商商品包含颜色、款式、材质、适用人群等多重属性,人和商品之间的相似度也不是简单属于同一类。对比学习在连续的表征空间里表达相似关系,这种表达方式比"分类标签"灵活得多,也更贴近真实业务。

2. 核心组件拆解:正样本、负样本、损失函数、温度参数与投影头

理解了思想之后,就到了真正动手前必须搞清楚的五个关键设计。对比学习看起来只是一个损失函数的事,但它的效果好坏,几乎完全取决于这几个组件怎么配合。我逐个说下我的理解。

2.1 正样本对:数据的"两个视角"

对比学习的第一个关键设计,是怎么定义"正样本对"。没有标签的情况下,我们只能手动制造语义一致的样本对。最常用的做法是数据增强:对同一个训练样本做两次不同的随机变换,得到两个"视角"。比如一张商品图,一次做随机裁剪、颜色抖动,另一次做旋转、模糊,这两张图内容不同但语义一致,就被当成一个正样本对。

数据增强的选择直接决定了模型学到的是"语义"还是"像素"。如果增强太弱,两张视角几乎一模一样,模型走个捷径就能把损失降到很低,根本接触不到语义层面的差异;如果增强太强,正样本对的语义都被破坏了,模型又会觉得这俩根本不是同一个东西,训练起来很困难。这里需要在"够难"和"别太离谱"之间找一个平衡点,等讲踩坑时我会再细说。

2.2 负样本:从Batch内构造

负样本的定义通常比正样本简单粗暴一些:在一个训练批次里,除了样本自己对应的那个增强视角之外,其他所有样本都算是它的负样本。也就是同一个batch里,N个样本各自生成两个视角,共2N条数据,对于其中任何一条数据来说,它的正样本是唯一的另一半视角,剩下的2N-2条都是负样本。

这个设计的精妙之处在于,它不需要额外的采样逻辑,只要batch内样本分布够随机,每个样本天然能拿到一大批有区分度的负样本。batch size越大,负样本越多,模型面对的区分难度越大,学到表征的判别力也越强。这也是为什么对比学习普遍推荐用大batch训练,后面我会给具体参数。

2.3 损失函数:拉近正样本、推开负样本

损失函数是整个训练的"指挥棒"。行业内最通用的是InfoNCE家族系列的变体,核心逻辑就两件事:让正样本对的表征相似度尽量高,让负样本对的表征相似度尽量低。相似度一般用余弦相似度来算,取值在-1到1之间,正好适合这种做"远近"度量的场景。

如果把训练目标翻译成一句话:在给定一个锚点样本的情况下,模型要从2N个候选里,把那个唯一的正样本准确挑出来。这样一来,对比学习就被定义成了一个极端多分类问题。相比于让模型直接回归某个相似度数值,这种"从人群中认出你"的方式学到的特征往往更鲁棒,因为负样本的分布范围广、难度各异,模型必须真正理解什么是核心语义才能稳定地做对选择。

2.4 温度参数:控制惩罚力度的旋钮

温度参数t是InfoNCE里最敏感的旋钮之一,作用是把相似度分数做非线性的缩放,从而改变模型对难分样本的注意力。形象一点说,温度参数决定了"分数差距要多大的时候,模型才会认真去区分它们"。

t值设得小,比如0.07,相似度分数被拉大,模型会非常严厉地惩罚那些稍微相似的负样本,逼迫它把特征分布压得非常集中,类内间距小、类间间距明显,但训练也容易变得不稳定;t值设得大,比如0.5,模型对难分样本就没那么敏感,训练过程平稳,但学出来的表征可能比较"松散",判别力不足。

我在实验里对比过一组数据,同一个模型在t=0.07和t=0.5下,下游分类准确率能差出8个点以上。所以这个参数值得专门做一轮搜索,别直接用默认值。

2.5 投影头:训练完就扔掉的那一层

很多第一次接触对比学习的人,都会对网络结构里的"projection head"感到困惑。实际上这个设计非常有讲究:编码器负责把原始输入转成特征向量,投影头再接一层MLP,把特征向量映射到另一个低维空间,训练的时候用投影后的向量来算对比损失,训练完只保留编码器,投影头直接舍弃。

为什么要多此一举?因为直接约束编码器输出会损伤它的泛化能力。想象一下,如果你要求特征在训练时已经挤得非常紧,编码器学到的就很难迁移到新的下游任务。而接一个投影头作为"缓冲层",让编码器只负责提取那些通用的、结构化的信息,让投影头去完成那些跟训练任务绑定的紧凑化要求,最终保留下来的是一个干净、通用的表征。这是我在实践中觉得非常"反直觉但就是有效"的设计之一。

3. 真实场景实操:某电商商品表征项目的训练与调优

3.1 项目背景和数据管道设计

我实际跑对比学习的场景,是给一个电商策略团队做商品通用表征。当时手里的数据大概五千万条商品记录,每条包含主图、标题、类目和几个关键属性,标签很少且质量参差不齐。做有监督模型基本没戏,所以我把宝压在无监督对比学习上。

数据管道的第一步是构建输入对。我选择的方案是图文分开各自做增强:图像随机裁剪、颜色扰动、旋转,文本用随机删除、同义词替换、词序打乱。然后把图像和文本向量在某个特征层拼接起来,作为编码器的输入。这样一个商品就成了两条增强后的数据,形成正样本对。因为涉及多模态,数据管道会比纯视觉复杂一些,清洗逻辑也要特别注意:图片损坏的记录直接丢弃,文本清洗掉乱码和全数字标题,避免模型学到异常分布。

这里有一个经验:清洗质量对无监督学习的影响,比对有监督学习更大。有监督场景里,少量脏数据可能被正确的标注稀释掉;无监督场景里,没有标签兜底,脏数据形成的错误结构会被对比学习放大,最终污染表征空间。

3.2 模型结构与关键参数选择

在框架上我试过几种设计,最终采用的是"双塔结构加一个共享编码器"的方案。双塔的直观理解是:两侧输入分别走各自的编码器,得到一个向量;共享编码器则是两边用同一套参数,好处是大幅减少了参数量,而且迫使模型忽略输入的模态差异,更关注语义对齐。做多模态的时候,共享编码器比完全独立的双塔更容易训练,这是我自己的结论。

训练参数上,我直接给了以下这组经过几轮调优后的配置,供参考:

参数设定值说明
编码器结构12层Transformer处理文本序列和图像patch序列
projection维度128投影头输出维度,不算太大但足够用于训练
batch size2048单机多卡,每卡256,共8卡
优化器AdamW权重衰减0.01,beta设为(0.9, 0.999)
学习率1e-3采用warmup策略,前10个epoch线性升到峰值
训练epoch60超过60个epoch后增益不明显,开始过拟合
温度参数t0.1经过0.05到0.5的搜索,0.1附近效果最稳
图增强裁剪幅度0.2到1.0裁剪比例下限设0.2,太小的裁剪会切掉主体
文本删除概率0.1逐词随机删除,删除太多会丢失关键信息

你可能会问为什么batch size要开这么大。前面说过,对比学习中负样本来自batch内部,batch越大,负样本数量越大,模型就近看到的"硬负样本"就越多,训练效率越高。如果显存不够大,可以把批次分成多个mini-batch,用梯度累积来模拟更大的batch,不过实际效果还是会比"真大batch"差一点,因为负样本池在反向传播前就被隔离了。

3.3 训练过程中的loss曲线变化

训练刚开始的五到十个epoch,loss会下降得很快,这是正常现象。模型正在快速学会区分那些最"粗糙"的差异,比如颜色、背景、文本长度这些浅层特征。之后loss下降速度会明显放缓,这时候模型才开始慢慢琢磨那些细粒度的语义差异,需要一些耐心。

我在这个阶段经常去看的是"hard negative"的表现。简单说就是那些表面上很像、实际语义不同的负样本对,比如两个不同品牌但款式外观接近的商品。如果训练后期,模型在这些hard negative上的相似度排名中依然频繁犯错,说明表征还没有学到足够细致的语义信息,可以考虑继续训练或用更强的数据增强。

训练进行到40个epoch左右,我观察过loss和下游任务准确率的对照,发现loss并不是越低越好。某个检查点上loss继续下降,但检索质量指标反而掉了。这说明模型开始过拟合到增强模式下的一些伪规律,而不是真正的语义结构。所以确定epoch数量不能只盯训练loss,一定要结合下游任务指标来综合判断。

4. 效果好不好,不能靠感觉:无监督表征的评估方法

4.1 为什么需要单独设计评估方案

无监督模型的评估比有监督要难一个层次。没有标注,没有验证集,loss又是一条平滑下降的曲线,你很难判断当前模型是"已经学得很好了"还是"根本没学会但在硬拟合"。我一开始也犯过这个错,训练了三十个epoch,自我感觉良好,结果一下游任务完全不行,才知道模型学到的东西根本不能迁移。

后来我建立了一套多层次的评估方案,每训练几个epoch就跑一轮,用不同的视角来检验模型状态。这套方案不新鲜,但很有效,尤其适合团队里没有专职算法评估人员的场景。

4.2 线性探测(Linear Probing):判断表征质量的硬指标

线性探测的思路是:把预训练编码器输出的特征固定住,只在上面加一层线性分类器,用少量有标签数据训练这个分类器,然后看它的准确率。因为线性分类器非常弱,它只能利用特征本身已经包含的线性可分的语义信息,所以准确率越高,说明表征质量越好。

我们当时用了一万条人工复盘过的商品小样本作为标记集,用线性探测跑了三分类、五分类和十分类三个任务。对比学习预训练得到的表征,线性探测准确率比一个从零训练的有监督小模型还要高。这一点让我彻底信了无监督表征的价值:它的确学出了一些有监督小样本学不到的通用结构。

关于线性探测,有个细节值得注意:线性分类器训练时的学习率不能照搬预训练参数,一般要单独搜索一轮,使用很小的学习率例如1e-3之一,训练10到20个epoch就足够,否则会把编码器学到的底层特征覆盖掉。有人在这里翻过车,把编码器一起微调了,测出来的结果虚高,下游迁移时复制不出来。

4.3 检索评测:贴近业务场景的验收方式

由于电商业务的核心诉求是"找相似商品",检索质量是最贴近业务的验收标准。我构建了一个小规模的检索评测集:人工标注了500组商品对,每组里面一个查询商品,若干候选商品,人工给出"相似程度"的排名。然后用模型输出的表征做余弦相似度排序,计算NDCG和Recall@10。

这个评测的妙处是:即使没有完整标注,只要每组有几百条相对顺序,就能得到一个相当稳定的质量评估。NDCG到了0.83之后,我在可视化工具里抽样看了一些case,发现模型确实能跳出"同颜色同款式"这些显式特征,开始捕捉"这种设计风格适合什么人群"这种更抽象的东西,效果比较让人放心。

如果只做离线指标,不抽样看case,很容易被数字欺骗。线上用户关心的是"看起来像不像一个东西",这些往往很难用单一的离线指标完全反映。所以哪怕只是随机抽200个case人工过一眼,都比只看指标要可靠。

4.4 特征可视化:给表征一个直觉印象

特征可视化主要是辅助手段,但能帮团队快速建立信心。我一般用t-SNE把编码器输出的高维表征降到二维平面,然后把商品样本按类目着色,看不同类目在平面上的分布是否自然成簇。有监督模型很容易形成一个个边界清晰的聚类;无监督模型如果学得好,聚类结构会存在,但边界往往是渐变的,中间会有大量过渡样本。这个特点不是缺陷,反而说明模型捕捉到了语义的连续性,比如从"运动鞋"过渡到"休闲鞋"再过渡到"皮鞋",这是一个连续的语义光谱。

所以我特别反对拿聚类纯度去衡量无监督表征。聚类本身不是对比学习的目标,表征的自然聚簇只是它学到语义结构后的副产品。我更看重特征可视化后是否呈现有意义的组织形态,以及是否跟业务认知一致。

5. 实战中遇到的两个典型问题与排查过程

5.1 难题一:loss不降,模型完全学不动

第一次训练到第三个epoch时,我发现loss几乎不再下降,卡在一个数值附近抖动。当时第一反应是学习率太大导致震荡,但降了学习率后loss更是纹丝不动。继续排查后,我发现问题出在数据增强上。那一版代码里,我用了过强的图像裁剪,随机裁剪范围最低到了原始图片的0.08,导致很多正样本对里两张图根本看不到同一个主体。比如一双鞋被裁出了鞋带和鞋底,另外一边裁出了鞋帮,这两个视角虽然来自同一商品,但视觉特征已经没有共同点了,模型怎么学都学不出"这俩是同一东西"。

把裁剪范围的下限从0.08提到0.2之后,loss在两个epoch内就开始正常下降。那次经历给我的教训是:对比学习的"无监督"并不等于"免设计",数据增强本身就是注入到模型里的最核心的先验知识。

5.2 难题二:训练正常,但下游任务就是不行

loss曲线一切正常,线性探测却始终上不去,这是比loss不降更让人头疼的情况。我排查了很久,最后定位到一个很隐蔽的问题:训练数据里存在大量的重复或近似重复商品。电商系统里同一款商品经常有多个商家上架,图片分辨率、拍摄角度、标题措辞都不同,但语义完全一致。对底层的对比学习来说,这些"同一个语义"的记录在batch里经常被当成负样本对,模型不断被告知"这两个看起来一样的东西并不一样",语义结构被严重干扰。

为了解决这个问题,我对训练数据做了基于minHash的近似去重:先对商品标题做shingle切分,再用minHash签名按概率把疑似重复的商品归到同一组,每组只保留一条代表性样本。去重之后,线性探测准确率提升了大概6个点。有时候问题不在模型,而在喂给模型的数据本身,这个排查思路值得记录下来。

5.3 一些小参数,调对了有大效果

最后说几个我实验过、效果明显的小参数。

投影头的输出维度不宜过大,我用128维比512维效果更好,原因可能是低维空间里对比损失的约束更有力,模型不能靠嘈杂的特征混过去,必须提炼出真正核心的信息。

学习率和batch size要联动调整。batch从1024提到2048时,学习率也要跟着调高一倍左右,否则训练速度会明显变慢,loss曲线变得拖沓。warmup的epoch数要与总epoch成比例,我在60个epoch的总长度下,warmup设为10个epoch,太长的warmup会浪费训练时间,太短则容易在初期就陷入糟糕的局部结构。

多模态场景下,不同模态之间的增强强度不能一刀切。图像增强的影响比文本增强更剧烈,因为视觉特征的底层变化空间比文本的词序变化大得多。我在两组模态各自的增强强度上分别调过参数,最后图像裁剪比例取0.2下限,文本删除只取0.1,比例高了都会显著降低最终表征质量。

对比学习做下来,我的整体感觉是:它在无监督大数据表征这个问题上,是当前最能打的方案之一,但它要求你付出额外的设计成本。你要精心构造数据增强,耐心稳定动态对比,细心监控评估指标。那些宣称"丢进去就能自己学"的说法,至少在我自己的实践里没有出现过。每一步都需要你回来盯数据、看loss、翻case,但当你看到模型在没有标签的情况下,自己把语义结构组织得井井有条时,那种感觉确实值得。最后分享一个小技巧:每次调整参数,记得把模型在不同epoch下的表征都存一个副本,后面做对比分析时,这些"过程版本"会成为你排查问题最有力的依据。

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

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

立即咨询