多模态对比学习预训练模型CLIP

我经常在面试的时候问候选人如何构建一个文本配图系统,有不少人都会想到OpenAI的 CLIP (Contrastive Language–Image Pre-training) 模型。确实,CLIP的思路应该是解决这个问题的一个好框架,正好之前的几篇文章又都是关于其中的关键技术,于是这篇文章重温一下CLIP。 方法 自然语言信号 At the core of our approach is the idea of learning perception from supervision contained in natural language. 正如作者所说,这是CLIP的核心,但并不是一个新的方法。很多过去的研究都使用自然语言信号来训练图片编码器,但大家使用的方法各不一样。 用自然语言信号有几个好处,一个是数据收集容易了,有相关性的图文在互联网上很多,不需要标注,第二个是与之前那种类别空间相比,自然语言信号更容易迁移,后面还会具体讲到。 更大的数据集 CLIP构建了一个400 million 图片-文本对组成的数据集。比之前类似工作所使用的数据集大了二十几倍。而且这些数据集都是互联网上现成的,只是做了一些过滤来保证质量。 it is trained on a wide variety of images with a wide variety of natural language supervision that’s abundantly available on the internet 更大的模型 文本编码器使用的是12层8个头512个隐层神经元的Transformers模型,但没有使用预训练模型。我猜测这是因为要跟图像编码器交互,所以预训练可能帮助不大,如果使用预训练模型还需要特殊的策略来让图像和文本编码器的embedding空间匹配起来。 图像编码器尝试了resnet家族和ViT家族。最佳结果是来自于ViT,并且ViT相比于Resnet有更高的训练效率。图像编码器同样也没有使用Imagenet上的预训练权重来初始化。ViT我们在之前有两篇文章介绍,感兴趣的同学可以参考。 更高效的训练目标 过去的SOTA CV模型,如Noisy Student EfficientNet-L2,只训练Imagenet就需要耗费大量的训练时长(33个TPU年),如何能够在超大规模、自然语言信号的数据集上训练出一个好模型是个挑战。这部分也是CLIP最核心的地方。 This data is used to create the following proxy training task for CLIP: given an image, predict which out of a set of 32,768 randomly sampled text snippets, was actually paired with it in our dataset....

December 13, 2021 · 2 min · Yuanhao

对比学习学习笔记

对比学习已经火了一阵了,之前看过一下SimCLR和SimCSE的论文,但走马观花也没有实践。这两天仔细学习了一下,大概明白了是怎么回事。 首先对比学习通常是在自监督的设定下进行表征学习,也就是不依赖标注数据获得一个编码器(Encoder),大致的环节如下 通过一些方式构造人工正样本对 在一个Batch内构造负样本对 设计一个loss,拉近正样本对表征(Embedding)间的距离,扩大负样本对表征间的距离 构造正样本对 对比学习一开始是在计算机视觉领域兴起的,CV论文里最初是通过对一张图片进行两次不同的数据增强来构造正样本对的。 SimCLR里用到的图像增强方法,可以看出来强度是比较高的,模型要学会图像间的关系不是那么容易 后来这把火烧到了NLP领域,最开始也是模仿CV的做法,通过例如删字词、换同义词等数据增强来构造。直到大名鼎鼎的SimCSE横空出世,提出了用两次不同的dropout来构造正样本对的方法,而且效果还特别好。这个方法的前提是在transformers里面每层都有dropout,但常见的卷积神经网络里面dropout往往都只在最后才有,所以并不能迁移到CV界;但最近ViT大火,应该也有人会试着使用这种方法。 SimCSE除了有自监督的版本,还有通过数据集特点构造的有监督版本 损失函数构造 SimCLR里面用的是NT-Xent Loss,它是the normalized temperature-scaled cross entropy loss的缩写,我来翻译的话会叫他“归一化的带温度交叉熵”。其公式如下 $$l(i,j)=-\text{log}\frac{e^{\text{sim}(z_i,z_j)/\tau}}{\sum_{k=1}^{2N}1_{k\ne i}e^{\text{sim}(z_i, z_k)/\tau}}$$ $$L=\frac{1}{2N}\sum_{k=1}^N[l(2k-1,2k)+l(2k,2k-1)]$$ SimCLR中一个batch是由N张图片通过两组不同的增强变成2N张并且穿插排列,即2k-1 和 2k 是由同一张图构造的一对人造正样本。从第二个式子可以发现,一个Batch的Loss是其中N对loss的均值。跟cross entropy相比,首先是指数项从模型预测的概率变成了样本对间的相似度。分子与正样本对的相似度相关,分母则与第i张图与其余图的相似度有关。注意分母中只有2N-1项,因为自己与自己天然组成正样本,不去除的话这个分式的极限值(完美模型的loss值)将变成0.5,总loss也就不是0了。 SimCSE里使用的loss是上面的变种,或者说是个简化版本。$z_i$是原始第i个样本的表征,$z’_i$是对应的人造正样本的表征。与上面不同的是原始样本表征之间的相似度、变换样本表征之间的相似度都没有参与loss计算。 $$l(i)=-\text{log}\frac{e^{\text{sim}(z_i, z’i)}}{\sum^N{j=1}e^{\text{sim}(z_i, z’_j)}}$$ 代码实现 下面是我实现的SimCSE版本的对比学习loss,供大家参考 class NTXentLoss(nn.Module): def __init__(self): super().__init__() def forward(self, rep1, rep2, temperature=0.5): normalized_rep1 = F.normalize(rep1) normalized_rep2 = F.normalize(rep2) dis_matrix = torch.mm(normalized_rep1, normalized_rep2.T)/temperature pos = torch.diag(dis_matrix) dedominator = torch.sum(torch.exp(dis_matrix), dim=1) loss = (torch.log(dedominator)-pos).mean() return loss 实验心得 我还是在之前提到的Pawpularity数据集上进行的实验,并且和论文里的表征学习不同,我是将对比学习作为一个辅助任务来帮助主任务的训练。经过一天的实验,有以下一些发现 在参数合理的情况下,加入对比学习作为辅助任务确实可以提升主任务的表现。 加入对比学习作为辅助任务看上去可以让模型收敛更加稳健,从而可以使用更大的学习率、更高强度的数据增强。 Loss中的温度是很重要的参数,在SimCLR论文中最好的温度是0.1,在SimCSE论文中最好的温度是0.05,但在我的实验里最好的值跟这俩差的很多。熟悉蒸馏的朋友应该知道,温度越高会让样本间的差异越小,loss趋近常数;温度越低则反之。SimCSE论文的消融实验尝试了不同数量级的温度,大家在用的时候也可以大胆地多尝试一下。 将对比学习作为辅助任务额外增加的时间代价不明显。 今天先到这里,上班去辽。

December 6, 2021 · 1 min · Yuanhao