luoganttcc头像

BEV(三) BEVFormer:Query 参数如何与 Feature 的 8 个 Head 交互

BEVFormer:Query 参数如何与 Feature 的 8 个 Head 交互

本文把下面这条计算链完整展开:

Query 产生 Offset 和 Weight
            ↓
控制从多相机、多尺度 Feature 的哪里读取、读取多少
            ↓
8 个 Head 分别采样并加权
            ↓
拼接、相机融合、输出投影
            ↓
Dropout 后与原 Query 残差相加
            ↓
LayerNorm 得到新 Query

核心结论是:

Query 不直接与图像 Feature 做点积。Query 产生读取地址和混合权重;Feature 提供被读取的数据;融合结果经过投影后作为增量写回原 Query。

在这里插入图片描述


1. 先区分所有变量

以下变量都针对某个 BEV 格子 p:

变量来源Base 中的形状作用
q p q_p qp​BEV Query[256]当前格子保存的状态
q ~ p \widetilde q_p q ​p​Query 加位置编码[256]预测采样控制参数
Δ p , h , l , k \Delta_{p,h,l,k} Δp,h,l,k​Query 路径[2]第 h,l,k 个采样偏移
α p , h , l , k \alpha_{p,h,l,k} αp,h,l,k​Query 路径标量该采样结果的混合权重
F ~ c , l ( x , y ) \widetilde F_{c,l}(x,y) F c,l​(x,y)图像 Backbone/FPN[256]相机 c、层级 l 的空间特征
V c , l ( h ) ( x , y ) V_{c,l}^{(h)}(x,y) Vc,l(h)​(x,y)Feature 的 Value 投影[32]Head h 的图像数据
f p , c , h , l , k f_{p,c,h,l,k} fp,c,h,l,k​双线性采样[32]从指定位置实际读取的特征
g p , c ( h ) g_{p,c}^{(h)} gp,c(h)​Head 内加权求和[32]一个 Head 的融合结果
g p , c g_{p,c} gp,c​8 Head 拼接[256]一台相机对该 Query 的结果
g ‾ p \overline g_p g​p​有效相机平均[256]六相机融合结果
o p o_p op​输出投影[256]准备写入 Query 的更新量

索引含义:

c:相机,0~5
h:Head,0~7
l:FPN Level,0~3
k:每个 Head、每个 Level 的采样点,0~7

Base 还有四个柱高参考点。八个采样点不是“每个高度八个点”,而是:

4 个高度 × 每个高度 2 个偏移位置 = 8 个采样点

2. 八个 Head 到底是什么

八个 Head 不是八台相机、八个 Query、八个目标,也不是八个单独保存的向量。

8 是模型结构中人为设定的超参数:

embed_dims = 256
num_heads = 8
head_dim = 256 // 8  # 32

因此同一个 Query 的一次 Attention 被组织为八条并行计算分支:

Head 0:32 维 Value + 自己的 Offset + 自己的 Weight
Head 1:32 维 Value + 自己的 Offset + 自己的 Weight
...
Head 7:32 维 Value + 自己的 Offset + 自己的 Weight

Head 本身只是一个计算分支编号。每个 Head 具体关注什么位置、尺度和特征,由训练决定。


3. Feature 路径:图像数据怎样进入 Head

六相机图像先经过共享的 Backbone 和 FPN。某个相机、某个 FPN 层、某个空间位置的特征为:

F c , l F P N ( x , y ) ∈ R 256 . F^{\mathrm{FPN}}_{c,l}(x,y)\in\mathbb R^{256}. Fc,lFPN​(x,y)∈R256.

加入相机编码与层级编码:

$$
\widetilde F_{c,l}(x,y)

F^{\mathrm{FPN}}_{c,l}(x,y)
+e_c^{\mathrm{cam}}
+e_l^{\mathrm{level}}.
$$

然后经过 Value Projection:

$$
V_{c,l}(x,y)

W_v\widetilde F_{c,l}(x,y)+b_v,
$$

其中:

