CLIP和改进工作串讲(LSeg、GroupViT、VLiD、 GLIPv1、 GLIPv2、CLIPasso)
一、CLIP
1.1 简介
1.1.1 前言
CLIP是OpenAI在2021年2月发表的一篇文章,其全称为Contrastive Language-Image Pre-training,即一种基于对比文本-图像对的预训练方法。CLIP用文本作为监督信号来训练可迁移的视觉模型,使得最终模型的zero-shot效果堪比ResNet50,泛化性非常好,而且CLIP还有很多好玩的应用。
zero-shot就是直接推理, 用见过的图片特征去判断没见过的图片的类别,而完全不用下游任务训练集进行微调。(相当于把模型用作特征提取,但是没有分类头)作者在30多个不同的计算机视觉数据集上进行基准测试,(这些数据集涵盖了OCR、视频中的动作识别、地理定位和许多类型的细粒度对象分类等任务)
CLIP通常都能够与监督模型的baseline效果相媲美。例如在ImageNet数据集上,
CLIP模型在不使用ImageNet数据集的任何一张图片进行训练的的情况下,最终模型精度能跟一个有监督的训练好的ResNet-50打成平手(在ImageNet上zero-shot精度为76.2%,这在之前一度被认为是不可能的)。
1.1.2 模型结构
训练过程:
如下图所示,CLIP的输入是一对对配对好的的图片-文本对(比如输入是一张狗的图片,对应文本也表示这是一只狗)。这些文本和图片分别通过Text Encoder和Image Encoder输出对应的特征。然后在这些输出的文字特征和图片特征上进行对比学习。
假如模型输入的是n对图片-文本对,那么这n对互相配对的图像–文本对是正样本(下图输出特征矩阵对角线上标识蓝色的部位),其它 对样本都是负样本。这样模型的训练过程就是最大化n个正样本的相似度,同时最小化 个负样本的相似度。
Text Encoder可以采用NLP中常用的text transformer模型;而Image Encoder可以采用常用CNN模型或者vision transformer等模型。相似度是计算文本特征和图像特征的余弦相似性
cosine similarity为了训练
CLIP,OpenAI从互联网收集了共4个亿的文本-图像对,论文称之为WIT(Web Image Text。WIT质量很高,而且清理的非常好,其规模相当于JFT-300M,这也是CLIP如此强大的原因之一(后续在WIT上还孕育出了DALL-E模型)。

分类
CLIP可以直接实现zero-shot的图像分类,即不需要任何训练和微调,这也是CLIP亮点和强大之处。用CLIP实现zero-shot分类只需要简单的两步:
- 根据任务的分类标签构建每个类别的描述文本:
A photo of {label},然后将这些文本送入Text Encoder得到对应的文本特征。如果类别数目为n,那么将得到n个文本特征; - 将要预测的图像送入
Image Encoder得到图像特征,然后与n个文本特征计算缩放的余弦相似度(和训练过程保持一致),然后选择相似度最大的文本对应的类别作为图像分类预测结果。进一步地,可以将这些相似度看成logits,送入softmax后可以到每个类别的预测概率。
我们不再需要预先定义好的标签(类别)列表,直接将图片喂给不同的文本句子,就可以知道图片中是否有我们感兴趣的物体。即,CLIP的多模态特性(利用文本监督信号)为具体的任务构建了动态的分类器,使得模型不再受限于预先定义好的类别,更加具有通用性和可用性。
比如新增三轮车的图片时,只需要在文本部分也加上三轮车这个类别,模型很有可能直接
zero-shot推理出图片属于三轮车这个类。而之前的模型,是永远不会预测出ImageNet1000个类之外的类的,这也是CLIP最吸引人的地方。类别单词变成句子,有
prompt engineering和prompt ensemble两种方法,进一步提高模型准确率,在论文后面会讲到
1.1.3 模型效果
1.1.3.1 对自然分布偏移的鲁棒性
如下图所示,作者还比较了zero-shot CLIP与现有ImageNet模型在自然分布偏移上的性能来验证它的鲁棒性。

- 左图的横纵坐标是ImageNet的分布偏移。黑色虚线是理想的鲁棒模型,是线性的、正比例的。普通的模型无法达到这样的理想效果,画出来的曲线只会在黑色虚线的下面。但这里可以看出
zero-shot CLIP的鲁棒性比标准的ImageNet训练的模型更好。 ImageNetV2是从ImageNet数据集中筛选出新的数据集,其更接近原来的测试集。然而在ImageNet上预训练的模型,在ImageNetV2上的测试性能下降了不少(76.2→64.3)- 右图中
ImageNet Sketch都是素描的图片、ImageNet-A包含很多对抗样本
CLIP和基于ImageNet上有监督训练的ResNet101,在ImageNet验证集都能达到76.2%,但是在剩下的五个数据集上,ResNet101性能下降得非常厉害,但是CLIP能依然保持较大的准确度。比如在ImageNet-A数据集上,ResNet101精度只有2.7%,而CLIP能达到77.1%。
这也说明CLIP学习到的视觉特征,已经和语言产生了很强的联系。这也不论是自然的香蕉还是动漫里的香蕉、素描的香蕉、加了对抗样本的香蕉,CLIP都知道图片是对应香蕉这个单词。
1.1.3.2 StyleCLIP
顾名思义,这是一篇CLIP+styleGAN的工作,可以通过文字的改变引导图像的生成。比如下面例子中,输入“Mohawk hairstyle”,就能改变奥巴马的发型;输入“Without makeup”,就可以一键卸装了;输入“Cute cat”(可爱的猫),猫的眼睛就睁大了。CLIP 也能理解各种抽象妆容,比如烟熏妆,吸血鬼妆。
1.1.3.3 CLIPDraw
论文《CLIPDraw: Exploring Text-to-Drawing Synthesis through Language-Image Encoders》

这也是一个利用CLIP预训练模型指导图片的生成。 CLIPDraw不需要进行训练,通过在一组RGBA Béezier曲线上执行梯度下降,就可以从文本合成一些简笔画图像。(目标是最小化生成图像的CLIP encodings与文本提示之间的余弦距离)。
在普通GPU上生成一张简笔画通常不需要一分钟。最后一张图的self表示自拍照
1.1.3.4 zero-shot检测
论文《Open-vocabulary Object Detection via Vision and Language Knowledge Distillation》(ICLR 2022)
CLIP可以应用在目标检测任务上,实现zero-shot检测,即检测训练数据集没有包含的类别。比如在CLIP出现的一个半月之后,谷歌提出的ViLD(见本文3.1章节)基于CLIP实现了Open-vocabulary的物体检测,其主体架构如下所示,其基本思路和zero-shot分类相似,只不过这里是用文本特征和ROI特征来计算相似度。

下面的例子中,如果用传统的目标检测算法的话,模型只会判断这些物体都是玩具,也就是图中蓝色的基础类。使用CLIP之后,就可以摆脱基础类的限制(Open-vocabulary Object),可以检测出新的类( 图中红色标识),比如颜色和动物类别。

Meta AI的最新工作Detic可以检测2000个类,背后也用到了CLIP。
1.1.3.5 CLIP视频检索
github上johanmodin/clifs仓库,展示了使用CLIP视频检索的工作。可以通过输入文本直接找到视频中出现的对应物体。比如输入“一辆印有odwalla的卡车”,就真的在视频中找到了这辆卡车(CLIP把这句话变成文本特征,然后将视频中每一帧都当成视觉特征,然后一帧帧的去和文本特征做对比,然后挑出相似性最高的那一帧)。

1.1.4 导言
现有的CV模型基本都是基于人工标注的数据集进行训练的,然后用来预测一组提前定义好的物体类别。这种提前定义好的标签集合,会大大简化问题本身(比如ImageNet固定的1000个类,COCO数据集固定80个类等等)。但正因如此,这种受限的监督信号限制了模型的泛化性和可用性。比如大多数模型都只能预测已知的图像类别。对于没有见过的图像类别,需要额外的信息才能识别。这样每次新增一些类别,都需要重新收集数据,训练一个新的模型。
而且无论是有监督还是自监督方法(基于对比学习的方法如MoCo和SimCLR,和基于图像掩码的方法如MAE和BeiT),在模型迁移时都需要需要进行有监督微调,比如微调固定类别的softmax分类器,而无法实现zero-shot。
作者认为,直接从自然语言中得到监督信息是一个很有前途的选择,因为其涵盖的范围更广(只要是语言描述过的物体,都有可能让视觉模型去识别)。CLIP利用多模态的对比学习,使得自然语言可以引导模型学习到视觉概念,从而实现非常灵活的zero-shot迁移(把分类问题转化为了跨模态检索问题)。
使用自然语言监督进行图像表示学习的工作很少,并且效果往往不如有监督模型,主要有两个原因:
- 早期nlp模型不太好学。
比如早期的n-gram模型非常复杂,不好跨模态训练。但是随着transformer的兴起,像BERT和GPT这种具有上下文表示的自监督训练模型做的越来越好,nlp模型也终于有了取之不尽的文本监督信号,而且使用简单,泛化性好,为多模态训练铺平了道路。 - 数据集或模型的规模不够。
比如VirTex和ICMLM都只训练了十几万的图片;ConVIRT非常类似CLIP,但只在医疗图像上做了预训练。从本质上来讲,CLIP其实并没有太大的创新,它只是将ConVIRT方法进行简化,并采用更大规模的文本-图像对数据集来训练。也可以说,相对于之前的对比学习,CLIP只是将单模态的 样本,换成了多模态的样本。
1.2 方法
1.2.1 自然语言监督的优势
使用自然语言监督信号来训练视觉模型,有两个最重要的优势:
-
不需要采用特别的标注数据,扩展性更强。
比如ImageNet需要先定义好1000个类,然后根据这些类去下载图片,清理数据集,再去标注所有图片,过程很复杂。而CLIP不要求这种经典的“”机器学习兼容“”的标注格式,只需要下载文字-图片对;且没有n选1的标签之后,模型的输入输出自由度大了很多。 -
CLIP学习到的是图像结合文字的多模态特征,从而实现灵活的zero-shot迁移。如果只是单模态的特征,无论是类似MOCO还是MAE,都很难做到这一点(zero-shot必须要加入文字特征才能做到)。
1.2.2 预训练方法(训练效率至关重要)
CV领域的模型都很大,训练起来也很贵。比如noise student之前在ImageNet一直霸榜,但是这个模型需要在一个 TPUv3上训 练33年,这还只是在包含1000类的ImageNet上预训练的,而且只训练视觉特征。
由于训练数据量和模型计算量都很大,训练效率成为一个至关重要的因素。作者做了很多尝试,最终选择了对比学习:
VirTex模型:预测文本,对应下图蓝色线Transformer Language ModelImage Encoder使用CNN模型,Text Encoder使用transformer模型,两个模型一起从头训练,任务是预测图片对应的文本(image caption)。- 这种方法的训练效率太慢,因为根据图片进行文本描述,可能性太多了,你可以从各个角度去描述一张图片。
Bag of Words Prediction(橘色线):不要求每个词都是按顺序的进行预测,所有词都预测出来就行。这样放宽了约束,训练速度提高了三倍。CLIP:简化版的ConVIRT,基于对比学习。- 只需要判断图文是否配对,进一步简化了训练任务,训练效率一下子提升4倍(绿色线)
- 训练任务更加合理。因为训练数据所包含的文本-图像对是从互联网收集来的,它们存在一定的噪音,二者并不完全匹配。适当的降低训练目标,反而能取得更好的收敛。

OpenAI是一家GPT化的公司,从GPT系列、DALL-E到Image-GPT等等都是基于GPT做的,唯有
CLIP因为效率的原因,选择了对比学习进行训练。
最终Text Encoder固定选择一个包含63M参数的text transformer模型,而Image Encoder采用了两种的不同的架构。因为CLIP虽然是多模态模型,但它主要 是用来训练可迁移的视觉模型。
Image Encoder架构- ResNet:ResNet50,ResNet101,RN50x4,RN50x16和RNx64(后面三个模型是按照EfficientNet缩放规则对ResNet分别增大4x,16x和64x得到)
- ViT:ViT-B/32,ViT-B/16和ViT-L/14。
- 所有的模型都训练32个epochs,采用AdamW优化器,batch size=32768。
- 只在ResNet50上训练一个epoch进行超参搜索,没有进行进一步的调参
- 两个最大的模型RN50x64需要在592个V100卡上训练18天,ViT-L/14需要在256张V100卡上训练12天
- ViT-L/14效果最好,所以作者还将其在336的分辨率下额外finetune了一个epoch来增强性能,记为
ViT-L/14@336px。后面论文中没有特别说明的情况下,进行对比实验的CLIP模型都是指这个。

- 训练细节
- 数据集非常大,几乎不会出现过拟合,所以
Image Encoder和Text Encoder不需要提前进行预训练。 - 只使用线性投射层(线性非线性影响不大)。
- 数据增强只使用图片的随机剪裁,这是因为数据集非常大。
- 对比学习目标函数中的超参数
τ,设置成可学习的标量,在训练中自动优化,而不用慢慢调参(还是因为数据集太大,训练很贵)。
- 数据集非常大,几乎不会出现过拟合,所以
另外还有很多的训练细节,才使得CLIP真正能被训练出来。训练超大模型,可以参考来自OpenAI的博文:《How to Train Really Large Models on Many GPUs?》及对应的CSDN翻译。
1.2.3 伪代码
# image_encoder - ResNet or Vision Transformer
# text_encoder - CBOW or Text Transformer
# I[n, h, w, c] - 输入图片维度
# T[n, l] - 输入文本维度,l表示序列长度
# 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
# 分别提取图像特征和文本特征
I_f = image_encoder(I) #[n, d_i]
T_f = text_encoder(T) #[n, d_t]
# 对两个特征进行线性投射,得到相同维度的特征d_e,并进行l2归一化,保持数据尺度的一致性
# 多模态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)
# 计算缩放的余弦相似度:[n, n]
logits = np.dot(I_e, T_e.T) * np.exp(t)
# symmetric loss function
labels = np.arange(n) # 对角线元素的labels
loss_i = cross_entropy_loss(logits, labels, axis=0) # image loss
loss_t = cross_entropy_loss(logits, labels, axis=1) # text loss
loss = (loss_i + loss_t)/2 # 对称式的目标函数
在MOCO中,真实标签都是0,因为其正样本都是放在第一位,所以正样本对应的索引永远是0;但是在CLIP中,正样本都是在对角线上,即(),所以真实标签为np.arange(n)。
1.3 实验
1.3.1 zero-shot 迁移
研究zero-shot的动机:之前的自监督或有监督训练的模型(MOCO、DINO等),主要是学习一种泛化好的特征,所以在做下游任务的时候,还是需要有监督的微调,就依然存在很多问题。比如下游任务的数据集不好收集,存在分布飘偏移(distribution shift)等等。而使用文本引导视觉模型训练,就可以很好的进行zero-shot迁移;模型就可以不再训练,不再微调。
如何用CLIP实现zero-shot分类?
这里我们给出了一个基于CLIP的一个实例(参考官方notebook),这里任务共有6个类别:“dog”, “cat”, “bird”, “person”, “mushroom”, “cup”,首先我们创建文本描述,然后提取文本特征:
# 首先生成每个类别的文本描述
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)
然后我们读取要预测的图像,输入Image Encoder提取图像特征,并计算与文本特征的余弦相似度:
# 读取图像
original_images = []
images = []
texts = []
for label in labels:
image_file = os.path.join("images", label+".jpg")
name = os.path.basename(image_file).split('.')[0]
image = Image.open(image_file).convert("RGB")
original_images.append(image)
images.append(preprocess(image))
texts.append(name)
image_input = torch.tensor(np.stack(images)).cuda()
# 提取图像特征
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
进一步地,我们也可以对得到的余弦相似度计算softmax,得到每个预测类别的概率值,注意这里要对相似度进行缩放:
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)
得到的预测概率如下所示,可以看到6个图像,CLIP模型均能够以绝对的置信度给出正确的分类结果:

