DERT模型:简单粗暴,开创先河

先是通过 backbone(resnet50)提取到特征图

通过1*1卷基调整通道数之后

然后加上位置编码

将每一个通道展平,组合成一个大的二维矩阵

这时候每一个toke就对应了backbone最后一层特征图的不同区域

输出就是一个二维矩阵


接下来的 encoder(6 层)

encoder的主要使命其实就是通过多头注意力

来提取到不同token之间的关系,融合全局上下文

encoder_block = 多头注意力机制+前馈网络

encoder_block 输入和输出的大小是一样的

因为自注意力机制中的矩阵点积和矩阵乘法只要两个矩阵都是大小相同的方阵结果的大小就不变


接下来的 decoder

decoder 的输入:

  • object queries 目标查询向量
  • encoder 的输出(key/value)

decoder 的单层结构(decoder block)

  • (可选)self-attention。QKV 都是来自于 encoder 的输出。这里的self-attention的主要作用是在一次让通道与通道之间相互关联,减少重复预测

  • cross-attention 交叉注意力(核心)。

    • Q 在最开始的第一层是随机初始化的,后面会不断学习。除了第一层之外,其他Decoder的Q都来自上一个Decoder的输出。每一层的 cross attention,都是一次“查询-响应”的过程,让每个 Q 从整张图中进一步收集和融合与自己目标相关的信息。
    • K 和 Q 一直都是 encoder 的输出经过一层 fc。为什么要经过一层 fc?为了支持多头交叉注意力机制。
    • 源码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    class TransformerDecoderLayer(nn.Module):
    def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1):
    super().__init__()
    # 多头注意力
    self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
    self.multihead_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)

    # 前馈网络
    self.linear1 = nn.Linear(d_model, dim_feedforward)
    self.dropout = nn.Dropout(dropout)
    self.linear2 = nn.Linear(dim_feedforward, d_model)

    # 层归一化和残差
    self.norm1 = nn.LayerNorm(d_model)
    self.norm2 = nn.LayerNorm(d_model)
    self.norm3 = nn.LayerNorm(d_model)
    self.dropout1 = nn.Dropout(dropout)
    self.dropout2 = nn.Dropout(dropout)
    self.dropout3 = nn.Dropout(dropout)

    def forward(self, tgt, memory, tgt_mask=None, memory_mask=None,
    tgt_key_padding_mask=None, memory_key_padding_mask=None):
    # tgt: object queries 的当前表示 (Q)
    # memory: encoder 的输出 (K, V)

    # Step 1: 自注意力(object queries 之间)
    q = k = tgt
    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)

    # Step 2: 交叉注意力(object queries attends to encoder output)
    tgt2 = self.multihead_attn(query=tgt, key=memory, value=memory,
    attn_mask=memory_mask,
    key_padding_mask=memory_key_padding_mask)[0]
    tgt = tgt + self.dropout2(tgt2)
    tgt = self.norm2(tgt)

    # Step 3: FFN + 残差 + LN
    tgt2 = self.linear2(self.dropout(F.relu(self.linear1(tgt))))
    tgt = tgt + self.dropout3(tgt2)
    tgt = self.norm3(tgt)

    return tgt


接下里是两个线性层

一个线性层是用来分类的

一个线性层是用来预测框位置的

如何用线性层来实现对框的位置的预测:

b=sigmoid(FFN(f)+[s⊤ 0 0])b=sigmoid(FFN(f)+[s⊤ 0 0]⊤)

其中,b 是一个四维向量,也即是我们的框:

image.png


损失函数

DETR(Detection Transformer)的损失函数采用两阶段设计,结合了匈牙利匹配算法(Hungarian Matching)和目标特定的回归与分类损失,实现端到端的训练。其核心结构如下:

DETR的损失函数分为两步:

  1. 匈牙利匹配(二分图匹配):为每个真实目标分配唯一的预测框,避免冗余预测。
  2. 损失计算:基于匹配结果计算分类损失与边界框回归损失。

数学表达式为:

LHungarian(y,y^)=i=1N[logp^σ^(i)(ci)+1{ci}Lbox(bi,b^σ^(i))]\mathcal{L}_{\text{Hungarian}}(y, \hat{y}) = \sum_{i=1}^{N} \left[ -\log \hat{p}_{\hat{\sigma}(i)}(c_i) + \mathbb{1}_{\{c_i \neq \varnothing\}} \mathcal{L}_{\text{box}}(b_i, \hat{b}_{\hat{\sigma}}(i)) \right]

其中 σ^\hat{\sigma} 是最优匹配索引,cic_i 是类别标签,bib_i 是边界框坐标。


Donate
  • Copyrights © 2015-2025 Xinyu Zhuang
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信