W v ∈ R 256 × 256 . W_v\in\mathbb R^{256\times256}. Wv​∈R256×256.

再将结果 reshape 为:

V c , l ( x , y ) ∈ R 8 × 32 . V_{c,l}(x,y)\in\mathbb R^{8\times32}. Vc,l​(x,y)∈R8×32.

即:

$$
V_{c,l}

\operatorname{Concat}
\left(
V_{c,l}^{(0)},
V_{c,l}^{(1)},
\ldots,
V_{c,l}^{(7)}
\right),
$$

其中:

V c , l ( h ) ( x , y ) ∈ R 32 . V_{c,l}^{(h)}(x,y)\in\mathbb R^{32}. Vc,l(h)​(x,y)∈R32.

不是机械切分原始 FPN 通道

由于切分前存在可学习的 W v W_v Wv​,可以把它按输出行理解为八块:

W v = [ W v ( 0 ) W v ( 1 ) ⋮ W v ( 7 ) ] , W v ( h ) ∈ R 32 × 256 . W_v= \begin{bmatrix} W_v^{(0)}\\ W_v^{(1)}\\ \vdots\\ W_v^{(7)} \end{bmatrix}, \qquad W_v^{(h)}\in\mathbb R^{32\times256}. Wv​= ​Wv(0)​Wv(1)​⋮Wv(7)​​ ​,Wv(h)​∈R32×256.

所以:

$$
V_{c,l}^{(h)}

W_v^{(h)}\widetilde F_{c,l}+b_v^{(h)}.
$$

每个 Head 的 32 维 Value 都可以综合原始全部 256 个 Feature 通道。


4. Query 路径:产生每个 Head 的控制参数

原 Query 为:

q p ∈ R 256 . q_p\in\mathbb R^{256}. qp​∈R256.

位置编码为 e p e_p ep​。用于预测采样参数的向量是:

q ~ p = q p + e p . \widetilde q_p=q_p+e_p. q ​p​=qp​+ep​.

4.1 产生 Offset

$$
\Delta_p

W_\Delta\widetilde q_p+b_\Delta.
$$

Base 中:

W Δ ∈ R 512 × 256 , W_\Delta\in\mathbb R^{512\times256}, WΔ​∈R512×256,

因为:

512 = 8 h e a d × 4 l e v e l × 8 p o i n t × 2 x y . 512 =8_{\mathrm{head}} \times4_{\mathrm{level}} \times8_{\mathrm{point}} \times2_{xy}. 512=8head​×4level​×8point​×2xy​.

reshape 后:

sampling_offsets
[8 Head, 4 Level, 8 Point, 2 xy]

第 h 个 Head 因而拥有自己的一组:

Δ p , h , l , k = ( Δ x , Δ y ) . \Delta_{p,h,l,k}=(\Delta x,\Delta y). Δp,h,l,k​=(Δx,Δy).

4.2 产生 Weight

$$
a_p

W_\alpha\widetilde q_p+b_\alpha.
$$

Base 中 a p ∈ R 256 a_p\in\mathbb R^{256} ap​∈R256,因为:

256 = 8 h e a d × 4 l e v e l × 8 p o i n t . 256 =8_{\mathrm{head}} \times4_{\mathrm{level}} \times8_{\mathrm{point}}. 256=8head​×4level​×8point​.

输出 reshape 为:

attention_logits
[8 Head, 4 Level, 8 Point]

每个 Head 独立对自己的 4 × 8 = 32 个 Logit 做 Softmax:

$$
\alpha_{p,h,l,k}

\frac{\exp(a_{p,h,l,k})}
{\displaystyle
\sum_{l’=0}{3}\sum_{k’=0}{7}
\exp(a_{p,h,l’,k’})}.
$$

因此:

∑ l = 0 3 ∑ k = 0 7 α p , h , l , k = 1. \sum_{l=0}^{3}\sum_{k=0}^{7} \alpha_{p,h,l,k}=1. l=0∑3​k=0∑7​αp,h,l,k​=1.

