共计 1819 个字符,预计需要花费 5 分钟才能阅读完成。
传统句子嵌入的痛点
在 NLP 任务中,传统的句子嵌入方法如 TF-IDF 或 Word2Vec 平均池化存在明显缺陷:

- 无法处理一词多义(” 苹果 ” 公司 vs 水果)
- 忽略词序(” 猫追狗 ” 和 ” 狗追猫 ” 得到相同表示)
- 长文本信息稀释(重要信号被常见词淹没)
BERT+ 对比学习的黄金组合
BERT 通过 Transformer 架构捕获上下文信息,而对比学习通过拉近相似样本、推远不相似样本来优化表示空间。二者的结合带来:
- 语义敏感度:BERT 的注意力机制识别关键词语义
- 空间一致性:对比学习使相似句子的嵌入距离更近
- 少样本适应:通过数据增强生成有效训练对
实战代码详解
环境准备
# Python 3.8+, PyTorch 1.12+
import torch
from transformers import BertModel, BertTokenizer
from torch import nn
import numpy as np
核心模型定义
class BertContrastive(nn.Module):
def __init__(self, model_name='bert-base-uncased'):
super().__init__()
self.bert = BertModel.from_pretrained(model_name)
# 用[CLS] token 作为句子表示
self.projection = nn.Linear(768, 256) # 降维减少计算量
def forward(self, input_ids, attention_mask):
outputs = self.bert(input_ids, attention_mask=attention_mask)
cls_embedding = outputs.last_hidden_state[:, 0, :] # 取 [CLS] 位置
return self.projection(cls_embedding)
对比损失实现(InfoNCE)
def contrastive_loss(embeddings, temperature=0.1):
# embeddings: [batch_size, dim]
sim_matrix = torch.matmul(embeddings, embeddings.T) / temperature
exp_sim = torch.exp(sim_matrix)
# 对角线是正样本对
pos_pairs = torch.diag(exp_sim)
# 每行的和减去自身是负样本对
neg_pairs = exp_sim.sum(dim=1) - pos_pairs
loss = -torch.log(pos_pairs / neg_pairs).mean()
return loss
训练关键参数
# 推荐配置
params = {
'batch_size': 64, # 太小影响对比学习效果
'learning_rate': 3e-5,
'temperature': 0.07, # 控制相似度分布陡峭程度
'max_length': 64 # 截断长文本
}
生产环境优化技巧
批量推理加速
# 启用自动混合精度
from torch.cuda.amp import autocast
@torch.no_grad()
def batch_inference(texts):
inputs = tokenizer(texts, padding=True, truncation=True,
max_length=64, return_tensors="pt")
with autocast():
embeddings = model(**inputs)
return embeddings.cpu().numpy()
维度选择建议
- 通用场景:256~512 维
- 计算敏感场景:128 维 +PQ 量化
- 高精度要求:保留 768 维原始 BERT 输出
常见踩坑与解决
- 损失不下降
- 检查数据增强是否有效(同义词替换 / 删除随机词)
-
调高 temperature 值(0.1→0.5)
-
GPU 内存溢出
- 减小 batch_size(64→32)
-
使用梯度累积(accum_steps=2)
-
相似度得分饱和
- 添加 LayerNorm 到投影层
- 改用 cosine 相似度替代点积
进阶方向
- 尝试 Sentence-BERT 的更优池化策略
- 加入对抗训练提升鲁棒性
- 在 STS- B 数据集上评估 Spearman 系数
完整代码已开源在 GitHub 仓库(伪链接),建议在您业务数据上尝试以下改进:
- 替换领域专用 BERT(如 BioBERT)
- 设计面向业务的正负样本策略
- 监控嵌入空间的类内距离变化
正文完
