做网站资源,wordpress批量修改字体大小,软文代写代发,aso推广1. 从BEV到Occupancy#xff1a;为什么我们需要更“立体”的眼睛#xff1f; 大家好#xff0c;我是老张#xff0c;在自动驾驶的感知算法领域摸爬滚打了十来年。今天想和大家聊聊一个非常“热”的话题#xff1a;3D环境感知。如果你正在做自动驾驶#xff0c;或者对这个…1. 从BEV到Occupancy为什么我们需要更“立体”的眼睛大家好我是老张在自动驾驶的感知算法领域摸爬滚打了十来年。今天想和大家聊聊一个非常“热”的话题3D环境感知。如果你正在做自动驾驶或者对这个领域感兴趣那你肯定绕不开两个词BEV和Occupancy。它们就像是自动驾驶汽车的两双“眼睛”一双看的是“平面地图”另一双看的是“立体世界”。几年前当BEV鸟瞰图感知范式火起来的时候我们团队都挺兴奋的。终于有个办法能把多个摄像头的画面“拼”在一起形成一个上帝视角的、统一的地图了。这解决了传统2D感知里一个老大难问题遮挡。比如前车挡住了行人在单个摄像头画面里行人就“消失”了但在BEV空间里通过多视角信息的融合我们有可能推断出被遮挡区域的情况。那时候基于LSS、BEVFormer这些方法我们确实把感知的稳定性和范围提升了一大截。但用着用着问题就来了。记得有一次路测我们的车在一个施工路段差点出问题。路面上方横挂了一条施工警示的彩旗离地大概三米。在BEV的“地图”里这条彩旗因为缺乏高度信息被“拍扁”在地面上系统把它识别成了一个地面上的长条形障碍物差点触发不必要的紧急制动。这就是BEV的一个核心局限它本质上是2.5D的。它把世界压扁了只关心物体在X和Y轴上的投影丢失了至关重要的Z轴高度信息。对于悬空的物体、斜坡、隧道顶壁这些有高度变化的场景BEV就显得力不从心。这时候Occupancy占用网络的概念就开始进入我们的视野。它的思路非常直观不再把世界看成一张地图而是把它划分成无数个小小的立方体格子我们叫它“体素”。然后去预测每一个小格子有没有被物体“占用”。这就像一个三维的“我的世界”游戏把真实世界数字化成了一个精细的网格模型。这样一来那条彩旗就能被准确地表达为一系列在Z轴上处于某个高度的“被占用”的格子系统就能明白这是个悬空物不会误判。所以从BEV到Occupancy在我看来是一次从“看地图”到“建模型”的思维跃迁。它不仅仅是算法的升级更是对自动驾驶环境理解完备性的一次深刻补全。接下来我就结合我这几年实战中的经验和踩过的坑带大家深入看看这两种范式到底有什么区别以及我们该怎么根据实际需求来选择和融合它们。2. 核心差异平面地图 vs 立体沙盘要理解怎么选首先得搞清楚它俩到底哪儿不一样。我习惯用一个比喻BEV像是一张精心绘制的二维军事地图上面标明了敌我位置和地形轮廓指挥官可以据此排兵布阵而Occupancy则像一个等比例缩放的三维战场沙盘山川河流、碉堡壕沟的高度、形状都一目了然甚至能看出碉堡有没有顶。2.1 信息维度少了“一层楼”的世界这是最根本的区别。BEV特征是在一个预设的BEV平面上进行编码和计算的。无论你用什么方法LSS的深度分布投影、Transformer的交叉注意力最终得到的都是一个[H, W, C]的特征图。这里的H和W是空间网格C是特征通道。它没有显式的高度通道。所有物体无论是地面上的车还是空中的招牌都被投影到了同一个平面上。Occupancy则直接对三维空间进行离散化形成体素网格特征通常是[X, Y, Z, C]。这个Z维度就是高度。这意味着悬空物体识别天桥、交通灯、悬挂的电缆、楼层牌都能被清晰地表示为在特定高度层上被占用的体素集合。复杂地形理解上下坡、楼梯、路沿的立体形状可以通过不同高度层的占用情况精确刻画。物体完整几何一个斜停的卡车在BEV里可能是一个扭曲的矩形但在Occupancy里你可以看到它从车头到车尾、从底盘到车顶的完整立体占据情况。我在项目里做过对比测试在同一段包含高架桥和桥下道路的场景中BEV模型常常把高架桥的影子投影误认为障碍物或者把桥体本身忽略掉因为训练数据里“天空”区域通常不被关注。而Occupancy模型则能稳定地将高架桥的桥面体素标记在正确的Z轴范围内与桥下道路清晰分离。2.2 对未知物体的态度从“认识”到“感知”这是Occupancy另一个巨大的优势。传统的感知模型无论是2D检测还是BEV检测都是“基于类别”的。模型在训练时见过“车”、“人”、“锥桶”它才能在测试时把这些东西框出来。但如果路上出现一个训练集里没有的物体比如一个翻倒的、形状怪异的家具或者一种新型的特殊工程车辆模型很可能“视而不见”因为它不认识。Occupancy从根本上改变了这个问题。它的任务是判断“这个格子有没有东西”而不是“这个东西是什么”。所以对于任何占据物理空间的物体无论它是什么类别Occupancy模型都有潜力将其标记为“被占用”。这是一种从“识别”到“物理存在感知”的范式转变极大地提升了系统对长尾、未知障碍物的应对能力这对安全性至关重要。我们曾经用仿真引擎生成了一些现实中极少见的障碍物比如一个巨大的球形雕塑加入测试集。BEV检测器在这些物体上的召回率几乎为零而Occupancy模型虽然无法说出它是什么但能稳定地输出一片被占用的体素区域成功触发了系统的避障模块。2.3 计算开销甜蜜的负担当然天下没有免费的午餐。Occupancy带来丰富信息的同时也带来了巨大的计算负担。这是它目前落地的主要瓶颈。BEV的计算主要集中在2D到BEV平面的视图变换View Transformation和BEV平面上的2D卷积/Transformer运算。计算复杂度大致与BEV网格的分辨率H*W成正比。Occupancy的计算引入了第三个维度Z。体素网格的数量是X * Y * Z。即使Z维度分辨率不高比如16层其计算量也远大于同XY分辨率的BEV。3D卷积、3D Deformable Attention等操作都非常耗时。简单算笔账假设BEV网格是200x200特征通道256这就是10万个空间位置。如果Occupancy网格是200x200x16那就是64万个空间位置直接翻了6倍多。这带来的显存占用和推理延迟是惊人的。所以在工程实践中我们不会粗暴地用Occupancy替换BEV而是必须做权衡和优化。比如在算力受限的嵌入式平台上我们可能只在城市复杂场景有大量悬空物和复杂结构启用Occupancy而在高速场景继续使用更轻量的BEV。或者采用稀疏Occupancy方法只对可能有物体的区域进行精细计算。3. 关键技术实战拆解从原理到代码光讲概念有点虚我们直接看几个有代表性的算法聊聊它们的核心思想和实战中的一些细节。我会尽量用代码片段和示意图来帮助理解。3.1 BEV的经典之作LSS与BEVFormerLSSLift, Splat, Shoot是早期将2D图像特征“抬升”到3D空间的经典方法。它的思想很直观Lift抬升对图像每个像素预测一个深度分布比如41个深度区间这样每个像素就变成了一串在射线上的3D点。Splat溅射把这些3D点根据内外参投影到BEV网格上同一个格子里的特征通过求和或求平均进行融合。Shoot规划下游任务使用这个BEV特征。它的优点是物理意义明确但深度估计的准确性是关键瓶颈。代码上深度分布预测通常是一个轻量级网络头。# 伪代码示意LSS的核心步骤 class LSSViewTransformer: def lift(self, image_features, depth_distribution): # image_features: [B, N, C, H, W] N个相机C通道 # depth_distribution: [B, N, D, H, W] D个深度区间 # 生成每个像素在每个深度下的3D点坐标和特征权重 points_3d, weights self._generate_3d_points(image_features, depth_distribution) return points_3d, weights def splat(self, points_3d, weights, bev_grid): # points_3d: [B, N, H*W*D, 3] 3D坐标 # weights: [B, N, H*W*D, C] 特征权重 # bev_grid: 预设的BEV网格 # 将点云特征“溅射”到BEV网格上常用体素池化Voxel Pooling或累积求和 bev_features self._voxel_pooling(points_3d, weights, bev_grid) return bev_features # [B, C, H_bev, W_bev]BEVFormer则采用了完全不同的思路它利用Transformer的注意力机制让模型自己学习如何从多视角图像中查询BEV特征。它定义了一组可学习的BEV Query每个Query代表BEV网格中的一个位置。然后通过时空交叉注意力让这些Query去参考多摄像头、多历史帧的图像特征。# 伪代码示意BEVFormer的时空交叉注意力 class SpatialCrossAttention(nn.Module): def forward(self, bev_query, image_features, camera_params): # bev_query: [B, H_bev*W_bev, C] # image_features: 多视角图像特征列表 # 1. 将bev_query投影到各个相机视角 # 2. 在每个视角下通过可变形注意力Deformable Attention采样参考点周围的图像特征 # 3. 聚合所有视角的特征 attended_features deformable_attn(bev_query, image_features, reference_points) return attended_featuresBEVFormer的强大之处在于其时序融合能力通过引入历史BEV Query它能构建一个具有时间连续性的BEV特征对运动预测非常友好。但它的计算量也很大对工程优化要求高。3.2 Occupancy的先锋VoxFormer与TPVFormer当大家意识到BEV高度信息缺失的问题后Occupancy网络开始涌现。这里我挑两个有代表性的讲讲。VoxFormer的思路很巧妙它知道直接处理稠密3D体素计算量太大所以采用了“由粗到精从稀疏到稠密”的策略。它先用一个轻量的网络比如基于BEV生成一个稀疏的3D提案Proposal这些提案是一些可能包含物体的3D区域。然后只在这些提案区域内部使用更强大的Transformer进行精细化的特征提取和占用预测。这就像先让一个“侦察兵”快速扫描战场标记出可能有敌人的区域然后再派“主力部队”去这些区域仔细清剿。# VoxFormer 核心步骤伪代码 class VoxFormer(nn.Module): def forward(self, image_features): # 第一阶段生成稀疏提案 # 例如使用一个BEV检测头输出3D框或者3D前景掩码 sparse_proposals self.proposal_head(image_features) # [B, N_proposal, 4] (x,y,z,size) # 第二阶段基于提案的精细化Occupancy预测 # 1. 以提案为中心初始化一组3D Query voxel_queries self._init_queries_from_proposals(sparse_proposals) # 2. 3D Query与多视角图像特征做可变形注意力提取特征 voxel_features self.deformable_cross_attn(voxel_queries, image_features) # 3. 预测每个Query对应区域的稠密占用和语义 occupancy_pred self.occ_head(voxel_features) return occupancy_pred这种方法极大地减少了需要处理的体素数量让高分辨率Occupancy预测成为可能。我们在部署时发现VoxFormer在保持较高精度的同时其计算量比纯稠密的方法可控得多。TPVFormer则提供了另一种优雅的思路。它认为直接用(X,Y,Z)三轴定义体素网格计算复杂于是提出了三视图Tri-Perspective View, TPV表示。它将3D空间分解为三个正交的2D平面俯视图XY平面、前视图XZ平面、侧视图YZ平面。每个点在这三个平面上都有投影。模型分别学习这三个平面的特征然后通过一个简单的公式如特征相加就能还原出任意3D点的特征。对于一个3D点P(x, y, z) 其特征 F(P) F_xy(x, y) F_xz(x, z) F_yz(y, z)TPV的妙处在于它将3D问题转化为了三个2D问题可以充分利用成熟的2D CNN/Transformer架构计算效率很高。特斯拉的Occupancy Network据说就采用了类似的思想。在实际调参中如何设计三个视图的特征交互和融合模块是关键。3.3 多模态融合让视觉与激光雷达互补纯视觉的Occupancy受限于图像本身的几何信息不足单目深度估计不准在距离和形状的绝对精度上有时会打折扣。而激光雷达能提供精确的3D点云但点云非常稀疏远距离和细小物体容易漏检。因此视觉激光雷达的多模态Occupancy是业界公认的高精度方案。融合不是简单地把特征拼起来。我经历的项目里试过几种方式早期融合数据级将点云投影到图像上或者将图像特征反投影到点云上在原始数据层面就进行关联。这种方式紧密但对传感器标定误差非常敏感一个像素的偏差可能导致融合失败。中期融合特征级这是最主流的方式。视觉分支通过LSS或Transformer得到3D体素特征V_vision激光雷达分支通过3D稀疏卷积或PointNet得到体素特征V_lidar。然后进行融合拼接ConcatF [V_vision; V_lidar]简单但特征维度翻倍。加权求和F α * V_vision (1-α) * V_lidarα可以是可学习的参数。注意力融合用V_vision作为QueryV_lidar作为Key和Value通过交叉注意力让视觉特征去查询相关的激光雷达特征这是效果最好的方式但计算量也最大。后期融合决策级两个分支独立预测出Occupancy结果然后通过规则如取置信度高的或一个小网络进行融合。这种方式鲁棒性强但损失了特征间的互补信息。我们目前线上系统采用的是特征级注意力融合。一个实用的技巧是由于激光雷达特征通常更几何可靠我们会让它作为Key和Value让视觉特征作为Query去“请教”激光雷达这样能有效校正视觉深度估计的偏差。4. 工程落地数据、训练与部署的挑战算法好看但真正要用到车上挑战才刚刚开始。Occupancy的落地难度比BEV高出一个数量级。4.1 数据之痛标注成本与质量Occupancy需要的是稠密的3D体素真值Ground Truth。想象一下你要把整个场景像切豆腐一样切成无数小方块然后人工标注每个方块里有没有东西、是什么东西。这几乎是不可能完成的任务。所以现在主流的做法比如nuScenes Occ3D数据集是利用多帧激光雷达点云自动化工具来生成伪真值。流程大致是聚合几十帧甚至上百帧的点云利用车辆自身的定位信息进行对齐。区分静态和动态物体。静态场景直接叠加动态物体需要估计其运动轨迹进行运动补偿后再叠加。这一步非常关键处理不好就会产生“鬼影”。对叠加后的稠密点云进行三维重建如使用TSDF、NeRF等技术生成一个连续的表面网格Mesh。将这个Mesh体素化得到稠密的Occupancy标签。最后还要结合相机图像进行可见性推理和精修剔除那些在相机视角下根本看不到的体素比如墙后面的体素因为你的模型是基于视觉的预测看不到的东西没有意义。即使这样数据的质量依然是瓶颈。我们自己在制作数据时最头疼的就是动态物体的“拖影”和地面“浮点”的清理。一个快速移动的车辆在多帧聚合后可能会拉出一条很长的“尾巴”这不是真实的占据。地面上的噪点如反射、灰尘也可能被误认为是障碍物。这些都需要大量的后处理算法和人工检查。4.2 模型训练损失函数与评估陷阱Occupancy模型的输出是一个三维的概率网格每个格子有一个“占用概率”和一个“语义类别”。因此损失函数通常是两部分几何损失常用带权重的二元交叉熵BCE或Dice Loss。由于场景中大部分体素是空的Free类别极度不均衡必须给被占用的体素前景赋予更高的权重。语义损失对于被占用的体素还需要用交叉熵损失来监督其类别预测。一个重要的细节是对于“未知”或“不确定”的体素在训练时应该被忽略Ignore不参与损失计算。这就是前面提到的“可见性掩码Visible Mask”。说到评估最常用的指标是mIoU平均交并比。但这里有个大坑Occ3D-nuScenes等数据集在计算mIoU时默认只计算相机可见区域的体素。这会导致一个严重问题模型会倾向于预测一个“厚表面”。比如一堵墙只要模型预测的厚度能覆盖住真实的墙面多预测出来的、墙后面的部分因为“不可见”而不被计入FP假阳性这样IoU就会很高。这显然是不合理的会严重高估模型性能。因此在学术界现在更推崇使用RayIoU或几何mIoU这类更严格的指标它们会考虑整个3D空间的预测或者沿着相机射线进行评估避免了“厚表面投机”的问题。我们在内部评估时一定会同时看多种指标并且会可视化3D预测结果肉眼检查那些“膨胀”的预测。4.3 部署优化让模型跑在嵌入式芯片上这是最大的挑战。一个中等分辨率如200x200x16的稠密Occupancy模型参数量可能不大但中间激活值Activation占用的显存和计算量是恐怖的。我们必须进行全方位的优化稀疏化这是最有效的路径。借鉴VoxFormer的思想使用一个轻量级的“引导网络”先找出可能被占用的区域只在稀疏的区域进行计算。或者使用完全稀疏的卷积网络只处理非空的体素。知识蒸馏用一个庞大的、精度高的教师模型Teacher来训练一个小的学生模型Student。让学生模型不仅学习真实标签还学习教师模型的输出分布“软标签”往往能获得比直接训练小模型更好的效果。量化与编译将模型从FP32量化到INT8甚至INT4可以大幅减少内存占用和加速计算。然后利用TensorRT、CANN等推理框架针对特定的硬件如NVIDIA Orin华为昇腾进行图优化和算子融合榨干硬件性能。模型剪枝分析模型中不重要的通道或权重将其裁剪掉减少模型大小和计算量。我们团队花了近半年时间才将一个研究版的Occupancy模型优化到能在车规级芯片上以10Hz的频率稳定运行。这个过程充满了各种“坑”比如量化后精度暴跌、稀疏操作导致内存访问不连续反而更慢、自定义算子不被推理框架支持等等。每一个点都需要算法工程师和底层优化工程师紧密配合去攻克。5. 如何选择与融合给工程师的实战指南看到这里你可能会问到底该用BEV还是Occupancy我的答案是看阶段看场景看资源。1. 研发阶段与量产阶段研发/前沿探索强烈建议从Occupancy入手尤其是多模态Occupancy。它能给你最丰富的3D环境表示是构建下一代感知系统的基石。即使暂时无法部署其输出的真值或中间特征也可以作为BEV模型训练的强监督信号或辅助任务提升BEV模型的能力。量产/当前项目如果算力预算紧张且主要运行在结构化道路高速、城市快速路高性能的BEV模型仍然是性价比最高的选择。它的技术栈更成熟部署工具链更完善。可以优先把BEV做到极致。2. 场景驱动城市NOA导航辅助驾驶场景极其复杂有大量的悬空物体红绿灯、招牌、天桥、行人天桥、不规则障碍物施工围挡、临时摆放的物体。Occupancy的优势非常明显甚至是必须的。高速NOA场景相对简单障碍物主要是车辆且基本都在地面。BEV完全够用而且速度更快。泊车/低速场景对近距离、低矮障碍物马路牙子、石墩、小孩的感知要求高。Occupancy的精细几何表示很有用但也可以考虑用稠密BEV增加高度维的离散化作为折中方案。3. 融合策略最理想的路线不是二选一而是BEV与Occupancy的协同。我目前看到比较有前景的架构是BEV作为基础感知层一个轻量、快速的BEV网络负责处理大部分常规感知任务车道线、车辆、行人检测并提供给规划控制模块实时结果。Occupancy作为增强与安全冗余一个稍慢但更精细的Occupancy网络异步运行。它主要用于处理BEV的疑难案例当BEV对某个区域的判断置信度低时查询Occupancy的结果。提供未知障碍物检测作为安全冗余检测BEV不认识的物体。构建高精动态地图离线或在线生成更精细的周围环境占据栅格用于更长期的规划。在模型设计上也可以让两者共享大部分特征提取骨干网络Backbone只在头部Head进行分化一个输出BEV特征图一个输出Occupancy网格这样可以最大程度复用计算降低总开销。这条路我们正在探索初步效果显示这种“BEV为主Occupancy为辅”的架构能在增加有限计算成本的情况下显著提升系统在复杂场景下的鲁棒性和安全性。毕竟对于自动驾驶来说安全永远是第一位的而多一份不同维度的环境理解就多一份保障。