Offset 决定“在哪里读”,Weight 决定“读到的数据占多少”。

4.3 Offset 一开始从哪里来

Offset 不是每次随机生成的。官方实现将 sampling_offsets.weight 初始化为零,将 bias 初始化为八个 Head 各自方向不同的放射状位置。训练开始后,weight 和 bias 都通过反向传播学习。

attention_weights 的 weight 和 bias 初始为零,因此初始 Softmax 权重都是 1 / 32 1/32 1/32;训练后才会针对不同 Query 形成不同的采样权重。

因此训练后的 Offset 是 Query 的确定性函数:

Δ p = W Δ q ~ p + b Δ . \Delta_p=W_\Delta\widetilde q_p+b_\Delta. Δp​=WΔ​q ​p​+bΔ​.

它的数值以当前 FPN 特征图的网格为尺度。比如 Δ x = 2 \Delta x=2 Δx=2 表示在该 Level 上横向移动约两个 Feature cell;它不是移动两个 BEV 格子。Offset 可以是小数,所以采样点也可以落在四个 Feature cell 之间。


5. Query 和 Feature 第一次交互:Offset 控制读取地址

BEV 三维参考点投影到相机后得到几何基准位置:

ρ p , c , m ∈ [ 0 , 1 ] 2 . \rho_{p,c,m}\in[0,1]^2. ρp,c,m​∈[0,1]2.

Base 使用四个高度锚点、每个高度两个 Offset。源码把八个 Offset 临时 reshape 为:

[8 Point, 2 xy] → [2 Offset-group, 4 Height, 2 xy]

用扁平索引 k k k 表示时:

k = 4 j + m , j ∈ { 0 , 1 } , m ∈ { 0 , 1 , 2 , 3 } . k=4j+m, \qquad j\in\{0,1\}, \qquad m\in\{0,1,2,3\}. k=4j+m,j∈{0,1},m∈{0,1,2,3}.

所以:

m ( k ) = k   m o d   4. m(k)=k\bmod4. m(k)=kmod4.

这就是下式中的 m ( k ) m(k) m(k):它指出第 k k k 个 Offset 应加到四个高度参考点中的哪一个。

Query 预测的 Offset 按当前 FPN 层宽高归一化。最终采样位置是:

$$
s_{p,c,h,l,k}

\rho_{p,c,m(k)}
+
\left(
\frac{\Delta x_{p,h,l,k}}{W_l},
\frac{\Delta y_{p,h,l,k}}{H_l}
\right).
$$

这里没有执行 Query 与 Feature 的向量乘法。

Query 产生的 Offset 改变了 Feature 的读取地址:

几何基准位置 ρ
        +
Query 预测偏移 Δ
        ↓
最终 Feature 读取位置 s

6. 根据地址,从 Feature 中读取 32 维向量

采样位置 s = ( s x , s y ) s=(s_x,s_y) s=(sx​,sy​) 是 [0,1] 归一化坐标。对第 l 层特征图,连续特征坐标为:

x = W l s x − 1 2 , y = H l s y − 1 2 . x=W_ls_x-\frac{1}{2}, \qquad y=H_ls_y-\frac{1}{2}. x=Wl​sx​−21​,y=Hl​sy​−21​.

通过四邻域双线性插值,Head h 读取:

$$
f_{p,c,h,l,k}

\mathcal B
\left(
V_{c,l}^{(h)},
s_{p,c,h,l,k}
\right).
$$

结果为:

f p , c , h , l , k ∈ R 32 . f_{p,c,h,l,k}\in\mathbb R^{32}. fp,c,h,l,k​∈R32.

所以:

Query 提供 s:在哪里读取
Feature 提供 f:读取到什么内容

7. Query 和 Feature 第二次交互:Weight 控制贡献比例

Query 产生的 α p , h , l , k \alpha_{p,h,l,k} αp,h,l,k​ 是一个标量;采样得到的 f p , c , h , l , k f_{p,c,h,l,k} fp,c,h,l,k​ 是一个 32 维向量。

