DETR(Detection with transformer)
DETR:End to End Object Detection with Transformer
论文链接:2005.12872 (arxiv.org)
参考视频:https://www.bilibili.com/video/BV1GB4y1X72R/?spm_id_from=333.788&vd_source=cdb0bc0dda1dccea0b8dc91485ef3e74
前言
2020年,Facebook使用Transformer进行目标检测。全新的架构,目标检测里程碑式工作。
之前目标检测中不论proposal based的方法还是anchor based 的方法,都需要nms(非极大值抑制)等候处理的方法筛选bbox(bounding box)。由于nms的操作,调参比较复杂,而且模型部署起来也比较困难。因此,一个端到端的目标检测模型是一直以来所追求的。
DERT很好的解决了上述问题,不需要proposal和anchors,利用Transformer全局建模的能力,把目标检测看成集合预测的问题。而且由于全局建模的能力,DETR不会输出太多冗余的边界框,输出直接对应最后bbox,不需要nms进行后处理,大大简化了模型。
摘要
将目标检测看作集合预测任务,不需要nms处理和生成anchor。DETR提出两个东西,一是目标函数,通过二分图匹配的方式,使得模型输出独一无二的预测,就是说没有那么多冗余的框了。二是,使用Transformer的编码器解码器架构。具体还有两个小细节,一个是解码器这边还有另外一个输入,learned object query,类似于anchors,DETR可以将learned object query和全局图像信息结合起来,通过不停的做注意力操作,从而使得模型直接输出最后的预测框。二是并行的方式,与2017Transformer用在NLP领域使用掩码解码器(自回归方式:一个单词一个单词翻译)不同,这里视觉任务中,图像中目标没有依赖关系。另一方面也是希望越快越好。DETR最主要的优点就是非常简单,性能也不错,在COCO数据集可以和Faster RCNN基线网络打平。另外,DETR可以非常简单的拓展到其他任务上,例如全景分割。
1.介绍
目标检测任务是对于每个这个感兴趣的物体区预测出框和物体类别,实际上就是集合预测问题,但是现在都是用间接的方式去处理集合预测的问题。例如proposal的方式,Faster R-CNN、Mask R-CNN、Cascade R-CNN。anchors方式,YOLO、Focal loss。还有no anchor based 的方法,用物体中心点(window centers)Center Net、FCOS。这些都没有直接去做这个几何预测的任务,而是设计了一个替代的,要么是回归要么是分类的任务去解决目标检测问题。但是其性能很大程度上受限于后处理这部操作,即NMS操作,因为这些方法都会生成冗余框,所以需要使用nms。
为简化这些管道,本文提出一种直接集预测方法来绕过代理任务。这种端到端哲学导致了复杂结构化预测任务(如机器翻译或语音识别)的重大进展,但在目标检测方面还没有:以前的尝试要么添加了其他形式的先验知识,要么没有被证明与具有挑战性的冷基准的强大基线具有竞争力。本文旨在弥合这一差距。
不需要很多先验知识,就是端到端得出结果
DETR训练过程:
第一步用CNN抽特征。
第二步用Transformer编码器(encoder)去学全局特征,为了解码器(decoder)出预测框做铺垫。
- 为什么使用transformer encoder
- 如果使用了它,那么每一个点或者每一个特征就和图片里其他的特征都会有交互,因此它大概就知道哪里是该物体,哪里是另一个物体。对同一个物体来说,就应该只出一个框,而不是出好多框。所以这种全局的特征非常有利于移除这种冗余的框。
第三步,结合learned object query用Transformer解码器生成很多预测框。(有了图像的特征之后,会有一个object query,这个Object query就是限定了要出多少个框,然后通过query和这个特征不停地做交互,在decoder里做自注意力操作,从而得到了最后的输出的框,论文里选择的框数=100)
第四步,将预测框与GT框做匹配,在匹配上的框里做目标检测的loss。(100个框如何与Ground truth框做匹配算loss,作者把该问题看成了一个集合预测的问题,最后就能用这种二分图匹配的方法去算loss)
DETR推理过程:
第一步:用CNN抽特征。
第二步:用Transformer编码器去学全局特征,帮助后边做检测。
第三步:结合learned object query用Transformer解码器生成很多预测框。
第四步:置信度大于0.7的作为前景物体保留,其余作为背景。
性能方面,在COCO数据集上,能和Faster RCNN打成平手,不论是AP还是模型规模和速度上。DETR对大物体检测效果比较好,不受限于生成anchor 的大小。但DETR在小物体上效果就差一点,但是作者很乐观,接下来会有跟进工作解决小物体检测问题。另一方面是DETR训练比较慢,作者训练了500个epoch,一般只需十几个epoch。
FPN对Faster RCNN通过使用多尺度多特征能够提升小物体的检测
不到半年Deformable DETR出现,不仅很好的通过这种多尺度的特征解决了小物体的问题同时也解决了DETR训练太慢的问题。
DETR对全景分割、目标追踪、视频里的姿态预测、视频里的语义分割等等各种任务。
2.相关工作
2.1 集合预测 set prediction
2.2 Transformer Decoder 并行
2.3 目标检测研究现状
现在研究都是基于初始预测进行检测,two stage 的方法基于proposal,signal stage的方法基于anchors(物体中心点)。最近的一篇论文做了一个详细的比较,之前的这些方法他们的性能与刚开始的初试的猜测非常相关,所以如何进行后处理得到最后的预测对最后的性能的影响是至关重要的。所以作者从两个方面阐述这件事情。
-
proposal和 anchors的联系:当anchor生成以后就要生成最终的Proposal了。首先对anchor有两部分的操作:分类和边框回归。分类通过softmax进行二分类,将anchor分为前景和背景,分别对应positive和negative。边框回归获取anchor针对ground true的偏移。得到这两个信息后开始选取符合条件的anchor作为Proposal。
第一步:先将前景的anchor按照softmax得到的score进行排序,然后按设定值取前N个positive anchor;
第二步:利用im_info中保存的信息,将选出的anchor由M×N的尺度还原回P×Q的尺度,刨除超出边界的anchor;
第三步:执行NMS(nonmaximum suppression,非极大值抑制);
第四步:将NMS的结果再次按照softmax的score进行排序,取N个anchor作为最终的Proposal;
1.set-based loss(集合的思想)
之前的工作有这种思想的:可以学习的NMS方法、关系型的网络,它们都可以利用类似于注意力的方法去处理物体之间的联系,从而最后能得出独一无二的预测,这样就不需要任何后处理的步骤了。但是这种算法的性能往往比较低,为了与当时比较好的方法性能对齐,这些方法往往加了人工干预,例如用手工设计的场景特征去帮助模型进行学习。但是DETR的目标是想让这个目标检测做的尽可能简单,所以他不希望这个过程特别复杂,也不希望用到过多的这种人工先验的知识。
2.recurrent detectors
与我们的方法最接近的是对目标检测[43]和实例分割的端到端集合预测[41,30,36,42]。与我们类似,他们使用基于cnn激活的编码器-解码器架构的二部匹配损失来直接产生一组边界框。然而,这些方法只在小型数据集上进行了评估,而没有针对现代基线进行评估。特别是,它们基于自回归模型(更准确地说,是rnn),因此它们没有利用最近的transformer进行并行解码。
3.DETR方法部分
3.1 目标检测集合预测的目标函数
DETR最后的输出是一个固定的集合,不论图片是什么,最后都会输出n个输出,这篇论文n=100,如何匹配预测框和ground truth的bounding box,如何算Loss,如何知道哪个预测框对应那个Ground truth框。所以作者将其转化成了一个二分图匹配的问题。
匈牙利算法主要用于解决任务分配问题,即如何将一组任务分配给一组工人,使得总成本最小化。这个问题可以形式化为一个二分图的最大匹配问题,其中每个工人和每项任务是二分图的两个顶点集合,工人与任务之间的成本构成了边的权重。
匈牙利算法解决二分图匹配问题。Scipy中有linear-sum-assignment函数,输入为cost matrix,输出为最优的方案。
目标检测的损失由两部分组成,一是分类的loss(分类类别对不对),二是目标检测框的准确度。(遍历所有的预测框,那这些预测的框与ground truth的框去算这两个loss,将这个loss放到cost matrix)。
这里找最优匹配的方式和原来利用先验知识去把预测和proposal和anchors匹配的方式一样,只不过这里的约束更强,一定要得到一个一对一的匹配关系,后续就不需要nms处理。
一旦得到了最佳匹配,即知道生成的100个框中哪个与gt是最优匹配的框,就可以进一步与GT框计算损失函数,然后做梯度回传。
作者在这里发现第一部分分类loss去掉log对数,可以使得前后两个损失在大致的取值空间。第二部分边界框回归损失,不仅使用了L1-loss(与边界框有关,大框大loss),还使用了generalize iou loss(跟框大小无关的一个目标函数)。
3.2 DETR模型架构
第一步,输入3×800×1066,经过CNN得到2048×25×34,然后经过1×1的卷积降维得到256×25×34的特征图,加入位置编码后拉长得到850×256(序列长度850,嵌入维度256)。
第二步进入Transformer encoder得到850×256的输出(可以理解为做了全局信息的编码)。
第三步Transformer decoder的输入为可学习的object queries100×256(100个框256维度)+ encoder得到的全局特征是850×256。反复做自注意力操作,最后得到100*256的特征。encoder和decoder都是6层。decoder每层的输入输出都是100×256保持不变。
- 补充材料里说明:在decoder里都会先做一次object query的自注意力操作。但是在第一层的decoder里是可以不做,可以省掉,但是后面那些层都不能省掉。目的:移除冗余框。因为它们互相通信之后就知道每个query可能得到什么样的框,尽量不要去做重复的框。
- 在最后算loss的时候,为了让模型收敛的更快或者训练的更稳定,在这个decoder后面加了很多auxiliary loss,也就是加了很多额外的目标函数。这是一个很常见的trick,分割里经常使用。
第四步通过FFN也就是全连接层,每个框得到6个输出分别对应前景背景概率,框的边界信息(对角线两个坐标。)然后使用匈牙利算法计算最匹配的框,然后根据GT计算梯度,反向回传更新模型。
import torch
from torch import nn
from torchvision.models import resnet50class DETR(nn.Module):def __init__(self, num_classed, hidden_dim, nheads,num_encoder_layers,num_decoder_layers):super().__init__()# we take only convolutional layers from ResNet-50 modelself.backbone = nn.Sequential(*list(resnet50(pretrained=True).children())[:-2])# 投射层,将2048--->256self.conv = nn.Conv2d(2048, hidden_dim, 1)self.transformer = nn.Transformer(hidden_dim, nheads,num_encoder_layers, num_decoder_layers)# 一个FFN做类别的预测self.linear_class = nn.Linear(hidden_dim, num_classed + 1)# 一个FFN做框的预测self.linear_bboc = nn.Linear(hidden_dim, 4)# query objectself.query_pos = nn.Parameter(torch.rand(100, hidden_dim))# row_embedding和col_embedding是最开始与卷积神经网络的特征加在一起的固定的embeddingself.row_embed = nn.Parameter(torch.rand(50, hidden_dim // 2))self.col_embed = nn.Parameter(torch.rand(50, hidden_dim // 2))def forward(self, inputs):x = self.backbone(inputs)h = self.conv(x)H, W = h.shape[-2:]# 位置信息编码pos = torch.cat([self.col_embed[:W].unsqueeze(0).repeat(H, 1, 1),self.row_embed[:H].unsqueeze(1).repeat(1, W, 1),], dim=-1).flatten(0, 1).unsqueeze(1)# flatten 将h拉直变成850*256的特征# transformer两个输入,前者是从图像得出的全局特征输入,后者是object query输入h = self.transformer(pos + h.flatten(2).permute(2, 0, 1),self.query_pos.unsqueeze(1))return self.linear_class(h), self.linear_bbox(h).sigmod()deter = DETR(num_classed=91, hidden_dim=256, nheads=8, num_encoder_layers=6, num_decoder_layers=6)
deter.eval()
inputs = torch.randn(1, 3, 800, 1200)
logits, bboxes = detr(inputs)
4.实验部分
4.1性能对比
gflops代表模型大小,FPS代表推理速度。虽然DETR的GFLOPS和参数量相对于Faster RCNN较少,但是推理速度还是稍微慢一点。对于小物体,Faster -RCNN比DETR要高4个点左右,但是对于大物体,DRTE要比Faster-RCNN高出6个点左右。作者认为DETR没有anchors尺寸的限制,并且使用的Transformer具有全局建模能力,对大物体比较友好。(APs小物体,AP_L大物体)
4.2 可视化
作者将transformer里的encoder即编码器的注意力可视化出来了,每个物体选一个点计算自注意力。我们可以发现,经过Transformer Encoder后每个物体都可以很好的区分开来了,这时候再去做目标检测或者分割任务就简单很多了。
不同深度的Transformer层对模型性能的影响。模型越深效果越好,并且没有明显的饱和的倾向。
4.3 Transformer解码器
把每个物体的自注意力用不同的颜色表示出来
对于小象和大象存在较大的重叠部分,大象用蓝色表示,大象的蹄子部分以及尾巴部分都是蓝色的标记。小象背部黄色的标记。这都说明解码器能够将两个目标各自的部分区分开来。另外就是斑马的条纹,DETR依然能够区分出每个斑马的轮廓并学到各个目标的条纹。
DETR的encoder是学一个全局的特征,让物体之间尽可能分得开。但是对于轮廓点这些细节(例如头尾巴这些极值点)就需要decoder去做,decoder可以很好的处理遮挡问题。
4.4 object query可视化
作者将COCO数据集上得到的所有输出框全都可视化出来。作者将100个object query中20个拿出来,每个正方形代表一个object query。每个object query相当于一个问问题的人,绿色代表小的检测框(bounding box),红色代表横向大的检测框(bounding box),蓝色代表竖向的大的检测框。
其实object query与anchor有点像,anchor是提前定义好一些bounding box,然后最后将预测的结果与这些提前定义好的bounding box做对比。object query是一个可以学习的东西,例如每次给它一个图片,第一个object query会不断查询左下角是否有小的目标,中间是否有大的横向的目标。当经过100个不同object query查询完成后,目标也就检测完成了。
5.结论
DETR在COCO数据集上与Faster R-CNN基线模型打成平手,并且在分割任务上取得更好的结果。最主要的优势是简单,可以有很大的潜能应用在别的任务上。作者又强调了一下,DETR在大物体上效果非常好(原因:自注意力带来的全局信息)。文章存在的缺点作者也自己指出:推理时间有点长、由于使用了Transformer不好优化、小物体上性能也差一些。后来,Deformable DETR解决了推理时间和小物体检测差的不足。
后续工作:omni-DETR;up-DETR;PnP-DETR;SMAC-DETR;Deformer-DETR;DAB-DETR;SAM-DETR;DN-DETR;OW-DETR;OV-DETR
DETR使用object query代替了原来生成anchors的方式,运用二分图匹配代替了nms这一步,将很多不可学习的东西变得可以学习了,从而得到了一个简单有效的端到端的网络,也因为其使用了transformer,所以后续在它上面做这种多模态的工作也多了很多,也在它的推动之下,后续还有pixel to sequence这篇论文将输入输出全部搞成序列的形式,从而能和NLP那边完美兼容。