1.3.2 Prompt Engineering and Ensembling
- Prompt Engineering
作者还验证了文本描述时采用prompt的有效性(精度提升1.3%)。简单来说,prompt learning的核心是通过构建合适prompt(提示)来使预训练模型能够直接应用到下游任务中。
推理时,只使用类别标签作为文本描述效果并不够好,原因有二:
-
词语存在歧义性
如果我们直接采用类别标签作为文本描述,那么很多文本就是一个单词,缺少具体的上下文,并不能很好的描述图片内容。-
比如在做物体检测时,有一个类别是remote(遥控器)。但如果直接喂给文本编码器,很可能被模型认为是遥远的意思。
-
同一个词语在不同数据集中所表示的意思可 能有所不同。例如在 Oxford-IIIT Pets 数据集中,boxer指的是狗的一个种类,在其他数据集中指的是拳击运动员。
-
所以 CLIP预训练时,用来描述图片内容的文本是一个句子,比如
A photo of {label}。这里的label就只能是名词,一定程度上消除了歧义性。
-
-
使推理和预训练时保持一致(消除distribution gap)。
另外,还可以根据不同的数据集来调整这个模板,进而提升zero-shot的性能。
例如当数据集是Oxford-IIIT Pets数据集时(类别都是动物),就可以将模板写成: A photo of a {label}, a type of pet. ;或者在做OCR任务时,在想找的那个文本或者数字上打上双引号,模型就可能知道你是想找双引号里面的内容。
- prompt ensembling
作者尝试了集成多个模板的效果,即在多个zero-shot分类器上进行集成,这些分类器使用不同的提示模板来构造不同的文本。由于是在嵌入空间(embedding space)而不是概率空间(probability space)上集成的,因此节约了计算成本。在大多数数据集上,prompt ensembling都能够提升模型性能。
最终作者使用了80种模板来进行集成,每种模板使用了不同的形容词,来,描述不同的情境。