二者交互为标量乘向量:

α p , h , l , k f p , c , h , l , k . \alpha_{p,h,l,k}f_{p,c,h,l,k}. αp,h,l,k​fp,c,h,l,k​.

例如:

α = 0.7 , f = [ 10 , 20 , 30 ] , \alpha=0.7, \qquad f=[10,20,30], α=0.7,f=[10,20,30],

则:

$$
\alpha f

0.7[10,20,30]

[7,14,21].
$$

Weight 不改变采样坐标,只改变这个采样特征对最终结果的贡献。


8. 一个 Head 的完整计算

每个 Head 在四个 FPN Level、每层八个位置采样。每层的八个位置来自“四个高度 × 每个高度两个 Offset”,因此共有:

4 × 8 = 32 4\times8=32 4×8=32

个采样结果。

第 h 个 Head 的融合结果为:

$$
g_{p,c}^{(h)}

\sum_{l=0}^{3}
\sum_{k=0}^{7}
\alpha_{p,h,l,k}
f_{p,c,h,l,k}.
$$

把 f f f 展开:

$$
g_{p,c}^{(h)}

\sum_{l=0}^{3}
\sum_{k=0}^{7}
\alpha_{p,h,l,k}
\mathcal B
\left(
V_{c,l}^{(h)},
s_{p,c,h,l,k}
\right).
$$

输出仍然是:

g p , c ( h ) ∈ R 32 . g_{p,c}^{(h)}\in\mathbb R^{32}. gp,c(h)​∈R32.


9. 八个 Head 合并为一台相机的结果

八个 Head 分别输出:

Head 0 → g⁽⁰⁾[32]
Head 1 → g⁽¹⁾[32]
...
Head 7 → g⁽⁷⁾[32]

将它们按通道拼接:

$$
g_{p,c}

\operatorname{Concat}
\left(
g_{p,c}^{(0)},
g_{p,c}^{(1)},
\ldots,
g_{p,c}^{(7)}
\right).
$$

所以:

g p , c ∈ R 256 . g_{p,c}\in\mathbb R^{256}. gp,c​∈R256.

八个 Head 的目标不是产生八个检测结果,而是共同生成一个更丰富的 256 维 Query 更新候选。


10. 六台相机如何合并

设能看到格子 p 的有效相机集合为 V p \mathcal V_p Vp​:

N p = max ⁡ ( 1 , ∣ V p ∣ ) . N_p=\max\left(1,\left|\mathcal V_p\right|\right). Np​=max(1,∣Vp​∣).

官方实现对有效相机结果做算术平均:

$$
\overline g_p

\frac{1}{N_p}
\sum_{c\in\mathcal V_p}g_{p,c}.
$$

这里没有额外的跨相机 Softmax。

在官方实现中,同一个 Query 被复制到它可见的相机分支,并且所有相机共享 W Δ W_\Delta WΔ​ 和 W α W_\alpha Wα​。因此,同一个 Query 在不同相机分支产生的 Offset 和 Weight 数值相同。相机差异来自投影基准位置 ρ p , c , m \rho_{p,c,m} ρp,c,m​ 和图像 Value V c , l V_{c,l} Vc,l​,所以最终采样位置与读取内容不同。


11. 输出投影:把 Feature 结果变成 Query 更新量

六相机融合结果为:

g ‾ p ∈ R 256 . \overline g_p\in\mathbb R^{256}. g​p​∈R256.

它来自图像 Value 空间,还需要经过输出投影:

o p = W o g ‾ p + b o , o_p=W_o\overline g_p+b_o, op​=Wo​g​p​+bo​,

其中:

W o ∈ R 256 × 256 . W_o\in\mathbb R^{256\times256}. Wo​∈R256×256.

o p o_p op​ 可以理解为:

本次相机观测准备写入该 BEV Query 的 256 维更新量。

output_proj 还会重新混合八个 Head 的通道,使结果适合与 Query 相加。


12. Dropout 不是残差

