这个博客开了有两个月,一直没写成,最近封寝给它完成~躺平第三天
CLIP应用领域概览:
1. LSeg
原论文地址:https://arxiv.org/abs/2201.03546
代码:https://github.com/isl-org/lang-seg
这个图就很清楚的说明了zero shot 的强大作用,可以说是想分啥他就给你分出什么。
模型结构:
模型整体看来与 CLIP 模型非常相似,只是将单个的图像文本特征换成语义分割中逐像素的密集特征。除了上方的文本编码器提取的文本特征要与密集图像特征相乘来计算像素级的图文相似度之外,整个网络与传统的有监督网络完全一致,都是有一个图片,然后进了一个分割的模型,最后得到一个特征图,这个特征图通过一些upscaling,将其放大,因为我们做的这个密集任务,最后的输出应该跟原来图像的大小一致,所以就要做一些升维的操作。最后就是模型的输出,跟ground truth supervision做一个cross entropy loss(交叉熵损失) 就可以。
图像的编码器是DPT的结构,也就是前面一个ViT,后面一个decoder,decoder的作用就是把瓶颈特征Upscale上去,就相当于把一个H×W×3的一个图像变成了一个,,C的一个特征图,, 跟原图相比,可能降维了一些,C是特征维度,一般就是512或者768,然后视觉特征就算是抽完了。文本分支将n个标签通过文本编码器,得到n个文本特征,维度为N×C,这里n是可以随意改变的,将视觉特征和文本特征相乘就能得到一个H×W×N的一个tensor,这也就跟传统的分割模型没什么区别了。这篇论文虽然说是zero shot,但是其实是有监督的训练。
这篇论文的意义就是把文本的分支加到有监督分割模型的pipeline中了,将文本特征和视觉特征结合起来,使得模型可以学习到一些language aware的视觉特征,从而使得可以通过文本的prompt去任意得到想要的分割效果。
其他细节如下:
(1)LSeg 整个文本编码器就是 CLIP 的文本编码器的模型和权重,并且训练、推理全程中都是冻结的
(2)LSeg 的图像编码器可以是任何网络(CNN/ViT),需要进行训练;
(3)Spatial Regularization Blocks 是本文提出的一个模块,为了在计算完像素级图文相似度后有一些可学习的参数来理解计算结果,是由一些卷积和逐深度卷积组成;
2.GroupViT
原论文地址:https://arxiv.org/abs/2202.11094
代码:https://github.com/NVlabs/GroupViT
LSeg虽然使用了CLIP的预训练参数,但是其实依旧是依靠语义mask作为监督信号,并没有把文本当成一个监督信号来使用,还是依赖于手工标注的语义mask,但是语义mask很贵哈哈哈,这篇论文在使用文本作为监督信号方向是一个比较有贡献的工作,为什么要叫group ViT呢?其实在视觉这边,很早之前做无监督分割的时候,经常用的一类方法就是grouping,类似于如果有一些聚类的中心点,然后从这个点开始发散,把附近周围相似的点扩充成一个group,这个group就相当于语义mask,是一种自上而下的方式,论文作者认为能把这个方法用到当前这个框架中,他们提出了一个计算单元,下图右边,叫做grouping block,还有一些可以学习的group tokens,该方法的目的就是想让这个模型在初始学习的时候就能慢慢地把相邻相近的像素点group起来变成一个又一个的语义mask,从图中可以看出,在模型刚开始的浅层,分割的效果还不是很好,但是经过学习,到深层的时候效果已经十分不错了。
对于图像编码器来说,其实就是vision transformer,一共有12层,也就是有12个transformer layers,图像编码器的输入其实有两个部分,一个是来自原始图像的patch embedding,也就是线性投影层的输出,另外一个就是这篇论文提出来的可学习的group tokens,也就是更右边一点的彩色矩形。
patch embedding就是加入我们这里有个24*24的图片,patch size 选择16*16,就有一个14*14,196序列长度的一个序列,经过这个Linear Projection,就得到了一些patch embedding。维度就是196*384。
group token可以理解为之前的cls token,就是说用这个token去代表整个图片,但是这里之所以是64而不是1,是因为之前为1的时候是代表整个图片有一个特征,但是现在是做分割,所以是每个类别或每个小块都有一个特征,不过两个token的学习过程都是一样的,都是通过transformer layer里的自注意力去学习这些图像的patch属于哪个token,经过6个transformer layer之后,使用一个grouping block进行cluster,将图像patch embedding分配到到64个group token,相当于做了一次聚类的分配,由于有64个聚类中心,所以最后剩下64个token,grouping block另一个好处是变相地把序列长度降低了,计算复杂度和计算时间也就相应减少了。
grouping block,首先用类似于自注意力的方式先算一个相似度矩阵,通过这个矩阵去帮助image token做一个聚类中心的分配,从而实现降维,不过分配聚类中心这个过程是不可导的,所以用了一个trick,也就是gumbel softmax,从而把这个过程变成可导的。这样整个模型就可以端到端的进行训练了。
由于一般的数据集或图片里的种类也不会太多,所以作者希望能把64个聚类中心变得更少,所以加了新的8个group token,通过transformer的学习将64个语义token再次映射到8个聚类中心上,这里用的是3个transformer layer,然后再通过grouping block,最终得到一个8*384的token,也就是图像被分成8大块,每一个块有一个特征。
训练过程与CLIP类似,通过图像文本对去算一个对比学习的loss,从而训练整个网络,但是这里有一个问题,CLIP中一个图片是一个特征,文本也是一个特征,但是现在文本是一个特征,但是图像有8大块的特征,所以作者通过一个平均池化融合8大块特征,再通过一层MLP得到整个图像的特征,接下来就跟CLIP完全一致。
在推理的时候,文本编码器每一类生成一个特征,图片生成8个group embedding,进行对比,由于只有8个group embedding,所以图片只能检测到8类。
局限性:只能识别到8类,多就不行了,但可以调,作者实验发现8最好。
3. ViLD
原论文地址:https://arxiv.org/abs/2104.08860
代码:tpu/models/official/detection/projects/vild at master · tensorflow/tpu · GitHub
ViLD 干了啥:现有数据集上,不标注,拥有能够检测到任意的新的物体类别的能力
a为有监督baseline的方法,b,c,d是ViLD的网络结构。
其实这个baseline就是一个mask-RCNN,是一个两阶段的分类器,第一个阶段会出n个proposal,第二个阶段根据这N个proposal经过detection head得到一些region embedding,再通过一个分类头,得到抽取到的bounding box的类别,这样就完成了目标检测。
目标检测从目标函数来看可以分为两块,一个是怎么定位,一个是怎么分类,定位就是bounding box画得准不准,分类就是bounding box里面的物体判断得准不准,这篇论文有点把这两块解耦开来的意思,这里所有的框架图都是从第二个阶段开始,输入都是N个proposal,第一阶段没有画。
(1)ViLD-text:想做zero-shot的目标检测,肯定得跟文本联合起来,那怎么把文本加进来呢?最简单的方式就是像CLIP一样,先用一个图像的backbone去抽一些图像的特征,再去找一个文本的网络抽一些文本的特征,最后把这两个特征做个点乘,算一下他们的相似度就可以了,这里也一样,作者采取的就是这种最简单的方式,N个proposal进入检测头,经过一些操作之后得到N个region embedding,也就跟之前的基线网络的N个region embedding差不多,接下来就是算一些文本的embedding,文本的embedding其实就是把物体的这些类别拿过来,然后给一些prompt,然后生成一个句子,然后把这个句子扔给任何一个文本编码器就可以了,这里要注意的是文本来自于物体的类别,也就是做得还是有监督的学习,而且类别还是base category,就是数据集里的基础类,这里baseline和ViLD-text都是在同样的数据集上做有监督的训练,而且是在基础类上训练,所以在这个阶段,ViLD-text其实只是把文本特征和图像特征联系到了一起,但是zero-shot的性能还有待加强。图中text embedding标成了蓝色,也就是说这里的模型参数一直都是锁住的,并没有参与训练,跟LSeg一样,文本端是锁住的。一旦有了图像特征和文本特征,就可以直接做一个点乘,相似度就可以当成最后分类的那个logits,就可以去做交叉熵损失,进行模型的训练了。
back ground,因为现在做的是有监督的训练,用的都是基础类,那不在这些基础类中的所有别的类别就只能全部塞给这个背景类了,所以这个背景类的学习非常的关键,需要专门去学习一个背景的embedding。
(2)ViLD-image:CLIP预训练的图像编码器非常好,而且跟文本的关联也做的很好,所以作者就希望模型输出的图像embedding与CLIP输出的图像embedding尽可能一致,而做到这一点的最好方式就是知识蒸馏。
当有一些抽好的proposal,也就是得到的那些bounding box,就可以把它抠出来做一些resize的操作,然后就可以把它扔给CLIP预训练好的图像编码器,然后就可以得到图像的特征了,这里预训练好的图像编码器也是锁住的,就可以保证抽出来的特征跟CLIP的一样好,然后把这一个分支,也就是ViLD-image右边这个分支作为teacher网络,student网络就是之前用的目标检测的框架,就是先有一些proposal,过检测头,然后抽一些特征,作者希望这里的特征跟CLIP抽出来的特征尽可能地接近,这里直接用一个L1 loss做一个蒸馏就可以了。这里值得一提的是,现在监督信号不再是人工标注了,而是CLIP带来的图像编码,所以就不受基础类的限制了,所以抽出来的proposal既可以有基础类里来的proposal,也可以有新类里来的proposal。
最后的框架d就是两个框架的合体,左边是目标检测的分支,右边是CLIP的图像embedding分支,而且右边只有在训练的时候才用,测试没用,为了计算上的简单,作者把N个propo和M个pre-computed proposal全都一起给目标头,然后得到N+M个embedding,然后在劈开,N个embedding去算交叉熵损失,M个pre-computed proposal去算蒸馏的L1 loss。
还剩几篇文章,看别人的视频看的我都累,感叹大佬的脑子,为啥我的脑子啥也记不住!微笑.jig