上次说到视觉语言模型是一种结合了计算机视觉和自然语言处理技术的模型,主要基于注意力机制和Transformer架构。按照训练范式的不同,主要有基于对比式、遮掩式、预训练式和生成式的。这次就介绍对比式中非常具有影响力的模型,CLIP(Learning Transferable Visual Models From Natural Language Supervision)1.
基于对比式的视觉语言模型
介绍CLIP之前,我们先回顾下什么是基于对比式的视觉语言模型。对比式的视觉语言模型基于对比学习的方法,思想就是同性相吸,异性相斥。具体来讲是将不同模态的内容进行编码得到不同模态的特征,不同模态的特征通过对比学习损失以拉近或推远,从而学习良好的特征表示。
动机
作者发现之前自监督的方式都在学习特征表示,应用到下游任务的时候,还需要少量标签做微调。那能不能进一步与下游任务再进行解耦呢?作者通过引入文本特征作为监督信号,告诉我们这是完全没问题的!
CLIP模型框架
CLIP出自OpenAI,是典型的基于对比的视觉语言模型,启发了后面一大推的工作,影响不可谓不大2 3。它模型非常的简单,思想是以文本特征作为监督信号,引导模型更新参数与推理。效果非常的好,在经过预训练后,下游任务上甚至零样本(Zero-shot)效果都能达到SOTA。
为什么说CLIP模型非常简单呢,请看图1的模型框架图。如图1,我们清晰可见一共是三部分组成,第一部分是对比预训练,文本和图片分别经过编码器得到不同模态(所谓模态是指事物经历、发生或捕捉的方式,可以理解为感知或表达事物的方式)的特征,不同模态特征计算相似性后,利用标签计算对比损失,以此拉近正例,推远负例(所谓正例和负例都是人们规定的,这里的正样本就是图片与相适配的文字描述)。第二、三部分是说CLIP如何零样本结合下游任务的,对于一个分类任务,比如有1000类,那么就对应1000个单词,经过了文本编码器得到文本模态的特征,再和图像模态的特征计算相似性,以概率大者为类别标签。由于训练的时候,输入不是单词,是文本,因此对单词进行扩充为句子,即如图所示的A photo of a {object}. 其实,这就是Prompt而已,而Prompt的本质是缩小搜索空间,缩小了搜索空间,自然更容易命中answer。
图1 CLIP模型的框架图
那么文本编码器和图像编码器又是什么呢?
作者也说了,图像编码器可以采用ResNet和ViT等,文本编码器可以采用Transformer。
好了,CLIP模型框架就讲完了,真特喵的简单!可谓大道至简了。这里不放模型效果图啦,有兴趣可以去看1,作者真的做了非常非常多的实验。
对比学习的高效
CLIP没有使用之前OpenAI的基于GPT的方式,也没有Bag of Words方式,也就是说CLIP不需要你逐字逐句去预测文本内容了,而是采用了对比学习方式。文本相互适配即可,从这个角度看,约束是被放宽了。作者做了实验发现采用对比方式,其学习效率是其他方式的若干倍,如图2所示。
图2 不同训练方式的对比
个人认为,引入文本监督信号后,文本本身具有解释、概括和抽象等功能,能学习更快更好也很合理。
尽管CLIP模型效果非常好,但也需要知道,毕竟作者收集了4亿多张图片-文本对来训练模型,这么多的数据是远远大于下游任务的数据集大小的。从这个角度来看,这样的比较本身就很难说是公平的。
微调与线性探测(Linear probe)
最后再说说这两兄弟,对于上游训练好的大模型。我们可以对大模型进行微调或者Linear probe.
前者要变动训练的模型参数,后者是添加个分类头之类的,往往是若干线性层构成。
辨证来看,前者往往更加灵活,效果好,但与下游任务联系紧密。后者看着呆萌,但与下游任务解耦。
CLIP的有限性
CLIP简单且有效,当然它也有一些问题,例如
- CLIP效果不错,但与一些数据集的SOTA还是有差异的。
- CLIP对推理能力有限,比如物体计数任务等。
- CLIP对数据敏感,训练数据中如果见得不多的样本,那么对应数据集效果就比较糟糕,例如MNIST数据集。
- CLIP还不是生成模型,尽管不受数据集类别限制了,但还需要提供类别,要是生成模型,那将会更加自动化。
当然还有其他的问题,感兴趣的也可以看原文。
Colab上CLIP的使用4
既然CLIP这么简单且强大,我们不妨试一试使用下CLIP在Colab上。如果你还不会使用Colab,可以看这博主的使用教程5,写得较为详细。
首先,我们先安装所需要的包,并加载预训练的模型。
# pip packages
! pip install ftfy regex tqdm
! pip install git+https://github.com/openai/CLIP.git
# import packages
import clip
import torch
import numpy as np
from PIL import Image
# load
device= 'cuda' if torch.cuda.is_available() else 'cpu'
net, preprocess= clip.load('ViT-B/32', device= device)
然后,下面是展示图片的代码,
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
img= mpimg.imread('sample_data/bookshop.jpg')
imgplot= plt.imshow(img)
plt.axis('off')
plt.show()
如图3所示,这是我拍的南京先锋书店的照片(补充,先锋书店真的很有意境,适合去看看书,但是我还是倾向于网上买书,不是它不好,而是网上买更有性价比)。
图3 南京先锋书店
其实,如果我们看图片的话,还是挺有挑战的,毕竟是繁体字哈。让我们看看模型的表现吧。
image= preprocess(Image.open('sample_data/bookshop.jpg')).unsqueeze(0).to(device)
text= clip.tokenize(['bike', 'japan', 'china', 'book', 'bookstore']).to(device)
with torch.no_grad():
image_features= net.encode_image(image)
text_features= net.encode_text(text)
logits_per_image, logits_per_text= net(image, text)
probs= logits_per_image.softmax(dim= -1).cpu().numpy()
print(probs)
# [[0.00268872 0.14200783 0.09471603 0.00353696 0.75705045]]
可以看到哈,CLIP真的很厉害,选择bookstore的信心很高。但是感觉还是有不足的地方。比如直觉上看book的概率应该超过japan吧,japan的概率竟然超过了china,有点迷,要是有知道为什么的小伙伴可以跟我讲讲。