训练阶段对更新量应用 Dropout:

d p = Dropout ⁡ ( o p ) . d_p=\operatorname{Dropout}(o_p). dp​=Dropout(op​).

如果 Dropout 概率为 r r r,训练时每个通道近似为:

$$
d_{p,i}

\frac{m_i}{1-r}o_{p,i},
\qquad
m_i\sim\operatorname{Bernoulli}(1-r).
$$

Dropout 的作用是随机抑制更新分支中的部分通道,减少过拟合。

推理时:

Dropout ⁡ ( o p ) = o p . \operatorname{Dropout}(o_p)=o_p. Dropout(op​)=op​.

所以 Dropout 不是残差,也不会产生一条新的残差来源。


13. 原 Query 才是残差分支

残差相加为:

$$
\widehat q_p

\underbrace{q_p}{\text{原 Query,残差分支}}
+
\underbrace{\operatorname{Dropout}(o_p)}
{\text{图像更新分支}}.
$$

随后执行:

$$
q_p^{\mathrm{new}}

\operatorname{LayerNorm}(\widehat q_p).
$$

这里要区分代码边界:SpatialCrossAttention.forward() 只计算

q ^ p = q p + Dropout ⁡ ( o p ) . \widehat q_p=q_p+\operatorname{Dropout}(o_p). q ​p​=qp​+Dropout(op​).

紧随其后的 LayerNorm 由外层 BEVFormerLayer 按 cross_attn → norm 的顺序执行。

残差的含义是:

新状态 = 原状态 + 本次相机观测带来的修正量

它保留了 Query 中已有的:

  • BEV 位置先验;
  • Temporal Self-Attention 融合的历史信息;
  • 前面 Encoder 层已经写入的图像信息。

如果图像更新量接近零:

o p ≈ 0 , o_p\approx0, op​≈0,

则:

q ^ p ≈ q p . \widehat q_p\approx q_p. q ​p​≈qp​.

原状态不会被一次无效观测直接覆盖。


14. 一次交互的闭环

将所有阶段按依赖关系排列:

                         Query 路径
qₚ[256] ───────────────────────────────────────────────┐
   │                                                   │
   ├─ + position ─→ Linear ─→ Offset Δ                 │
   │                          │                        │
   │                          └─→ 最终采样位置 s       │
   │                                                   │
   └─ + position ─→ Linear ─→ Weight α                 │
                                                       │
                         Feature 路径                   │
图像 ─→ Backbone/FPN ─→ camera/level embed ─→ Wᵥ       │
                                                │      │
                                                └→ 8 Head × 32
                                                        │
s ─────────────────────────→ 双线性采样 Feature         │
                                      │                 │
                                      └→ f[32]          │
α ───────────────────────────────────────×              │
                                               │        │
                                每个 Head 加权求和       │
                                               │        │
                              8 Head Concat → g[256]     │
                                               │        │
                                      有效相机平均       │
                                               │        │
                                     output_proj → o[256]
                                               │        │
                                         Dropout(o)     │
                                               │        │
qₚ 残差路径 ────────────────────────────────────┴─→ 相加
                                                        ↓
                                                   LayerNorm
                                                        ↓
                                                 qₚ_new[256]

两种真正的 Query–Feature 交互是:

  1. Query 的 Offset 控制从 Feature 的哪里读取;
  2. Query 的 Weight 控制读到的 Feature 占多大比例。

第三步是状态融合:图像结果经过 W o W_o Wo​ 后与原 Query 相加。


15. 一个可以手算的双 Head 例子

为了方便手算,假设:

Query/输出维度:4
Head 数量:2
每个 Head:2 维
每个 Head 只采两个位置
推理阶段 Dropout 关闭

原 Query:

q = [ 1 , 2 , 1 , 0 ] . q=[1,2,1,0]. q=[1,2,1,0].

Query 为 Head 0 产生权重:

α ( 0 ) = [ 0.8 , 0.2 ] . \alpha^{(0)}=[0.8,0.2]. α(0)=[0.8,0.2].

