CLIP打通文本图像壁垒,为AI图像生成打下基础

时间:2022-12-12 11:23:38

本文有5230字,阅读大概需要10分钟。10分钟你肯定看不完,老老实实看吧。


碎碎念

事情是这样的,前两天晚上我嵩突然发了DreamStudio让我们玩一下。

CLIP打通文本图像壁垒,为AI图像生成打下基础

其实我现在正在做的方向就是扩散模型,然后恰好这个DreamStudio就是扩散模型,更巧的是它列了四条技术,第一个就是CLIP。那我们就来说一下CLIP是什么东西。


CLIP

论文地址:[2103.00020] Learning Transferable Visual Models From Natural Language Supervision (arxiv.org)

代码地址:openai/CLIP: Contrastive Language-Image Pretraining (github.com)

这个工作我们称之为CLIP,是OpenAI的一个工作,方法简单有效,用的就是我之前讲到的对比学习的方法。虽然方法简单,但是迁移学习能力无敌,他训练出来的模型可以在任意的数据集(作者们在30多个数据集上进行测试)上取得很好的效果,并且重点是它是zero-shot,完全不需要你再去微调模型。

模型总览

CLIP打通文本图像壁垒,为AI图像生成打下基础

预训练

可以看一下(1),预训练阶段使用的是对比学习,我们可以看到是把一组文本和一组图片丢进了一个孪生网络。使用自然语言处理的结果作为监督信息公提供给图像进行学习。

图片进入图片编码器获得对应的图片特征$I_i$,文本进入文本编码器获得对应的文本特征$T_j$,之后二者组成矩阵,矩阵对角线上的特征是图文对应的信息,矩阵其他位置的特征是图文不对应的信息,这样我们就可以将对应的信息作为正样本,不对应的信息作为负样本,从而进行对比学习。在这样的设置之下,假设我们一个batch size大小设置为n,那我们就能获得$n$个正样本和$n^2-n$个负样本。

这样就不需要图片标签,使用对比学习进行预训练了。但是对比学习需要大量的数据,为此OpenAI也是下了大功夫,收集了4亿个text-image对,并做的极好的数据清晰,才能保证模型最终获得如此优秀的效果(主要原因之一)。

分类器

因为使用对比学习,所以CLIP是没有分类头的,所以作者得想个办法让它能去做分类。在这里就用到了NLP中的一个方法——“prompt template”。

看看图中的(2),用左边不同的词汇(多少类别就是多少词汇)去替换中间方框中的那个句子A photo if a _____ .,把一个单词变为一个句子。之后使用编码器对其进行编码获得特征。其实在这里不是必须将其变为一个句子,单个的单词也是可以进行的,但是会和训练阶段产生较大的差异,所以作者在这里还是麻烦了一点,将其都变为句子。这里怎么变为句子还是有说法的,具体可以看一下这篇文章:

然后看图中的(3),在预测阶段,我们拿到一张图之后将其丢进图片编码器,获得一个特征,之后我们使用余弦相似度计算我们获得的句子特征和图片特征,取得最终的分类结果。

补充一下,在CLIP,模型训练完之后因为是zero-shot的,所以完全可以摆脱categorical label的限制,(2)中的列表我们可以替换为任意的单词,完全不要纠结于ImageNet的1000类还是3000类,图片也可以是任意出处的图,不拘泥于某一个数据集。

总结: 因为其独特的训练方式,所以CLIP将图片和文本语义做到了强关联,每个图片都有非常好的语义特征,所以迁移效果非常好。凭借这一点,CLIP在ImageNet数据集上打败了ResNet101等专门在ImageNet上训练的模型。因为和自然语言处理的结合,CLIP训练出来的模型可以在图片域变化非常大的情况下也获得很好的效果。


Learning Transferable Visual Models From Natural Language Supervision

少说点

在之前的一些模型都需要一些预定义的类,比如cifar-10有10个类,提前定义好的类别会影响模型的泛化性,因为之前的类别中没有设置到这些内容,所以遇到一些新数据可能会出现无法处理等问题。所以这个作者们想做一个泛化能力强的模型,大家就考虑能不能借助自然语言处理,从文本中获得一些监督信号,这样的话监督信号就很丰富了,你只要能用语言描述,我就可以将你作为文本信息标签,将其放到视觉模型中。

所以作者就去爬了4亿的数据,使用图片文本多模态做了一个对比学习的预训练。为了验证模型的有效性,作者去30个数据集上进行了多个任务的测试,在不需要任何数据集专门训练的情况下,能和之前的一个完全用有监督方法训练出来的模型取得相同的效果甚至吊打人家。

作者在论文里稍微提了一下之前的工作,但是效果不行,总结原因就是他们没有OpenAI的 钞能力

