Files
tokenresearch/detr_transformer_process.md
2026-06-08 13:38:23 +08:00

523 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# DETR 中 Transformer 的过程说明
DETRDetection 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` 维的视觉 tokenEncoder 负责理解整张图Decoder 使用 `100``256` 维 object queries 从图像特征中查询目标,最终每个 query 预测一个类别和一个由 `4` 个归一化坐标数值组成的边界框。