Contrastive Learning(对比学习)–CLIP笔记(一)
参考:CLIP 论文逐段精读【论文精读】_哔哩哔哩_bilibili
CLIP简介
CLIP是一种多模态预训练模型,由OpenAI在2021年提出,论文标题:Learning Transferable Visual Models From Natural Language Supervision ([2103.00020] Learning Transferable Visual Models From Natural Language Supervision (arxiv.org))
论文有四十多页,作者做了超级多的实验,看李沐老师和朱老师的视频讲解也算是一次知识蒸馏([1503.02531] Distilling the Knowledge in a Neural Network (arxiv.org) by Hinton)了
通过大量的图像-文本对进行训练,CLIP的核心思想是通过对比学习来训练模型。它将图像与文本配对,并尝试将它们映射到相同的特征空间中。在训练过程中,模型区分真实配对的图像和文本与错误配对的图像和文本。
clip涌现出的能力:很强的迁移能力,很强的zero shot能力,在不使用imagenet微调的情况下,和resnet50效果接近
在超过三十个数据集上测试,包括ocr,视频动作检测等任务
而且是一篇多模态的工作
如何训练
训练文本图像对的模型需要大数据集,所以OpenAI收集了很多数据,训练样本是图片文本对(4亿),如图所示,利用自然语言处理获得的监督信号进行训练
对角线是正样本(n个),负样本(n^2-n个)
用自然语言作为监督信号:(1)不需要再标注数据,只需要下载图片和文字的配对
(1,n)的标签->文本,模型的输入输出自由度变大很多
(2)图片文本绑定,学习到的不只是视觉特征,多模态特征容易去做zero shot 学习
对比任务:判断文本和图片是不是一个配对,而不是逐字逐句的去预测图像对应的文本,所消耗的计算资源大大减少,且更简单(生成式变为判别式)
生成型对比函数换成对比型函数,训练效率提升四倍
clip训练伪代码:
I[n,h,w,c]图片维度(batch_size,244,244,3)(例如)
T[n,l]文本维度(batch,length)
通过文本,图像编码器得到文本和图像特征,经过归一化(中间还要经过一个投射层,主要是为了从单模态转换到多模态)
有了n个图像的特征和n个文本的特征,计算图像特征和文本特征之间的余弦相似度
(logits):用于分类的logits
使用logits和ground truth做loss
创建ground truth的方式和moco不同,对角线上的元素才是正样本
大多数对比学习工作(-2022)用的都是这种对称式的目标函数
文中提到因为数据集很大,所以训练不太可能有过拟合的问题
投射层使用线性投射层,为什么不使用非线性的:在moco,simclr中使用非线性投射层带来的提升很大,但是在clip多模态的预训练中作者发现线性和非线性投射对性能影响不大
论文中只用了数据裁剪做数据增强
对于对比学习的temperature参数的调整会对性能带来很大改变,clip直接将T设置为了可以学习的标量,在模型训练过程中优化
使用Adam优化器训练
做了超参数搜索
混精度训练,分布式并行训练:节省内存
clip如何做zero shot推理:
clip预训练后只得到视觉和文本上的特征,没有在任何分类的任务上做训练和微调,没有分类头(详解深度学习图像分类中的分类头-CSDN博客)
使用prompt template方法:
例如imagenet,将1000个类,变成一个句子,比如plane变为A photo of a plane
1000个句子通过预训练好的文本编码器,得到1000个文本的特征
预训练时看到的基本上都是句子,推理时如果变为直接编码类别的那一个单词,效果会下降,句子的选取也很重要(prompt engineering和prompt ensemble)
推理时图片的特征和文本的特征做相似性(cosine similarity)
和哪个文本特征最相似,就将那个句子挑出来,完成分类任务
zero shot的推理方式任何图片+任何文本
几乎摆脱了categorical label的限制,而且clip将视觉和文本的语义联系到一起,所以学到的特征的语义性非常强,迁移性能也很强
prompt engineering and ensembling
主要是微调阶段/推理时使用的一种方法(不需要太多的计算资源)
prompt:提示作用(文本的引导作用)
(1)文本的多义性,歧义性:
只给一个单词而不加任何的上下文语义信息,文本编码器很容易理解错误
(2)预训练时用的是句子-图像,在推理时如果只给一个单词,没有上下文语义信息,会导致效果没有用句子好
作者使用了一个简单的prompt template,将所有类别都写成A photo of a {label}.的句子形式
当推理前知道在做什么任务,可以很好的帮助推理,比如知道要推理的图片是一种宠物,就可以:
clip做OCR:
多用几种模板做多次推理,综合结果
论文中使用了80个提示模板
实验
zero shot transfer
CLIP之前的自监督、无监督的方法主要是去学习比较好的泛化能力强的特征,应用到下游任务还是要微调
CLIP推理时encoder都是已经预训练好的,而且推理是并行的
在27个数据集上的效果:
对于难任务的few-shot迁移(比如带有特定领域知识的)
如果下游任务用全部的数据:
作者只训练linear probe(linear probe不太需要调参,简化方法之间的对比),不fine-tune的情况下,使用下游任务的全部数据和之前的工作做了对比,效果也很好(这里就不放图了,论文作者做的实验特别特别多,还做了人工和模型的对比实验(我爱发明人工VS机器🤦))
不足
有些数据集在zero shot不是很好,有些数据集没有和sota对比
在自然图像上好,在合成数据集,out of distribution的类别也不是特别好
没有全部自动化(自动生成类别)gpt化
结合对比学习和生成式的目标函数
需要新的零样本性能测试数据集
使用clip
# $ conda install --yes -c pytorch pytorch=1.7.1 torchvision cudatoolkit=11.0
!pip install ftfy regex tqdm
!pip install git+https://github.com/openai/CLIP.git
import torch
import clip
from PIL import Image
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load("ViT-B/32", device=device)
image = preprocess(Image.open("/content/test.png")).unsqueeze(0).to(device)
text = clip.tokenize(["a banana", "lyrics", "a song","a album cover"]).to(device)
with torch.no_grad():
image_features = model.encode_image(image)
text_features = model.encode_text(text)
logits_per_image, logits_per_text = model(image, text)
probs = logits_per_image.softmax(dim=-1).cpu().numpy()
print("Label probs:", probs) # prints: [[0.9927937 0.00421068 0.00299572]]
我这里用的是一张地下丝绒(the velvet underground)的专辑封面和歌词:
运行代码后可以看到,CLIP对于a banana和lyrics的预测概率是比较高的,还是很准确的,这也对应了OpenAI展示的CLIP超强的泛化能力,不论是真实的水果图片还是抽象的水果图片,识别准确率都很高
相关工作(-2022年底)
styleclip(用于图像生成,用文本对图像进行修改和处理)
CLIPDraw生成简笔画
物体检测和分割:
open vocabulary detector,摆脱基础类的限制
视频检索:clifs,通过输入文本的来检索
后记
其实CLIP提出的方法在之前就有人提过类似的,只不过算力和数据量都没有到达一定的规模,CLIP也是OpenAI经典的大力出奇迹,简单有效的方法加上大规模的数据和算力得到了惊人的成果,作者文章写的十分全面,对前人的工作介绍也都很详细(十分谦逊的致敬了之前的那些工作(respect)),而且思考了很多模型之外的问题,比如安全问题和数据没有经过笔记完善的清洗会导致的一些偏见问题,而且作者将自己工作的不足之处一一指了出来,为后人的研究指明了很多方向。