根据 Head 0 的 Offset,在 Feature 中读取:

f 1 ( 0 ) = [ 10 , 0 ] , f 2 ( 0 ) = [ 0 , 8 ] . f_1^{(0)}=[10,0], \qquad f_2^{(0)}=[0,8]. f1(0)​=[10,0],f2(0)​=[0,8].

因此:

g ( 0 ) = 0.8 [ 10 , 0 ] + 0.2 [ 0 , 8 ] = [ 8 , 1.6 ] . g^{(0)} =0.8[10,0]+0.2[0,8] =[8,1.6]. g(0)=0.8[10,0]+0.2[0,8]=[8,1.6].

Query 为 Head 1 产生权重:

α ( 1 ) = [ 0.25 , 0.75 ] . \alpha^{(1)}=[0.25,0.75]. α(1)=[0.25,0.75].

根据 Head 1 的 Offset,在 Feature 中读取:

f 1 ( 1 ) = [ 2 , 6 ] , f 2 ( 1 ) = [ 10 , 2 ] . f_1^{(1)}=[2,6], \qquad f_2^{(1)}=[10,2]. f1(1)​=[2,6],f2(1)​=[10,2].

因此:

g ( 1 ) = 0.25 [ 2 , 6 ] + 0.75 [ 10 , 2 ] = [ 8 , 3 ] . g^{(1)} =0.25[2,6]+0.75[10,2] =[8,3]. g(1)=0.25[2,6]+0.75[10,2]=[8,3].

拼接两个 Head:

$$
g

\operatorname{Concat}
\left(g{(0)},g{(1)}\right)
=[8,1.6,8,3].
$$

为了演示,暂时假设 W o W_o Wo​ 是单位矩阵,则:

o = g = [ 8 , 1.6 , 8 , 3 ] . o=g=[8,1.6,8,3]. o=g=[8,1.6,8,3].

推理阶段 Dropout 关闭,因此:

q ^ = q + o . \widehat q=q+o. q ​=q+o.

q ^ = [ 1 , 2 , 1 , 0 ] + [ 8 , 1.6 , 8 , 3 ] = [ 9 , 3.6 , 9 , 3 ] . \widehat q =[1,2,1,0]+[8,1.6,8,3] =[9,3.6,9,3]. q ​=[1,2,1,0]+[8,1.6,8,3]=[9,3.6,9,3].

最后再执行 LayerNorm 得到新 Query。

这个例子中的分工非常明确:

Query:产生两个 Head 的采样位置与权重
Feature:提供四个被采样的 2 维向量
Head:分别完成加权求和
残差:把结果写入原 Query,而不是覆盖原 Query

16. 与普通 QKᵀV Attention 的区别

普通 Attention 使用:

$$
\alpha

\operatorname{Softmax}
\left(
\frac{QK^T}{\sqrt d}
\right).
$$

权重来自 Query 与 Key 的相似度。

BEVFormer Spatial Cross-Attention 使用:

Δ = W Δ q ~ + b Δ , \Delta=W_\Delta\widetilde q+b_\Delta, Δ=WΔ​q ​+bΔ​,

$$
\alpha

\operatorname{Softmax}
\left(W_\alpha\widetilde q+b_\alpha\right),
$$

f = B ( V , ρ + Δ ^ ) , f=\mathcal B(V,\rho+\widehat\Delta), f=B(V,ρ+Δ ),

g = ∑ α f . g=\sum\alpha f. g=∑αf.

当前层中不存在完整的 Query–Feature 点积矩阵。Feature 主要作为被动态寻址和加权的数据源。


17. 为什么后续层仍然能根据 Feature 调整控制参数

虽然当前层的 Weight 不是通过 q T f q^Tf qTf 计算,但本层结束时:

$$
q^{(r+1)}

\operatorname{LayerNorm}
\left(
q{®}+o{®}
\right).
$$

o ( r ) o^{(r)} o(r) 来自相机 Feature,所以新的 Query 已经包含图像信息。

