目标检测:DETR详解

  • 前言
  • DETR
  • Backbone
  • Encoder
  • Decoder
  • 实验


前言

目标检测当中分类错误 目标检测detr_深度学习

DETR是第一篇将Transformer应用到目标检测方向的算法。DETR是一个经典的Encoder-Decoder结构的算法,它的骨干网络是一个卷积网络,Encoder和Decoder则是两个基于Transformer的结构。DETR的输出层则是一个MLP。

它使用了一个基于二部图匹配(bipartite matching)的损失函数,这个二部图是基于ground truth和预测的bounding box进行匹配的。

最终性能与Faster-RCNN持平。

DETR

目标检测当中分类错误 目标检测detr_目标检测_02

Backbone

当我们利用卷积神经网络时,会有两个假设:

平移不变性:kernel 的参数在图像任何地方时一致的。
局部性: 要找某一个特征只需要在一个区域的周围检索,不需要全局观察。

而detr则是从0开始学起的,所以它的backbone采用经典的ResNet101网络对图像提取特征,为下面的Encoder获取先验知识。
流程如下:

  1. 假设我的图像输入为:3 * 800 * 1066 (CHW)。
  2. 通过CNN提取特征后,得到了 2058 * 25 * 34的feature map。
  3. 为了减少计算量,下采样feature得到 256 * 25 * 34。

Encoder

在这里需要把 数据转化为序列化数据,直接把hw合并,维度转化为 256 * 850.

在这里作者采用二维sin、cos的位置编码(通过实验各位置编码方法结果相差不大),具体公式本文不在展示。

Detr与Transformer相比,后者是直接在Encoder之前做 position encoder,然后在生成 qkv,然而Detr则是只对 key 与 query 编码。我认为key query 是负责取检索特征计算注意力分数,而value只负责提供对应位置的值,从而不需要位置编码。

把位置编码与feature结合的方式主要是add操作,所以我们要把位置编码的维度与feature的维度一致。其中我们的编码方式是根据feature的x、y两个方向的编码。
流程图下:

由于相应的feature map 的 H * W 为 25 * 34

  1. 在H方向上为每个对应点赋予 128 * 25 * 34
  2. 在W方向上为每个对应点赋予128 * 25 * 34
  3. add 成 256 * 25 * 34
  4. 与feature map add
  5. 把数据转化为序列化数据
  6. 用 没有position的feature生成 V,有的生成KQ,执行attention
  7. 通过Encoder后,feature map 与input一致,还是 256 * 850

Decoder

目标检测当中分类错误 目标检测detr_目标检测当中分类错误_03

这里的Decoder的输入有两个:

  1. Encoder的输出
  2. object queries

首先我们说一下object queries,在代码中,它的本质实际就是一个 learnable Embedding position。这里假设 初始化100(远远大于 num_classes)个object queries,每个的维度为256(方便与encoder输出矩阵乘法),所以它的维度为 256 * 100.


这里说个番外~,为什么object queries是一个 learnable position Embedding 呢?,我们知道,初始化要先通过一个Embedding层后才能输入后面的注意力层,而这个embedding层我们可以把它理解为全连接层,权重矩阵为w,这里的w是就是代码中用来学习object query的“learnable position embedding”,代码如下:

self.query_embed = nn.Embedding(num_queries, hidden_dim)

decoder 源码:
其中 tgt 就是实质上的 object query(全0初始化), 而之前所指的 learnable position embedding 是tgt的embedding权重,它是可学习的,tgt通过learnable position embedding 编码得到真正的 object query用来 在后面的cross attention 与encoder 中的 v、k 计算attention 。

class TransformerDecoderLayer(nn.Module):
    def forward_post(self, tgt, memory,
                     tgt_mask: Optional[Tensor] = None,
                     memory_mask: Optional[Tensor] = None,
                     tgt_key_padding_mask: Optional[Tensor] = None,
                     memory_key_padding_mask: Optional[Tensor] = None,
                     pos: Optional[Tensor] = None,
                     query_pos: Optional[Tensor] = None):
        q = k = self.with_pos_embed(tgt, query_pos)
        tgt2 = self.self_attn(q, k, value=tgt, attn_mask=tgt_mask,
                              key_padding_mask=tgt_key_padding_mask)[0]
        tgt = tgt + self.dropout1(tgt2)
        tgt = self.norm1(tgt)
        tgt2 = self.multihead_attn(query=self.with_pos_embed(tgt, query_pos),
                                   key=self.with_pos_embed(memory, pos),
                                   value=memory, attn_mask=memory_mask,
                                   key_padding_mask=memory_key_padding_mask)[0]
        tgt = tgt + self.dropout2(tgt2)
        tgt = self.norm2(tgt)
        tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt))))
        tgt = tgt + self.dropout3(tgt2)
        tgt = self.norm3(tgt)
        return tgt

模型通过学习会把它图像分成100个区域,每个queries负责关注特定的区域。到这里你会发现:Object queries充当的其实是位置编码的作用。


通过embedding后,把它传输给multi-head self-attention层,然后这里与传统的Transformer不同,这里是直接输出所有的prediction,而 Transformer采取的是 自回归的方式从左到右依次输出。

到了每个Decoder的第2个multi-head self-attention,它的Key和Value来自Encoder的输出张量 ,其中Key值还进行位置编码。Query值一部分来自第1个Add and Norm的输出,另一部分来自Object queries,充当可学习的位置编码。

实验

目标检测当中分类错误 目标检测detr_计算机视觉_04