目录
0. CLIP的出现
在计算机视觉领域,最常采用的迁移学习方式就是先在一个较大规模的数据集如ImageNet上预训练,然后在具体的下游任务上再进行微调。这里的预训练是基于有监督训练的,需要大量的数据标注,因此成本较高。自监督方法的好处是不再需要标注。但是无论是有监督还是自监督方法,它们在迁移到下游任务时,还是需要进行有监督微调,而无法实现zero-shot。
- 对于有监督模型,由于它们在预训练数据集上采用固定类别数的分类器,所以在新的数据集上需要定义新的分类器来重新训练。
- 对于自监督模型,代理任务往往是辅助来进行表征学习,在迁移到其它数据集时也需要加上新的分类器来进行有监督训练。
- NLP领域,基于自回归或者语言掩码的预训练方法已经取得相对成熟,而且预训练模型很容易直接zero-shot迁移到下游任务,比如OpenAI的GPT-3。
这种差异一方面是由于文本和图像属于两个完全不同的模态,另外一个原因就是NLP模型可以采用从互联网上收集的大量文本。
作者认为谷歌的弱监督方法和之前的方法的一个重要的区别在于规模,或者说算力和数据的规模不同。
但是新的问题来了:采用什么样的方法来训练。OpenAI首先尝试了VirTex模型,即联合训练一个CNN和文本transformer来预测图像的文本(image caption),但是发现这种方法的训练效率(用ImageNet数据集上的zero-shot性能来评估)还不如直接预测bag of words,如下图所示,两者的训练效率能相差3倍。如果进一步采用ConVIRT,即基于对比学习的方法,训练效率可以进一步提升4倍。之所出现这个差异,这不难理解,训练数据所包含的文本-图像对是从互联网收集来的,它们存在一定的噪音,就是说文本和图像可能并不完全匹配,这个时候适当的降低训练目标,反而能取得更好的收敛。而从任务难度来看:Transformer Language Model > Bag of Words Prediction > Bag of Words Contrastive (CLIP)。由于训练数据量和模型计算量较大,训练效率成为一个至关重要的因素。这就是作者最终选择对比学习的方法来训练的原因。
从本质上来讲,CLIP其实并没有太大的创新,它只是将ConVIRT方法进行简化,并采用更大规模的文本-图像对数据集来训练。
1.工作过程
CLIP(Contrasive Language-Image Pre-training):用文本作为监督信号来训练可迁移的视觉模型。这是一种基于对比文本-图像对的预训练方法或模型。
Text Encoder:用于提取文本特征,可采取NLP常用的text transformer模型
Image Encoder:提取图像特征。采用CNN模型或者vision transformer
对于N个文本-图像对的训练batch,将N个文本特征和N个图像特征两两结合,CLIP模型会预测出个可能的相似度(计算文本特征和图像特征的余弦相似性cosine similarity)
对角线元素为正样本,有N个;剩余为负样本。
训练目的:最大N个正样本相似度,同时最小化个负样本相似度
其过程伪代码如下:
# 分别提取图像特征和文本特征
I_f = image_encoder(I) #[n, d_i]
T_f = text_encoder(T) #[n, d_t]
# 对两个特征进行线性投射,得到相同维度的特征,并进行l2归一化
I_e = l2_normalize(np.dot(I_f, W_i), axis=1)
T_e = l2_normalize(np.dot(T_f, W_t), axis=1)
# 计算缩放的余弦相似度:[n, n],并进行缩放(让N个匹配的图文对比相似度最大,不匹配的图文对比相似度最小)
logits = np.dot(I_e, T_e.T) * np.exp(t)
# 对称的对比学习损失:等价于N个类别的cross_entropy_loss
labels = np.arange(n) # 对角线元素的labels
# 对每一行和每一列求交叉熵损失
loss_i = cross_entropy_loss(logits, labels, axis=0)
loss_t = cross_entropy_loss(logits, labels, axis=1)
loss = (loss_i + loss_t)/2
2. 实现zero-shot分类
补充知识:ZSL(zero-shot learning)零样本学习,让计算机模拟人类的推理方式,利用已有知识对新对象进行识别。
利用类别的高位语义特征代替样本的低维特征,使得训练出来的模型具有可迁移性。
CLIP可以直接实现zero-shot的图像分类,既不需要任何训练数据,就能在具体下游任务上实现分类。两步过程:
1. 根据人物的分类标签构建每个类别的描述文本:a photo of { label }。将这些文本送入Text Encoder得到对应的文本特征。
2. 将要预测的图像送入Image Encoder得到图像特征,然后与N个文本特征计算缩放的余弦相似度,选择相似度最大的文本对应的类别作为图像分类预测的结果;进一步的,可以将这些相似度看成logits,送入softmax后可以得到每个类别的预测概率。
# 首先生成每个类别的文本描述
labels = ["dog", "cat", "bird", "person", "mushroom", "cup"]
text_descriptions = [f"A photo of a {label}" for label in labels]
text_tokens = clip.tokenize(text_descriptions).cuda()
# 提取文本特征
with torch.no_grad():
text_features = model.encode_text(text_tokens).float()
text_features /= text_features.norm(dim=-1, keepdim=True) #归一化
#读取图像文件,存储相关信息
original_images = []
images = []
texts = []
for label in labels:
image_file = os.path.join("images", label+".jpg") #将图像文件的路径构建为 "images/label.jpg" 的形式
name = os.path.basename(image_file).split('.')[0] #提取文件名,去掉扩展名,以获取一个与图像相关的文本描述
image = Image.open(image_file).convert("RGB") #使用PIL库打开图像文件,然后将其转换为RGB格式。
original_images.append(image) #添加原始图像
images.append(preprocess(image)) #将经过预处理的图像添加到 images 列表中
texts.append(name) #添加文本描述
image_input = torch.tensor(np.stack(images)).cuda() #将预处理后的图像数据堆叠成一个张量,(直接传递给深度学习模型进行批量处理)将其移动到GPU
#提取图像特征
with torch.no_grad():
image_features = model.encode_image(image_input).float()
image_features /= image_features.norm(dim=-1, keepdim=True) #归一化
#计算余弦相似度
similarity = text_features.cpu().numpy() @ image_features.cpu().numpy().T
logit_scale = np.exp(model.logit_scale.data.item())
text_probs = (logit_scale * image_features @ text_features.T).softmax(dim=-1)
top_probs, top_labels = text_probs.cpu().topk(5, dim=-1)
#如果相似性分数的尺度较小,可能会导致 softmax 操作的输出在某些情况下过于集中
#使得模型难以区分不同样本之间的差异。
#通过乘以一个较大的 logit_scale,可以增加相似性分数的范围
#使得 softmax 操作更能够捕捉概率分布中的细微差异。
另外,文本描述的生成也可以直接使用类别标签,prompt learning
补充知识:核心是构建合适的prompt(提示)来使预训练模型能够直接应用到下游任务,和之前的预训练+微调属于不同的范式。直接使用类别标签作为文本提示缺少上下文,与CLIP的训练数据不太一致。
论文实验采用了80个不同的prompt进行集成,对比了基于ResNet的CLIP模型直接采用类别名与进行prompt engineering和ensembling的效果对比:
3. 对比其他方法
1. VISUAL N-GRAMS
2. we compare to the performance of a simple off-the-shelf baseline: fitting a fully supervised, regularized, logistic regression classifier on the features of the canonical ResNet-50. In Figure 5 we show this comparison across 27 datasets.
其中,在MINIST这个简单数据集上表现较差。作者探索发现,因为在4亿的训练数据中基本没有和MINIST比较相似的数据,所以这个对于CLIP来说属于域外数据。
CLIP仍然无法解决域外泛化这个深度学习难题。
3. few-shot:只用少量的样本来微调模型
4. 表征学习(representation Learning)实验,即自监督学习中常用的linear probe
4. Limitation
可能存在数据泄露:训练集包含一些测试数据集的样例。
论文采用一个重复检测器对测评的数据集重合做了检查,发现重合率中位数为2.2%,平均值3.2%
去重后大部分性能没有发生太大的改变