

代码来源UP主 ↗,感谢大佬开源~
CLIP(Contrastive Language-Image Pre-training)是OpenAI在2021年提出的突破性多模态模型,它通过对比学习的方式将图像和文本映射到同一个语义空间中。
核心思想:CLIP同时训练图像编码器和文本编码器,让配对的图像-文本对在向量空间中尽可能接近,而不配对的图像-文本对尽可能远离。这种对比学习范式使得模型能够理解图像和文本之间的语义关联。
多模态就是指不同领域的输入数据,比如文字、图片、语音、视频等。在传统方法中,每个领域都有一些经典的处理算法,比如用于处理文本的RNN、LSTM、Transformer,用于处理图像的各类卷积神经网络等,各领域间相对独立。但是,人们总会遇到需要联合领域数据的时候,比如给一张图片,输出一段关于这个图片的描述;或者给一段文字,输出一张符合文字描述的图片。而实现这一目标的难点在于:不同领域数据间的特征分布、特征信息是不一样的。因此多模态模型的总体目标就是:训练一个模型,一方面能统一特征表达,另一方面又能让不同模态特征间学到相关性。
下面介绍CLIP模型的训练:
主要流程分为两步:
- 使用对比学习进行预训练
- 进行零样本预测
CLIP的训练数据是<图像,文本>pair。如图所示,一个batch的数据里,有若干张图像,每张图像配有相应的文字描述信息(Prompt),比如:
一张小狗图片,Prompt为<dog>,或者为<A photo of a dog>bash值得一提的是,CLIP的作者发现,Prompt的设计也会影响模型最终的效果。比如把Prompt从单词<dog>换成句子<A photo of a dog>后,模型在ImageNet分类任务上的准确率直接提高了1.3%。
CLIP模型由两个主体部分组成:Text Encoder和Image Encoder:
-
对于
Text Encoder,CLIP借鉴的是GPT2的架构。对于每条Prompt,在进入Text Encoder前,都会添加表示开始和结束的符号[SOS]与[EOS]。最终将最后一层[EOS]位置的向量作为该Prompt的特征表示向量,也就是图中所绘的。举个例子: 输入 “a photo of a cat” 会变成:
bash[SOS] a photo of a cat [EOS]“最后一层 [EOS] 位置的向量”是什么意思? 经过
Text Encoder(多层Transformer)处理后,每一层都会为每个token输出一个向量。我们关注的是 最后一层(final layer) 的输出。在这个输出序列中,对应[EOS]这个token位置的那个向量,就被选作整个句子的“代表” -
对于
Image Encoder,CLIP则尝试过5种不同的ResNet架构和3种VIT架构,最终选用的是架构为Large,patch_size=14的ViT,同时在整个CLIP预训练结束后,用更高分辨率(336*336)的图片做了一个epoch的fine-tune,目的是让CLIP能涌现出更好的效果。与Text Encoder类似,每张图片对应一个最终特征表示向量。Vision Transformer(ViT)在处理图像时,会: (1)将输入图像(如224×224)切分成若干个patch(例如patch_size=14→ 每个 patch 是14×14像素)。 (2)每个patch被展平并通过一个线性层映射为一个嵌入向量。 (3)在patch序列最前面额外添加一个可学习的特殊token,称为[class] token。所以输入序列是:
bash[class], patch_1, patch_2, ..., patch_N经过多层
Transformer编码器后,最后一层会输出与输入等长的向量序列。 其中,第一个位置(即[class] token对应的位置)的输出向量,被认为聚合了整张图像的全局信息。 这个向量通常记作z_cls,维度为ViT的隐藏层维度(例如ViT-L/14的hidden size = 1024)。在CLIP中会使用这个向量z_cls,将其映射到一个共享的多模态嵌入空间。这个投影后的向量才被归一化并用作最终的图像特征表示 。
接下来是第一步对比学习:
假设一个batch中共有N对<图像,文字>对,那么过完各自的Encoder后,就会分别产生:
- N条文字向量[]
- N条图片向量[]
这两组向量,将会分别过一次多模态Embedding(Multimodal Embedding),也就是在途中代表文字的紫色向量下,还有一层参数(图中没有画出来),文字向量需要先和做矩阵相乘后,才能得到最终文字向量。对图片向量,同理也有个对应的。和的作用可以理解成把文字、图片特征投影到多模态的特征空间中去。
经过多模态Embedding的处理,我们得到了最终的[]和[]。接下来,模型就能**通过“对比学习”,找到图像和文字的相似关系。**做法也很简单,对于图中列出的N*N个格子,只需要计算每个格子上对应的向量点积(余弦相似度)即可。对于对角线上的图片-文字对是Ground Truth,希望对角线上的相似度可以最大,据此可以设置交叉熵函数,来球的每个batch下的Loss。
需要注意的是,在计算Loss时,会算两个Loss再取平均,这是因为CLIP按行计算Loss和按列计算Loss。
- 按行计算
Loss,在每一行的范围内做softmax,然后计算cross_entropy(蓝色格子部分是Ground Truth)。这样计算Loss的意义是:对于每一张图片,我们都希望找到和它最相似的文字。 - 按列计算
Loss,在每一列的范围内做softmax,然后计算cross_entropy(蓝色格子部分是Ground Truth)。这样计算Loss的意义是:对于每一张文字,我们都希望找到和它最相似的图片。 - 最后将这两个
Loss相加取平均,代表在模型优化过程中考虑了“图片->文字”和“文字->图片”的双向关系。
第二部就是用训练好的模型来做zero-shot预测了,流程如下:
- 首先,创建一个标签全集,如图中(2)所示,并得到每一个标签的特征向量
- 然后,取一张图片,如图中(3)所示,过
Image Encoder后得到该图片的特征向量 - 最后,计算图片向量和文字向量的相似度,取相似度最高的那条
label即可。
值得注意的是,对于标签来说,CLIP需要一个标签全集。也就是说,当喂给CLIP一张图时,不管这张图片它是否有见过,CLIP都不会生成一个全新的标签,而是去全集标签中找一个最相似的给你(这也是CLIP的缺陷之一)。
至此,CLIP技术部分已经讲完。
那么CLIP模型有什么缺陷呢?
缺陷一:Zero-shot能力很强,但不是最强的
根据实验结果,CLIP从来没有用ImageNet的数据训练过,但它在ImageNet的预测效果可以达到76.2%,和用ImageNet做训练集的ResNet50基本一致。但ResNet50并不是在ImageNet分类任务上表现最SOTA的模型,例如MAE之类在ImageNet上可以达到80%+。虽然CLIP同样具有涌现能力,即当模型变大时,模型的效果会更好,但是因为CLIP训练昂贵的原因,为了提升预测百分点而需要的代价是巨大的。因此这也是CLIP当前的限制之一。
缺陷二:CLIP无法处理更抽象的任务
抽象的任务是指:输出图片中物体的个数等需要一定逻辑思维推理的任务。在论文的实验中也有给出一些说明,下图中刻画了CLIP和ResNet在不同数据集任务上的表现情况。绿色表示CLIP表现更好的数据集,蓝色标线ResNet表现更好的数据集。注意到蓝色部分的DTD(纹理分类)和CLEVRCountS(给图中物体计数)这两个数据集,都是相对抽象的任务,在这方面CLIP表现明显不如ResNet。
缺陷三:当测试数据集分布严重偏移时,CLIP也束手无策
虽然 CLIP 以 Zero-shot 标榜,但是当测试数据集分布相对于训练数据集分布存在严重偏移情况时,CLIP 的表现也不理想。论文中提出了一个很有代表性的例子:MNIST(手写数字数据集)。这样一个简单的数据集,可能由 CV/M 都能做到 90% 以上的准确率了,但 CLIP 在上面的表现只有 88%。原因就在于 CLIP 的训练数据主要来自互联网图像和文本对(如网页上的图片和标题),其风格和内容偏向于自然场景、日常物体等,而 MNIST 是一种高度结构化、低分辨率、黑白线条构成的手写数字图像,与 CLIP 训练数据的视觉风格差异巨大。
缺陷四:文字标签是个闭集 前文说过,在对 CLIP 做 zero-shot 预测时,我们的文字标签是一个闭集(closed set),模型输入一张可能从未见过的图片,然后从这个预定义的标签集合中找出最匹配的一个,而不是去预测一个全新的文字标签。从这一点来看,CLIP 依然不够自动化。
缺陷五:受限于计算资源,无法做图像-文本的生成式网络 这个在 CLIP 看来是缺陷的问题,不久之后已经被我们熟知的 DALL·E 2 和 Stable Diffusion 所解决(没错,正是站在 CLIP 的肩膀上)。因此,这是 CLIP 的一个限制,但同时也为后续研究提供了重要的启发点。