update at 2026-06-08 13:38:23
This commit is contained in:
522
detr_transformer_process.md
Normal file
522
detr_transformer_process.md
Normal file
@@ -0,0 +1,522 @@
|
||||
# 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` 个归一化坐标数值组成的边界框。
|
||||
Reference in New Issue
Block a user