上图横坐标表示模型算力,纵坐标表示在多个数据集上的平均分数。绿色曲线表示本文中使用Prompt engineering and ensembling的结果,蓝色曲线表示直接使用无提示上下文的类名的结果。
3.3.3 zero-shot分类效果对比(ResNet-50)
为了测试CLIP的zero-shot分类的效果怎么样,作者将在27个数据集上的分类效果做成了对比图,下图就是CLIP与基于ResNet-50做Linear Probe的对比。

- Linear Probe on ResNet-50:
- Linear Probe就是冻住预训练好的模型,只训练最后一层的分类器,相当于将预训练模型做特征提取器。
- ResNet50是在ImageNet上用有监督的方式预训练好的
- 对比结果:
-
绿色 + 表示相比ResNet-50提升了多少,蓝色 - 表示相比ResNet-50降低了多少。
-
最终在27个数据集中,CLIP在16个数据集上都超越了有监督训练好的ResNet-50。
-
对于普通的物体分类任务,CLIP可以很好的做zero-shot迁移,例如车、食物、CIFAR10等数据集,因为图像中有可以描述出来的物体,那对应的文本中也就有这种描述,因此可以很好的匹配;
-
但CLIP对于更加复杂或抽象的任务就表现比较弱,例如卫星图像分类、淋巴结肿瘤检测等需要特定领域知识的分类任务,CLIP并没有预训练到这些标签信息。
-
1.3.4 few-shot分类效果对比
作者认为,这种特别难的任务,完全不给任何标签信息, 有点强人所难了,不是很合理。所以论文还对比few-shot性能,即只用少量的样本来微调模型,这里对比了3个模型:
- 在ImageNet21K上训练的
BiT-M(big transfer),是一个很强的baseline。 - 基于SimCLRv2训练的ResNet50,
- 有监督训练的ResNet50。

