大家好,今天这个串讲其实是主要想说一下在过去一年中,大家是怎么把 CLIP 这个模型或者 CLIP 这个思想应用到其他领域中去的。本来是想先做一下这个多模态的串讲的,但是就在前几天看到了 CLICK puzzle 这篇论文,获得了这个今年 c GRAPH 的最佳论文,所以突然觉得先串讲一下这个 CLIP 的一些后续工作,可能对讲接下来的这个多模态学习也有一些帮助,所以就先做了这一期的串讲。
那其实自从 CLIP 去年大概2月底的时候出来,在过去的一年半的时间里,已经被应用到方方面面的各个领域里去了,比如说用到分割里就有Lseg,还有group。VIT。用到目标检测里就有viewed,还有 clip V1, clip V2,当然在目标跟踪里也有对应。的工作。然后如果放在视频里也有 video clip,然后 clip four clip,还有。action clip。还要把 clip 用到很多别的领域,比如说用到 Optical flow depth 里,这有 depth clip,然后还有这个 3D 里的这个 point clip,然后还有甚至用到这个语音里的 Audio clip,然后在图像生成这边也有这种 clip puzzle 或者 VQ gan clip,还有上次我们提到过的 clip draw 以及就到了这个多模态领域。最近也有一篇论文说这个 clip 模型,那到底能对这个 vision language 的下游任务起到一个怎样的提升作用?所以说 CLIP 真的是被用到了方方面面,那鉴于有这么多论文,可能我一次串讲也讲不完,今天可能主要就先说的是这个分割和目标检测。
1 CLIP简单回顾
那在开始之前我们先快速回顾一下CLIP,就是用对比学习的方式去训练一个视觉语言的多模态模型,它的训练方式非常简单,就是给定一个图像。文本,对。图像通过这个图像的编码器文本,通过文本的这个编码器就会得到一系列的这些图像文本的特征。那这个对应的图像文本,对,也就是这种 IET 一I2、 T2 一直到INTN,它们就都算是正样本,因为这个文本描述的就是这个图片,但是所有不是对焦线上的元素,它就都是负样本了。作者这里就假设,比如说TN,它肯定就不是在描述I3,它们之间没有对应关系,所以就是负样本。然后就用这么一个简单的对比学习的目标函数,在超大规模的这个 4 个亿的图像文本对上,训练完之后,这个 CLIP 模型就获得了强大的性能,尤其是这个 Zero shot 的能力,简直是让人。叹为观止。那在推理的时候,如果你想给任意的一张图片去做这个分类,你这时候就可以把它可能的那些标签全都通通的做一个这个template,就说这是一个什么什么样的图片,然后把这些所有的文本都传给这个文本编码器,你就会得到一系列的这个文本特征,那你这里有多少个标签,你最后就会得到多少个文本特征,就相当于你给定一张图片之后,你不停地问它,你这个图片里有没有个狗?你这个图片里有没有个飞机?你这个图片里有没有只。鸟?然后你通过这样不停地问,其实就是不停地去算这个图像特征和这些所有的文本特征之间的相似度,最后你就会得到一个。最大的相似度。CLIP 模型就认为这个最大的相似度所对应的那个文本标签就是你这张图片的标签。类别。所以说做起推理栏非常的灵活,真的是 Zero shot。
2 领域一:分割
那简单回顾完了CLIP,那接下来我们就来串一下今天要讲的第一个领域就是分割,这个任务其实跟分类很像,它无非就是把这个图片上的这个分类变成了这个像素级别的分类,但是往往在图片分类那边用的这个技术都能直接用到这个像素级别的分类上来。这也就是为什么过去几年分割这个领域这么的卷,而且论文非常的多。如果你去看 paper with code,你去查每个领域的论文,你就会惊奇地发现分割的论文竟然是最多的,我记着我去年查的时候就有几千篇。因为每当分类那边有什么技术出来以后,分割这边就可以直接拿来用,那这个模型的backbone,这样就不用多说了,那分类那边用了自注意力,分割这边也有了自注意力。分类那边有对比学习,分割这边紧接着就出了这个密集对比学习,那分类那边用了Transformer,分割这边迅速 set tra SEC former, mask former 就全来了。分类那边用了 seed labeling,分割这边也很快用了 seed labeling,
2.1 Lseg:分割的 Zero shot
那这回也不例外,分类有了CLIP,那怎么能少了分割的 Zero shot 呢?
2.1.1 分割效果非常好
很快今年的这个ICLEAR。2022。就有一篇论文,直接拿 clip 预训练的模型去做这种 language driven 的语义风格,而且这篇论文的方法非常的简单,写的也很好,所以我们就从这篇文章开始。那我们先来看一下这篇论文的图一看一看 Zero shot 的分割效果有多么的好。
在这用了这个 CLIP 之后,确实效果很拔群。我们先来看一下这个第一个例子,看看它这个灵活性,这个就是说草地上有只狗,如果我现在要对它进行分割,假如说我的这个文本给的是 other 和dog,就是说狗或者其他的物体。他就把这个狗完美的这个分割出来了,然后剩下的其他都是黑色的这个背景也就是other。那如果这个时候你说我想检测点别的东西,我想把这个树也检测出来,那你就在这个文本这把这个数也加上,你就会发现树它也给你分割出来了,狗还是很好的分割出来了。
然后这个时候作者还想再展示一下这个模型的能力,一个就是它的这个容错能力。比如说如果我多给了一个这个汽车的标签,那这张图里是没有汽车的,那无论如何他都不应该给出来这个汽车的mask,那确实在下面这个图里却没有标出来汽车。
另外一个它想展现的就是这种强大的 Zero shot的能力。就是它能检测这个类别的这个子类或者父类。因为之前这里躺着一只狗,所以你知道它是个狗,那现在作者给了pet,也就是宠物,相当于是狗的一个超集(superset)。那这个时候模型还是能检测出来,因为在整张图片里也就只有这一块儿看起来像pet。所以说它还是把这块儿分割成了pet。
那我们再来看一个更难的例子,就是他这里的第三张图是一个室内的图片,那他上来先说检测一个椅子,那他就把这个椅子给检测出来了,然后别的全都是背景,然后这个时候作者又多加了一些,比如说把这个墙加上,就会发现这个墙非常完美的这个分割出来了,然后剩下的就还是这个背景。
然后这个时候作者想检测更多的东西,更细致的这种分类,作者就把这个窗户、地板、天花板全都加上,然后你就会发现天花板也标出来了。两个大窗户也标出来了,这个地板它也标出来了,所以说真的感觉很神奇,像指哪儿打哪儿一样。不过确实现在这种 language guided 的这个分割做的是挺好的,所以这就让这个图像 PS 达到了一个新的高度。就我直接可以说我想把这边这个人给 PS 掉,因为我现在能做非常完美的这种分割,所以我就可以把这个人从这里抠掉,然后再换上别的东西。
2.1.2 模型总览图
那看完了这个很好的结果,那我们现在就直接来看这个模型的总览图
然后你一看这个图 2 你就会发现,诶它跟这个 CLIP 的这个模型总览图怎么这么像呢?都是这块有一个图片,这块有一些文字,然后图像通过图像编码器,文字通过文本编码器,然后得到了一些文本特征,然后图像这边只不过是从简单的这种图像特征变成了这种比较密集的 dence features,然后通过做点击,你也有类似的这么一个矩阵,然后最后得到一些结果。看起来非常的像。
那现在我们先假设没有上面的这个文本这一支,我们就看底下这个图像这一支,我们就会发现其实它跟这种正儿八经的有监督的语义分割其实没有任何的区别,它都是有一个图片,然后进了一个这个分割的模型,最后就能得到一个特征图,然后这个特征图通过一些 upscaling 就把它放大。因为我们现在做的是一个密集任务,它最后的这个输出应该跟原来图像的大小是一致的,所以这块就要做一些升维的操作,然后最后模型的输出去跟那个 ground truth 的 supervision 去做一个 cross entrpy loss 就可以。那细致点来说,这个图像的编码器这边其实是一个 DPT 的结构,也是这篇论文的几个作者之前做的一篇语义分割的工作,是拿 vision Transformer 去做有监督的语义风格的。简单来说,这个 DPT 的结构就是前面有一个 vision Transformer,后面加了一个decoder。decoder 的作用就是把一个 bottleneck feature 慢慢的把它upscale上去。就像我们之前说的 PSP 或者 ASPP 这种层一样。然后我们就相当于把一个 H*w*3 的一个图像就变成了一个 H'*T*'C一个特征图。那 H'*T*'C其实就是跟原图相比,它可能降维了一些。比如说是原来的 1/ 4 或者 1/ 16 这样的大小。 c 是指这个特征的维度,一般就是 512 或者768,然后视觉特征其实就算抽完了。
那我们先来再来看文本的这一支文本就是假设你这个数据集你有 n 个label,也就这里说的people, tennis record 这些标签,你就把这些标签通过这个文本编码器,你就会得到 n 个这个文本特征,那这里对 n 其实是没有限制的,也就跟我们刚才的样例一样,你也可以只检测狗,你也可以检测狗和树或者更多的东西。这个 n 是可以随时都可以改变的。然而这个文本通过文本编码器之后,就会得到一个 n *c的一个矩阵, c 依旧是特征的维度,也就是 512 或者768。那到这儿其实我们就把文本的特征也算抽出来了
那现在如果我们来仔细看一下它的这个特征维度,我们就会发现文本这边你得到了一个 n *c矩阵,然后图像这边你得到一个H'*T*'C的一个tensor。然后你对这两个矩阵在这个 C这个 dimension 上进行一下相乘的话,你就会得到一个 h 乘 w 乘n的一个tenser。n就是你有多少个标签,也就是多少个类别。那其实做到这就跟传统的有监督的分割没有任何区别了。因为传统的有监督的分割也是会得到这么一个 h 乘 w 乘 n 的一个特征,然后拿这个特征去跟最后的 ground truth 去做 cross centrip loss。
那这篇论文它虽然说是用了CLIP,它虽然说是 Zero shot,但其实它的训练过程是有监督的训练。它是在 7 个分割数据集上一起训练出来的,也就是说它最后是有 ground truth mask 的,它的目标函数就是跟那些 ground truth mask 去做的cross entry loss。而不是像 CLIP 一样是对比学习的loss,它不是一个无监督训练的工作。那这篇论文的意义其实就是把文本的这一支加入到了这个传统的有监督分割的模型的这个 pipeline 里来,通过这块的这么一乘,它就把这个文本特征和这个图像特征给结合起来了,那它这个模型再去做训练的时候,就能学到一些 language aware 的这种视觉特征,从而在最后你在做推理的时候,你能用文本的这种 prompt 就任意的得到你最后想要的这种分割的效果。
2.1.3 Lseg和CLIP的关系
那最后来说一下这个工作跟 CLIP 的关系,虽然这篇文章的作者说它这里这个图像编码器可以用任意的这个网络结构,它这里的这个文本编码器也可以用任意的网络结构或者那些预训练的模型参数。但是在这篇论文里,为了达到最好的效果,它这里的文本编码器其实就是用了 CLIP 里的那个文本编码器,一点儿都没动,而且在训练的时候也都没有动,就是自始至终而这个文本编码器都是锁住的,并没有进行训练。 clip 是什么样,它这就是什么样。这个可能也是作者担心,因为在这个 7 个 segmentation 数据异常训练的时候,虽然你听起来好像有 7 个数据集,但其实分割这边的数据集都很小,即使是 7 个,它的规模也还是非常小的,可能也就是十几万 20 万张图片。那这个时候如果你在这么小的数据集上,你想去 fine tuning CLIP 的那个预训练参数,你很有可能就把那个参数给带跑偏了。所以说为了不让模型训练变得更加困难,为了不让原来的 CLIP 模型这么好的特征又被学坏了。所以说作者这里就没有动这个文本的编码器。
然后图像抽取特征这边其实就是 VIT 加了一个decoder,那 VIT 这边作者也试了,要么呢用 clip 提供的那个 VIT 预训练参数,要么呢就是用之前别的工作,比如说原始的 VIT 或者 DEIT 那些工作预训练的参数。结果作者最后发现用那些 VIT DEIT 训练的参数效果更好,用 CLIP 的反而不太行。当然作者也没有解释说为什么不行,我其实也想不出一个合理的解释,就全当是实验科学了。
2.1.4 Spatial regularization blocks可以忽略
然而这篇论文技术上作者其实还提出了另外一个东西,叫做 special regularly block。但不知道是为了增加一些 novelty 还是说增加一些内容。其实这个 block 也就是一些 conv 或者 depth wise com的层。
作者应该是觉得在你这个文本和视觉特征进行相乘之后,我应该还有一些可学习的模型参数在它后面,然后去多理解一下这个文本和视觉到底应该怎么去交互,从而达到最好的这个效果。所以作者就在这块又额外的加了一些这种block。但是作者也没有过多强调后面的消重实验也做得比较短,比如说他发现加两个这种 block 效果最好,但是加到四个 block 的时候突然这个性能就崩了,但是作者也没有说为什么会崩,也没有任何解释,所以我们其实完全可以忽略这个东西。这个其实对整篇文章的理解或者说最后的性能都没有多大的影响。
2.1.5 实验结果
因为是论文串讲,我们还有很多内容,所以说实验部分我们就只挑最有意思的那些实验结果,大概看一下就好了。这篇论文它选择的数据集和这个评价的标准至少对于我来说其实不是很常见。
他是 follow 了之前几个做 few-shot分割的这个工作,他是在 Pascal 五、 Coco 二十和 FSS 1000 上做的这个评价,它其实的意思就是说把原来的一个数据集分成了四份,比如说 Pascal 的话,它本来有 20 类,它现在把这 20 类分成四份儿,每一份儿就有五类。然后这样当前的 5 类其实就是我们知道的类,剩下的 15 类我们就当不知道的类,这样你就可以去做这种 Zero shot 或者 feel shot 这个实验。然后这里这个 i 其实就代表你选你这里选的第几份。
那同样的道理,这个 COCO 20 也就是把 80 类分成了 4 份,那如果是 COCO 20 也就是第一类,也就是说把前 20 类当成我们知道的类,把后 60 类当成我们不知道的类,然后你就可以在后 60 类上去做这种 Zero shot 或者few。shot 的实验了。
然后这个 FSS 1000 这个数据集也很有意思,它有 1000 类。我之前还不知道分割有数据集有这么多类别的
那我们简单看一下表格,那我们先看 Pascal 上的结果,其实这篇文章这个LSEG提出的方式,它是 Zero shot,它这个结果比之前的这种 Zero shot 方法还是提升不少的,大概提了十几二十个点。但是跟之前哪怕是 one shot 的这种方式比,它还是差得挺远的。而且如果你考虑到之前的方法还都用的是rise。101。而 l SEC 这篇论文已经是用 VIP large 模型了,你的模型其实比 rise 101 大了非常多倍,也就是说现在 Zero shot 分割跟这个有监督的分割距离还是非常远的。中间能提升的空间至少是几十个点。
那同样如果我们来看 Coco 二十的话,也是一样的道理,它的这个 Zero shot 比之前的 Zero shot 好一些,但是哪怕是跟之前 one shot 的比,还不是跟用所有的数据比,它们之间的这个差距也还是非常明显。
2.1.6 failure case
那作者最后还展示了一些这个 failure case,这个还比较有意思。当然之前他还列举了很多成功的情况,那些就跟我们刚开始看的图差不多了,所以我们就不一一过了。这里如果我们来看这个例子
这图里还是草地和狗,但是我的文本给的是草地和玩具。那最后就把这个狗判断成了玩具,所以这里还是同样的问题,就是说这个模型还有跟clip,或者说一切用了 clip 模型的这些工作因为本质上它都是在算这个图像特征和文本特征之间的相似性,他并不是真的在做一个分类,所以说谁跟他最接近,他就选谁在这里这只小狗肯定不是草,而这种样子的小狗看起来其实跟玩具也差不多,所以就把这只狗分类分给了玩具。
而且其实更有意思就是这篇论文是有代码,而且是有预训练模型的。我之前也玩过。其实如果你把这里的词再换一换,会有很多有意思的情况,就比如说你如果把这里的 toy 换成 face 就是脸。那它其实就会把脸也分给狗。还有这篇论文里经常使用的这个 other 就是代表背景的这种other,你也可以把它换成别的词,你可以把它换成 a an 这种没有意义的词,或者那种 and but i me you 这种没有明确的物体语义的这个词。你就会发现它们都可以拿来替代这个other,当成是这个背景类的这个提示词。所以总之这个 Zero shot 去做分割,能提升的空间还非常的大,要走的路也非常的远。最近也陆陆续续又出来了一些工作,比如马上我们就要讲group VIT。这个方向其实算是个不错的坑,有兴趣的同学都可以来玩一玩。
2.2 groupViT:摆脱手工标注,用文本做监督信号做无监督的训练
那说完了 l SEC,那接下来我们来看一下更新的一篇 C V P R 2022 的论文,叫做groupV I T。那其实我们刚才也强调过了,那 LSEG那篇论文,它虽然用了 clip 的这个预训练参数,而且这个图画的也很像clip。但是终究它的目标函数也不是对比学习,它也不是无监督学习的框架,它其实并没有把文本当成一个监督信号来使用。这就会导致一个什么问题:就是它还是依赖于这个手工标注的这个segmentation mask。这个就比较难办,因为就像我们刚才说的一样,虽然他用了七个数据集去训练,但其实这所有的这七个数据集也没有很大。跟别的任务相比,不论是有监督还是无监督,一二十万的这个训练量都非常非常的小。对于分割来说,你去手工标注的那个 Mask 是非常非常贵的一件事情,所以说如何能摆脱掉这个手工标注,如何能真的去做到用文本来做这个监督信号,从而能达到无监督的训练,这个才是大家更想要的东西。
那 group i t 就算是这个方向上比较有贡献的一个工作了,你从题目里也可以看出来,它的监督信号就是来自于文本,它并不依赖于 segmentation mask 的这种手工标注,而是可以像 CLIP 那样就利用图像文本堆来进行这种无监督的训练,能让模型进行简单的这种分割的任务。
2.2.1 模型到底是怎么工作的?为什么要叫groupVIT?
那模型到底是怎么工作的?为什么要叫groupVIT?其实在视觉这边,很早之前做无监督分割的时候,经常就是用一类方法叫做Grouping。它就类似于说如果你有一些聚类的那个中心点,然后我从这个点开始发散,然后把附近周围相似的点逐渐扩充成一个group,那这个 group 其实就相当于是一个 segmentation mask 了,是一种自下而上的方式。那在这里作者其实相当于是重新审视了一下这个 Grouping 的方法,发现其实能把 Grouping 完美的用到当前的这个框架中来。
他们提出了一个计算单元,也就是右边儿的这个东西叫做 grouping block。然后还有一些可以学习的这个 group tokens,它主要的目的就是想让这个模型在初始学习的时候,就能慢慢地一点一点地。把这个相邻相近的像素点都慢慢地 group 起来,变成一个又一个的这个 segmentation mask 就跟它右边图里画出来一养。在模型刚开始的浅层的时候,他学到这些 group token,这个分割的效果还不是很好,我们这里还能看到一些五颜六色的颜色块,但是经过模型的学习,等到深层一点的这些 group token 的时候,我们就可以看到它的这个分割已经做得相当不错了,已经能够把这几个大象房子后面的树林和草地全都分割出来了。
所以 group VIT 的贡献就是在一个已有的 VIT 的框架之中加入了这个 Grouping block,同时加入了这个可学习的group tokens。
2.2.2 什么是 Grouping block,什么是 group token?
那接下来我们就来仔细的看一下什么是 Grouping block,什么是 group token?
那老样子我们还是用一个具体的例子来说明这个情况。首先对于图像编码器来说,它这边就是一个 vision Transformer,从头到尾一共有 12 层,也就是说有 12 个这个 transformer layers。
那图像编码器这边的输入其实有两个部分,一个就是来自于原始图像的这个 patching bedding,另外一个就是这篇文章提出来的这个可学习的group tokens。
- patch embedding,其实就是假如我们这儿有个 224 *224 的图片,然后我们的 patch size 选成 16 * 16,那其实我们就有一个 14 * 14,一个 196 序列长度的一个序列。然后经过这个 linear projection 就得到了一些这个Patch embedding。它的维度其实就是 196 乘384,因为这里用的是 VIT small,所以这个特征的维度是384,那另外一个输入 group tokens 作者这里刚开始设的是 64 * 384,384是为了保持维度不变,所以能够和这个 196 * 384 去做直接的拼接。那这个 64 是希望你刚开始的时候有尽可能多的这个聚类中心,因为反正你回头还可以合并。所以刚开始就设了一个不大不小的值64。
- 这个 group token 你其实就可以理解为是这个之前我们说的 cl s token,就是说他想用这个 token 就代表整个这个图片,但是我们这里是用了 64 个 group token,而不是一个 group token。为什么呢?也很简单,因为过去你用一个的原因是因为你想代表整个图片有一个特征,但是你现在你是想做分割,所以你是想每一个类别或者说每一个小块它都有一个特征去表示它。所以说在这篇论文里它刚开始设的就是 64 个,也就是说你有 64 个起始点,或者说你有 64 个聚类中心。把那些看起来相似的或者语义接近的像素点都归结到这 64 个 cluster 里面。至于学习的过程,其实 group token 和这个 cls token 学习都是一样的,就是通过这个 transformer layer 里这个自注意力去不停地学习到底这些图像的 patch 哪些属于这个token哪些属于这个token,然后经过了几层 consumer layer 的学习之后。比如说在这篇论文里经过了 6 层 Transformer layer 之后,然后就在这 6 层之后加了一个 grouping block,就是作者认为你现在已经互相教会了 6 个 Transformer layer 了,这个 group token 可能已经学的差不多了,这个 clustering center 也学的差不多好了,那这个时候。我得试着来 cluster 你一下把你合并成为更大的group,学到一些更有语义的这个信息。所以它就利用这个 grouping block,把之前的这些图像 patch embedding 直接 assign 到这 64 个 group token 上,相当于做了一次这个聚类的分配,那你一旦分配完,那你有 64 个聚类中心,那你就当然只剩下64个 token 了。所以做完这一步操作之后得到的这个 segment token,也就是这些颜色相间的token,它的这个维度就是 64 * 384 了。当然这里 grouping block 还有另外一个好处就是它相当于变相的把这个序列长度给降低了,那这个模型的计算复杂度,还有这个训练时间也就相应的都减少,它就跟 swin Transformer 一样,是一个层级式的网络结构。
那我们现在具体来看一下 Grouping block 是怎么操作。其实 grouping block 就是用类似于自助意义的方式,先算了一个相似度矩阵,然后用这个相似度矩阵去帮助原来的这个 image token 做一些这个聚类中心的分配,从而完成了把这个输入从 196 * 384 降维到这个 64 * 384 的这个过程。当然大家都知道你做这种聚类中心的分配这个过程,它其实是不可导的。所以作者这里用了一个trick,也就是用个gumbles of the Max。从而把这个过程变成可导的,这样整个模型就可以端到端的进行训练了。那到这儿其实我们就完成了第一阶段的这个grouping,就把这个输入序列从 196 加 64 的这个长度变成了一个 64 * 384 的序列。
然后因为一般的数据集或者说常见的这个图片里,它的种类也不会太多,所以作者希望能把这 64 个聚类中心变得再小一点,把一些相似的小的这个类别块,尽量的把它再合并成大的这种块,所以它就又加了新的 8 个这个 group tokens,也就是8 *。384。希望能通过进一步 translora 这个学习,能把这 64 个 segment token 再次映射到这 8 个聚类中心上。那在文章中,作者其实是在第九层 consumer layer 之后又加了一次grouping block。也就是说在这个 grouping blog 之后,又过了 3 层transmer layer 的学习,作者觉得新加的这八个 segment token 其实就学得差不多了,于是乎再做一次这个 grouping block,就把这个 64 + 8 的这个序列分配到这 8 * 384 的这个token 上了。也就是说这个图像分成了八大块儿,然后每个块儿对应的有一个特征。
2.2.3 模型怎么训练?
那说到这儿,其实已经把这个 grouping block 和 group token 都已经说完了,那整个这个模型该怎么去训练?其实这也就是 group VIT 和 clip 的这个相似之处了,它们都是通过这个图像文本堆儿去算了一个对比学习的loss,从而训练整个网络的。但是这里问题就来了,你原来做 clip 的时候,你是一个图片有一个特征,然后那个文本有一个特征,所以你图像文本的特征很容易算一个对比学习的loss。但是现在你的文本端还是通过文本编码器得到了一个这个文本特征ZT。但是你的图像因为做这种 group token 和 group MERGING 的操作,它到目前为止得到的是一个序列长度为 8 的这个特征序列,那怎么能把这 8 大块的特征融合成一块,变成整个图像的这个 image level 的特征?那作者这里就选择了最简单的一种方式,就是我直接做一下这个 average pulling,直接把这些特征平均一下不就完了?那它就得到了一个384的特征。那这个特征通过一层 MLP 就得到了整个图像对应的这个特征ZL。那这样接下来就跟 clip 完全一样。
总体而言, group VIP 还是一个非常简单的方法,它没有在这个 vision Transformer 的基础上加什么特别复杂的模块,它的目标函数也跟 CLIP 保持一致,所以就意味着它的这个 skill 的性能非常的好。如果你把它这个模型变大,或者说如果你给它更多的数据,它有可能就能给你更好的学习结果。当然,在这篇论文里,作者就选择了 vision consumer small,而且数据集最大也直到 29 million,也就是 2900 万个图像文本对儿,如果像 CLIP 那样用 4 个亿的图像文本盾儿训练,不知道最后的这个分割效果。会不会更好?
2.2.4 怎么做zeroshot推理?
那说完了模型是怎么训练的?那接下来就说一下这个模型是怎么去做 Zero shot 的推理的,其实跟 CLIP 还是非常的像,比如说给定一个图片。
图片首先经过 group i t 的这个结构,也就是左边的那个图像编码器,它就会得到最后的这八个这个 group embedding。然后这个时候我们再把有可能这些标签,通过这个文本编码器得到一系列的这个文本特征。那接下来我们只要算这些图像的 grouping embedding
和这些文本的特征之间的相似度,就可以知道每个这个 grouping embedding 到底对应什么样的class。
当然这里我们能看到一个很明显的一个局限性,也就是说因为这个模型最后只有 8 个这个 group embedding,也就意味着其实这个图片的分割最多只能检测到 8 类,再多就不可能了。因为这边这个维度只有 Z1 到 Z 8 只有 8 个group token。了,这个使用多少个这个 group token,或者最后用多少个 output token,这些都是可以调的超参数。作者这里也试了一下各种各样的这个 group token 和 output token,比如这里一路从 16 试到64,这边从 4 试到16,但是作者发现就用最后这 8 个 output token,最后结果是最好的。所以就选择了这个设定。
2.2.5 有意思的可视化
那接下来我们看一个比较有意思的。可视化。因为说白了你加了这些 group token,你加了这个 grouping stage,它到底工作没工作?它到底是怎么工作的?其实你不知道,那作者这里就把第一个 stage 还有第二个 stage 里的一些这个 group token 拿出来可视化了一下,看看这些 token 到底有没有成为一个聚类中心,那是不是某一个token,它就对应的具体的某一个类别?我们发现,诶还确实如此。比如说在前面的这个 stage 一的时候,一般他关注的就是比较小的区域,因为那个时候还有 64 个token。作者这里就发现说假如说第五个group,其实它对应的就是眼睛,不光是人的眼睛,还有狗的眼睛,各种各样的眼睛其实都能被它分割出来。那如果我们换一个token,换到这个第 36 个group token。我们就会发现其实他说的是这个四肢,而如果我们换到第二个阶段,我们就可以看到它对应的这个区域明显就扩大了很多,因为这个时候已经是 8 大类了。比如这个时候我们看这个第六个 group token,就会发现它对应的全都是这个草地,那或者说这个第七个 token 对应的就全都是人脸。所以确实如你所愿,这个 group VIP 里的这个 group token 起到了这个聚类中心的作用,真的用 grouping 的这种思想完成了这种无监督的分割。
2.2.6 数值上的比较
那最后我们来看一下这个数值这样的比较,在 Pascal VOC 和 Pascal context 这两个数据集上,这个 group it 分别取得了 52. 3 和 22. 4 的这个结果。跟他这里说的这些 baseline 方法比起来,确实有很大的提升。而且也确实是用这个文本做监督信号的第一个工作,而且还可以做 Zero shot 的inference所以还是相当厉害的。但如果我们考虑一下它这个有监督的这个上限是多少,我们就会发现这里这个差距还是非常非常的大的。比如说在 Pascal VOC 上之前最好的方法,比如说 deep lab V3 plus,我记得好像已经是 8788 的这个 MLU 了,也就说比这里的 52. 3 高了30多个点。那 Pascal context 的数据集也一样,最好的有监督的方法应该也是五六十的准确度,所以也是差了 30 多个点,所以说无监督的这个分割还是很难的。能做的东西非常多
2.2.7 局限性
2.2.7.1没有很好的利用这种 dence prediction 的特性
作者这里也列举出来了它的两个这个limitation,大概说了一下它未来可能才会做哪些改进。那其中的一个局限性就是说现在这个 group it 的结构其实还是更偏向于是一个图像的编码器,它没有很好的利用这种 dence prediction 的特性,比如说之前在分割这边用的很火的这种 dilated convolution 或者 pyramid pooling 或者 unit 的这种结构,从而你能获得更多的这个上下文信息,而且能获得更多的这个多尺度的信息能帮助你更好地去做分割任务。但目前 group it 这边都还没有考虑这些。所以每一个刚才说的东西都有可能未来成为一篇论文。
2.2.7.2 学不到分割任务中的背景类
那另外一个局限性就是分割这边存在的一个东西叫做背景类,那 group VIT 在这个推理的过程中是怎么考虑这个背景类的?这个刚才我也忘了说,就是我们在做 Zero shot 的这个推理的时候,不光是选择最大的那个相似度,因为有的时候你这个最大的相似度可能也比较小,可能最后就只有 0. 20. 3 这样,那作者这里为了尽可能提高前景类的这个分割性能,所以它设置了一个阈值,就是这个相似度的阈值。比如说对于 Pascal VOC 这个数据集来说,它的阈值就设置了 0. 9 还是 0. 95。也就是说这个 grouping embedding 和这个文本的特征,它的这个相似度必须超过 0 点儿九,而且是取的最大的那一个,你才能说这个 group embedding 属于这一类。如果你这个 group embedding 跟所有的这个文本的特征的相似度都没有超过零点儿9,那 group i t 就认为你就是个背景类,你就不是一个前景。那这套推理方案对于 Pascal VOC 来说还好,因为本来它的这个类别数就少,而且一般都是实打实的这个物体有非常明确的语义信息,所以它不太存在这个背景类干扰的问题当然也有了,但是如果当你把这套框架移到 Pascal context 或者做 Coco 数据集的时候,这个问题就非常显著。因为这个时候你的类别非常的多,那你的这个置信度,或者说你这个相似度一般就会比较低,就很容易出现你的这个前景物体的置信度和你这个背景物体差不了多少,那这个时候怎么设置这个阈值就成为了一个很关键的问题。如果我们把这个阈值设得很高,那基本大多数全都变成背景物体了,那这这样前景类别的这个 MLU 分数肯定就会变得很低。那如果我们把这个阈值设得很低,就会造成一个错误分类的问题,就是有可能它相似度最高的那一类并不是真正正确的那一类。也就是论文作者自己这里发现的一个问题,就是他们通过这个肉眼的观察。他们发现其实 group VIP 这个 group token 学的挺好的,就是真正的那个分割已经做得很好了,还真的把那个人呐或者那个马呀,那个桌子都分割出来了。但是只不过最后的这个分类给分错了。那作者这里为了验证一下到底是不是因为分类的错误导致这个 Coco 和这个 context 数据集这个性能这么低。它就做出了一个上线的实验。如果 group VIT 给了它一个输出的这个 prediction mask,它就拿这个 mask 去跟所有的这个 ground truth mask 去做这个对比。一旦他发现哪个 IOU 最大,他就把那个 ground truth 的那个 label 直接就给这个 group VIT prediction mask 当成它的标签。那这样一来,只要你这个分割做得好,那你这个分类就肯定不会错,因为你相当于是直接从 ground truth 那边拿过来的这个标签。作者就发现不论是对 VOC 来说,还是后面这两个更难的数据集来说,它的这个上线的 MLU 一下就增加了二三十个点,现在就跟这个有监督的那边最高的这个性能就差不多了。这也就验证了,其实 group it 的这个结构,尤其是 group token 和 grouping block 其实非常的有效,因为它已经把这个 segmentation mask 生成的很好,它分割做得很好,它只是没有把语义分割做得很好。因为它分类错了很多。那这个怪谁?这个其实是怪这个 clip 的这种训练方式,因为 clip 的这种训练方式只能学到那种物体语义信息非常明确的东西,它学不到这种很模糊的。比如说什么是背景,因为背景可以代表很多很多类,它是一个很模糊的概念。所以说 CLIP 这种训练方式就没有办法学到这些背景类,那对于这个 limitation 其实也有很多的解决方案,比如说那个阈值该怎么设?是不是应该根据每一个类别去设?是不是应该可以有一个可学习的阈值,或者说整个把这个 Zero shot 的这个推理过程给改了,或者说你在训练的时候再加上一种约束,能把背景类这个概念融入到你的训练之中,所以这里也有很多可以挖掘的东西。
总结
总之分割这边就讲 l SEG 和 group i t 这两篇工作,第一篇就是直接使用了 CLIP 的这个预训练模型,而且也使用了它的这个大概框架,从而把这个图像和文本的特征融合在了一起,能够去做这种 language driven 的语义分割,但是它还是一个有监督的学习。
那第二个工作 groupvit 它并没有使用 CLIP 的这个预训练参数,它反而是自己从头训练了一个分割模型。但是它的目标函数就用的是 CLIP 的目标函数,一点儿都没有变。
那接下来我们还会讲这个目标检测,还会讲这个视频,还会讲一些其他的领域。我们就都可以发现这个 CLiP 出来以后,大家一般刚开始就是先用下它这个预训练的参数,大家做一些简单的改动,然后再把 clip 的特性和这个下游任务的特性结合起来。要么是利用 clip 的这个目标函数,要么是利用 clip 的一些其他特性去把这个下游任务做得更好。
3 领域二:目标检测
那说完了 clip 在分割里的应用,接下来我们就来看一下 clip 在目标检测这边是怎么使用目标检测的。目标检测这个网络结构一般是要比这个分类或者分割要复杂一些的,但是好像也丝毫没有影响这篇论文出来的这个速度。
3.1 ViLD:OPEN-VOCABULARY OBJECT DETECTION VIA VISION AND LANGUAGE KNOWLEDGE DISTILLATION
虽然这篇论文是 iclear 二的一篇中稿论文,但事实上它在 21 年的4月 28 号就已经上传到 ARCHIVE 上。我们之前在讲 clip 的时候也提到过 clip 这篇论文是在 21 年2月 26 号传到ARCHIVE上,意思就是说这篇论文从看到 clip 到写出来这个 21 页的 i clear 的论文,中间只花了两个月的时间。而且后面我们也可以看到它训练模型用了 18 万个iteration,大概换算过来就是 460 个epoch。这是一个非常长的训练时间,有几十个上百个TPU,应该是没办法在这么短的时间内完成这么高质量的工作。
那我们言归正传,这篇论文叫做ViLD,就是 vision language knowledge distillation,然后你一看题目open vocabulary。你就知道这多多少少跟 clip 肯定有点关系。然后你再读到后面 vision language knowledge distillation,你就大概知道了他肯定是把 clip 模型当成了一个teacher,然后去蒸馏他自己的那个网络。从而达到能 zero shot 去做目标检测这个目的。
3.1.1 研究动机
接下来我们直接跳到引言,这篇论文的引言写得非常好,我也想给大家安利一下这种写作的方法,它一上来就给了一张图,然后根据这张图,作者就问了一个问题,直接就把这篇文章到底要做什么给引出来了。真的就是一句话,把这篇文章的研究动机说得明明白白的。紧接着就直接说,在这篇论文里,我们就是想做一个 open vocabulary 的目标检测,从而能够检测到任意的这个新的物体类别。
那我们来看看图一作者给的例子,其实很简单,那就说现在的这些目标检测的数据集,其实它标注的类别都很有限,这些有限的类别叫做 base category,就是基础类。比如说像这张图里的这些蓝框标出来的东西,这三个东西都叫玩具,那也就是说如果你在这种数据集上去训练一个目标检测器,你就只能检测出玩具。但是你得不到更细致的这个检测结果。比如说我想检测这里这只鸭子,或者我想检测这里绿色的这个玩具。你都做不到。那作者提的问题就是说我们能不能在现有数据集的基础之上,不去额外的标注这些黄鸭子或者绿鳄鱼的这些标注,但是我这个模型就能直接做到检测这些物体的能力。也就是说我的模型应该拥有能够检测这种 novel category 就是新的类别的能力。所以这一下就把这个问题说得很清楚,然后同时也展现了一下他们最后这个模型的能力,就是 ViLD在这些新的类别,比如说黄色的玩具,或者说玩具鸭子,它都可以检测出来,所以说就是这么简单的一张图。但其实你就已经不需要再去读它的引言和相关工作了,直接就可以跳到方法部分,看它具体是怎么做的。这样的论文审稿人很喜欢,而且读者也很喜欢。至少在我们第一次读任何一篇论文的时候,我们都不希望从头读到尾才能知道这篇论文在讲什么,对吧?肯定是越早知道这篇论文跟我相不相关,这篇论文到底有没有意思。才能激起读者的兴趣,保持住他们读下去的这个动力。
3.1.2 主体方法
那接下来我们就直接来看这个图3,了解一下论文的这个主体方法部分。那说目标检测复杂,它确实是复杂,我们可以看到这个
a 其实就是一个 baseline 的方法,就是有监督的一个baseline,
然后接下来这个b、c、 d 全都是 ViLD的这个方法。 b 是它提出的ViLD的 text 这一个分支, c 是 ViLD的image,然后最后把这两个合起来变成了ViLD,其实后面他还提出了一个能让这个推理更快的这个ViLD ensemble。
所以说东西有点多,我们一个一个来看。那首先我们先来看一下这个baseline,还有他们提出的第一个这个 ViLD的 text 模型,其实这个 baseline 就是一个maskRCNN。它是一个两阶段的分类器,第一阶段会出一些 region proposal,也就是这里这个 n 个proposal。第二阶段就是根据这 n 个proposal,然后去过一个这个 detection head,得到一些 region embedding,然后最后再通过一些分类头得到到底这些抽出来的 bonding box 是什么类。这样就完成了目标检测。目标检测其实从这个目标函数来看,我们可以知道它一般分为两块,一个是怎么定位,一个是怎么分类。定位就是你这个 bonding box 画的准不准,分类就是你这个 Bonnie box 里面的物体判断的准不准。这篇论文其实相当于把这两个东西有点解耦开来的意思,因为你看它所有的这个框架图基本都是从第二个阶段才开始的,他的这个输入都是 n 个proposal,就直接第一阶段他没有画,都是从这个 proposal 拿到之后再开始看接下来怎么做。
那首先我们来看一下它第一个这个 ViLDtext,那因为如果你想做这种 open vocabulary,或者你想做这种 Zero shot 的这个 object detection,那你就肯定得跟这个文本联合起来,你才能去做Zero shot。那怎么把这个文本加进来?那最简单的方式就像 CLIP 一样,就是你先用一个图像的 backbone 去抽一些这个图像。特征。然后你再去找一个文本的网络,抽一些文本的特征,然后最后你把这两个特征做个点乘,算一下它们的相似度就可以了。所以说这里面也一样,作者采取的就是这种最简单的方式。前面就是 n 个proposal,然后进这个检测头,然后经过一些操作之后,就得到了这 n 个 region embedding,也就跟之前那个基线网络这边 n 个 region embedding 差不多。那接下来我们就是要去算一些这个文本的embedding。那文本的 embedding 其实就是把物体的这些类别拿过来,然后给一些prompt,然后生成一个句子,然后把这个句子扔给任何一个这个文本编码器就可以了。那这里首先我们要注意的一个点,就是我们的文本来自于这个物体的类别,也就是说我们做的还是有监督的学习。而且我们的这个类别还是 base category,就是那些数据集里的基础类,也就是我这里强调的这个 CB 就是class base。也就是说这个基线网络这边这个 mask RCN 也是在这些基础类上进行这种有监督的训练,那这个 ViLD text 也是在这些数据集上做有监督的训练,而且是在这些基础类上训练。所以在这个阶段这个 ViLD text 模型其实只是把图像的特征和文本的特征联系到了一起,但是它 open vocabulary 就这种 Zero shot 的性能还有待加强。那继续说回来这个文本特征这块,作者这里把它标成蓝色,也就是说这里的这个模型参数自始至终都是锁住的,它并没有参与训练。就跟我们刚才讲的那个 l SEG 那篇论文一样,文本端是锁住的,那你一旦有了这个图像特征,你又有了这个文本特征,那其实你就可以直接做一个点乘,然后那个相似度你就可以当做最后分类的那个logics,你就可以去做这种 cross entry pay loss,然后进行模型的训练。
那这里有一个额外需要提的,就是这个background,那再次说明,因为你现在做的是有监督的训练,你用的都是这些基础类,那不在这些基础类里的所有别的类别怎么算?那就只能全都塞给这个背景类了,所以说这个背景类的学习非常的关键,专门有一个这个背景的embedding,你需要在这个模型训练的时候去把它学好。至于具体的计算,其实这个背景类的 embedding 和这个 text embedding 一样,都是去跟这个图像 embedding 直接做点乘就可以了。
那看完了 ViLD text 的这个模型总览图,我们再来看一下它的这个数学上的公式,就能更清晰的明白它是怎么训练的了。那这里就是假设你有一个图片i,然后这个就是去抽取一下图像的特征,然后这个 r 就是你提前知道那些proposal,就你抽出来的那些 Bonding box candidate。然后再经过一些额外层的这个计算,也就是这个r,我们就得到了这个 region embedding
,这个 er 就是图像的这个 region embedding。
然后接下来我们定义了一个 background 的这个embedding。然后还要从文本那边来的t1, t2 一直到tCB,那这也就我们刚才说的,你这个数据集里有多少个基础类,也就是你有多少个CB,这么多类。你这个 text 就有多少个embedding。接下来你这个图像的 region embedding 就分别去跟 background 和所有的这些文本类去做这种点成相似度计算,最后其实就得到了这个 ViLD text 模型的输出的一个类似于 logist 的东西。
那你一旦有了logics,然后你去做一个Softmax。你就能和 ground truth 去直接算这个 cross entry loss,这个就是 ViLD text 模型训练的目标函数。
如何能拓展到这个CN?就是那些新的类别上?或者说我们如何巧妙地把 clip 引入到这个框架里来?
那我们刚才也说了,这个 ViLD text 只是把图像的特征和文本的特征做了一下关联,这样接下来就能去做 Zero shot 了。但是具体这个 Zero shot 这性能怎么样?而这个 ViLD text 还不能做得很好,毕竟它只是在这个 CB 上去训练的。那如何能拓展到这个CN?就是那些新的类别上?或者说我们如何巧妙地把 clip 引入到这个框架里来?而接下来作者就提出了这个 ViLDimage。那 ViLD image 这个想法其实也很简单,那就是说你这个 CLIP 预训练好的这个图像编码器非常的好,而且跟文本那边的关联也做得非常的好。那我就希望我这边图像编码器输出的这个 region embedding,如果能尽可能地跟 clip 输出的那个图像 embedding 尽可能的一致就好了。
那你如果想做到这一点,其实最简单的方式就是这个知识蒸馏。具体来说就是当你有一些抽好的proposal,也就是得到的那些 bonding box,然后你就可以把它抠出来,然后做一些 resize 的操作,比如说变成 224 * 224,然后这个时候你就可以把它扔给这个 clip 预训练好的这个图像编码器,然后你就可以得到这个图像的特征了。那这里面这个图像编码器这块是蓝色,也就是说它也是锁住的,从头到尾它都没有训练,这样就能保证这块抽出来这个图像特征就跟CLIP一样。好。所以说我们就把这一支当做是这个teacher网络。
那我们的 student 网络,也就是之前一直用的这个目标检测的框架,就是我先有一些proposal,然后过这个检测头,然后抽一些特征,那我就希望这个抽出来的特征跟 clip 出来的车特征尽可能的接近。
那我们就直接用一个简单的 l one loss 去做一下这个蒸馏就可以了。
这里面值得一提的是,因为现在这个监督信号不再是什么人工标注了,而是这个 CLIP 给你带来的这个图像编码,所以说你就不再受这个就是基础类的限制了。你抽的这个 region proposal,它既可以有这个基础类里来的proposal,也可以有那些新类里来的proposal。你都可以去训练,反正你的监督信号都是从 CLIP 里来的,而不是从数据集的人工标注里来。所以说 ViLD image 就通过利用 CLIP 模型大大地加强了这个做 open vocabulary 的能力,不过这里其实也有一个小小的弊端,大家可能也发现有一个小小的区别,就是之前这个 ViLD text 做的时候,它都是 n 个proposal,最后得到的也是 n 个embedding。为什么到 ViLD image 指标就成 m Pre computed proposal,而且最后都是 m 个 embedding 了?那其实这个主要是为了让这个训练变得更加的快速,理论上你前面这个模型的 backbone 给你多少个proposal,那这个 ViLD text 和 ViLD image 都可以用这些proposal,就是理论上你都可以用这 n 个。proposal。但是事实上如果你每次都在模型训练的时候再去抽这个 CLIP 的特征的话,这个就太慢了,因为它这里想用一个比较大的 CLIP 模型,比如说 clip 公开的最大的那个 VIP large,那你如果做一次这个前向过程是非常贵的,尤其如果你这里有 300 个或者 1000 个 proposal 的时候,你相当于要前向这么多次才能得到这些特征。而且是每个训练 iteration 你都要前向这么多次,对这个计算代价非常的高,肯定就把这个训练时长拉到无限长了。所以作者这里就取了个折中,就是说我提前先把你每个图片利用我已经训练好的那个RPN,就那个 region proposal network,我先去预抽取你这m个proposal。就在 ViLD这个模型还没开始训练之前,我就把你这些 proposal 全抽好了,而且这些 proposal 也全都 crop and resize,也全都通过 clip 模型把你这个 embedding 也都抽好了。所以说在训练的时候,作者只需要去硬盘上把这个抽好的这个 embedding load 进来就可以了。那只要这个机器的内存足够大,其实所有的这些 embedding 都可以直接存到内存里面。那这个蒸馏过程做起来这个 loss 算起来那就非常的快了。所以所以说为了让这个训练快速起来,作者不得不在这使用了 m 个预训练好的proposal,那这个跟网络在训练的时候左边出来的这 n 个 proposal 就不一样了,这个 n 个 proposal 是随时可以改变的,所以说这个是一个值得注意的点。
那最后这个 ViLD 其实就是 ViLD image 和 ViLD text的合体。因为其实那两个也就是两个目标函数。整体的这个模型框架是没有改变,左边就是目标检测的这个分支,右边就是 clip 的图像 embedding 这个分支。而且右边其实也就是只有在训练的时候才会用到,它就是个蒸馏,在测试的时候是完全没有用到的。为了计算上的简单,其实作者就是把 n 个 proposal 和 m 个 Pre computer proposal 全都一起给这个目标头,然后得到所有的这 n + m 个embedding,然后它再把它劈开,这 n 个 embedding 就去算这个 cross entropy loss,然后 m 个 Pre computer embedding 就去算这个蒸馏的Lone loss。但总体上来说 ViLD 就是 ViLD image 和 ViLD text 两个的合体。
那作者这里详细讲完每一个模块之后,它在这个图 2 里还给了一个总体的模型总览图,我们现在就可以来快速的过一下。那上面这一部分其实就是模型的训练,如果你给定一个图片,而且还有它对应的这个绿色的这个基础类,那图片就是先通过一个 RPN 得到一些region proposal。然后通过 RI align 和一些 comm 层,最后得到一些regionembedding。然后这个绿色的基础类先得到一个prompt,然后通过这个文本编码器就得到了一些绿色的这个文本编码。
那像 CLIP 一样,我们有了这个图像编码和文本编码之后,我们就可以去算一下这个 cross centrib loss,这也就是 ViLDtext,
然后对于 ViLDimage,就是说上面我还有一个这个 CLIP 的图像编码器。我把那些已经抽取好的那些 region proposal,也就这个色子或者这个 stop sign 全都通过这个 CLIP model 就会得到一些 clip 的这个图像 embedding,那我呢是希望这个 R1R 2 尽可能的跟这个 I1I2 去接近,所以我就用这个 I1I2 去对它做了一个蒸馏,也就是这里说的这个 l one loss,这样的话整个训练过程就完成了。
那在做推理的时候就是给定一个图片,然后不光是基础类,我还有蓝色的这些新的类别,然后图片还是老样子,通过一个 backbone RPN 得到一些 region proposal,然后去得到一些 region embedding。那这里面那个 region embedding 应该已经非常的强大了,因为它已经得到过 clip 的这个蒸馏了。然后文本这边就是不论是基础类还是新类,都通过这个template,然后再通过这个文本编码器得到了所有的这些文本编码。前面的就是基础类,后面就是新类,然后我只需要像 clip 一样去做一个点成这个similarity计算就可以了,哪个类别最高,我最后就说它是哪一个类,这样就完成了整个 Zero shot 的目标检测。
实验结果
那说完了 ViLD这篇论文的方法,我们接下来就看一下它主要的一个表格,也就是它在 Elvis 这个数据集上的结果。 Elvis 这个数据集是一个非常长尾的一个目标检测数据集,它一共有 1203 类,所以类别数非常的多,但其实它的图片还用的是 Coco 的图片,所以你就可以想象到它有很多那种特别小或者特别不常见的物体,它就只标注了一次或者两次,他就把这些全都算到这个人工标注里了。于是这个数据集还有一个分类,就是它把它的类别分成这个frequent,就是常见类,还有 common 就一般的类,还有这个 rare 就是基本不常见,就是标注特别少的那些类。这样它去算 AP 的时候,它就可以针对这几个分别去算AP,看看这个模型的效果在这三类上分别如何,那在这篇论文里,因为作者主要想强调就是 open vocabulary,也就是说怎么能做 Zero shot,怎么能去检测这种新类。所以作者就把这个 common 和 frequent 算成了这个 base category 就是基础类,那这个就一共有 866 类,那这 866 类就是在训练的时候可见的那些类,然后他把后面剩下的这 337 类就是不怎么常见的,就当做了 novel category,就从来没见过,所以我们就可以在上面去做 Zero shot,那这个 APR 就是在这个 rare class 上的这个 AP 其实就是他最看重的那个衡量标准。
然后作者这里说 ViLD的非常厉害,就是说之前如果你是一个有监督训练出来的网络,而且你还用了 repeated factor sampling,就是一种这个数据采样的方式,能够帮助你解决这个数据长尾问题,就尽可能的多去踩一些那些尾部的类别,少踩一些头部的类别,尽量让它均衡一点。总之就是说这算一个很 strong 的一个基线模型了。然后网络就用的是rise 50。那在 数据集 上的结果就只有12。3,就是这个APR。但是看 ViLD这边, ViLD text 和 ViLD image 就已经比较接近这个数字了,如果我们把 ViLD合起来,它就一下达到了 16. 1,这个结果就比之前的这个 APR 超过了 3. 8 个点。
作者认为这很厉害,因为你这是 Zero shot,而且大幅度超过了之前的这个 有监督的基线模型,但是这个也不是说不好理解,因为就像我刚刚说的一样,对于这个数据集来说,其实最后这 337 这个尾部的类,它的标注数非常之少。可能有的类别就只有一个标注或者两到三个标注。那这个时候不论你用不用 RFS 这种sampling,或者用其他的这个技术,你都很难把尾部的这些类做好,尤其是有监督的训练,你有可能越训越差,还不如不训练就直接 Zero shot 就完了。所对这里这么好的这个结果对比,其实也是利用了 LVS 这个数据集的一个特性,所以带来了这么大的提升。那如果我们看总体的AP,我们会发现 ViLD其实和之前的这个有监督还是有差距的,不过总之 ViLD是一个很好的一个开山的工作,它的实验做的真的非常全,比如说它这里如果把这个网络的backbone换了,或者后面的这个预训练方式数据集换了,你就会发现 ViLD 都是可以直接用过来的,而且这个性能也大幅度的提升。甚至能够直逼当年这个 2020 年这个 always challenge 的那个冠军的解决方案。所以对于一个 Zero shot 的工作来说,这个性能已经是非常强大。
另外一个比较好的结果就是说你作为一个 Zero shot 这个方法。就是说你肯定可以直接拓展到其他数据集上,那作者这里就把这个 LVS 上训练的模型直接拓展到Pascal,VOC,Coco,还有这个 object 365 数据集上。我们可以发现 ViLD 作为一个 Zero shot 的方法,虽然说跟有监督的方法比差的还是有一些距离,但是在这种小规模的 VOC 或者 Coco 数据集上其实已经比较接近了,所以它的这个 open vocabulary 的能力还是挺好的。那 ViLD其实就算讲完了,但其实 ViLD这篇论文附录还有很多很多的内容,感兴趣的同学都可以仔细的去读一下。就跟作者说的一样, ViLD 是第一个在 always 这么难的数据集上去做这种 open vocabulary 的 detection 的,这也算是 detection 这边儿一个里程碑式的工作,它利用了一些 clip 的思想,而且也借鉴了 clip 这个预训练的参数就跟分割那边儿的套路其实也很像,最后的结果也很好。
3.2 GLIP Grounded Language-Image Pre-training
研究动机
那接下来对标分割那边儿的 group VIT,那我们讲一下目标检测这边儿的GLIP。那接下来我们就来看一下 GLIP 这篇论文。你听这个名字就跟 CLIP 很像,只不过是把 contrasted 变成了这个grounded,所以就是GLIP。这篇文章主要的研究动机,还是说我怎么能利用更多的这个数据?因为跟分割一样,就是这些精心标注好的这些数据很难得。而且对于现实生活中那些边边角角的类,还有层出不穷的这些新类,我们没有办法去训练一个模型,然后把这些都做得很好,我们只能依赖于这种能做 open vocabulary 的 detection 模型去把这些 corner case 处理好,那如果我们想训练一个这个特别强大的 open vocabulary 的这个 detection 模型,那就要求我们必须像 CLIP 一样能有一个很好的这个预训练数据集,最好这个规模能上千万上亿。然后能把这种文本和图像之间的关系也学得很好,同时把这个定位也学得很好。那 CLIP 论文的作者就想,我怎么能像 CLIP 一样把这个图像文本对儿用上,因为确实这种图像文本对儿的数据很好收集,很轻松就上亿了。然后这个时候他发现在这个 vision language 这个下游任务里面还有一类任务叫做 vision grounding,其实说白了就是给你一句话,然后你去把这句话里的一些物体在这个当前的图片里,你去把它定位出来,所以叫 vision grounding,那这个说白了其实就跟目标检测是一样的,只不过目标检测就是给你一个图片,你去把 Bonnie boss 给我找出来,这个就是给你一个图片,然后再给你一个文本,你去根据这个文本把物体给我找出来。那作者就想我能不能把这两个任务结合起来,那通过这种结合我是不是就能用很多这种图像文本对去训练我的模型了?结果最后作者发现,诶,还真行,真的可以把 detection 还有这个 freeze grounding 这两个任务合起来,变成一个统一的框架去做这种模型的预训练。而且这样能用的数据集也变得更多了。同时如果再把伪标签那一系列的方法加进来,也就这里说的self。training。这样模型就可以在这种没有标注过的这个图像文本对上去生成这些 bonding box的标签。从而扩大整个训练的数据集的数量,然后把这个模型训练得更好。最后作者说在这个大规模的数据集进行预训练完之后,他直接把这个模型拿过来做测试,然后发现在 Coco 和 LVS 上都能直接达到 49. 8 和 26. 9 的AP,而且这个是完全没有看到过任何 Coco 的这个训练数据集的。这个结果还是相当高的。因为我们也知道之前像这种 fast RCN 这种基线模型,也就是40的AP。DETR其实也就是 40 出头的AP,它们都是有监督里表现很好的这些基线模型了,但是 GLIP 的模型不看任何的 Coco 图片,直接 Zero shot 就能达到 50 AP 了,所以这个性能非常的强。
Zero shot 推理怎么做
那至于这个 Zero shot 推理怎么做,其实作者在这个图一里也大概展示了一下,就是不论你现在给我的是一些物体的标签,比如说像目标检测一样,你给我这个人、自行车。什么的。我就把这个标签把它变成一句话,然后把这句话扔给 GLIP 模型, GLIP 就帮我把这些新的类别那就全都检测出来了。或者说就跟 freeze grounding 那个任务一样,你给我一句话,就直接告诉我这个马路上有很多洞,然后我就把马路上的这些坑就全都给你检测出来了。这个其实还挺有用的,因为之前我还看到过有一些公司有这方面的需求,就是去检测这个路上有没有这种坑,看需不需要检修。那如果平时做这种任务,你还得去收集这些数据集,然后再训练一个目标检测器。但是现在你直接把 GLIP 拿过去,直接 Zero shot 做推理就可以了,至少能先做个demo。
目标函数:glib 这个模型是怎么把目标检测和这个 freeze grounding 这个任务结合起来的
那具体来说, glib 这个模型是怎么把目标检测和这个 freeze grounding 这个任务结合起来的?作者这里就先做了一下这个背景介绍,他说对于这个目标检测来说,一般其实你的这个训练目标函数就是一个分类的loss,还有一个这个定位的loss,我们刚才其实在 ViLD 里也刚。讲过。对于目标检测或者 vision grounding 来说,其实这个定位部分都差不多。这个定位主要是根据你这个模型是什么,它来选择你怎么去生成这个定位框的。它们的区别就在于你怎么算这个分类的 loss 上。因为对 detection 来说,它的标签是一个或者两个单词,是 one hot 的这种标签,但是对于 vision grounding 来说,它的标签是一个句子。所以作者接下来就强调了一下这个 detection 这边儿的这个分类loss怎么算。这个 vision grounding 那边儿的分类loss怎么算。以及如何把它们两个能合并到统一的一个框架下面来。
那我们先来看目标检测,作者这里其实是比较简化的写了一下,
比如说给定一个图片,我现在有一个这个图像的backbone,我就会得到这个 region embedding O。那我们可以看到这块儿这个 o 就是
n 乘 d 的一个region embedding。意思就是说假如说你有 n 个这个 bonding box,然后每个 bonding box embedding 的维度就是d。接下来要做的就是后面接一个分类头,看一看你每一个这个 bonding box 里面的物体到底是哪个类。那其实这个分类头就是一个矩阵
,它的维度就是
c 乘d, c 就是你有多少个类别了。那所以你把这个 region embedding 和这个 w 乘一下以后,你就会得到最后的这个分类的logics
,然后这个时候你用 NMS 把这些 bonding box 筛选一下,然后再去跟 ground truth
去算这个 cross entropy loss,就能得到最终的这个分类 loss 了
。
那对于 vision grounding 这个任务来说,它的这个分类 loss 又是怎么算的?
作者这里说其实它是算了一个这个匹配的分数。它就是想看看图像中的这些区域和这个句子里的那些单词是怎么能匹配上的。那至于图像这边还是一样的处理,有一个 image backbone,大家得到了一些 region feature,但是接下来就不是一个分类头了。接下来就像我们刚才说的 ViLD一样,它就换成了一个文本的编码器,你给我一个句子,就这里的这个prompt,然后我通过一个文本编码器,我就能得到这个文本的embedding
,然后我有了这个文本的 embedding 之后,我跟图像的这个 embedding 去算一下 similarity
就可以得到最终的这个 region word alignment score。那这块儿如果画成图,其实就是刚才我们说的 ViLD里的那个 ViLD text 分支,一模一样。
然后作者发现其实这两种方式都差不多,只需要做一点小小的改动就能让这个目标检测和 vision grounding 联合起来了。这个小小的改动就是判断一下什么时候算是一个 positive match,什么时候算是一个 negative match。然后理论上推完了之后,作者觉得这两个任务其实是可以统一起来的,但实际上你还得再跑一下实验去验证一下,作者这里就把目标检测换成他们现在统一过后的这个框架,去重新验证了一下之前的模型在这个 Coco 上的分数,结果发现是完全匹配的。也就是说用他们这个方法训出来的模型,也就是 GLIP 是完全可以迁移到任何一个目标检测的数据集上的。那一一旦确认了这个事情,接下来就是看怎么能扩大数据集,怎么能把这个预训练模型训练的更好了。
预训练数据集
那说到数据集,我们直接来看文章的这个表一里说这个 GLIP 模型有几个变体,每个变体运用的训练数据集也不一样,比如说这里这个GLIP-T (B)GLIP-T(C),这两个是属于比较小的模型,是用来验证一些想法的,那比如说 b 其实就是在这个 object 365 的数据集上训练。这个数据集真的很好,你在它上面做完预训练之后,再去 Coco 上做这个微调,一般效果都会特别好。
然后这篇论文作者主要想讲的点是说,如果我们能把这个 detection 和 vision grounding 合并成一个任务,那 grounding 那边标记好的数据我们是不是就能拿来用了?所以这里面他们又用了一个 GoldG,就是专门做 grounding 的一个数据集。其实这个数据集是好几个数据集的合体,比如说visual、genome、 VQA 什么。之类的。这些数据集也都是标记好的,它虽然每个图片对应的是一个文本,那其实它也有 bonding box 的annotation,所以这里面其实这个表格上面其实都是用已有的数据集,就是已有的这些标记好的数据集去做已有监督的训练。作者这里只是想说,我能把 detection 和 grounding 的数据集合并到一起,让这个数据集变得更大一些。但是终究用已有的数据集,你始终逃不过这个就是边边角角的这些 corner case,而且你也不能很好的把这个数据集变得很大,那你如果想把数据集变得很大,你就只能借鉴于 unlabeled data。所以作者接下来又引入了这个图像文本对,也就是他这里说的 CAP4 million 和 CAP 24 million 这两个数据集。但是你为了训练你的这个目标检测模型,你必须得有 bounding box 的 ground truth,而且你还得知道这个 bounding box 对应于句子里的哪个单词。所以作者这时候就采取了 self training 借鉴这种伪标签的方式,也就是说它拿已经训练好的这个 GLIP tiny c,然后它直接在这些图像文本对上去做推理,它推理出来当前的这个图片上有哪些 bonding box,它就把这些 bonding box 当成ground truth 了。这里面当然肯定有错了,所以也就是为什么叫伪标签。但是其实最近几年伪标签的用处非常广泛,而且伪标签使用了以后,一般都能让模型的性能变得更好,尤其是这个模型的稳健性可能也。变得很好。所以作者这里就通过提供伪标签的这种方式,再一次把这个数据集扩大得很大。然后当他们训练他们最后的最大那个模型 GLIP large 的时候,他用的是 swing large。模型。然后在有监督的这个数据这边,他用了四个这个有监督的目标检测数据集,就是把 open image、 object 365 还有这个 LVS 就全都加进来了,然后把 grounding 那边也加进来了,所以对于有监督来说已经是把能用的全用。然后对于无监督伪标签那边,他们也把规模扩大到 24 million,所以总体上来说这个 Pre training 的数据集就已经非常大了,已经足够能训练出来一个不错的模型了。
模型总体框架
那说完了目标函数,也说完了这个预训练数据集,我们最后来看一下这个模型的总体框架,其实还是跟 clip 非常相似的一个图片一些文本。图片过图像编码器得到一些 region embedding,文本过文本编码器得到一些文本 的embedding。然后我们可以先跳过中间的这些东西,然后直接到最后来看它的这个目标函数是怎么算的。因为这个工作其实是一个有监督学习的工作,也就是说它时时刻刻都是有 bonding box annotation。所以说当你抽出来这个O1, O2 这些 region 的时候,其实我知道它跟这边这些单词是怎么去一一对应的。这样在算完这个 o 和 p 的这个相似度点乘之后,我就可以去跟这个 ground truth 去算这么一个alignment loss。这样就完成了文本和图像特征之间的这个融合,这样接下来你就可以去做 Zero shot。那对于这个定位 loss 来说,其实因为你有这个 ground truth,所以就是最基本的算一个 l one loss 就可以了。
那我们回过头来看中间这个diffusion,其实作者这里的意思就跟分割那边LSET那篇论文一样。就是当我把这个文本的特征和这个图像的特征抽出来之后,理论上我是可以直接去算后面这个相似度矩阵的。但是如果你直接这么算的话,这个图像文本的这个 joint embedding space 还没有学得很好。如果我们能再多加一些层数去让它们之间融合一下,可能它们就会学会相似的概念,我就拉近一些不相似的概念我就拉远一些。总之能让最后的这个文本特征和这个图像特征更加的强,而且更加的有关联性,这样你再去算后面的这个相似度的时候,也就更有针对性。然后这里的操作,其实本文就是用 cross attention 把这个文本和图像的特征交互了一下,但是你也可以选很多其他的结构去做这件事情。
然后说白了这个 diffusion 的技术,其实你也可以把它再用到分割那边去,比如说 group VIP、 group VIT,目前就是一个图像分支和一个文本分支,它们之间只有最后做了一下这个 contrast learning,但其实如果你在之前能做一些这些early Fusion。它的效果有可能会更好,因为对于分割来说它也存在这么一个就是句子里的单词和这个图像里的这个region,它的这个匹配的问题。对,有可能也是一个很有趣的方向,毕竟目标检测和分割都属于这种稠密性预测任务的一种,就都是 dance prediction,它都需要同时分类和定位,所以很多方法也都是可以互相借鉴。
那 Glip 的方法其实就已经说完了,它跟 clip 模型一样,也是有两个分支,最后也是算了一个这个相似度矩阵,然后去算了一下目标检测特有的这种。alignment loss。就完成了这种 Zero shot。这个目标检测它跟我们刚刚讲的那个 ViLD 也有很强的关系,因为它里面的这个 alignment loss 其实说白了就是 ViLD 里的 ViLD text 分支。
结果
那最后我们先来看一下结果,作者这里展示了两个非常难的这个检测,或者可以说 vision grounding的任务。比如说在第一个图里,他就说我要检测到两个这个针管,还有一小瓶这个疫苗。那按道理来说,我是不知道有任何数据集是能检测针管或者检测疫苗这种东西的。但是通过GLIP,通过它对文本的理解,他就做出了自己的这种猜测和推断。他就因为这里面这是两个针管,然后这个是那个小瓶的这个疫苗,定位也非常准确。
那下面这个例子也挺难的,他给了几个句子,比如说第一句是在古巴的一个比较好看的这个海滩,然后这个景色是从这个海滩的上面往下看的,最后是能看到很漂亮的这个加勒比海,而且是这种特别好看的这种海绿色。这些其实都已经不太算是物体了,它已经有点概念就这种 concept 感觉了。但是 glip 也能做得很好,它把这个漂亮的这个海绿色也能框出来,整个海滩也能框出来,包括整个图片,其实就是一个从上往下看的这么一个view,全都定位出来了。
那如果我们来简单地看一下这个数值上的结果,就能更加理解 glib 模型的这个强大之处。那这里面是在 Coco 这个数据之上的结果。首先我们可以来看一下这个 Zero shot,那之前的这些方法,比如说 fast RCN,或者最近刚出的这个非常强的模型,SoftTeacher、DyHead-T这些在 Coco 上都榜上有名,但是他们都不能做 Zero shot,因为他们是纯视觉的模型,他们只有经过微调之后才能在COCO 上有一个分数。但这个分数确实。是不错。那对于格里普而言,它可以做 Zero shot,我们可以看它在 Coco 上,如果用它们最大的模型,在最多的这个数据集上经过预训练之后,甚至可以直接达到这个 50 AP 的这个 Zero shot 的性能。基本上是比 19 年之前大部分的这个有监督目标检测器训练得都要好了。那如果我们现在再在这个预训练好的这个 GLIP 模型之上,再让它去 fine tuning 一下,我们就会发现在同样都是这个 swin large 的这个模型之下,它最后的结果也能在 Coco 上达到 60 或者 61 的这个分数,结果也是不错的。
但是这也就是看一下比较一下,因为毕竟这个预训练的数据集也都不一样,训练的时候用的各种 trick 可能也不一样,所以不能算是一个完全公平的比较。只能说 GLIP 不论是 Zero shot 还是 fine tuning,它的结果都非常的强。
然后其实两个月之前 glib 还有一篇新的这个拓展工作,叫做GLIPv2: Unifying Localization and VLUnderstanding。它就是把更多的这个任务,更多的这个数据集就都融合进来了。所以说它的题目也就是 unify localization 和 VL understanding,就是把所有这种带定位的任务,比如说分割检测,还有这种就是 vision language 的这些任务,比如说 VQA 或者vision grounding。还有这个 vision captioning 就全都放到一起了。
那这里我们就不细讲了,但是我们可以看一下它的图,一来看看 GLIP where 到底干了一件什么事儿。
它的大概思想其实跟 GLIP 还是差不多的,整个框架也差不多,只不过是带入了更多的这个任务和数据。比如说这个图像这边还是就给了一个图片,通过一个这个图像编码器,但是文本这边就变得花哨多了。那对于 localization 的这些任务来说,它不光是做了这个目标检测,它还把这个 instant segmentation 也加进去了。那对于这个 vision language understanding 这边来说,它不光是像之前一样做了 visual grounding,还做了 VQA 和这个 image captioning,这样这个文本端就丰富了很多,这些通通都可以通过这个文本编码器,然后接下来做这个 language image 的这种diffusion。现在这样做也算是一个趋势,比如说去年有一个工作叫做OFA,还有今年的 Alan Institute,还有这个 unified IO,他们都是提供了一个统一的框架,然后去囊括更多的这个任务,更多的这个数据集,更多的这种模态,然后争取能把这个预训练的模型训练的又大又好。