4亿(图像,文本)对
,基于此数据集,训练一个预测哪一个文本描述当前哪一个图像的预训练任务, 此任务取得了SOTA的图像表示。预训练之后,可以通过自然语言匹配视觉概率从而实现zero-shot的迁移。
CLIP算法的核心是利用自然语言包含的监督信号来训练视觉模型。相比于其他的训练方法,从自然语言中学习具有以下两个优势。首先,相比于标准的有标签图像分类数据集,这种方法无需标注,就很容易扩展数据集;其次,图像和文字配对训练,学习到的特征不单单是一个视觉特征,而是多模态的特征,有助于zero-shot的迁移学习。
图像和文本的配对训练需要一个足够大的数据集,然而现有的数据集要么数据量不够,要不标注质量太差,为了解决这个问题,OpenAI他们从互联网上的各种公开来源公收集了4亿(图像,文本)对。
最近视觉领域的算法训练都需要巨大的计算量。 在ImageNet数据集上训练ResNeXt101-32x48d模型需要19个GPU年,训练Noisy Student EfficientNet-L2模型需要33个TPUv3 core-years。那么从自然语言中直接学习视觉概念的开放集合这一任务所需要的计算资源令人望而生畏。经过一些列的努力,他们发现训练效率对多模型预训练是至关重要的。
最初的方法,与VirTex相似,联合训练一个图像CNN和文本transformer去预测图像所对应的文本。然而,一个6300万参数的transformer语言模型,比ResNet-50图像编码器多了两倍的计算量,学习识别ImageNet类别的速度比一个更简单预测同一文本的BOW编码器慢了三倍。它们试图预测每张图片所附文本的确切单词,这种做法显然是比较困难的。对于一张图片来说,可以有不同的描述。比如下面一张图,你可以描述“有一只狗在草地上”,也可以描述“这是一张小狗的图片”,还可以描述“一条小黑狗伸着小舌头”等等。
最近在图像对比表征学习方面的工作发现,contrastive objectives可以比同等的predictive objective学习更好的表征,而且其他工作发现,图像的生成模型相比同性能的对比模型相比,需要更多的计算量才能够学习到高质量的图像表示。基于此,将文本看做一个整体,而不是一个个单词,与图像进行配对。将基准BOW编码器的预测性的目标函数替换成对比性的目标函数,训练效率提高了4倍。
下图是CLIP的伪代码。CLIP包含两个编码器,一个图像编码器和一个文本编码器,图像编码器的输入形式是 [ n , h , w , c ] [n,h,w,c] [n,h,w,c], n n n是批次大小, h , w , c h,w,c h,w,c是图像的大小,比如 224 × 224 × 3 224 \times 224 \times 3 224×224×3;文字编码器的输入形式是 [ n , l ] [n,l] [n,l],由于是图像文本对,所以文本编码器中的批次是与图像编码器中的批次是一样的, l l l是序列长度。图像编码器可以是深度卷积网络,也可以是Transformer;文本编码器可以是CBOW,也可以是Text Transformer。
图像输入和文本输入分别进入图像编码器和文本编码器之后,得到相应的特征表示;然后后接一个归一化的操作。归一化操作时,牵涉到线性投射层 n p . d o t ( I f , W i ) np.dot(I_f, W_i) np.dot(If,Wi)和 n p . d o t ( T f , W t ) np.dot(T_f, W_t) np.dot(Tf,Wt)。线性投射层将每个编码器的表示映射到多模态嵌入空间。归一化操作后得到用于对比的特征 I e I_e Ie和 T e T_e Te。接下来,计算 n n n个图像的特征和 n n n个文本的特征的余弦相似性。伪代码中的余弦相似性值为 l o g i t s logits logits,logits的形状大小为 n × n n \times n n×n,然后logits与分别与图像和文本的gt标签做交叉熵目标函数,最后的损失函数为对称损失函数。gt的计算使用了arrange 函数,labels的取值为 1 , 2 , 3 , 4 , 5 , ⋯ , n 1,2,3,4,5, \cdots ,n 1,2,3,4,5,⋯,n,CLIP的正样本标签为对角线上的元素。
OpenAI收集了4亿图像文本对,数据量过于巨大,所以图像编码器和文本编码器无预训权重。由于文本是被当做一个句子,所以文本编码器对文本无增强操作;图像编码器中的图像增强方式也仅仅使用了resize和随机裁减。温度参数 τ \tau τ,控制softmax中logits的范围,在训练过程中直接被优化为标量,而不是作为一个超参数。
当使用训练好的CLIP模型进行推理时,首先需要使用clip.load()
加载模型,然后分别对图像和文本进行前处理。文字前处理是对数据集中的所有类别进行prompt engineering处理,将每个类别转换成句子,clip.tokenize()
将句子长度padding到77个token长度。下面的代码中,图像选取了CIFAR100数据集中的其中一张。接下来,将图像和文字分别喂入图像编码器和文字编码器,提取图像特征和文字特征,分别将图像特征和文字特征正则化之后,计算图像特征和文字特征之间的相似度,并对相似度进行softmax操作。
# 下面代码使用CLIP进行zero shot预测,从CIFAR-100数据集中挑选一张图片,预测这张图像最有可能与此数据集中100个标签中哪一个标签最相似。
import os
import clip
import torch
from torchvision.datasets import CIFAR100
# Load the model
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load('ViT-B/32', device) # 加载模型,返回的preprocess中包含一个torchvision transform依次执行Resize,CenterCrop和Normalization等操作。
# Download the dataset
cifar100 = CIFAR100(root=os.path.expanduser("~/.cache"), download=True, train=False)
# Prepare the inputs
image, class_id = cifar100[3637]
image_input = preprocess(image).unsqueeze(0).to(device) # 图像前处理
text_inputs = torch.cat([clip.tokenize(f"a photo of a {c}") for c in cifar100.classes]).to(device) # 文字前处理
# Calculate features
with torch.no_grad():
image_features = model.encode_image(image_input) # 图像编码器提取输入图像的特征
text_features = model.encode_text(text_inputs) # 文字编码器提取输入文字的特征
# Pick the top 5 most similar labels for the image
image_features /= image_features.norm(dim=-1, keepdim=True) # 正则化
text_features /= text_features.norm(dim=-1, keepdim=True) # 正则化
similarity = (100.0 * image_features @ text_features.T).softmax(dim=-1) #计算图像特征与文字特征之间的相似度
values, indices = similarity[0].topk(5)
# Print the result
print("\nTop predictions:\n")
for value, index in zip(values, indices):
print(f"{cifar100.classes[index]:>16s}: {100 * value.item():.2f}%")
The output will look like the following (the exact numbers may be slightly different depending on the compute device):
Top predictions:
snake: 65.31%
turtle: 12.29%
sweet_pepper: 3.83%
lizard: 1.88%
crocodile: 1.75%
大多数标准的图像分类只会使用标签的数字id来注释图像,并包含一个将这些数字id映射回其英文名称的文件。这样就导致一个最常见的问题就是多义性。当类的名称作为唯一的信息提供给CLIP的文本编码器时,由于缺乏上下文,它无法区分词义。在某些情况下,同一个单词的多个含义可能做为不同的类包含在同一数据集中。比如在ImageNet数据集中,建筑起重机和飞行的鹤。而且,在CLIP的预训练数据集中,与图像配对的文本中只有一个单词的情况是相对罕见的。通常,文本都是一个描述图像的完整句子。为了弥合这一分布差距,作者团队发现使用提示模板“A photo of a {label}”是一个很好的选择,有助于指定文本是关于图像的内容。与仅使用标签文本的基线模型相比,通常会提升性能。
在官方提供的Prompt_Engineering_for_ImageNet.ipynb中,ImageNet数据集总共包含1000个类,CLIP团队陆陆续续地提供了80个提示模板。
Visual N-Grams是17年的工作,它是首个将零样本迁移到现有图像分类数据集的算法。它使用一般预处理模型研究zero shot到标准图像分类数据集的迁移。
下表展示了Visual N-Grams和CLIP在三个数据集上的性能对比。在ImageNet数据集上,CLIP模型在没有使用这128万标注数据的前提下,将准确率从Visual N-Grams的11.5%提升到76.2%。在aYahoo和SUN数据集上,CLIP模型相比于Visual N-Grams模型的性能有所提升。
CLIP与Visual N-Grams比较相似,但是17年的时候,transformer还没有出世,上述的比较,主要是为了了解CLIP的性能。
2015年时,深度学习模型在ImageNet测试数据集的性能超过人类,但是这些模型仍然会犯一些简单的错误,我们戏称为人工智障。我们知道,深度学习模型的训练和测试数据集遵从独立同分布IID假设,这样就导致模型对分布外的数据分类性能较差。最常见的一个解释就是:深度学习模型非常善于找到其训练数据集中的一些相关性和模式,而这些相关性和模式实际上是伪造的,不适用于其他分布,导致模型在其他数据集上的性能大幅下降。为了使模型泛化性能更好,有一些学者在研究分布外OOD(out-of-distribution)分类问题。
CLIP模型从一个不同于以往的角度研究这个问题,它在一个非常大的数据集上通过自然语言监督进行训练模型,能够实现zero-shot的高性能。直观上说,zero-shot 模型由于没有针对某个分布进行训练,它不能够学习到仅在特定分布上保持的虚假的相关性和模式,因此,zero-shot模型应当具有更高的鲁棒性。
ImageNetV2、ImageNet Sketch、ObjectNet, ImageNet Adversarial 和 ImageNet Rendition这几个数据集,为ImageNet数据集的分布偏移。训练集为ImageNet数据集训练得到的模型,在这五个数据集上的表现都低于在ImageNet测试数据集上的性能;而zero-shot CLIP模型则取得较好的性能,如下图所示,尤其实在ImageNet-R数据集上,有51.2%的性能提升。