Date: 2021/02/02
Coder: CW
Foreword:
DETR提出后,Transformer就被带到目标检测这边玩起来了,而且还玩出各种花样,你看,这不就来了个可变形的DETR——Deformable DETR(名字倒是挺帅)。看到'Deformable'字样,估计各位炼丹师第一反应都会是DCN(Deformable Convolutional Networks)。没错,这里就是借鉴了DCN的思想,将其应用在注意力机制上。
相对于Transformer那种全局(global)&密集(dense)的注意力机制,这里提出了一种新玩法:每个参考点仅关注邻域的一组采样点,这些采样点的位置并非固定,而是可学习的(和可变形卷积一样),从而实现了一种局部(local)&稀疏(sparse)的高效注意力机制。
OK,接下来一起和CW看看具体是怎么玩的吧!
附:Paper & Code
主要内容
I. 研究动机
II. 方法概述
III. 主要方法
i). Multi-Scale Features & Scale-Level Embedding
ii). Deformable Attention(& Multi-Scale)
iii). Deformable Transformer
-Encoder
-Decoder
IV. 改进策略
a. Iterative Bounding Box Refinement
b. Two-Stage Deformable DETR
V. 头脑风暴
1. 为何不需要FPN也能达到跨层融合的效果?
2. 为何注意力权重可由query直接通过全连接层预测?
3. 为何检测头部的回归分支预测的是偏移量而非绝对坐标值?
VI. 与其它方法比较
i). vs DETR
ii). vs Sparse R-CNN
I. 研究动机
DETR腻害啊,DETR好哇(猜测作者内心:太好了,我可以在这基础上玩,然后发paper了)!作者开篇先吹了DETR一波,那麼腻害在哪里、好在哪里呢?
i). 第一个端到端的目标检测器;
ii). 不需要众多手工设计组件(如anchor、固定规则的标签分配策略、NMS后处理等)
iii). DETR实质上相当于是给出了一个方法论,犹如“普度众生”,告诉大家Transformer可以拿到目标检测中来玩,并没有过多地追求其它方面的成就(没有使用一些骚里骚气的tricks去涨点),剩下的就让你们去玩吧,真是良心了!(私以为,作者盛赞DETR最真实的在于这点哈哈哈~!)
OK,这波吹完后,作者开始为他的工作作铺垫了,一个‘However’可谓峰回路转:
Howerver, it suffers from slow convergence and limited feature spatial resolution, due to the limitation of Transformer attention modules in processing image feature maps.
也就是说DETR收敛慢而且能够处理的特征分辨率有限,而且,锅还甩在了Transformer上(Transformer内心:我好不容易来CV界混一混,还没过足瘾这就被喷了!?)。至于原因嘛,主要有以下两点:
i). Transformer在初始化时,分配给所有特征像素的注意力权重几乎是均等的,这就造成了模型需要长时间去学习关注真正有意义的位置,这些位置应该是稀疏的;
ii). Transformer在计算注意力权重时,伴随着高计算量与空间复杂度。特别是在编码器部分,与特征像素点的数量成平方级关系,因此难以处理高分辨率的特征(这点也是DETR检测小目标效果差的原因)
至此,作者认为铺垫得差不多了,再喷下去就过分了(Tranformer内心:我太难了~),见好就收。
II. 方法概述
铺垫完,是时候秀秀自己的工作了。作者认为,既然要学习稀疏的空间位置,为何不用可变形卷积那套呢?但是,可变形卷积同时也缺乏关系建模能力,而这点恰好是Transformer最擅长的,于是作者最终就将两者放在一起玩,这个玩法就是 Deformable DETR。
当然,这不是玩玩而已,Deformable DETR是能解决DETR的慢收敛与高计算复杂度问题的。作者秀到:这个玩法最大的亮点在于提出了可变形注意力模块,相比于Transformer那种有点'low'的方式,在这里,每个特征像素不必与所有特征像素交互计算,只需要与部分基于采样获得的其它像素“亲密接触”(交互)即可,这就大大加速了模型收敛,同时也降低了计算复杂度与所需的空间资源。另外,该模块能够很方便地应用到多尺度特征上,连FPN都不需要。
这么一看,好像有点腻害哦,具体是怎么做到的?下面CW就带大家一起来看看。
III. 主要方法
i). Multi-Scale Features & Scale-Level Embedding
在上一节也提到过,作者说可变形注意力能够用于处理多尺度特征,于是在backbone部分提取了不同层级的特征,总共有4层,其中~来自ResNet,下采样率对应为8、16、32,由经过步长为2的3x3卷积得到。
要知道,DETR仅用了单尺度特征,于是对于特征点位置信息的编码,使用的是三角函数,不同位置的特征点会对应不同的编码值,没问题。但是,注意了,这仅能区分位于单尺度特征点的位置!而在多尺度特征中,位于不同特征层的特征点可能拥有相同的(h,w)坐标,这样就无法区分它们的位置编码了。
针对这个问题,作者增加使用一个称之为'scale-level embedding'的东东,它仅用于区分不同的特征层,也就是同一特征层中的所有特征点会对应相同的scale-level embedding,于是有几层特征就使用几个不同的scale-level embedding。
另外,不同于三角函数那种固定地利用公式计算出来的编码方式,这个scale-level embedding是随机初始化并且是随网络一起训练的、是可学习的:
在实际使用时,这个 scale-level embedding 与基于三角函数公式计算的 position embedding 相加在一起作为位置信息的嵌入:
ii). Deformable Attention(& Multi-Scale)
可变形注意力的道理用大白话来说很简单:query不是和全局每个位置的key都计算注意力权重,而是对于每个query,仅在全局位置中采样部分位置的key,并且value也是基于这些位置进行采样插值得到的,最后将这个局部&稀疏的注意力权重施加在对应的value上。
OK,“普通话”讲完,该高大上(公式+代码)一番了。Transformer中多头注意力的公式如下:
其中,看作query,由经过线性变换生成,是对应的索引,是key的索引,即所有的k集合,m代表是第几个注意力头部,是对注意力施加在value后的结果进行线性变换从而得到不同头部的输出结果,' 用于将变换成value,代表归一化的注意力权重。
由此可知,在Transformer的多头注意力计算中,每个query都要与所有位置的key计算注意力权重,并且对应施加在所有的value上。
再来看看我们(哦,不是我们,与我无关,你们要吗?)的Deformable Attetion:
和Transformer的很像是不是?(老师我没有抄作业,别凶..)可以看到,这里多了和。其中,前者代表的位置(理解成坐标即可),是2d向量,作者称其为参考点(reference points);而后者是采样集合点相对于参考点的位置偏移(offsets)。
可以看到,每个query在每个头部中采样个位置,只需和这些位置的特征交互(代表基于采样点位置插值出来的value),并不需要像Transformer般一开始先从全局位置开始学习才能逐渐过渡到关注局部(&稀疏的)的、真正有意义的位置。
需要注意的是,如可变形卷积一样,位置偏移是可学习的,由query经过全连接层得到。并且,注意力权重也一样,直接由query经过全连接层得到(因此,在可变形注意力机制下,其实没有真正所谓的key来与query交互计算,为何可以这样做,后文CW会谈自己的看法)!同时在K个采样点之间归一化,而非像Transformer般是由query与key交互计算得出的。
OK,顺着来,看看可变形注意力是如何应用到多尺度特征上的,依旧是公式走起:
这个也和上面的非常想是不是!?(老师我真的没有抄作业啊..太难了~)相比于上面,这里多了和。另外头上多了个小尖角,代表归一化到[0,1],而正是用于将归一化的坐标映射(re-scales)到各个特征层去,这样,每个参考点在所有特征层都会有一个对应的(归一化)坐标,从而方便计算在不同特征层进行采样的那些点的位置。至于嘛,当然就是代表多尺度特征咯,代表第层的特征。
在这里,每个query在每个特征层都会采样个点,共有层特征,从而在每个头部内共采样个点,注意力权重也是在这个点之间进行归一化。
另外,作者还提到,当且' 是identity矩阵时,该模块就退化成可变形卷积;相对地,当采样所有可能的位置(即全局位置)时,该模块等效于Transfomer中的注意力。
道理说完,依旧如CW的风格,是时候上代码了。
接下来有个亮点,在以上最后的_reset_parameters()中,是关于生成初始的采样点位置的:
具体实现以及道理看以上代码和CW的注释,最终效果就是,初始的采样点位置相当于会分布在参考点3x3、5x5、7x7、9x9方形邻域。在github上有朋友提过相关的issue,CW那时正好逛到,也给予了相应的互动:Why sampling_offsets in `MSDeformAttn` is normalized by n_points
另外,对于注意力权重的初始化,CW发现作者的源码实现和paper中描述得有出入:
若按照以上的实现,感觉明显不合理,这样会导致注意力权重为全0,从而使得这个模块的输出结果也会变为全0。CW在github上提了issue,暂未有回复:Initialization for bias parameters of the attention weights seems to be wrong
接下来看看最重要的前向过程:
Deformable DETR有2-stage模式,后文会讲到。在2-stage模式下,输入到Decoder的参考点和object query&query embedding会有所不同。
以下主要是计算出采样点的位置。2-stage模式下,输入到Decoder的参考点是Encoder预测的top-k proposal boxes,也就是说是4d的(非2-stage情况下是2d),于是需要分情况处理:
注意力权重有了,采样点位置有了,最后就是计算结果了。
在这里,将注意力权重与value进行weighted sum的实现是调用了用CUDA来实现的版本,因为Pytorch版性能有点尴尬,不过我们也可以看看Pytorch的实现,了解其中的逻辑。
以下就是基于采样点位置插值出对应的采样特征(value):
最后就是将注意力权重和采样特征进行weighted sum:
iii). Deformable Transformer
这里的Transformer和DETR中的大体过程一致,最主要的区别在于用可变形注意力替代了Encoder中的自注意力(self-attention)以及Decoder中的交叉注意力(cross-attention)。在分别解析Encoder和Decoder前,CW先向大家梳理下这里Transformer的整个pipeline(有源码解析哦!)。
1). 为Encoder的输入做准备
主要是将一些输入元素的维度展平(flatten),这些输入元素包括:多尺度特征图、各尺度特征图对应的mask(指示哪些部分属于padding)、各尺度特征图对应的位置信息(position embedding + scale-level embedding),另外还有些辅助信息,比如:各尺度特征图的宽高、不同尺度特征对应于被flatten的那个维度的起始索引、各尺度特征图中非padding部分的边长占其边长的比例。
2). Encoder编码特征
源码对应上图最后一句。
输出memory(编码后的特征表示),shape是 (bs, h_lvl1*w_lvl1+h_lvl2*w_lvl2+.., c=256),其中h_lvli和w_lvli分别代表第i层特征图的高和宽,于是第二个维度就是所有特征点的数量。编码后,特征的最后一个维度(hidden_dim)为256。
3). 处理Encoder的输出,为Decoder的输入做准备
这一步主要是得到参考点(reference points)。需要说明下,在2-stage模式下,参考点和输入到Decoder的object query及query embedding的生成方式和形式会有所不同:
--如果是2-stage模式,那么参考点就是由Encoder预测的top-k得分最高的proposal boxes(注意,这时参考点是4d的,是bbox形式)。然后通过对参考点进行位置嵌入(position embedding)来生成Decoder的object query(target) 和对应的 query embedding;
--否则,Decoder的 object query(target )和 query embedding 就是预设的embedding,然后将query embedding经过全连接层输出2d参考点,这时的参考点是归一化的中心坐标形式。
另外,两种情况下生成的参考点数量可能不同:2-stage时是有top-k(作者设置为300)个,而1-stage时是num_queries(作者也设置为300)个,也就是和object query的数量一致(可以理解为,此时参考点就是object query本身的位置)。
在阅读源码的过程中,CW发现这里有个小问题,貌似不妥。由于分类预测头部的输出维度是多分类的,而proposals仅需二分类就足够了,作者在取top-k得分时直接用第一个类别预测的结果来计算:
同时,在不使用iterative bbox refine策略的情况下,会使得在第二阶段对解码输出进行分类时都倾向于预测第一个类别(使用iterative bbox refine时,对Decoder每层都有不同的分类预测头部实例,参数不共享,并且在这里会额外使用一个独立的分类预测头部,与应用到Decoder中的不相关)。关于检测头部的设置,代码如下:
继续,紧接着pipeline来吧。
4). Decoder解码特征并输出参考点
若使用了iterative bbox refine策略,则Decoder每层都会预测bbox,这些bbox就会作为新一轮的参考点供下一层使用,相当于coarse-to-fine的过程,不断地对参考点进行校正,最终会返回最后一层的校正结果。
由此可知,即便不是2-stage模式,只要使用了iterative bbox refine策略,这里返回的参考点也会变为4d的形式。因为检测头部的回归分支预测出来的结果是4d(xywh)形式的,而且是相对于参考点的偏移量(并非绝对坐标位置)。如果初始进来的参考点是2d的,那么wh就仅由检测头部的预测结果决定。
相对地,如果没有使用iterative bbox refine策略,那么这里返回的参考点和初始输进来的一样,保持不变。
5). 输出解码特征和参考点
这里输出的参考点有两个,包括初始进入Decoder前的和Decoder返回的。在上一步也说过,如果没有使用iterative bbox refine策略,则两者是一样的。
Encoder
这里的Encoder与Transformer中最主要的区别在于使用可变形注意力替代了原生的自注意力。类似地,在每层编码时会将上一层输出的编码特征作为下一层的输入,这个输入与position emebdding结合作为query、而经过线性变换则作为value。
现在具体来看看主要有哪些过程:
i). 计算参考点的位置
这里的参考点实质就是多尺度特征点的归一化坐标。注意,每个特征点在所有特征层都会计算出一个对应的归一化坐标(后文会谈到为何这样做)。
CW通过源码发现有个小问题:这里在对坐标归一化时使用的是非padding部分的特征图边长,而不同层非padding部分的边长比例有可能由于计算时的舍入误差而不一致,从而导致最终归一化后的坐标值大于1。
ii). self-attention
使用(多尺度)可变形注意力模块替代原生的Transformer自注意力,query和value均来自特征图,只不过query要结合position embedding,注意,这里的position embedding实质是position emebedding + scale-level emebedding。
iii). feed-forward network
前向反馈网络,和Transformer中的一致:由全连接层、激活函数、Dropout、残差连接以及层归一化(LayerNorm)组成。
Decoder
这里与Transformer中主要的区别在于使用可变形注意力替代了原生的交叉注意力。类似地,每层的解码过程是self-attention+cross-attention+ffn,下一层输入的object query是上一层输出的解码特征。
一起具体来看看每层的主要过程:
i). 将参考点坐标映射(re-scales)到各尺度特征层
将每个参考点的坐标分别都乘以各特征层非padding部分边长的比例,使得一个参考点在所有尺度特征层上都有相应的归一化坐标值(后文会谈到为何这样做)。
ii). self-attention
这一步是为了学习各个目标之间的关系,query和key都是object query+query embedding,value就是object query(注意不需要位置嵌入哦)。
iii). cross-attention
使用(多尺度)可变形注意力模块替代原生的Transformer交叉注意力,object query来自self-attention层的输出,同时也要加上query embedding;value由Encoder编码的特征经过线性变换得到。
iv). feed-forward network
输入来自cross-attention的输出,详细过程就不再阐述了,都是老朋友了~
v). iterative bounding box refinement
仅当使用了iterative bbox refine策略时有这一步:使用bbox检测头部对解码特征进行预测,得到相对于参考点(boxes or points)的偏移量,然后加上参考点坐标(先经过反sigmoid处理,即先从归一化的空间从还原出来),最后这个结果再经过sigmoid(归一化)得到校正的参考点,供下一层使用(在输入下一层之前会取消梯度,因为这个参考点在各层相当于作为先验的角色)。
vi). 输出各层的解码特征和参考点
IV. 改进策略
Deformable DETR是怎么让DCN和Transformer一起玩的,CW在上述已基本解析完毕。无奈作者还研究了“高配版”的Deformable DETR,涉及两个提升性能的策略:iterative bounding box refinement & two-stage。于是,CW又要多码不知道多少字了..
a. Iterative Bounding Box Refinement
字面意思就是迭代地对bbox进行校正,类似于cascaded head,实质上也是coarse-to-fine不断校正的一个过程。第d层Decoder校正后归一化的bbox用公式表示如下:
其中是第d层Decoder利用检测头部的回归分支预测的结果(偏移量),和分别代表sigmoid和反sigmoid函数。
在这里需要注意两点:1. 各层的检测头部是不共享参数的;2. 校正后的bbox梯度会被阻断(detach),不会跨层传播
具体实现和解析在上一节讲Decoder的时候已详细说明,这里就让CW偷懒一下下吧~
b. Two-Stage Deformable DETR
2-stage模式下,Encoder会输出一批proposals(并不是基于网络预测,而是像anchor一样计算出来的),boxes中心就是各特征点的中心,而宽、高的设置则与所在的特征层相关,base值设置为0.05。这时的proposals相对于anchors的角色。
然后,使用检测头部的分类分支对Encoder编码的特征(memory)进行预测,对应各个proposals的分类结果;同时使用回归分支也对编码特征也进行预测,得到相对于proposals(xywh)的偏移量,接着将偏移量加在proposals的中心坐标和宽、高上得到第一阶段预测的proposals。
最后,取top-k分数最高的那批预测proposals作为Decoder的参考点。并且,Decoder的object query和query embedding都由参考点通过位置嵌入(position embedding)来生成。
具体的代码过程在前面Deformable Transformer已有解析,这里就不再重复啦~
V. 头脑风暴
如果认真思考,会发现Deformable DETR中有许多值得考量的地方。
1. 为何不需要FPN也能达到跨层融合的效果?
作者在paper中说到,多尺度可变形注意力可以在不同尺度的特征之间交换信息,因此不需要FPN:
Note that the top-down structure in FPN (Lin et al., 2017a) is not used, because our proposed multi-scale deformable attention in itself can exchange information among multi-scale feature maps.
那么到底是为何?具体是怎么做到的呢?
其实前文也提到了,每个参考点在各尺度特征层都会进行采样。而且在上述处理参考点坐标的过程中,我们也可以看到,无论在Encoder还是Decoder,都会对参考点进行处理,使得一个参考点在所有尺度特征层上都有相应的归一化坐标值。为什么这样做呢?这样做其实就是为了计算出每个参考点在各尺度特征层对应的采样点位置。
那么你可能又会奇怪了,一个参考点明明是只处于某个特定的特征层,怎么能够把它放到另一个特征层去呢?这样合理吗?
合理不合理由网络去进行学习,基于最终的匹配效果来证明。但是可不可行我们倒是可分析的,可以这么看:我们知道,由于特征图是经过原图下采样得到,因此一个像素点无论是处于原图还是各层特征图中,其坐标的归一化值应该是一致的(忽略细微的计算误差)。那么,既然这里参考点坐标是归一化的,它就能够映射(re-scales)到各尺度特征中去,这部分对应以下公式中的函数:
作者在paper中是这么描述的:
Function re-scales the normalized coordinates to the input feature map of the l-th level.
2. 为何注意力权重可由query直接通过全连接层预测得到?
我们知道,在Transformer中,注意力权重是由query和key交互计算得到的。然而,在这里却像开挂般直接通过query经全连接层输出得到(好家伙~!),这节奏是不是不对劲呢?要分析这个问题,不妨先来看看Deformable DETR中参考点(reference points)和query之间的关系。
在Encoder中:参考点是特征点本身的位置,query embedding是特征图对应的position emebdding(其实还加上了scale-level embedding),object query则来自于特征图,最终注意力机制中的query就是object query + query embedding。
在Decoder中:2-stage时,由参考点经过位置嵌入生成query embedding和object query;而1-stage时,object query和query embedding都是预设的embedding,参考点则由query embedding经全连接层生成,最终注意力机制中的query也是object query + query embedding。
综上可知,参考点(reference points)和query之间是存在着对应关系的(就有点“你生我、我生你”的feel~)。
OK,既然这样,那么基于参考点位置采样插值出来的特征(value)自然就能够和通过query经过线性变换得到的注意力权重对应起来了,这就是为什么可变形注意力模块中不需要key与query来交互计算注意力权重了。
打个比方:A与B已建立起了对应关系,之后A再通过某种映射关系得到C,B也通过某种映射关系得到D,那么C与D之间必然会有某种程度的耦合与对应关系。这里A、B、C、D就分别指代query、reference points、attention weights以及value。
还有个问题值得思考,为何在Decoder中,2-stage时由reference points生成query embedding是通过position embedding,而1-stage时由query embedding生成reference points时却用全连接层呢?
对此,CW是这么想的:2-stage时,参考点是由Encoder预测出来的proposals,本身一定程度上代表着物体的位置信息了(虽然这个位置可能并不精确),因此有必要用位置嵌入将这“宝贵"的信息给记录下来;而1-stage时,预设的query embedding本身就是一个抽象体,盲猜的东西,因此用线性变换来做维度映射得到参考点比较合理,因为毕竟其本身并没有实际意义的位置信息。
3. 为何检测头部的回归分支预测的是偏移量而非绝对坐标值?
这个问题估计很多人会提出,为何这里不像DETR一样直接预测bbox的坐标而是预测偏移量呢?请你想想,Deformable DETR相比于DETR多了一个很显眼的东西是什么?是参考点(reference points)啊!(感觉通篇它都在秀存在感..)
采样点的位置是基于参考点和对应的坐标偏移量计算出来的,也就是说采样特征是分布在参考点附近的,既然这里需要由采样特征回归出bbox的位置,那么预测相对于参考点的偏移量就会比直接预测绝对坐标更易优化,更有利于模型学习。
Because the multi-scale deformable attention module extracts image features around the reference point, we let the detection head predict the bounding box as relative offsets w.r.t. the reference point to further reduce the optimization difficulty.
另外,由于采样特征中注入了注意力,而预测框是基于采样特征回归得到的,loss是基于回归结果计算的,梯度是通过loss反向传播的,因此最终学习到的注意力权重就会和预测框有相对较强的联系,这也起到了加速收敛的效果。
In this way, the learned decoder attention will have strong correlation with the predicted bounding boxes, which also accelerates the training convergence.
VI. 与其它方法比较
Deformable DETR是在DETR基础上提出的,因此,在这最后一部分CW打算将其与DETR作个比较;另外,CW觉得其与Sparse R-CNN也有值得比较的地方(毕竟之前在CW的这篇文章: Sparse R-CNN: 青出于蓝的R-CNN家族新晋小生,稀疏交互机制 & No RPN & No NMS = E2E 中说过Sparse R-CNN像是DETR的小弟哈哈哈)。
以下列出的点都是仅出现在 Deformable DETR 中而在 DETR / Sparse R-CNN 中是没有的。
i). vs DETR
1. 多尺度特征;
2. 新增scale-level embedding,用于区分不同特征层(由于第1点);
3. 使用了多尺度可变形注意力替代Encoder中的自注意力和Decoder中的交叉注意力;
4. 引入了参考点,某种程度上起到先验的作用;
5. 为自己开发了“高配”版:迭代的框校正策略 和 两阶段模式;
6. 检测头部的回归分支预测的是bbox偏移量而非绝对坐标值
ii). vs Sparse R-CNN
1. 没有使用FPN;
2. 使用了位置嵌入;
3. 2-stage时,proposals是predicted的(而非Sparse R-CNN直接使用learnable embedding);
4. 使用了Transformer;
5. 注意力机制是one-to-many iteraction(Sparse R-CNN由于‘Sparse’偶像包袱太重,是彻底的sparse,是one-to-one实例级别的交互);
6. 检测头部的回归分支预测的是bbox偏移量而非绝对坐标值
End
作者洞悉到DETR慢收敛和小目标检测效果差的原因在于Transformer的注意力计算模块——其对全局密集的关系进行建模,这使得模型需要长时间去学习关注真正有意义的稀疏位置,同时还带来了高复杂度的计算与空间资源消耗。
联想到稀疏空间位置的学习是DCN的强项,但同时其又缺乏关系建模能力,于是作者机智地将DCN与Transformer放在一起愉快地玩耍,最终提出 Deformable DETR。
CW认为Deformable DETR的思想和整体工作还是很值得学习的,所以就决心研究一番,也在此和大家分享了自己的思考与见解。CW在学习过程中,看过不少解析Deformable DETR的相关文章,但它们几乎要不是将论文通俗地翻译一遍就是泛泛而谈,没有一些深入的思考以及注入自己的见解,这种风格实在太无聊了些..
吾以为,既然要写,就应该写出自己的风格,更重要的是要注入自己的思想(考),提出自己的见解,甚至去怀疑(不一昧向权威低头),不然,真的很无趣耶!所以说,CW不要无聊的风格~