CLIP series
paperreading
本文字数:2.3k 字 | 阅读时长 ≈ 9 min

CLIP series

paperreading
本文字数:2.3k 字 | 阅读时长 ≈ 9 min

CLIP

利用文本监督学习通用视觉模型

在计算机视觉领域,传统的深度学习模型往往需要大量标注数据来进行训练,并且在迁移到新任务时需要重新训练。而 CLIP(Contrastive Language-Image Pretraining) 由 OpenAI 提出,通过 自然语言监督(text supervision) 训练视觉模型,使其具备**零样本学习(zero-shot learning)**能力,能够直接识别未见过的类别。

1. CLIP 的核心思想

CLIP 的核心思路是利用文本来监督图像模型的学习。在传统的视觉模型中,我们通常使用固定类别的标签(如 ImageNet 中的 1000 类),而 CLIP 采用 大规模的图像-文本对(image-text pairs) 作为训练数据。例如:

CLIP 通过对比学习(contrastive learning),让正确的图像-文本匹配度高,错误的匹配度低,从而学习到更具泛化能力的视觉表示。

CLIP 收集了 400M 的图像-文本对用于训练模型,通常 batch_size 很大,可以提供充足的负样本,从而让模型学习到更鲁棒的特征。

2. CLIP 的模型架构

CLIP 主要由两个部分组成:

训练过程中,CLIP 通过对比损失(contrastive loss),让匹配的图像和文本 embedding 靠近,不匹配的远离。

CLIP model card

3. CLIP 的训练过程

ViT-B/32 视觉编码流程(CLIP)

在 CLIP 训练过程中,视觉 Transformer (ViT-B/32) 负责将输入图像转换为视觉特征。处理流程如下:

  1. 通过卷积层 conv1 进行初步特征提取,将输入图像转换为固定通道数的 grid 结构。
  2. 展平特征,并调整维度,使其适配 Transformer 结构。
  3. 在 token 序列前加入 class_embedding,用于全局图像表征。
  4. 添加 positional_embedding 以保留空间信息,并进行 LayerNorm 归一化。
  5. 输入 Transformer 进行特征提取,获取增强后的视觉特征。
  6. 取出 class_embedding 位置的特征,并进行后归一化 (ln_post)。
  7. 若存在投影矩阵 proj,则执行线性变换,使视觉特征与文本特征对齐。
def forward(self, x: torch.Tensor):
    x = self.conv1(x)  # shape = [*, width, grid, grid]
    x = x.reshape(x.shape[0], x.shape[1], -1)  # shape = [*, width, grid ** 2]
    x = x.permute(0, 2, 1)  # shape = [*, grid ** 2, width]

    # 添加 class token
    x = torch.cat([
        self.class_embedding.to(x.dtype) + 
        torch.zeros(x.shape[0], 1, x.shape[-1], dtype=x.dtype, device=x.device), 
        x
    ], dim=1)  # shape = [*, grid ** 2 + 1, width]

    # 添加位置编码和归一化
    x = x + self.positional_embedding.to(x.dtype)
    x = self.ln_pre(x)

    # 经过 Transformer 计算
    x = x.permute(1, 0, 2)  # NLD -> LND
    x = self.transformer(x)
    x = x.permute(1, 0, 2)  # LND -> NLD  # shape = [1, 50, 768]

    # 提取 class token 并归一化
    x = self.ln_post(x[:, 0, :])

    # 线性投影
    if self.proj is not None:
        x = x @ self.proj

    return x

文本编码流程(CLIP)

CLIP 的文本编码器采用 Transformer 结构,将输入的文本序列转换为嵌入向量,并最终映射到与视觉特征相同的空间。

输入文本首先经过 token_embedding 转换为词向量,并添加 positional_embedding 以保留序列信息。然后,文本经过 Transformer 处理,得到每个 token 的上下文表征。

为了获取整个文本的全局表示,CLIP 选择 EOT (End-of-Text) token 对应的嵌入作为文本特征,而不是简单地使用 [CLS] token(类似 BERT),因为 EOT 位置可以灵活适应不同长度的输入文本。最后,特征经过 text_projection 投影到与视觉特征相同的空间,最终得到的文本嵌入与视觉嵌入维度一致,使得 CLIP 能够高效地进行图文对比学习。

def encode_text(self, text):
    # 词嵌入
    x = self.token_embedding(text).type(self.dtype)
    x = x + self.positional_embedding.type(self.dtype)

    # Transformer 计算
    x = x.permute(1, 0, 2)  # NLD -> LND
    x = self.transformer(x)
    x = x.permute(1, 0, 2)  # LND -> NLD

    # 归一化
    x = self.ln_final(x).type(self.dtype)

    # 提取 EOT token 作为文本全局特征
    x = x[torch.arange(x.shape[0]), text.argmax(dim=-1)] @ self.text_projection

    return x

CLIP 训练中的损失计算

在 CLIP 训练过程中,图像和文本分别通过视觉编码器和文本编码器转换为嵌入向量,并进行归一化,使其在单位球面上分布。然后,通过计算图像与文本特征的余弦相似度,获得相应的匹配分数,并通过对比学习损失 (Contrastive Loss) 进行优化。

  1. 归一化特征向量
    为了确保特征的数值稳定性并增强对比学习效果,模型先对图像特征 image_features 和文本特征 text_features 进行 L2 归一化
