拓冰建站拓冰建站
首页 / 资讯中心 / 正文

BEVFormer深度解读:Transformer如何重构BEV感知与3D目标检测

做自动驾驶感知的人这两年应该都躲不开BEV这个词。BEV视角到底好在哪以前我用一个词形容全局视野。前视摄像头只能看到前方雷达点云又稀疏得让人头疼而BEV把多个相机拍到的画面统一投影到自车俯视图上所有目标的位置、走向、速度一目了然。但真正让我下决心仔细啃一遍的还是BEVFormer这篇论文——它用Transformer把2D图像特征和3D空间位置直接做注意力关联省掉了显式深度估计那一大堆麻烦事。如果你正在做环视感知、多传感器融合或者想搞懂Transformer在自动驾驶里是怎么落地的这篇解读应该能帮你少走不少弯路。我写这篇解读的时候会先讲清楚BEV视角为什么重要再拆BEVFormer的整体架构和四个核心模块然后补训练细节和踩坑经验。中间会夹着一些我自己跑代码、复现论文时的心得尽量让每个结论都有实际依据。1. 先搞清楚BEV视角为什么这么火1.1 前视视角到底卡在哪传统视觉感知走的是“前视感知”路线就是让模型在相机图像平面上去检测目标、估计深度和速度。问题是图像是透视投影远处物体又小又模糊近处物体又大又变形物体之间的遮挡关系也乱成一团。你让模型在这样一个视角下去做3D定位相当于让一个人只靠一只眼去看世界还得估算出每个物体的距离和速度能准吗而且前视感知有个更麻烦的麻烦——时间维度上的目标跟踪。同一辆车在相邻两帧图像里因为相机朝向前方车辆从远处驶近时图像上的位置、大小、外观全都变了。模型需要重新识别这个目标才能保持ID一致。如果换到BEV视角车辆在鸟瞰图里只是沿着车道方向平移位置变化规律非常清晰跟踪任务瞬间简单了一个量级。1.2 BEV给自动驾驶带来的三个直接好处BEV视角对自动驾驶系统来说至少有三个非常直接的好处第一多传感器贴合。激光雷达点云天然就是3D坐标BEV网格可以直接把点云和图像特征放在同一个坐标系里做融合不用费劲去对齐两个差异巨大的数据形式。第二时序融合自然。自车运动过程中BEV特征可以做坐标变换对齐上一帧和当前帧的物体位置可以直接做运动补偿时间信息用起来非常顺手。第三下游任务友好。无论是规划、控制还是预测最终决策都是在一个俯视图坐标系里进行的。感知模块直接输出BEV特征规划和预测模块拿来就能用省掉了坐标变换和空间理解的过程。这也是为什么从2021年底开始越来越多的自动驾驶团队把感知主干切到BEV方案不只是学术界刷榜工程上确实好用。1.3 Transformer凭什么来做BEVTransformer最拿手的事情就是建模长距离依赖关系。图像上一根车道线可能跨越几百个像素一个十字路口的左右来车需要综合多个视角才能判断这种跨区域、跨模态的关联正是Transformer的强项。BEVFormer做了一个很聪明的设计它不给模型规定“哪个图像区域应该放到哪个BEV网格”而是让模型通过注意力机制自己去学。每个BEV网格负责询问对应空间位置上的特征跨6个相机视图去采样并聚合信息。这种自动化、动态化的信息映射比传统基于几何投影的方法灵活得多也更容易学到不同相机布局下的统一表达。2. BEVFormer整体架构一句话版本和六层Encoder2.1 整体pipeline一张图看懂你要问我BEVFormer怎么运作的我用一句话概括输入多相机环视图像用Backbone和FPN提取多尺度2D特征然后用6层BEVFormer Encoder把这些2D特征逐步转成一个200x200的BEV特征网格最后在BEV特征上接检测头完成3D目标检测。对于输入论文用的是6个环视相机覆盖了车周围360度视野。图像分辨率通常是1600x900这个不算特别高主要受限于显存。Backbone用的是ResNet101-DCNDCN是可变形卷积对几何形变建模能力更强很适合处理环视相机带来的大透视变形。Backbone之后接FPN输出多个尺度的特征图后面做空间交叉注意力的时候会用到这些多尺度特征。Encoder部分是BEVFormer的核心由6层堆叠的BEVFormer layer组成。每一层做的事情都一样先对输入BEV Query做时间自注意力Temporal Self-Attention再对多相机2D特征做空间交叉注意力Spatial Cross-Attention最后过FFN。6层重复堆叠让BEV特征逐层精化信息在时间维度和空间维度上反复融合。2.2 Backbone和Neck怎么选论文默认的Backbone是ResNet101-DCN但这不是必须的。我试过换成ResNet50速度能快不少精度会掉一点具体看你的算力。Swin Transformer这类ViT主干也有人试过整体思路是把2D特征提取得更好但计算量也上来了。FPN头的作用是输出多尺度特征我用表列一下这几个尺度的感受野差异特征图尺寸下采样倍数适合检测的目标原始图像的1/88近处小目标、行人1/1616中型目标、普通车辆1/3232远处目标、重型车辆1/6464全局上下文、大目标后面做空间交叉注意力时模型会在多个尺度上采样小目标信息和大目标信息都吃得到不会出现漏检远处大车或者近处行人的情况。这个多尺度设计挺关键早期我试过只输出单尺度特征近处行人的检测明显变差加了FPN之后改善很大。2.3 六层Encoder的“空间快递站”逻辑把这6层Encoder类比成一个快递分拣系统就好理解了。BEV Query一开始是一堆空白地址卡片上面写着坐标位置但还没有内容。第1层Encoder负责从2D图像里找每个地址附近的初步特征往卡片上填一点信息第2层继续精化结合更广范围的信息修正之前填的粗糙内容到第6层卡片上的特征已经聚合了多尺度、多视角、多时刻的信息内容非常丰富足够用来做检测了。每一层都包含时间自注意力和空间交叉注意力这两个模块是我理解BEVFormer的两个关键钥匙我把它们单独拆开细讲。3. 四个核心模块逐层拆解3.1 BEV Query在网格上“问问题”BEV Query是BEVFormer里第一个让我拍大腿的设计。简单说它是一个形状为200x200x256的可学习特征网格每个网格像素对应现实世界中一块0.5m x 0.5m的区域。整个网格覆盖了自车前后左右各50米也就是总共100m x 100m的感知范围。为什么要叫Query因为它在Transformer里的角色就是查询者。你把整个BEV空间想象成一片空地上面打了200x200个格子每个格子都在举手发问我这里有什么东西可能是车、可能是行人、也可能是马路牙子。这个问题会被带到相机图像里去寻找答案。之前在做DETR系列的时候object query数量就几十个每个query对应一个候选目标。BEV Query完全不同它是密集规则排列的每一个都有明确的物理坐标含义。这意味着BEV Query天然自带位置编码——它在网格中的位置就是它在真实世界中的位置不需要额外学习位置嵌入这个设计非常优雅。3.2 Spatial Cross-Attention把2D图像特征搬到3D网格这一块是BEVFormer把几何先验和Transformer融合得最巧妙的地方。每个BEV Query对应世界坐标系中的一个(x, y)位置但现实中这个位置可能有不同高度比如一个网格可能越过天桥、地面、地下车库。所以模型在z方向上也做了采样论文默认在z轴上均匀采样4个点每个点再在2D图像上对应一个投影位置。具体操作分三步。第一步取BEV Query中心点对应的3D坐标(x, y, z)通过相机内外参投影到每个相机的像素坐标系得到像素坐标(u, v)。第二步如果这个像素坐标落在图像范围之外就跳过这个相机如果落在图像内就以这个像素为中心用可变形注意力在周围再采样4个偏移点。第三步对落在有效范围内的所有采样点做注意力聚合把2D特征“搬”回到3D网格上。这个过程中有一个我踩过的坑论文里说的参考点采样不只是采样那4个高度位置。每个高度位置在图像上还会扩展出4个偏移点。所以每个BEV Query在单个相机上最多有16个采样位置。你如果不看代码只读论文很容易漏掉这层细节导致复现的模型效果和论文对不上。3.3 Temporal Self-Attention让网络“记得”上一帧时间信息在BEV感知里非常重要。一辆静止的车和一个正在起步的车在单帧图像上看起来几乎一样只有通过时序才能判断它的运动状态。BEVFormer处理时间信息的方式是在每帧BEV Query进入空间注意力之前先和历史BEV特征做一次自注意力。这里有个关键步骤历史BEV特征必须先做对齐。上一帧的自车位置和当前帧不一样直接做注意力会错位。论文的做法是用两个时刻之间的自车位姿变换把上一帧的BEV特征做一次坐标变换也叫warp变换到当前帧的坐标系下。所有物体在空间上对齐之后再和当前帧的BEV Query拼在一起做注意力。做时序融合的时候还有一个特殊情况如果是推理的第一帧没有历史BEV可用。论文的处理方式是让模型在训练时随机丢弃部分帧的历史BEV用一组可学习的参数去代替缺失的历史特征。这样模型就学会了自己区分“有历史”和“没有历史”两种情况实际部署时即使第一帧也能正常工作。我用实际效果说明这个模块的价值单独关闭时间自注意力模型NDS大概会掉4到5个点检测稳定性和速度估计都会明显变差。时间模块在BEVFormer里是不可或缺的。3.4 多尺度特征映射不同尺度信息都别丢BEVFormer在做空间交叉注意力的时候并不是只在单一尺度的特征图上采样。它会在FPN输出的多个尺度特征上同时进行注意力操作然后把结果融合。这背后的直觉是一个BEV Query投影到图像上时对应目标可能大小不一在不同尺度采样才能确保信息完整。近处目标在小分辨率特征图上占的面积大远处目标在大分辨率特征图上更清晰。多尺度采样相当于让模型戴上了一副可变焦眼镜。工程实现上每层Encoder都要维护一个可学习的尺度权重用来平衡不同尺度特征的贡献。这个设计不算复杂但对最终检测指标的提升非常可观。我在实验里把多尺度改成单尺度mAP直接掉了一个多点NDS也掉了。所以如果你打算简化网络多尺度这块建议保留。4. 训练细节与部署经验4.1 训练参数与资源BEVFormer在nuScenes上的训练配置最开始我是照着论文里的参数表复现的。Backbone用ResNet101-DCN预训练权重初始化训练图像尺寸1600x900BEV网格200x200。优化器是AdamW初始学习率2e-4权重衰减0.01学习率用cosine schedule衰减。整体训练分两个阶段先在纯空间模式下训练不带时间模块跑60个epoch然后加载已训练好的权重把时间模块加进来再微调20个epoch。这个两阶段训练策略非常重要。直接带上时间模块从零训练模型很难收敛因为时空信息互相纠缠梯度信号太复杂。先让模型学会单帧的BEV表示再教它结合历史信息稳定很多。算力方面我自己的单卡A100训练一次完整流程大概要3天左右。8卡并行可以缩短到6到8小时。如果你只有消费级显卡建议把图像分辨率调低一点或者减少Encoder层数能跑通但不追求完整指标。4.2 工程上值得注意的三个trick第一个trick是Pre-Norm。BEVFormer的Encoder层用的是Pre-Norm结构也就是先做LayerNorm再做注意力。这个看起来不起眼的细节直接影响训练的稳定性。我刚开始复现的时候改成Post-Norm训练到中途loss直接炸了。换成Pre-Norm之后整个训练过程平滑很多。第二个trick是混合精度训练。BEVFormer的计算量很大尤其是空间交叉注意力那一层需要投影多个3D点到多个相机图像显存开销高得吓人。开启Apex或者PyTorch自带的AMP混合精度显存能省一半以上速度也快不少。代价是精度几乎无损所以这个优化建议无脑开。第三个trick是检查相机外参标定的精度。这一点非常关键但特别容易被忽略。BEVFormer空间交叉注意力里的坐标投影用的就是相机内外参。如果标定不准确所有BEV Query在地图上的位置都会偏检测框的位置偏移也会非常明显。我实测过外参偏移超过5厘米NDS就能掉2个点左右。跑任何实验之前先确认标定数据没问题。4.3 实际部署时对模型做哪些调整部署到实车上和离线训练不一样算力受限延迟敏感。我一般会做这几项调整。第一减小BEV网格尺寸比如从200x200降到150x150感知范围不变但每个网格代表的物理尺寸变大计算量明显下降。第二把Encoder层数从6层减到3层检测精度会掉但延迟能减半。第三把图像分辨率从1600x900降到1280x720对近距离和中距离目标影响不大远处小目标会略差。还有一个思路是把时间自注意力改成异步模式。实车上历史BEV特征是现成的可以在当前帧还没处理完的时候先用上一帧的BEV特征做一次轻量推理这样整体帧率能提不少。这个方案需要自己写异步调度逻辑但效果立竿见影。5. 常见问题与排查技巧5.1 问题速查表我把复现BEVFormer过程中遇到频率最高的问题整理成了一张表方便快速定位问题现象可能原因排查方法训练时loss不下降学习率过高或预训练权重没加载调低学习率到5e-5检查backbone权重路径检测框整体偏移相机外参标定错误用标定场验证投影点是否对应正确像素BEV特征图有黑边参考点全部投影到图像外检查BEV感知范围是否超过相机视场车辆速度估计错误时间对齐失效检查自车位姿变换是否正确warp历史BEV小目标检测效果差多尺度特征未生效确认FPN输出是否正常检查尺度权重初始化显存不足BEV网格过大或层数过多减半BEV网格或改用混合精度训练5.2 跑代码时最常踩的几个坑第一个坑是数据加载顺序和时间戳对齐问题。nuScenes的数据里6个相机的采集时间戳不是完全同步的如果你不做时间对齐直接用同一时刻的相机数据投影位置就会有很小的时间偏差。虽然差异只有几十毫秒但在高速场景下会造成几厘米到十几厘米的位置误差对精度要求高的场景影响不小。第二个坑是BEV网格坐标系和导航坐标系不一致。有些代码实现里BEV网格的原点设置在自车正下方x轴朝前y轴朝左。如果你习惯用东北天坐标系一定要做坐标变换否则检测结果是歪的。我建议直接复制论文官方代码里的坐标约定别自己改。第三个坑是历史BEV特征没有做梯度截断。时间自注意力模块里历史BEV特征是从之前的帧计算出来的如果每一轮都反向传播到这个历史特征上会形成很长的时间梯度链训练不稳定。我的做法是detach掉历史特征的梯度让模型只通过当前帧的梯度更新。这个改动对训练稳定性帮助很大。还有一个容易被忽略的点——长尾类别样本不均衡。nuScenes数据集里行人和车辆样本占比很大但像自行车、摩托车这种样本少检测率低。BEVFormer本身没有做特殊的类别均衡处理我自己的实验里加一个focal loss的gamma参数调大一点长尾类别会好一些整体指标也不掉。最后再分享一个小细节如果你打算从零复现BEVFormer我建议先把Spatial Cross-Attention单独抽出来做一个单元测试手动构造一对虚拟的3D点和相机内外参验证投影计算是否正确再用一个batch的假数据跑一次正向传播确认shape和预期一致。这三个模块对整体质量影响最大值得每个细节都抠清楚。我早期就是在这里走了弯路最后发现代码里的像素坐标和归一化坐标没换算对导致所有参考点都投影偏了。BEVFormer这篇论文的精髓不在于某一个花哨的模块而在于它把Transformer、几何先验和时间融合这三件事有机地结合在了一起每一块都服务于“重建统一BEV空间”这个目标值得你花时间去吃透。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门