- 横坐标:每个数据集每个类别里,用了多少个标注样本进行Linear Probe的分类器训练。0就相当于
zero-shot了。 - 纵坐标表示在20个数据集上的平均分类准确度(有7个数据集每个类别不够16个)
- 当每类有16个训练样本时,
BiT-M模型的性能才和zero-shot CLIP打成平手。 - 紫色曲线说明:每类的训练样本只有1个或2个的时候,效果还不如zero-shot CLIP;但当每类的训练样本增加到8个或16个的时候,效果则超越了zero-shot CLIP。这说明对于一些难的数据集来说,有一些训练样本还是非常有必要的。
CLIP在做
Linear Probe的时候,需要扔掉文本编码器部分,接着在图像编码器之后加一层线性分类器,所以分类方式不再是看图像特征与文本特征最相近,而是重新训练一个线性分类器.新加的一层线性分类器是随机初始化的,所以每类有1个标注样本是不够的。这也是为什么一开始性能会比较差,但随着训练样本的增多,模型的分类性能会逐渐提升。
1.3.5 Linear probe CLIP对比
对比完了zero–shot和few-shot,下面自然就是拿下游任务的所有训练集来训练,进行效果对比了。作者在这里选择Linear probe CLIP的方式。
之所以选择Linear probe而不是微调,因为Linear probe只有最后一层FC是可以训练的,可学习的空间比较小,相比微调没那么灵活。如果预训练模型没有训练好的话,在下游任务上训练再久也很难优化到一个特别好的结果,所以用Linear probe能更准确的反映预训练模型的好坏。另一个原因就是Linear probe不需要怎么调参(因为微调的话,不同数据集可调的参数就太多了)。

