# DETR 中 Transformer 的过程说明 DETR(Detection Transformer)把目标检测任务改写成一个集合预测问题。它先用 CNN 提取图像特征,再把二维特征图展平成 token 序列,送入 Transformer Encoder 建模全局关系,最后用 Transformer Decoder 中的 object queries 去图像特征中查询目标。 ## 1. 整体流程 原版 DETR 的主要流程如下: ```text 输入图像 ↓ CNN Backbone,例如 ResNet ↓ 二维特征图 feature map ↓ 1x1 卷积降维到 d_model = 256 ↓ 加入二维位置编码 positional encoding ↓ Transformer Encoder ↓ Transformer Decoder + object queries ↓ 分类头 + 边界框回归头 ↓ 输出固定数量的检测结果 ``` 原版 DETR 常见配置: | 数字 | 单位 / 含义 | | --- | --- | | `256` | 特征维度,单位是“维”,也就是每个 token 或 query 向量包含 256 个数值 | | `6` | Encoder 层数,单位是“层” | | `6` | Decoder 层数,单位是“层” | | `8` | attention head 数量,单位是“个 head” | | `100` | object query 数量,单位是“个 query”,表示最多输出 100 个候选检测槽位 | ## 2. Backbone 提取图像特征 输入图像的形状通常可以写成: ```text [B, 3, H, W] ``` 其中: | 符号 / 数字 | 单位 / 含义 | | --- | --- | | `B` | batch size,单位是“张图像”,表示一次输入多少张图 | | `3` | 颜色通道数,单位是“个通道”,RGB 图像有 3 个通道 | | `H` | 图像高度,单位是“像素” | | `W` | 图像宽度,单位是“像素” | 图像经过 ResNet 这类 CNN backbone 后,会得到一个低分辨率的二维特征图。例如 stride 为 `32` 时,空间尺寸大约缩小为原图的 `1/32`: ```text [B, C, H/32, W/32] ``` 这里的 `32` 表示下采样倍数,单位可以理解为“倍”。如果输入图像高度是 `800` 像素,那么经过 stride `32` 的 backbone 后,特征图高度大约是: ```text 800 / 32 = 25 ``` 也就是 `25` 个特征图位置。 以 ResNet-50 为例,最后输出通道数常见为: ```text [B, 2048, h, w] ``` 其中: | 数字 / 符号 | 单位 / 含义 | | --- | --- | | `2048` | CNN 输出通道数,单位是“个通道” | | `h` | 特征图高度,单位是“个 feature map 网格位置” | | `w` | 特征图宽度,单位是“个 feature map 网格位置” | 然后 DETR 使用一个 `1x1` 卷积把通道数从 `2048` 降到 `256`: ```text [B, 2048, h, w] → [B, 256, h, w] ``` 这里: | 数字 | 单位 / 含义 | | --- | --- | | `1x1` | 卷积核尺寸,单位是“特征图网格”,表示卷积核覆盖 1 个高方向位置和 1 个宽方向位置 | | `2048` | 输入通道数,单位是“个通道” | | `256` | 输出特征维度,单位是“维”或“个通道”,也是 Transformer 的 `d_model` | ## 3. 把二维特征图展平成 token 序列 Transformer 处理的是序列,因此 DETR 会把二维特征图展平成一维 token 序列。 降维后的特征图形状是: ```text [B, 256, h, w] ``` 展平空间维度后: ```text [B, 256, h*w] ``` 再调整为 Transformer 常用格式: ```text [h*w, B, 256] ``` 其中: | 符号 / 数字 | 单位 / 含义 | | --- | --- | | `h*w` | token 数量,单位是“个 token”,每个 token 对应特征图上的一个空间位置 | | `B` | batch size,单位是“张图像” | | `256` | 每个 token 的向量维度,单位是“维” | 例如,如果特征图尺寸是: ```text 25 x 34 ``` 其中 `25` 是特征图高度,单位是“个网格位置”;`34` 是特征图宽度,单位也是“个网格位置”。那么 token 数量是: ```text 25 * 34 = 850 ``` 也就是 `850` 个视觉 token。 ## 4. 加入二维位置编码 Transformer 本身不知道 token 在图像中的二维位置,所以 DETR 需要加入位置编码。 图像特征 token 是: ```text src: [h*w, B, 256] ``` 位置编码是: ```text pos: [h*w, B, 256] ``` 其中 `256` 的单位是“维”,表示位置编码向量和图像 token 向量具有相同维度,方便相加。 在 attention 中,通常把位置编码加到 query 和 key 上: ```text Q = src + pos K = src + pos V = src ``` 这样 attention 在计算图像 token 之间关系时,就能利用空间位置信息。 ## 5. Transformer Encoder Encoder 的作用是让每个图像 token 都能关注整张图中的其他 token,从而获得全局上下文。 一层 Encoder 通常包含: ```text Multi-Head Self-Attention ↓ Add & Norm ↓ Feed Forward Network ↓ Add & Norm ``` 在 Encoder self-attention 中: ```text Q = 图像 token + 位置编码 K = 图像 token + 位置编码 V = 图像 token ``` 输入形状和输出形状保持一致: ```text [h*w, B, 256] → [h*w, B, 256] ``` 其中: | 符号 / 数字 | 单位 / 含义 | | --- | --- | | `h*w` | 图像 token 数量,单位是“个 token” | | `B` | batch size,单位是“张图像” | | `256` | token 特征维度,单位是“维” | 原版 DETR 使用 `6` 层 Encoder。这里的 `6` 单位是“层”,表示上述 Encoder block 重复堆叠 6 次。 ## 6. Object Queries Object query 是 DETR 的核心设计之一。 原版 DETR 默认使用: ```text num_queries = 100 ``` 也就是 `100` 个 object queries。这里的 `100` 单位是“个 query”,每个 query 可以理解为一个检测槽位。 每个 query 是一个可学习向量: ```text object_queries: [100, 256] ``` 扩展到 batch 后: ```text [100, B, 256] ``` 其中: | 数字 / 符号 | 单位 / 含义 | | --- | --- | | `100` | query 数量,单位是“个 query” | | `B` | batch size,单位是“张图像” | | `256` | 每个 query 的向量维度,单位是“维” | 可以把这 `100` 个 query 理解成 `100` 个检测槽位。每个槽位最后要么预测一个目标,要么预测 `no object`。 ## 7. Transformer Decoder Decoder 的输入包括两部分: ```text object queries: [100, B, 256] encoder memory: [h*w, B, 256] ``` 其中: | 名称 | 单位 / 含义 | | --- | --- | | `object queries` | 检测查询向量,单位是“个 query” | | `encoder memory` | Encoder 输出的图像特征 token,单位是“个 token” | 每一层 Decoder 通常包含: ```text Object Query Self-Attention ↓ Cross-Attention with Encoder Output ↓ Feed Forward Network ``` 原版 DETR 使用 `6` 层 Decoder。这里的 `6` 单位是“层”,表示 Decoder block 重复堆叠 6 次。 ## 8. Decoder Self-Attention Decoder 的 self-attention 发生在 object queries 之间。 输入形状: ```text [100, B, 256] ``` 其中 `100` 是 query 数量,单位是“个 query”;`256` 是向量维度,单位是“维”。 这一步的作用是让不同 query 之间互相交换信息,减少多个 query 重复预测同一个目标的情况。 在 Decoder self-attention 中: ```text Q = object queries K = object queries V = object queries ``` 输出形状仍然是: ```text [100, B, 256] ``` ## 9. Decoder Cross-Attention Cross-attention 是 DETR Decoder 中最关键的一步。 在 cross-attention 中: ```text Q 来自 object queries K 来自 encoder 输出的图像 token V 来自 encoder 输出的图像 token ``` 对应形状是: ```text Q: [100, B, 256] K: [h*w, B, 256] V: [h*w, B, 256] ``` 其中: | 符号 / 数字 | 单位 / 含义 | | --- | --- | | `100` | object query 数量,单位是“个 query” | | `h*w` | 图像 token 数量,单位是“个 token” | | `B` | batch size,单位是“张图像” | | `256` | Q、K、V 向量维度,单位是“维” | 每个 object query 会对整张图的所有图像 token 做 attention,从图像特征中汇聚和自己相关的信息。 输出形状仍然是: ```text [100, B, 256] ``` ## 10. Attention 中 Q、K、V 的维度 原版 DETR 的 Transformer 常见配置是: ```text d_model = 256 num_heads = 8 ``` 其中: | 数字 | 单位 / 含义 | | --- | --- | | `256` | Q、K、V 投影后的总向量维度,单位是“维” | | `8` | multi-head attention 的 head 数量,单位是“个 head” | 因此在 attention 中,Q、K、V 的总维度都是: ```text Q: 256 维 K: 256 维 V: 256 维 ``` 拆成 `8` 个 head 后,每个 head 的维度是: ```text 256 / 8 = 32 ``` 这里的 `32` 单位是“维”,表示每个 attention head 内部处理的 Q、K、V 子向量维度。 所以可以总结为: | 项目 | 数值 | 单位 / 含义 | | --- | --- | --- | | Q 总维度 | `256` | 维 | | K 总维度 | `256` | 维 | | V 总维度 | `256` | 维 | | attention head 数量 | `8` | 个 head | | 每个 head 的维度 | `32` | 维 | ## 11. 输出预测 Decoder 最终输出: ```text [100, B, 256] ``` 每个 query 对应一个候选检测结果。随后 DETR 使用两个预测头: ```text 分类头 classification head 边界框回归头 box regression head ``` 分类头输出: ```text [100, B, num_classes + 1] ``` 其中: | 符号 / 数字 | 单位 / 含义 | | --- | --- | | `100` | query 数量,单位是“个预测槽位” | | `B` | batch size,单位是“张图像” | | `num_classes` | 数据集类别数,单位是“个类别” | | `+1` | 额外的 `no object` 类,单位是“个类别” | 边界框头输出: ```text [100, B, 4] ``` 这里的 `4` 单位是“个坐标数值”,通常表示: ```text (cx, cy, w, h) ``` 含义是: | 坐标 | 单位 / 含义 | | --- | --- | | `cx` | 边界框中心点 x 坐标,通常归一化到 `[0, 1]`,单位是“相对图像宽度的比例” | | `cy` | 边界框中心点 y 坐标,通常归一化到 `[0, 1]`,单位是“相对图像高度的比例” | | `w` | 边界框宽度,通常归一化到 `[0, 1]`,单位是“相对图像宽度的比例” | | `h` | 边界框高度,通常归一化到 `[0, 1]`,单位是“相对图像高度的比例” | 例如,`w = 0.5` 表示预测框宽度约占整张图宽度的 `50%`。 ## 12. 匈牙利匹配与 no object DETR 输出固定数量的预测,例如 `100` 个预测槽位。但一张图中的真实目标数量通常远少于 `100`。 训练时,DETR 使用 Hungarian matching,也就是匈牙利匹配,把预测结果和真实目标做一对一匹配。 例如一张图有 `3` 个真实目标。这里的 `3` 单位是“个目标”。DETR 输出 `100` 个预测,其中只有 `3` 个预测会被匹配到真实目标,剩下的 `97` 个预测应该输出 `no object`: ```text 真实目标: 3 个 预测结果: 100 个 匹配到目标的预测: 3 个 no object 预测: 97 个 ``` 因为训练时强制一对一匹配,所以 DETR 推理时通常不需要 NMS。 ## 13. 完整例子 假设输入图像经过 CNN 后得到: ```text [B, 2048, 25, 34] ``` 其中: | 数字 / 符号 | 单位 / 含义 | | --- | --- | | `B` | batch size,单位是“张图像” | | `2048` | CNN 输出通道数,单位是“个通道” | | `25` | 特征图高度,单位是“个网格位置” | | `34` | 特征图宽度,单位是“个网格位置” | 经过 `1x1` 卷积降维: ```text [B, 2048, 25, 34] → [B, 256, 25, 34] ``` 展平成 token 序列: ```text [25*34, B, 256] = [850, B, 256] ``` 其中 `850` 的单位是“个图像 token”。 送入 Encoder: ```text Encoder input: [850, B, 256] Encoder output: [850, B, 256] ``` 准备 object queries: ```text [100, B, 256] ``` 送入 Decoder: ```text Decoder query: [100, B, 256] Encoder memory: [850, B, 256] Decoder output: [100, B, 256] ``` 最后输出: ```text class logits: [100, B, num_classes + 1] boxes: [100, B, 4] ``` ## 14. 总结 DETR Transformer 的核心过程可以概括为: ```text CNN 把图像变成二维特征图 二维特征图被展平成图像 token 序列 Encoder 让所有图像 token 建立全局关系 Decoder 用 100 个 object queries 去图像 token 中查询目标 每个 query 输出一个类别和一个边界框 ``` 一句话总结: DETR 先把图像变成一串 `256` 维的视觉 token,Encoder 负责理解整张图,Decoder 使用 `100` 个 `256` 维 object queries 从图像特征中查询目标,最终每个 query 预测一个类别和一个由 `4` 个归一化坐标数值组成的边界框。