前言
2017 年,Google 发表**《Attention Is All You Need》**,Transformer 横空出世,彻底颠覆了自然语言处理领域。短短几年间,它一路 "破圈",成为计算机视觉、自动驾驶感知、BEV 建模、矢量化高精地图构建的绝对核心支柱。
无论你是在研究 MapTR、MapTRv2,还是正在复现最新的 CAFMap,都会发现一个共性:整个模型的灵魂,就是 Transformer。
一、Transformer 核心基础
1. 起源与核心思想
在 Transformer 出现之前,序列建模的主流是 RNN/LSTM。但它们有一个致命缺陷:必须按顺序逐个处理元素,无法并行计算。处理长序列时,不仅速度极慢,还会丢失早期的信息。
Transformer 的核心突破,就是用自注意力机制替代了循环结构:
让序列中的任意两个元素,都能直接建立联系,一步捕获长程依赖。
这意味着,无论序列多长,计算复杂度都是 O (N²),且可以完全并行化,训练和推理速度得到了数量级的提升。
2. 整体架构:编码器 - 解码器
Transformer 采用经典的 "编码器 - 解码器" 架构,这也是所有后续变体(包括你用的 MapQR)的基础:
输入序列 → 位置编码 → 编码器(N层堆叠) → 全局记忆特征 → 解码器(N层堆叠) → 输出序列
- 编码器:负责处理输入数据,提取全局上下文特征,输出一个 "全局记忆"
- 解码器:结合编码器输出的全局记忆,逐步生成最终结果
- 位置编码:注意力机制本身不感知元素的顺序,必须额外注入位置信息,否则模型会把 "ABC" 和 "CBA" 当成同一个序列
二、最核心:自注意力机制(Self-Attention)
自注意力是 Transformer 的灵魂,所有的魔法都来自这里。
1. 一句话通俗解释
让序列中的每个元素,都去 "看" 其他所有元素,根据它们的重要程度打分,然后加权求和,更新自己的特征。
2. 计算步骤(极简版,对应代码)
假设输入是一个序列特征 X,形状为 [N, C](N 是元素个数,C 是特征维度):
步骤 1:生成 Q/K/V
用三个独立的线性层,把输入 X 转换成三个不同的向量:
- Query(查询):我要找什么
- Key(键):我有什么
- Value(值):我能提供什么
python
Q = X @ W_q # [N, C]
K = X @ W_k # [N, C]
V = X @ W_v # [N, C]
X:输入序列特征,形状[N, C]- 在 BEV 编码器 里,
X是展平后的 BEV 特征:[40000, 256](40000=200×200 个 BEV 格子) - 在你的 MapQR 解码器自注意力 里,
X是实例查询:[900, 256](900 个待预测的地图元素)
- 在 BEV 编码器 里,
@:PyTorch 中的矩阵乘法操作符W_q,W_k,W_v:三个可学习的权重矩阵,形状都是[C, C]- 它们的作用是把输入
X"变换" 成三个不同的向量:Query、Key、Value
- 它们的作用是把输入
步骤2:计算注意力权重
Query 和 Key 做点积,得到每个元素对其他元素的相似度,再用 Softmax 归一化,得到 0-1 之间的权重:
Attention_Weight = Softmax(Q @ K.T / sqrt(d_k)) # [N, N]
K.T:Key 矩阵的转置 ,把形状从[N, C]变成[C, N]Q @ K.T:Query 和 Key 做矩阵乘法 ,得到形状[N, N]- 这个矩阵里的每个元素
(i, j),表示 "第 i 个元素对第 j 个元素的相似度"
- 这个矩阵里的每个元素
sqrt(d_k):缩放因子 ,d_k是特征维度C(比如 256)- 为什么要除以它?因为如果 Q 和 K 的维度很大,点积结果会非常大,导致 Softmax 之后梯度消失(几乎全是 0 或 1)
- 除以
sqrt(d_k)可以把点积结果 "拉回" 到一个合理的范围
Softmax(...):Softmax 归一化函数- 把相似度矩阵变成注意力权重矩阵 ,每个元素都在 0 到 1 之间,且每一行的和为 1
- 这样,每个元素对其他元素的 "重要程度" 就变成了概率分布
- Softmax实际就是把任意一组实数,转换成0到1之间、且和为1的概率分布
步骤 3:加权求和
用注意力权重对 Value 加权求和,得到最终的输出特征:
Output = Attention_Weight @ V # [N, C]
Attention_Weight @ V:用注意力权重对 Value 做加权求和- 每个元素的输出,都是 "所有元素的 Value 乘以对应的注意力权重,再加起来"
- 这样,每个元素都能 "博采众长",融合整个序列的信息
Output:最终的输出特征,形状和输入X一样,都是[N, C]
3. 多头注意力(Multi-Head Attention)
单个注意力头只能学习一种模式,多头注意力把 Q/K/V 分成多个独立的 "头",每个头学习不同的注意力模式,最后再拼接起来。
比如在你的 MapQR 中,8 个注意力头可能分别关注:
- 头 1:车道线的方向
- 头 2:道路的连接关系
- 头 3:路口的局部细节
- 头 4:整个道路网络的全局布局
这样,模型就能同时捕捉到不同尺度、不同类型的信息。
三、(结合个人项目)Transformer 在 MapQR/CAFMap 项目中的 3 个关键应用
1. BEV 编码器中的 Transformer
位置 :GKT 视图转换之后,解码器之前代码对应 :projects/mmdet3d_plugin/models/bev_encoder.py输入 :200×200 的 BEV 特征图(展平成 40000 个元素的序列)输出:增强后的 BEV 全局特征
作用 :CNN 只能捕获 3×3、5×5 这样的局部邻域信息,无法让 BEV 图左上角的格子 "看到" 右下角的格子。而 Transformer 的自注意力机制,可以让任意两个 BEV 格子直接建立联系,从而理解整个道路网络的全局布局,比如 "这条直路在 50 米后会左转"。
2. MapQR 解码器中的 Transformer(核心中的核心)
这是你代码中MapQRDecoderLayer的核心,也是整个矢量化地图生成的大脑。它包含两种关键的注意力机制,分工明确、缺一不可。
(1)自注意力(Self-Attention)
输入 :900 个实例查询代码位置 :mapqr_decoder.py中的self.self_attn
作用:让 900 个地图元素查询之间互相通信、互相协调。比如:
- 左边的车道线查询会告诉右边的车道线查询:"我在这里,你要和我保持 3.5 米的距离"
- 人行道查询会告诉路口查询:"我在你旁边,你要给我留出位置"
这样就能避免预测出重复、重叠、矛盾的道路,保证整个地图的结构合理性。
通俗比喻:900 个工人一起画地图,自注意力就是工人之间的对讲机。
(2)交叉注意力(Cross-Attention)
输入 :实例查询(作为 Q) + BEV 特征(作为 K/V)代码位置 :mapqr_decoder.py中的self.cross_attn
作用:这是连接 "查询" 和 "真实环境" 的唯一桥梁。实例查询通过交叉注意力,去 BEV 特征图中 "查找" 对应位置的信息:
- "我这个位置是不是车道线?"
- "这条道路往哪个方向拐?"
- "道路边界在哪里?"
没有交叉注意力,查询就是一堆随机的向量,模型只能瞎画。
通俗比喻:工人手里没有地图,交叉注意力就是他们手里的卫星图。
3. CAFM 模块中的全局分支(类 Transformer 注意力)
这是你自己添加的创新点,也是 CAFMap 超越 MapQR 的关键。代码位置 :cafm.py中的全局分支
本质:一个简化版的 Transformer 自注意力,专门用于增强 BEV 特征。
和标准 Transformer 的区别:
- 标准 Transformer:在一维序列上做注意力
- CAFM 全局分支:在二维 BEV 特征图上做注意力,同时加入了深度卷积增强局部特征
作用:Transformer 擅长全局结构,但不擅长局部细节;CNN 擅长局部细节,但不擅长全局结构。CAFM 把两者结合起来,同时捕获道路的整体走向和车道线的精细边缘,从而提升地图的精度。