- 横坐标表示对于一张图像来说,做一遍前向过程用多少的计算量
- 纵坐标表示在多个数据集上的平均准确率。
- 对比模型有有监督的EfficientNet、用了伪标签的EfficientNet、弱监督的在Instagram上训练的模型、自监督的对比学习模型、以及一些经典的有监督的baseline模型。
- 结果越靠近左上角,模型的性能越好。
- 左图是在12个数据集上的平均结果,这12个数据集和ImageNet是类似的。所以有监督的在ImageNet上预训练的模型,效果比CLIP好是可以预见的
- 右图是在27个数据集上的平均结果。
从图中可以看到,在12个数据集上,用ViT结构的CLIP效果最好,用ResNet的效果也比大多数模型要好;在27个数据集上,CLIP的效果就吊打其他所有模型了。这个结果就证明了CLIP模型的强大。
1.3.6 与Noisy Student EfficientNet-L2 对比
作者还在27个数据集上可视化了CLIP模型和用伪标签训练的EfficientNet的性能差异(ImageNet上表现最好)。
从图中可以看到,CLIP在21个数据集上的性能都超过了EfficientNet,并且很多数据集都是大比分超过。在其余6个表现不如EfficientNet的数据集上,CLIP也只比EfficientNet稍微低一点,差距并不大。

1.4 与人类的差异(略)
1.5 数据重叠分析
CLIP能实现这么好的zero-shot性能,大家很可能质疑CLIP的训练数据集可能包含一些测试数据集中的样例,即所谓的数据泄漏。关于这点,论文也采用一个重复检测器对评测的数据集重合做了检查,发现重合率的中位数为2.2%,而平均值在3.2%,去重前后大部分数据集的性能没有太大的变化,如下所示:

