共计 2072 个字符,预计需要花费 6 分钟才能阅读完成。
为什么需要对比学习?
CLIP 论文提出的对比学习机制,主要解决图文跨模态对齐的难题。传统方法通常需要大量标注数据来建立图像和文本之间的联系,而对比学习通过自监督方式,让模型自动学习两种模态的共享特征空间。具体来说,给定一批图像 - 文本对,正样本是匹配的图文对,负样本是非匹配的组合,模型需要拉近正样本距离,推远负样本距离。

技术方案选型
在对比学习之前,常见的跨模态学习方法包括:
- 孪生网络:两个共享权重的网络分别处理不同模态,但无法有效处理大量负样本
- 三元组损失:需要精心设计三元组采样策略,计算复杂度随样本量增长较快
对比学习的优势在于:
- 可以同时利用大量负样本
- 通过温度系数控制样本难度
- 向量化实现效率高
核心算法实现
模型架构
CLIP 采用双编码器结构:
- 图像编码器:基于 Vision Transformer(ViT)
- 文本编码器:基于 Transformer
两个编码器输出的特征向量会归一化到单位球面上,方便计算余弦相似度。
相似度计算
给定 batch 内的图像特征 $I$ 和文本特征 $T$,相似度矩阵 $S$ 计算为:
$$ S_{i,j} = \frac{I_i \cdot T_j}{\tau} $$
其中 $\tau$ 是温度系数,控制样本对的难易程度。
损失函数
InfoNCE 损失函数实现如下:
def info_nce_loss(image_features, text_features, tau=0.07):
"""
计算对比学习损失
Args:
image_features: 图像特征 [batch_size, dim]
text_features: 文本特征 [batch_size, dim]
tau: 温度系数
"""
# 归一化特征
image_features = F.normalize(image_features, dim=1)
text_features = F.normalize(text_features, dim=1)
# 计算相似度矩阵
logits = torch.matmul(image_features, text_features.T) / tau
# 构建标签(对角线为正样本)
batch_size = image_features.shape[0]
labels = torch.arange(batch_size, device=image_features.device)
# 计算交叉熵损失
loss_i = F.cross_entropy(logits, labels)
loss_t = F.cross_entropy(logits.T, labels)
return (loss_i + loss_t) / 2
工程实践技巧
负样本队列
为增加负样本数量,可以使用 memory bank 技术:
class MemoryBank:
def __init__(self, size=65536, dim=512):
self.size = size
self.memory = torch.randn(size, dim)
self.ptr = 0
def update(self, features):
"""更新记忆库"""
batch_size = features.size(0)
end = self.ptr + batch_size
if end <= self.size:
self.memory[self.ptr:end] = features
else:
split = self.size - self.ptr
self.memory[self.ptr:] = features[:split]
self.memory[:batch_size-split] = features[split:]
self.ptr = end % self.size
数值稳定性
- 梯度爆炸问题:
计算 logsumexp 时使用稳定实现:
logits_max, _ = torch.max(logits, dim=1, keepdim=True)
log_sum_exp = torch.log(torch.sum(torch.exp(logits - logits_max), dim=1)) + logits_max.squeeze()
- 混合精度训练:
使用 torch.cuda.amp 自动管理精度转换,但要注意:
– 保持 softmax 计算在 fp32
– 损失缩放防止下溢
常见问题与解决
模态坍塌
当温度系数 $\tau$ 设置过大时,所有样本相似度趋同,表现为:
- 损失值不再下降
- 特征向量高度集中
解决方案:
- 适当降低温度系数
- 增加 batch size
- 添加正则化项
参数调优
温度系数 $\tau$ 的经验范围是[0.01, 0.1],需要根据具体任务调整:
- 从 0.07 开始尝试
- 观察正负样本相似度分布
- 太大导致学习缓慢,太小导致训练不稳定
延伸思考
- 温度系数与 batch size 的关系:
- batch size 增大时,是否需要调整 $\tau$?
-
设计实验:固定其他参数,扫描不同 batch size 下的最优 $\tau$
-
跨语言应用:
- 如何将对比学习扩展到多语言场景?
- 能否建立统一的多模态多语言特征空间?
实践建议
对于初学者,建议:
- 先用小 batch size 调试模型
- 可视化特征分布监控训练过程
- 逐步增加模型复杂度
完整实现可参考 Colab Notebook:[链接]
正文完
发表至: 未分类
近一天内