image_features = image_features / image_features.norm(dim=1, keepdim=True)
text_features = text_features / text_features.norm(dim=1, keepdim=True)

这一步确保所有嵌入向量都分布在单位球面上,使得后续计算的余弦相似度等价于点积。

  1. 计算余弦相似度

在归一化后,计算图像与文本之间的余弦相似度,并使用 logit_scale 进行缩放:

logit_scale = self.logit_scale.exp()
logits_per_image = logit_scale * image_features @ text_features.t()
logits_per_text = logits_per_image.t()
•	logit_scale.exp() 作用是提供一个可学习的温度参数,控制 softmax 的锐度,影响对比损失的梯度。
•	logits_per_image 表示每张图像与所有文本的匹配分数,其形状为 [batch_size, batch_size]。
•	logits_per_text 是 logits_per_image 的转置,表示每个文本与所有图像的匹配分数。
  1. 对比学习损失

CLIP 采用 InfoNCE (Contrastive Loss) 进行优化,使正确的 (image, text) 对的相似度最大化,而其他错误匹配的相似度最小化:

labels = torch.arange(batch_size, device=device)  # 生成 0,1,2,...,batch_size-1 作为正确匹配索引
loss_img = F.cross_entropy(logits_per_image, labels)  # 图像->文本的对比损失
loss_txt = F.cross_entropy(logits_per_text, labels)  # 文本->图像的对比损失
loss = (loss_img + loss_txt) / 2  # 计算最终损失
•	交叉熵损失 (F.cross_entropy) 计算每个样本的 softmax 归一化分布,并鼓励正确的 (image, text) 对的匹配分数最大。
•	labels 指定匹配关系,即 labels[i] = i,表示第 i 张图像应该与第 i 条文本匹配。
•	loss_img 约束给定图像预测正确文本,loss_txt 约束给定文本预测正确图像,最终取平均。
  1. 训练目标

CLIP 通过最小化上述对比损失,使得:
• 相关图像和文本的相似度最大化(靠近单位球面上的同一区域)。
• 非匹配的图像-文本对的相似度最小化,提高检索和对比学习能力。

最终,这种方式使得 CLIP 能够在大规模数据集上学习到通用的跨模态表征,提升零样本分类和图文匹配能力。

4. CLIP 的推理过程

在推理阶段,CLIP 进行图像分类时,不需要重新训练,只需提供文本类别描述。例如,我们要识别一张图片的类别,流程如下:

  1. 输入一张图片,用图像编码器提取图像 embedding。
  2. 输入多个文本类别(如 “a photo of a dog”, “a photo of a cat”),用文本编码器提取文本 embedding。
  3. 计算余弦相似度,选择最相似的文本类别作为最终预测结果。

这样,CLIP 可以直接进行零样本分类,不需要额外的标注数据。

EVA-CLIP

1. 预备知识 EVA

在讲解 EVA-CLIP 之前,先介绍一下 EVA 模型。

EVA 主要 motivation 有下面几个:

核心思想是让图像经过 CLIP 并得到视觉 embedding 后,这个视觉 embedding 具有多模态语意,然后将其此图在经过 EVA,在经过一个 projector 得到最终的视觉 embedding,并且与 CLIP 的视觉 embedding 维度相同,随后将 CLIP 的输出和 EVA 的输出进行对比学习,loss 就是余弦相似度,综上就可以让 EVA 同时学习到高维和低维信息,如下

2. EVA-CLIP

EVA-CLIP 是 CLIP 的升级版,主要有两个改进:

训练的有很多 trick,例如 LAMB 优化器,flash attention,混合精度训练,mask 50% 的 token 等等。

3. Model Card

参考 EVA-CLIP model card

  1. EVA-01-CLIP Series
Model Name Image Encoder Text Encoder Total Parameters
EVA01_CLIP_g_14_psz14_s11B EVA01_g_psz14 openai/clip-vit-large-patch14 1.1B
EVA01_CLIP_g_14_plus_psz14_s11B EVA01_g_psz14 laion/CLIP-ViT-H-14-laion2B-s32B-b79K 1.3B
  1. EVA-02-CLIP Series
Model Name Image Encoder Text Encoder Total Parameters
EVA02_CLIP_B_psz16_s8B EVA02_B_psz14to16 openai/clip-vit-base-patch16 149M
EVA02_CLIP_L_psz14_s4B EVA02_L_psz14 openai/clip-vit-large-patch14 428M
EVA02_CLIP_L_336_psz14_s6B EVA02_CLIP_L_psz14_224to336 EVA02_CLIP_L_psz14_224to336 428M
EVA02_CLIP_E_psz14_s4B EVA02_E_psz14 laion/CLIP-ViT-H-14-laion2B-s32B-b79K 4.7B
EVA02_CLIP_E_psz14_plus_s9B EVA02_E_psz14 laion/CLIP-ViT-bigG-14-laion2B-39B-b160k 5.0B
4月 06, 2025
12月 31, 2024
11月 25, 2024