- 左:虽然几个数据集在检测到的重叠和干净示例上的zero-shot准确度有高达±20%的明显差异,但在35个数据集中只有5个具有99.5%的Clopper-Pearson置信区间,排除了0%的准确度差异。其中2个数据集在重叠数据上表现更差。
- 右:由于检测到的重叠示例的百分比几乎总是个位数,因此由于重叠导致的整体测试准确度增益要小得多,Birdsnap的最大增幅仅为0.6%。同样,当使用单边二项式检验计算时,只有6个数据集的准确性提高具有统计学意义。
由此可以得出结论,这样的数据重叠不会带来明显的准确率提升。
1.6 局限性
-
性能有待提高
CLIP在很多数据集上,平均下来看可以和ResNet-50打成平手(ImageNet精度为76.2),但与现在最好的模型(VIT-H/14,MAE等精度可以上90)还存在十几个点的差距。预测大概还需要当前1000倍的规模才可以弥补上十几个点的这个差距,现有的硬件条件也无法完成。所以扩大数据规模是不行了,需要在数据计算和高效性上需要进一步提高。 -
难以理解抽象/复杂概念
CLIP在一些更抽象或更复杂的任务上zero-shot表现并不好。例如数一数图片中有多少个物体,或者在监控视频里区分当前这一帧是异常还是非异常,因为CLIP无法理解什么是异常、安全。所以在很多情况下,CLIP都不行。 -
out-of-distribution泛化差
对于自然图像的分布偏移,CLIP还是相对稳健的。但如果在做推理时,数据和训练时的数据相差太远(out-of-distribution),CLIP泛化会很差。例如CLIP 在MNIST数据集上精度只有88%,随便一个分类器都都能做到99%,可见CLIP还是很脆弱的。(作者研究发现,4亿个样本没有和MNIST很像的样本) -
虽然CLIP可以做zero-shot的分类任务,但它还是从给定的那些类别里去做选择,无法直接生成图像的标题。作者说以后可以将对比学习目标函数和生成式目标函数结合,使模型同时具有对比学习的高效性和生成式学习的灵活性。
-
数据的利用不够高效
在本文的训练过程中,4亿个样本跑了32个epoch,这相当于过了128亿张图片。可以考虑使用数据增强、自监督、伪标签等方式减少数据用量。 -
引入偏见
本文在研发CLIP时一直用ImageNet测试集做指导,还多次使用那27个数据集进行测试,所以是调了很多参数才定下来网络结构和超参数。这并非真正的zero-shot,而且无形中引入了偏见。 -
社会偏见
OpenAI自建的数据集没有清洗,因为是从网上爬取的,没有经过过滤和审查,训练的CLIP模型很有可能带有一些社会偏见,例如性别、肤色。 -
需要提高few-shot的性能
很多复杂的任务或概念无法用文本准确描述,这时就需要提供给模型一些训练样本。但当给CLIP提供少量训练样本时,结果反而不如直接用zero-shot。例如3.1.4中CLIP的few-shot分类。后续工作考虑如何提高few-shot的性能
1.7 demo
下面是复制自CLIP官网的一段代码,使用红包图片(不在ImageNet那1000个类里面)进行一下简单的测试:

import numpy as np
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) # 加载base模型
image = preprocess(Image.open("red_envelope.png")).unsqueeze(0).to(device)
text = clip.tokenize(["plane", "dog", "a cat","bird"]).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)
Label probs: [[0.3131486 0.3174914 0.08763372 0.28172636]]
可以看到对于text给出完全不相关的类别,模型很困惑。
下面添加红包这个类别,模型做出正确的检测。
text = clip.tokenize(["plane", "dog", "a cat","bird","red_envelope"]).to(device)
Label probs: [[0.00437422 0.00443489 0.00122411 0.0039353 0.98603153]]
下面我们实验一下,模型到底是通过什么方式知道这张图片是红包呢?是颜色还是信封(envelogp)?下面添加这两个类:(不知道为啥,和老师演示的不一样)
text = clip.tokenize(["plane", "red", "envelope","bird","red_envelope"]).to(device)
Label probs: [[0.00259908 0.39436376 0.01481757 0.00233828 0.5858813 ]]
最后看看CLIP能不能学到相关的语义。红包一般是中国特有的,新年的时候都会在里面塞钱。下面改成这几个词试试:
text = clip.tokenize(["money", "new year","red","envelope","china"]).to(device)
Label probs: [[0.01408994 0.015231 0.05491581 0.00206337 0.91369987]]
可以看到模型没有选择红色或者是信封,而是选择了和红包紧密结合的china这个概念,可见模型的相关语义还是学的很好。但是光从分类角度,是否应该分类为信封呢?
二、CLIP语义分割
参考:
- 李沐论文精度系列之《CLIP 改进工作串讲》
- 博文《CLIP改进工作串讲(上)》
CLIP是OpenAI于2021年2月发表的,在过去的一年多时间里,已经被用到各个方面:
- 语义分割:Lseg、GroupViT
- 目标检测:ViLD、GLIP v1/v2
- 视频理解:VideoCLIP、CLIP4clip、ActionCLIP
- 图像生成:VQGAN-CLIP、CLIPasso、CLIP Draw
- 多模态:VL Downstream
- 其他:depthCLIP、pointCLIP、audioCLIP(语音)、CLIPasso
2.1 LSeg
语义分割可以看做是像素级的分类,因此分类的新技术、新思路,一般可以直接用过来。LSeg是2022年1月10号发表在ICLR的文章。与 CLIP 实现 zero-shot 的方式类似,LSeg通过类别 prompt 作为文本输入,然后计算相似度,也实现了zero-shot 语义分割。
LSeg的意义在于将文本的分支加入到传统的有监督分割的pipeline模型中,通过矩阵相乘将文本和图像结合起来了。训练时可以学到language aware(语言文本意识)的 视觉特征,从而在最后推理的时候能使用文本prompt得到任意你想要的分割结果。
2.1.1 模型效果
下图展示了LSeg的检测效果。给定一张图片,然后通过文本提示,给出需要检测的类别,就可以实现对应的语义分割。