方法

概述

CLIP方法的核心就是借助自然语言,之前的NLP的transformer和自监督训练兴起之前,很难将其应用到图像这边,但是现在NLP发展起来了,可以使用自监督学习获得上下文语义,使用海量的无标签数据获得又大又好用的模型了。

为什么CLIP要用自然语言的监督信号训练视觉模型?

  • 不需要再去标注数据了。在ImageNet上是128万图片及其1000类,但是使用自然语言,就不需要这么麻烦了,你只需要去网上爬到对应的文本数据对。并且现在图片对应的不再是标签,而是变成了文本,这样模型的输入输出更加灵活。

  • 训练过程将图片文本绑定到一起,模型学到的是多模态的特征,更有利于模型的泛化。

  • ……

CV方向的模型都很大,训练起来都很费钱费时间。举个夸张的例子,ResNeXt101-32x46d需要训练33个TPUv3年,如果你用GPU的话可能要算好几个世纪了。之前模型的数据集都没有CLIP大,虽然OpenAI的钞能力是出了名的,但是作者也不敢想象要烧多少亿才能把模型训练起来。所以作者们进行了一系列的尝试,比如图片用CNN,文本用transformer,做一个预测任务。但是要知道预测任务的可能性太多了,比如给我们一张图,做这个图的caption。我们看一下下图,可以得到很多结果,比如:

  • 图上是杨戬。

  • 图上是LolitaAnn的老公。

  • 图中是一个男人的侧脸。

  • 这个男人看起来很悲伤

  • ……

CLIP打通文本图像壁垒,为AI图像生成打下基础

这种开放式的预测答案实在是太多了。但是如果使用对比学习的训练方法,我们仅需要判断图文能不能搭配起来即可。这样任务就被简化了很多,约束也放宽了很多。看一下下图,作者将预测型的目标函数转化为对比学习的目标函数之后,训练速度一下子提高了很多。

绿色的线是CLIP最终选择的对比学习训练方式,比中间橙色的线快了四倍。中间橙色的线是使用词袋模型,将内容都抽取为特征进行匹配,比蓝色的线快了三倍,蓝色的线是原来的预测型的训练方式。

CLIP打通文本图像壁垒,为AI图像生成打下基础

最终为了保证训练效率,选择了对比学习。

因为OpenAI的这个数据集太大了,所以训练过程中根本不用担心出现过拟合的问题,也不需要做什么数据增强,用的唯一一个数据增强就是一个随机裁剪(random square crop)。

因为模型实在是太大了,调参实在是太困难了,所以进行对比学习的时候将对比学习中很重要的一个t temperature parameter作为一个可学习的标量,所以这个参数在模型训练过程中直接就被优化了,不需要再调参了。

此外他们使用的图像和文本的编码器都不需要预训练,并且最后做projection的时候没有使用非线性的投射层,使用的是线性的投射层。

补充:看过之前我写的对比学习系列的应该知道,在SimCLR工作中因为加了一个非线性的projection之后获得了10个点的提升,但是CLIP的作者在工作过程中发现,多模态中使用线性还是非线性影响并不是很大,对此作者还进行了一个 猜测 ,这种非线性的projection应该只能适用于纯图片的单模态学习。

伪代码

# image_encoder - ResNet or Vision Transformer 
# text_encoder - CBOW or Text Transformer 
# I[n, h, w, c] - minibatch of aligned images 
# T[n, l] - minibatch of aligned texts 
# W_i[d_i, d_e] - learned proj of image to embed 
# W_t[d_t, d_e] - learned proj of text to embed 
# t - learned temperature parameter 

# extract feature representations of each modality 
I_f = image_encoder(I) #[n, d_i] 
T_f = text_encoder(T) #[n, d_t] 

# joint multimodal embedding [n, d_e] 
I_e = l2_normalize(np.dot(I_f, W_i), axis=1) 
T_e = l2_normalize(np.dot(T_f, W_t), axis=1) 

# scaled pairwise cosine similarities [n, n] 
logits = np.dot(I_e, T_e.T) * np.exp(t) 

# symmetric loss function 
labels = np.arange(n) 
loss_i = cross_entropy_loss(logits, labels, axis=0) 
loss_t = cross_entropy_loss(logits, labels, axis=1) 
loss = (loss_i + loss_t)/2

伪代码我就不讲了,具体看安安的这篇文章: CLIP模型伪代码详细解析

不是我的小号!

训练

We train a series of 5 ResNets and 3 Vision Transformers. For the ResNets we train a ResNet-50, a ResNet-101, and then 3 more which follow EfficientNet-style model scaling and use approximately 4x, 16x, and 64x the compute of a ResNet-50 . They are denoted as RN50x4, RN50x16, and RN50x64 respectively. For the Vision Transformers we train a ViT-B/32, a ViT-B/16, and a ViT-L/14. We train all models for 32 epochs. We use the Adam optimizer with decoupled weight decay regularization applied to all weights that are not gains or biases, and decay the learning rate using a cosine schedule.