下一层再用新 Query 预测:

Δ ( r + 1 ) , α ( r + 1 ) . \Delta^{(r+1)}, \qquad \alpha^{(r+1)}. Δ(r+1),α(r+1).

六层形成反馈迭代:

第 1 层 Query → 控制采样 → 将图像 Feature 写入 Query
                      ↓
第 2 层 Query → 根据已有图像内容重新控制采样
                      ↓
第 3~6 层继续修正

18. 对应源码

18.1 定义 Value、Offset 和 Weight 投影

spatial_cross_attention.py

self.sampling_offsets = nn.Linear(
    embed_dims,
    num_heads * num_levels * num_points * 2
)

self.attention_weights = nn.Linear(
    embed_dims,
    num_heads * num_levels * num_points
)

self.value_proj = nn.Linear(embed_dims, embed_dims)

18.2 Feature 投影并切为八个 Head

spatial_cross_attention.py

value = self.value_proj(value)

value = value.view(
    bs,
    num_value,
    self.num_heads,
    -1
)

18.3 Query 产生每个 Head 的 Offset 和 Weight

spatial_cross_attention.py

sampling_offsets = self.sampling_offsets(query).view(
    bs,
    num_query,
    self.num_heads,
    self.num_levels,
    self.num_points,
    2
)

attention_weights = self.attention_weights(query).view(
    bs,
    num_query,
    self.num_heads,
    self.num_levels * self.num_points
)

attention_weights = attention_weights.softmax(-1)

18.4 基准位置加 Offset

spatial_cross_attention.py

sampling_offsets = sampling_offsets / offset_normalizer
sampling_locations = reference_points + sampling_offsets

18.5 三种输入在采样算子中相遇

spatial_cross_attention.py

output = MultiScaleDeformableAttnFunction.apply(
    value,                 # 来自 Feature
    spatial_shapes,
    level_start_index,
    sampling_locations,    # 来自 Query 的 Offset + 几何参考点
    attention_weights,     # 来自 Query 的 Weight
    self.im2col_step
)

18.6 Dropout、残差和写回 Query

spatial_cross_attention.py

slots = self.output_proj(slots)

return self.dropout(slots) + inp_residual

其中:

slots        → 相机 Feature 产生的 Query 更新量
self.dropout → 只作用于更新分支
inp_residual → 原 Query,也就是残差分支

18.7 外层 LayerNorm

bevformer_base.py

operation_order=(
    'self_attn', 'norm',
    'cross_attn', 'norm',
    'ffn', 'norm'
)

encoder.py

elif layer == 'norm':
    query = self.norms[norm_index](query)

因此源码中的实际边界是:

SpatialCrossAttention:q_hat = q + dropout(o)
BEVFormerLayer:        q_new = norm(q_hat)

19. 常见误解

误解一:八个 Head 是八个 Query

不是。一个 BEV 格子仍然只有一个 256 维 Query。八个 Head 是八条并行采样分支,最后重新拼成一个 256 维结果。

误解二:Head 是从 Feature 中检测出来的八个目标

不是。Head 数量 8 是结构参数。每个 Head 的数据由可学习的 Value Projection 从 Feature 中产生。

误解三:Query 与 Feature 先做逐元素乘法

不是。Query 先产生地址和权重;地址控制 Feature 采样,权重再乘采样后的 32 维 Feature。

误解四:Dropout 是残差

不是。原 Query 是残差;Dropout 只作用于相机更新量。

误解五:新 Feature 直接替换 Query

不是。图像融合结果经过 W o W_o Wo​ 后作为增量与原 Query 相加。


20. 一句话记忆

Query 产生 Offset 决定“去哪里读”;
Query 产生 Weight 决定“相信多少”;
Feature 的 8 个 Head 提供“真正读到的数据”;
output_proj 把数据变成 Query 更新量;
Dropout 只正则化更新量;
原 Query 通过残差路径保留并接收这次更新。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/luoganttcc/article/details/168446034

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--