- 第一张图中,给出
dog,tree,others,就可以把狗和树检测出来,其它为背景色 - 为了验证模型的容错能力,加一个汽车
vehicle的标签,模型中也并没有出现汽车的轮廓 - 模型也能区分子类父类,标签中不再给出
dog而是给出pet,dog的轮廓同样可以被分割开来 - 第三张图中,椅子、墙壁甚至地板和天花板这种极为相似的目标也被完美的分割开来
值得一提的是,由于 CLIP 类的模型实质上都是通过计算图文相似度来实现分类或分割的,因此 ‘other’ 类的类别 prompt 文本实际可以是任何无意义的文本,如 ‘me’,‘a’,‘an’ 等,只要与目标类别不要太接近即可。
2.1.2 模型框架

如上图 4 所示,模型整体看来与 CLIP 模型非常相似,只是将单个的图像文本特征换成语义分割中逐像素的密集特征。
另外除了上方的文本编码器提取的文本特征,要与密集图像特征相乘来计算像素级的图文相似度之外,整个网络与传统的有监督网络完全一致。
- 文本编码器提取 的文本特征,图像编码器提取 的密集图像特征,二者相乘得到 的特征,再经过
Spatial Regularization Blocks上采样回原图尺寸。最后计算模型的输出与ground truth监督信号的交叉熵损失进行训练。 - 分别是类别 个数(可变)、通道数和特征图的高宽,C一般取512或者768。
Text Encoder: 直接用的是CLIP 文本编码器的模型和权重,并且训练、推理全程中都是冻结的。因为分割任务的数据集都比较小(10-20万),训练的话结果会不好。Image Encoder:DPT结构(使用了ViT进行有监督训练的语义分割模型,结构就是ViT+decoder),backbone可以是ResNet或者ViT。如果使用后者,其参数用的是Vit/DEit的预训练权重,直接使用CLIP的预训练权重效果不太好。Spatial Regularization Blocks是本文提出的一个模块。在计算完像素级图文相似度后继续学习一些参数,可以进一步学习文本图像融合后的特征。模块由一些卷积和DW卷积组成(当加了两个模块时效果提升,加了四个模块后效果崩溃,作者未解释):

模型在 7 个分割数据集上进行训练,这些数据集都是由有标注的分割图组成,所以模型是以有监督的方式进行训练的(损失函数是交叉熵损失而非无监督的对比学习目标函数)。推理时,可以指定任意个数、任意内容的类别 prompt 来进行 zero-shot 的语义分割。
2.1.3 实验结果
作者将PascalVOC数据集和COCO数据集,都按照类别分成四份。比如COCO有80个类,前20类作为当前已知类,后60类为未知类,然后就可以做zero-shot 和few-shot 了。
对比zero-shot推理的话,LSeg的效果确实好很多;但是与 few-shot 哪怕是 one-shot 相比,还是有很大的距离。再考虑到LSeg用的是ViT结构,可见LSeg需要提升的空间还是非常大的。

Failure cases
比如下图左侧,标签给定是toy, grass,在嵌入空间中(embedding space),狗的视觉特征明显更接近“玩具”而不是“草”,并且没有其他标签可以解释视觉特征,所以狗被检测为toy。如果标签是face,grass,狗会被检测为face。
也就是所有使用CLIP模型的工作,都是在计算图像和文本之间的特征相似度,谁相似就选谁,而不是真的在做分类。

