ECCV2020-DETR-End to End Object Detection with Transformers
arxiv
[打开本地pdf](eccv2020-DETR-End to End Object Detection with Transformers.pdf)
github仓库
DETR的卖点是End-to-End, 它没有复杂的后处理,把目标检测问题当作集合预测问题,直接输出框(只是转换cxcywh和乘宽高)。大致的流程为
cnn抽取特征
把特征送入transformer encoder-decoder, 输出N(本文N=100)个预测
训练时把这N个预测和gt做二分图匹配,匹配上的"预测-gt对",计算loss
如输入是3x800x1066的图片,经过cnn backbone后,输出2048x25x34的图像特征, 宽高降采样为1/8
backbone = nn.Sequential(
*list(resnet50(pretrained=True).children())[:-2])
x = backbone(inputs) # bx2048x25x34
transformer = nn.Transformer(256, 8, 6, 6)
conv = nn.Conv2d(2048, 256, 1)
h = conv(x) # bx256x25x34
row_embed = nn.Parameter(torch.rand(25, 256 // 2))
col_embed = nn.Parameter(torch.rand(34, 256 // 2))
pos = torch.cat([
col_embed.unsqueeze(0).repeat(25, 1, 1), # bx25x34x128
row_embed.unsqueeze(1).repeat(1, 34, 1) # bx25x34x128
], dim=-1) # bx25x34x256
pos = pos.flatten(0, 1).unsqueeze(1) # 850x1x256
h = h.flatten(2).permute(2, 0, 1) # 850xbx256
encoder_input = pos + h # 850xbx256
object_query = nn.Parameter(torch.rand(100, 256)) # 100x256
object_query = object_query.unsqueeze(1) # 100x1x256
tout = transformer(encoder_input, object_query) # 100xbx256
linear_class = nn.Linear(256, 91)
linear_bbox = nn.Linear(256, 4)
logits = linear_class(tout) # 100xbx91
bboxes = linear_bbox(tout) # 100xbx4
DETR使用scipy.optimize.linear_sum_assignment来做预测和gt的匹配,它的输入是cost matrix,对于一张图就是100xnum_gt的矩阵,i行j列的值为第i个预测与第j个gt的loss, 它返回的是一组匹配的索引,这组匹配的总loss是所有可能的匹配中最小的。
在这之前需要计算每个预测和每个gt的loss,它包含
为了好收敛吧,它在每层decoder的输出都算了loss, 辅助loss是一种常见的trick。
它最好的DETR-DC5-R101的AP=44.9,不如当时最好的检测网络(coco ap=58 huawei 2020-06-11), 他达到了detectron2中 Faster RCNN的水平,下表第一组是detectron中 Faster RCNN,第二组是使用了和DETR一样的训练策略,loss的Faster RCNN. 最后一组为DETR. 注意DETR-DC5-R101和Faster RCNN-R101-FPN+, 参数量相同,gflops相近,但是fps却只有faster rcnn一半,说明相同参数量和计算量下是比faster rcnn慢的。也说明参数量,gflops和速度fps没有直接的关系。DETR和第二栏的faster rcnn+比较,APL要高6个点,APS要低4个点,说明DETR对小物体表现差,对大物体表现好,毕竟没有加FPN之类的结构,也没有针对小物体做针对处理。
它对encoder的层数做了消融实验,层数越多,精度越高
对decoder的层数也做了实验,decoder层数越多,就越接近使用nms的性能
他们可视化了encoder中的自注意力,就是选择下图中4个参考点,并绘制出整图各位置和参考点的自注意力(应该是softmax(qk)),自注意力高的位置接近牛的分割mask了,他想说明encoder的自注意力学到了目标物的区域。
还可视化了decoder中object_query的注意力,表明decoder更关注物体的边缘区域。
下面这个消融实验非常有意思,spatial pos表示encoder部分的位置编码,output pos其实是object_query, 就是那100个query, 这是必须要使用的. encoder中spatial pos加在qk上,decoder中加在k上,output pos加在decoder的q上。
sine表示使用sin cos的位置编码
learned表示使用位置序号乘以可学习的weight作为位置编码
at input表示只加在输入上 (标准的transfomer)
at attn表示加在输入和encoder或decoder所有中间层上
none表示不使用位置编码
不使用spatial pos也有32的ap, 使用了spatial pos有明显提升(AP32->39), 最好的结果来自于每层都加位置编码,比标准的transformer(只加在输入)好1.4(AP39.2->40.6), spatial pos用sine at attn比用learned at attn好1.0(AP39.6->40.6)
在loss中,giou loss的提升最大, 下表AP35.8->39.9
DETR给了一份可读性很高的伪代码,很好滴帮助理解detr,前面的详细步骤也是照这个伪代码改的。过去也有人用集合预测做过目标检测,但是不work,detr 能work的主要原因还是在transfomer上. DETR给端到端的目标检测做了一个很好的示范。