训练过程作者是训练了5个ResNet网络和3个Vision Transformer模型,每个模型都训练了32个epoch。使用的是Adam优化器。

Initial hyperparameters were set using a combination of grid searches, random search, and manual tuning on the baseline ResNet50 model when trained for 1 epoch. Hyperparameters were then adapted heuristically for larger models due to computational constraints.

对于所有的超参数,作者也是做了一些简单的grid search和random search进行手动调整,为了调的快一点,用的都是标准的ResNet50去做的,并且就跑了一个epoch,就突出一个懒得调。更大模型直接摆烂根本不调的。

The learnable temperature parameter t was initialized to the equivalent of 0.07 from and clipped to prevent scaling the logits by more than 100 which we found necessary to prevent training instability. We use a very large minibatch size of 32,768.

训练的batch size直接拉满,到32768,我只跑过8192的,再次感叹一下OpenAI的钞能力!!!

Mixed-precision was used to accelerate training and save memory. To save additional memory, gradient checkpointing, half-precision Adam statistics, and half-precision stochastically rounded text encoder weights were used. The calculation of embedding similarities was also sharded with individual GPUs computing only the subset of the pairwise similarities necessary for their local batch of embeddings.

此外作者还用了这么多加速和省内存的tricks,通过这么多的努力才把CLIP训练起来。

一番烧钱操作之后,作者最终选定了ViT-L/14并对其进行微调。然后CLIP就定下用这个了,之后我们就确定以及肯定提到图片编码器用的就是ViT-L/14@336px

模型局限性

有的人会提出质疑,你这玩意儿效果好,是不是因为你四亿对数据集太大了,把人家其他数据集都涵盖了,所以你的结果才能这么好看?

为了防止这样的问题,作者对数据集进行了去重等一系列操作,最后的结论就是 **“我的模型就是好用”**。

吹了半天它多厉害之后我们讲一下模型的局限性。

作者说CLIP在很多数据集都能和简单的baseline打成平手的,比如ResNet50,但是要知道ResNet只是baseline,不是SOTA,CLIP目前在很多任务上是打不过SOTA的,所以是一个比较均衡的强大,但是能力不是很拔尖。

CLIP的如果继续扩大模型和数据集去追赶SOTA的话,作者预估的是还要扩大1000倍,但是即使对于OpenAI这样的钞能力公司来说也是跑不起的(其他人更别做梦了),所以想靠着扩大模型扩大数据集来改进模型,几乎不太可能。(**OpenAI:面子我给各位了,各位不要不识好歹。**)

另一个缺点是,CLIP在某些数据集上效果也就一般般,比如在细分类上zero-shot就不行,并且CLIP没办法做一些很抽象的东西,也没办法做一些异常检测之类的艰难任务。

第三个局限性是虽然泛化能力做的很好,但是如果在做图像推理过程中遇到真正的OOD是无法处理的,并且作者说很尴尬的一个事情是在MNIST中准确率只达到88%,作者找了一下原因,发现是四亿对图片居然没有和MNIST相像的图片,因为MNIST是简单的12345的数字识别嘛,他们的数据集里居然无!!!

第四个局限性是虽然可以做分类任务,并且你可以自定义分类的种类和列表,但是还是只能在你给定的类别里做选择。相比而言,直接去生成图像标题,让模型去做生成,这样会更灵活。这一点看出作者还是想秉承OpenAI一贯的工作去做预测任务,但是受限于计算资源没办法去实现,之后作者可能会考虑怎么合并一下对比学习的目标函数和生成式任务的目标函数,将二者的优势结合到一起。

第五个局限性是对数据的利用不是很高效,需要大量的数据集去投喂。你想32个epochs,每轮都是4亿图,这就是跑了128亿的图啊!!!DataLoader好辛苦啊……如果能优化数据用量就好了。如果能在这里改进就好了。

然后是下有数据的局限性。虽然一直都在说zero-shot,但是为了和其他模型去打一打,不停地在目标数据集上进行优化,不停用27个数据集去做测试,这样就在无形中引入了偏见,也就是说这个模型更偏向于打败这27个数据集。 我摊牌了

然后是他们的数据集是去往上爬的,数据清晰做不好的话可能会带有一些bias,会引发一些伦理问题。

很多很复杂的任务和概念,有的你用语言也是无法描述的,如果在下游任务中如果能给一些prompt会更好,但是CLIP做的目标就是zero-shot,你给他一些数据反而效果会变差,所以这也是很奇怪一点。