2.2 GroupViT
2.2.1 前言
上一节讲的LSeg 虽然能够实现 zero-shot 的语义分割,但是训练方式并不是对比学习(无监督训练),没有将文本作为监督信号来使用。因此LSeg还是需要手工标注的分割掩模(segmentation mask)进行训练。其使用的 7 个数据集加起来可能也就一二十万个样本,跟别的有监督无监督训练是远远不能比的。
GroupViT是2022年2月22发表在CVPR的文章。从标题可以看出,其监督信号来自文本而非segmentation mask。GroupViT通过文本自监督的方式进行训练,从而实现简单的分割任务(不再依赖segmentation mask)。
2.2.2 模型结构
GroupViT 的核心思想,是利用了之前无监督分割工作中的的 grouping。简单说如果有一些聚类的中心点,从这些中心点开始发散,把周围相似的点逐渐扩散成一个group,最后这个group即相当于一个Segmentation mask(感觉类似DBSCAN)。
Group ViT的贡献就是在现有的ViT模型中加入计算单元Grouping Block,同时加入了可学习的Group Tokens。这样模型在初期学习的时候就能慢慢一点点的将相邻的元素group起来,最后变成一个个segmentation mask。
比如下图,浅层的时候学习到的还是一些五颜六色的块,到深层大象、房子、草地等都已经分割出来了
下面来看一下 GroupViT 模型框架和具体的训练过程:

Image Encoder:- 结构就是Vision Transformer,一共是12层 Transformer Layer,其输入除了原始图像的Pacth embeddings,还有可学习的 group token 。
- 假设输入图像尺寸是224,×224,选择的
Image Encoder是ViT-Small/16,则输出Pacth embeddings尺寸是196×384,也就是图中的 。对应group token 的尺寸是64×384。 - 这里的 group tokens 就相当于分类任务中的 cls token。然后通过Transformer Layer的自注意力来学习到底哪些patch属于哪些group token。
由于分类任务一张图像只需要一个全图的 特征,因此只用一个 token 即可。而语义分割中一张图有多个目标,所以需要多个特征,也就是多个 group tokens。最初是选择64个 group tokens(聚类中心),不大不小,后期可以合并。
-
训练:
- 经过六层 Transformer Layers 的之后,学的差不多了。加入一个
Grouping Block来完成 grouping ,将图像块 token 分配到各个 group token 上,合并成为更大的、更具有高层语义信息的 group,即Segment Token(维度64×384,相当于一次聚类的分配)。 Grouping Block结构如上图右侧所示,其grouping做法与自注意力机制类似。计算 grouping token (64×384)与图像块 token (196×384)的相似度矩阵(64×196),将token分配到相似度最大的grouping token上面(聚类中心的分配)。这里为了克服 argmax 的不可导性,使用了 可导的gumbel softmax。合并完成后得到 (64×384) 。- 重复上述过程:添加新的 Group tokens (8×384),经过 3 层 Transformer Layers 的学习之后,再次经过grouping block 分配,得到 (8×384) 。
- 为了和文本特征进行对比学习,将最后一层Transformer Layers输出的序列特征(8×384)进行全局平均池化Avg Pooling,得到1×384的图片特征。再经过一个MLP层变成 维的图片特征。最后与文本特征 计算对比损失。
- 经过六层 Transformer Layers 的之后,学的差不多了。加入一个
-
推理
文本和图像分别经过各自的编码器得到文本特征和图像特征,然后计算相似度,得到最匹配的图像文本对,就可以知道每个group embedding对应什么class。局限性在于最后的聚类中心(Group Tokens)只有8类,所以一张图像中最多分割出八个目标。

总结:GroupViT 没有在ViT基础上加很复杂的模块,目标函数也和CLIP保护一致,所以其scale性能很好。即更大模型更多数据,其性能会更好。
其他细节:
-
论文中选用的是ViT-Small,数据集是2900万图文对。
-
除了与图形配对的文本本身,还将文本中 的名词提取出来,按照类似 CLIP 中的方法生成 prompt (如 “A photo of a {tree}.”),与某个图像特征计算对比损失,见原文 Figure 3;

-
消融实验中Group tokens个数选择64,8的组合效果最好

2.2.3 Group tokens可视化
为了验证加入的Group tokens、 Grouping Block到底有没有工作,Group tokens有没有成为聚类中心,又是否对应了某一个类别;作者将不同阶段不同 group token 对应的注意力区域进行可视化,结果如下所示:

- 在第一阶段,每个 token 都注意到一些语义明确的区域,如group5表示的是眼睛,group36表示的是四肢,并且都是些相对较小的区域;
- 在第二阶段,每个 token 注意到的语义区域则相对较大,如脸、身体。这正符合了作者想要的 group 分组合并的效果。