CLIP对比损失函数入门指南:从理论到PyTorch实现

1次阅读
没有评论

共计 1817 个字符,预计需要花费 5 分钟才能阅读完成。

image.webp

为什么需要对比损失

传统分类任务中,交叉熵损失函数通过优化预测标签与真实标签的差异来训练模型。其数学形式为:

CLIP 对比损失函数入门指南:从理论到 PyTorch 实现

$$\mathcal{L}{CE} = -\sum^N y_i \log(p_i)$$

但在多模态学习中,我们需要对齐不同模态(如图像和文本)的特征空间。这时交叉熵面临两个核心问题:

  1. 需要预先定义的固定类别体系
  2. 无法直接建模模态间细粒度关系

对比损失的核心思想

对比学习通过拉近正样本对、推开负样本对的距离来学习特征表示。给定一批 N 个图像 - 文本对,每个图像有 1 个正文本和 N - 1 个负文本。InfoNCE 损失函数定义为:

$$\mathcal{L}{InfoNCE} = -\frac{1}{N}\sum$$}^N \log\frac{\exp(s_{i,i}/\tau)}{\sum_{j=1}^N \exp(s_{i,j}/\tau)

其中 $s_{i,j}$ 是第 i 个图像与第 j 个文本的相似度,$\tau$ 是温度系数。

温度系数的魔法

温度系数控制着相似得分的分布陡峭程度:

  • 较大 $\tau$ 会平滑分布,使模型关注更多困难负样本
  • 较小 $\tau$ 会锐化分布,使模型更关注高相似度对

经验取值通常在 0.01 到 0.5 之间,需要通过验证集调整。

PyTorch 实现详解

import torch
import torch.nn as nn
import torch.nn.functional as F

class ContrastiveLoss(nn.Module):
    def __init__(self, temperature=0.07):
        super().__init__()
        self.temperature = temperature
        self.cos_sim = nn.CosineSimilarity(dim=2)

    def forward(self, img_emb, txt_emb):
        # 特征归一化
        img_emb = F.normalize(img_emb, dim=1)
        txt_emb = F.normalize(txt_emb, dim=1)

        # 计算相似度矩阵
        logits = self.cos_sim(img_emb.unsqueeze(1), txt_emb.unsqueeze(0)) / self.temperature

        # 创建标签(对角线为正样本)labels = torch.arange(logits.size(0), device=img_emb.device)

        # 计算交叉熵损失
        loss_i = F.cross_entropy(logits, labels)
        loss_t = F.cross_entropy(logits.T, labels)
        return (loss_i + loss_t) / 2

完整训练流程

def train_one_epoch(model, loader, criterion, optimizer, device):
    model.train()
    total_loss = 0

    for images, texts in loader:
        images = images.to(device)
        texts = texts.to(device)

        # 混合精度训练
        with torch.cuda.amp.autocast():
            img_feats = model.encode_image(images)
            txt_feats = model.encode_text(texts)
            loss = criterion(img_feats, txt_feats)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_loss += loss.item()

    return total_loss / len(loader)

工程实践建议

  1. 批处理大小:
  2. 更大的批次提供更多隐式负样本
  3. 但会占用更多显存,需在二者间平衡
  4. 推荐从 256 开始尝试

  5. 特征归一化:

  6. 必须对特征进行 L2 归一化
  7. 可防止梯度爆炸 / 消失
  8. 使相似度保持在 [-1,1] 范围

  9. 混合精度训练:

  10. 使用 torch.cuda.amp 自动管理精度
  11. 对损失值添加梯度缩放
  12. 可提升 30% 训练速度

关键参数参考

参数 推荐值 作用
温度系数 0.07 控制相似度分布
批大小 256 影响负样本数量
特征维度 512 表征空间大小
学习率 3e-4 优化器步长

延伸思考

对比损失的思想可以扩展到:

  1. 视频 - 文本检索
  2. 跨语言翻译
  3. 分子结构 - 性质预测

与 Triplet Loss 相比,对比损失:
– 能同时利用多个负样本
– 对采样策略更鲁棒
– 但对计算资源要求更高

建议在计算资源允许时优先选择对比损失。

正文完
 0
评论(没有评论)