最近多视图重叠过的,导致NaN问题,注意力机制的本质是“竞争“
对于一个包含nnn个参数的神经网络,梯度是一个nnng∂L∂w1∂L∂w2∂L∂wng∂w1∂L∂w2∂L∂wn∂L梯度范数∥g∥2∂L∂w12∂L∂w22⋯∂L∂wn2∥g∥2∂w1∂L2∂w2∂L2⋯∂wn∂L2学习率调整使用较小的学习率(如1e-4)配合学习率衰减策略。
文章目录
问题:

重叠超过50%时,重叠过大导致NaN(Not a Number)的主要原因在于数值不稳定性和梯度爆炸。
注意力权重极端化:当重叠区域过大时,多个视角对同一位置的特征贡献相似,导致注意力权重计算出现极端值(接近0或1)。在softmax计算中,如果输入值过大,会出现数值溢出,产生NaN。
梯度爆炸:重叠区域的特征在反向传播时,梯度会从多个路径回传,如果这些梯度方向一致,会产生梯度累加效应。当重叠比例过高时,梯度可能呈指数级增长,最终超出浮点数表示范围。
特征冲突放大:不同视角对同一物体的特征提取存在差异,重叠过大时这些差异会被反复计算,在特征融合过程中产生数值不稳定。
核心理解:注意力机制的本质是"竞争"
在Transformer的注意力机制中,每个位置需要从所有输入特征中"选择"最相关的信息。这个过程通过计算注意力权重来实现,权重越大表示该特征越重要。
具体过程:
查询-键值匹配:每个BEV查询位置会计算与所有图像特征(键)的相似度
softmax归一化:相似度经过softmax函数,得到0-1之间的权重,且所有权重之和为1
为什么重叠过大会导致极端值:
当多个视角对同一位置的特征贡献高度相似时,它们在相似度计算中会得到几乎相同的分数。在softmax计算中:
如果多个特征分数都很高且接近,softmax会将这些分数"拉平",使它们都接近0
如果某个特征分数显著高于其他,softmax会将其权重推向1,其他推向0
数值不稳定的根源:
当重叠过大时,多个视角的特征相似度差异极小(比如0.0001的差异),在softmax的指数运算中,这种微小差异会被指数级放大。即使进行了缩放,然而导致梯度累加后出问题。
例如:
场景设定
假设我们有一个BEV3D模型,正在处理自动驾驶场景中的一辆汽车。
参数:
- 3个相机视图:前视、左视、右视
- 每个视图都捕捉到了这辆车的不同部分
- 模型想要预测BEV空间中车辆中心点处的特征
BEV网格中的一个位置 P(x=10, y=5, z=1.5) 对应车辆中心
Query-Key点积计算
1. BEV Query
模型在BEV位置P处有一个Query向量:
Q_P = [0.8, 0.2, -0.3, 0.5, ...] # 维度d_k=256
2. 多视图中的对应位置
视图1(前视相机):
- 投影到像素坐标:(320, 240)
- 对应特征向量 K_front = [0.75, 0.25, -0.28, 0.52, …]
- 相似度:
Q_P · K_front = 0.8×0.75 + 0.2×0.25 + (-0.3)×(-0.28) + ...
视图2(左视相机):
- 像素坐标:(150, 200)
- 对应特征向量 K_left = [0.78, 0.22, -0.25, 0.51, …]
- 相似度:
Q_P · K_left = 0.8×0.78 + 0.2×0.22 + ...
视图3(右视相机):
- 像素坐标:(490, 210)
- 对应特征向量 K_right = [0.76, 0.24, -0.26, 0.53, …]
- 相似度:
Q_P · K_right = 0.8×0.76 + 0.2×0.24 + ...
实际计算(简化版)
假设每个向量只有4个维度以便计算:
# 维度d_k=4(实际是256,这里简化)
Q_P = [0.8, 0.2, -0.3, 0.5] # 范数sqrt(0.8²+0.2²+0.3²+0.5²)≈1.0
K_front = [0.75, 0.25, -0.28, 0.52] # 与Q_P高度相似
K_left = [0.78, 0.22, -0.25, 0.51] # 也很相似
K_right = [0.76, 0.24, -0.26, 0.53] # 也很相似
K_back = [0.1, -0.3, 0.6, -0.2] # 不相关的背景位置
# 计算点积
dot_front = 0.8*0.75 + 0.2*0.25 + (-0.3)*(-0.28) + 0.5*0.52
= 0.6 + 0.05 + 0.084 + 0.26
= 0.994
dot_left = 0.8*0.78 + 0.2*0.22 + (-0.3)*(-0.25) + 0.5*0.51
= 0.624 + 0.044 + 0.075 + 0.255
= 0.998
dot_right = 0.8*0.76 + 0.2*0.24 + (-0.3)*(-0.26) + 0.5*0.53
= 0.608 + 0.048 + 0.078 + 0.265
= 0.999
dot_back = 0.8*0.1 + 0.2*(-0.3) + (-0.3)*0.6 + 0.5*(-0.2)
= 0.08 - 0.06 - 0.18 - 0.10
= -0.26
关键问题:当d_k很大时
实际中d_k=256,点积会累积更多项,值会非常大。
假设每个维度对点积贡献约0.9(因为向量高度相似):
- 每个维度的平均贡献:0.9
- 256维的总点积:
0.9 × 256 = 230.4
但更现实的是,向量通常经过归一化,点积反映的是余弦相似度:
- 如果两个256维单位向量完全一致,点积最大为256
- 实际上相似向量点积可能达到200-250
缩放前:
dot_front ≈ 220.0
dot_left ≈ 222.0
dot_right ≈ 221.0
dot_back ≈ -30.0
softmax计算(无缩放时)
# 点积值很大
z = [220.0, 222.0, 221.0, -30.0]
# 直接计算指数会溢出!
# math.exp(220) ≈ 2.5e+95
# math.exp(222) ≈ 1.3e+96
# 已经远超float32范围(3.4e+38)
# 数值溢出,得到inf
exp_z = [inf, inf, inf, 0.0] # 最后一个exp(-30)很小但不是0
解决方案:缩放因子
缩放后(除以 d k = 256 = 16 \sqrt{d_k} = \sqrt{256} = 16 dk=256=16):
z_scaled = [220/16, 222/16, 221/16, -30/16]
= [13.75, 13.875, 13.8125, -1.875]
# 使用稳定softmax:先减去最大值13.875
z_stable = [13.75-13.875, 13.875-13.875, 13.8125-13.875, -1.875-13.875]
= [-0.125, 0.0, -0.0625, -15.75]
# 计算softmax
exp_z = [exp(-0.125), exp(0), exp(-0.0625), exp(-15.75)]
≈ [0.882, 1.0, 0.939, 1.4e-7]
sum_exp ≈ 0.882 + 1.0 + 0.939 + 0.00000014 ≈ 2.821
softmax_output ≈ [0.882/2.821, 1.0/2.821, 0.939/2.821, 1.4e-7/2.821]
≈ [0.313, 0.355, 0.333, ~0.0]
结果分析
| 视图 | 点积 | 缩放后 | 注意力权重 |
|---|---|---|---|
| 前视 | 220.0 | 13.75 | 31.3% |
| 左视 | 222.0 | 13.875 | 35.5% |
| 右视 | 221.0 | 13.8125 | 33.3% |
| 背景 | -30.0 | -1.875 | ~0% |
关键观察:
- 高度相似的视图:三个视图对同一BEV位置都有高相似度(~220),因为车辆在多视图中都可见
- 缩放的重要性:从220缩小到13.8,避免了数值溢出
- 注意力分布合理:三个相关视图获得几乎均等的注意力(31%-36%),背景被抑制
- 梯度保持良好:softmax输出在0.3-0.4之间,梯度不会消失
这个例子清晰地展示了:
- 多视图重叠 → 多个Key与同一Query高度相似 → 点积值非常大
- 无缩放时 → 点积值可达200+ → e 200 e^{200} e200 数值溢出
- 缩放后 → 点积缩小到合理范围 → softmax稳定计算
- 注意力机制 → 合理分配多视图权重 → 有效融合多视图信息
这就是为什么Transformer中的 1 d k \frac{1}{\sqrt{d_k}} dk1缩放因子如此关键——它不仅控制方差,更是避免数值溢出的必要保障。
出现NaN的根本原因
重叠多了出现NaN的根本原因不是softmax本身,而是训练过程中的梯度爆炸或数值不稳定导致的连锁反应。
虽然前面提到缩放因子和稳定softmax解决了理论上的数值溢出,但在实际训练中,当多视图重叠严重时,以下问题会累积导致NaN:
1. 梯度爆炸的连锁反应
问题根源:当多个视图对同一BEV位置都有极高相似度时,虽然softmax输出是合理的概率分布,但梯度计算可能不稳定。
梯度公式: ∂ L ∂ z i = a i − y i \frac{\partial L}{\partial z_i} = a_i - y_i ∂zi∂L=ai−yi
当多个视图的 z i z_i zi都非常大且接近时:
- 虽然 a i a_i ai在0.3-0.4之间,但 z i z_i zi本身可能很大(如200+)
- 如果梯度回传到 z i z_i zi的上一层,可能引发梯度爆炸
- 梯度爆炸导致网络参数更新过大,下一轮前向传播时 z i z_i zi变得更大
恶性循环:
大z_i → 梯度爆炸 → 参数更新过大 → 下一轮z_i更大 → 梯度更爆炸 → NaN
2. 多视图几何投影的不稳定性
相机参数误差:当多个相机视角重叠严重时,微小的相机标定误差会被放大:
- 同一3D点在不同视图中的投影位置略有偏差
- 模型需要学习"对齐"这些略有偏差的特征
- 如果相机参数不准,这个对齐过程可能不稳定
特征歧义:多个视图的相似特征可能对应不同的3D位置,模型难以区分,导致注意力权重震荡。
3. 实际训练中的解决方案
梯度裁剪:
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
限制梯度范数,防止梯度爆炸。
梯度范数(Gradient Norm)是衡量神经网络训练过程中梯度大小的指标,它表示所有参数梯度向量的长度(模长)。
数学定义
对于一个包含 n n n 个参数的神经网络,梯度是一个 n n n 维向量:
g = [ ∂ L ∂ w 1 , ∂ L ∂ w 2 , … , ∂ L ∂ w n ] \mathbf{g} = \left[\frac{\partial L}{\partial w_1}, \frac{\partial L}{\partial w_2}, \dots, \frac{\partial L}{\partial w_n}\right] g=[∂w1∂L,∂w2∂L,…,∂wn∂L]
梯度范数(L2范数)定义为:
∥ g ∥ 2 = ( ∂ L ∂ w 1 ) 2 + ( ∂ L ∂ w 2 ) 2 + ⋯ + ( ∂ L ∂ w n ) 2 \|\mathbf{g}\|_2 = \sqrt{\left(\frac{\partial L}{\partial w_1}\right)^2 + \left(\frac{\partial L}{\partial w_2}\right)^2 + \dots + \left(\frac{\partial L}{\partial w_n}\right)^2} ∥g∥2=(∂w1∂L)2+(∂w2∂L)2+⋯+(∂wn∂L)2
学习率调整:
- 使用较小的学习率(如1e-4)
- 配合学习率衰减策略
特征归一化:
- 在Query和Key计算前进行LayerNorm
- 确保特征分布稳定
损失函数设计:
- 添加正则化项(L2正则化)
- 使用smooth L1损失代替L2损失
4. 工程实践中的调试
当出现NaN时,通常需要:
- 检查梯度范数,如果过大则降低学习率或增加梯度裁剪
- 检查相机标定参数是否准确
- 检查数据集中是否存在极端重叠场景
- 添加数值检查,在训练过程中监控中间变量的数值范围
总结:虽然理论上缩放因子解决了softmax的数值问题,但实际训练中多视图重叠带来的梯度不稳定、几何投影误差累积等问题,仍然可能导致NaN。这需要通过梯度裁剪、学习率调整、特征归一化等工程手段综合解决。
更多推荐



所有评论(0)