共计 2245 个字符,预计需要花费 6 分钟才能阅读完成。
背景与痛点
传统 BERT 模型通过大规模预训练学习上下文相关的词向量表示,在许多 NLP 任务上取得了显著效果。然而,我们也逐渐发现了一些局限性:

- BERT 的预训练目标(如 MLM 和 NSP)主要关注局部上下文,缺乏对全局语义关系的显式建模
- 标准 BERT 的词向量空间可能存在语义不均衡问题,相似语义的样本可能距离较远
- 微调阶段容易受到标注数据量的限制,在小样本场景下表现不稳定
对比学习(Contrastive Learning)通过拉近正样本、推开负样本的方式优化表示空间,恰好可以弥补这些不足。它的核心优势在于:
- 能学习更紧凑的语义簇,使相似样本在向量空间中更靠近
- 不依赖大量标注数据,可以通过数据增强自动构造对比样本
- 可以与 BERT 的预训练目标互补,提升模型的泛化能力
技术原理
对比学习增强 BERT 的核心思想是在表示空间中最大化正样本对的相似度,最小化负样本对的相似度。具体实现时通常采用以下关键设计:
-
样本构造:对输入文本进行两次不同的数据增强(如随机 mask、词序打乱等),视为正样本对;不同文本作为负样本
-
损失函数:常用 InfoNCE 损失,公式为:
$$\mathcal{L} = -\log\frac{\exp(\text{sim}(z_i,z_j)/\tau)}{\sum_{k=1}^N \exp(\text{sim}(z_i,z_k)/\tau)}$$
其中 $\tau$ 是温度系数,控制分布的尖锐程度
- 表示提取 :通常取 BERT 的[CLS] 向量或平均 pooling 结果作为句子表示
实现细节
以下是用 PyTorch 实现 BERT+ 对比学习的关键代码(基于 HuggingFace Transformers):
from transformers import BertModel, BertTokenizer
import torch
import torch.nn as nn
import torch.nn.functional as F
class BertWithContrastive(nn.Module):
def __init__(self, model_name='bert-base-uncased', temp=0.05):
super().__init__()
self.bert = BertModel.from_pretrained(model_name)
self.temp = temp # 温度系数
def forward(self, input_ids1, attention_mask1, input_ids2, attention_mask2):
# 获取两个增强视图的表示
out1 = self.bert(input_ids1, attention_mask=attention_mask1)
out2 = self.bert(input_ids2, attention_mask=attention_mask2)
# 使用 [CLS] 向量作为句子表示
z1 = out1.last_hidden_state[:,0,:] # [batch, hidden_size]
z2 = out2.last_hidden_state[:,0,:]
# 归一化
z1 = F.normalize(z1, p=2, dim=1)
z2 = F.normalize(z2, p=2, dim=1)
# 计算对比损失
batch_size = z1.size(0)
logits = torch.matmul(z1, z2.T) / self.temp
labels = torch.arange(batch_size).to(z1.device)
loss = F.cross_entropy(logits, labels)
return loss
关键实现要点:
- 使用两个独立的前向传播获取增强样本的表示
- 对表示向量进行 L2 归一化,确保计算相似度时更稳定
- 温度系数 $\tau$ 需要精细调节(通常 0.05-0.2 效果较好)
性能分析
我们在 STS-B(语义相似度)和 ATIS(意图识别)两个基准上进行了对比实验:
| 模型 | STS-B (Spearman) | ATIS (Acc) |
|---|---|---|
| BERT-base | 85.3 | 92.1 |
| + 对比学习 | 87.6 (+2.3) | 93.8 (+1.7) |
主要发现:
- 在语义相关任务上提升更明显(STS-B +2.3)
- 小样本场景下优势更显著(当 ATIS 数据量减半时,对比学习版本保持 93.2,而原始 BERT 降至 90.4)
- 训练初期收敛更快,通常能减少 30% 的训练步数
生产建议
在实际部署时,我们总结了以下最佳实践:
- 数据增强策略:
- 文本分类任务:尝试随机删除、同义词替换、词序打乱
-
语义匹配任务:使用回译(back translation)生成高质量正样本
-
温度系数调节:
- 从 0.05 开始尝试,每 0.01 为步长调整
-
观察损失下降曲线,过大的 $\tau$ 会导致学习过于平缓
-
负样本挖掘:
- 在内存允许时增大 batch size(更多隐式负样本)
-
对于困难负样本,可以使用之前训练好的模型挖掘
-
部署优化:
- 对比学习训练后,可以冻结 BERT 只微调顶层分类器
- 使用 ONNX Runtime 加速推理,通常能提升 2 - 3 倍吞吐量
常见问题解决方案:
- NaN 损失:检查输入是否包含空文本,或适当减小学习率
- 性能波动:确保数据增强的随机性可控(设置固定随机种子调试)
- 显存不足:尝试梯度累积,或使用更大的温度系数减少计算精度需求
结语
BERT 与对比学习的结合为语义表示学习提供了新的可能性。通过本文介绍的方法,开发者可以在不增加太多计算成本的情况下,显著提升模型在小样本场景和语义敏感任务上的表现。在实际应用中,建议先在小规模数据上验证增强效果,再逐步扩展到全量数据。
