资讯动态

OmniDrive:端到端自动驾驶的多模态大模型实践

发布时间:2026/10/26 5:07:36 来源:尧图企业网站定制
做自动驾驶算法的人大概都有过这种体验感知模块跑得挺稳检测框画得也漂亮可一旦要回答“前面那辆车为什么在减速”“左边这条窄道能不能借一下”这类问题整条链路就哑了。传统模块化架构把感知、预测、规划切成三段每段各自优化各自的指标中间靠一层低维符号检测框、车道线、轨迹点传递信息信息在这一层被压得很扁。OmniDrive 这个方向想干的事情就是把这层“压缩”拆掉让一个模型同时吃下多视角图像、点云、历史轨迹和自然语言指令直接吐出可执行的行驶决策与轨迹。它解决的不是某个单点精度问题而是感知—推理—规划三者在表示层面割裂这个结构性毛病。这篇内容适合两类人看一类是想把大模型往车端塞、但被时延和显存卡住的工程同学另一类是想搞清楚“全模态驾驶智能体”到底怎么做数据对齐、怎么做训练调度的算法同学。下面我按自己趟过的顺序把这套东西拆开讲。1. 为什么非要把感知、推理、规划塞进同一个模型1.1 模块化链路的三处硬伤先说清楚痛点在哪不然“端到端”就只是个时髦词。模块化链路的第一处硬伤是信息不可逆丢失感知模块输出的是三维框和类别一帧画面里几万个像素被压缩成几十个向量纹理、光照、遮挡关系、路面材质的湿滑程度全没了。规划模块拿到这些符号只能靠规则和经验去猜遇到“前车尾灯没亮但在缓慢下沉”这种隐含制动意图的场景符号层根本没有对应字段可填。第二处是目标函数互相打架。检测头优化的是 mAP追求召回率宁可多报几个假框规划模块追求的是舒适性和安全性希望输入干净、少抖动。两个目标在联合训练时梯度方向并不一致中间又隔着一层不可导的 NMS梯度传不回去只能各训各的。第三处是长尾场景的规则爆炸每发现一个 corner case 就打一个补丁补丁之间还会互相冲突维护成本随时间指数上升。这三处加在一起就是为什么很多团队感知指标刷得很高实际路测体验依然僵硬。OmniDrive 的思路是把这三段合成一条可导的链路几何特征不经过符号化直接进入语言模型的表示空间规划输出也从“规则生成”变成“模型解码”。这样做的好处是梯度能从最终轨迹回传到图像编码器坏处是训练难度和推理成本都上了一个台阶——后面我会专门算这笔账。1.2 一个模型吃三件事的整体架构取舍架构上最核心的取舍是用什么样的中间表示把视觉几何和语言语义缝在一起。可选方案大致三种。第一种是纯文本桥接把感知结果转成一段描述性文字喂给大模型实现最简单但几何精度全丢相当于绕了一圈又回到符号化。第二种是纯 cross-attention 桥接让语言模型的每一层都去 attend 图像特征表达能力强但 token 数量爆炸7B 模型配上六路高分辨率图像显存直接翻车。OmniDrive 走的是第二条路的收敛版本先用一组可学习的 3D query 把多视角图像压成固定数量的稀疏 token再把这一小撮 token 投影进语言空间。固定数量是关键——它把视觉侧的 token 预算从“随分辨率线性增长”变成“常数”后面无论加多少路相机、提多高分辨率进语言模型的 token 数都是可控的。这是我实测下来最实用的一招也是整个框架能跑在车端算力上的前提。缺点也明显query 数量有限密集小目标远处锥桶、路面坑洞容易被漏掉需要靠额外的占用栅格头兜底。1.3 什么样的团队值得跟进这套思路不是所有人都该上这套。我的判断标准有三条一是你手上已经有带语言标注或可自动生成语言标注的多模态数据没有数据这块模型再漂亮也是空转二是你的算力至少能支撑一次 7B 级别模型的多卡联合训练哪怕只是 LoRA单卡 24G 是绝对不够的三是你的产品场景对“可解释”有需求比如需要向乘客解释为什么变道、为什么绕行纯数值规划器说不出人话。三条里满足两条以上这套路线就值得投入只满足一条建议先在仿真里做小规模验证别急着上车。2. 数据与模态输入到底长什么样2.1 六路环视图像、稀疏点云与文本指令的统一表示OmniDrive 的输入是异构的得先统一到同一套“帧 坐标系 时间戳”的规范下。图像侧一般是六路环视相机前视分辨率最高侧后视可以适当降采样我通常配成前视 1600×900、其余 800×450理由是前视承担了绝大部分远距离目标和交通标志识别任务侧后视主要用于近距离加塞和变道判断不需要那么高的解析度。点云侧是激光雷达的稀疏点不一定每一帧都同步可以按最近邻时间戳对齐或者干脆把点云只用作训练期的几何监督推理时不输入——后者在成本敏感的量产方案里更常见。文本侧是很多人容易做糙的地方。指令不能只有“向前行驶”这种废话得覆盖三类导航级指令“前方路口左转进辅路”、交互级指令“礼让右侧汇入车辆”、解释级问答“刚才为什么减速”。前两类用于训练规划第三类用于训练推理链。坐标系统一尤其要盯死所有真值轨迹必须落在自车当前帧的局部坐标系角度用弧度且范围统一到 [-π, π]一旦混进全局坐标系模型学到的就是“我在世界地图上的绝对位置”换个城市立刻失效。这个坑我踩过loss 曲线看着正常验证集上轨迹偏差却大得离谱查了两天才发现是某批数据的坐标系没转换。2.2 三维占用与检测标注如何跟语言对齐语言和几何的对齐不能靠模型自己悟得在数据层面给出锚点。具体做法是每条涉及空间关系的问答都绑定一组三维标注 ID。比如问“左前方那辆白色货车离我多远”答案里的“白色货车”对应一个具体的 3D 框 ID“12 米”对应这个框中心到自车中心的欧氏距离。这样训练时语言侧的 token 和几何侧的 query 就有了显式的对应关系模型不用从零学“哪个词指哪个物体”。占用栅格的标注更麻烦。公开数据集里的占用标注通常是体素级的 0/1 标签分辨率 0.4 米左右但语言问答题里经常会问“这条路能不能过”答案需要对通行性做出判断而不是逐个体素分类。我的做法是加一层轻量的几何后处理把自车前方一条走廊宽度约 3 米、长度 30 米内的体素统计出来占用率低于阈值就判为可通行再把这个判定和对应的问答对绑起来。这样语言侧的“能不能过”就有明确的数值来源不会变成模型瞎猜。2.3 数据配比与采样策略的实操心得配比这块没有标准答案但有几点是我试出来的经验。第一语言数据不要追求量大要追求分布均衡感知类问答、预测类问答、规划类问答、解释类问答大致按 3:2:3:2 分配某一类超过 40% 模型就会偏科问它“为什么”它给你背检测结果。第二长尾场景要过采样但不能只过采样雨天、夜间、隧道出口这些场景建议按 2 到 3 倍采样再高会让模型对正常天气的泛化变差。第三空帧要留连续几帧没有任何目标的空旷路段也得保留一定比例否则模型一看到空旷就慌输出莫名其妙的减速。采样策略上我用的是“场景簇均衡 帧级随机”的混合方式先把数据按场景类型城市拥堵、高速巡航、路口、泊车聚类每个 epoch 从每个簇里等量抽簇内再随机抽帧。这样能避免高速场景帧数多就把城市复杂场景淹掉的问题。代价是每个 epoch 的数据顺序不可复现调试时得固定随机种子。3. 核心结构与关键实现细节3.1 视觉编码与三维特征构建视觉主干我建议用 ViT 系列而不是 ResNet原因是 ViT 的 patch 表示更容易和语言 token 做维度对齐而且多尺度特征融合更自然。六路图像分别过共享权重的 backbone得到每路的多尺度特征图然后做视角变换。视角变换有两条主流路线一条是 LSS 式的显式深度分布预测加外积投影优点是几何可解释缺点是对深度估计误差敏感另一条是 BEV query 加 cross-attention 的隐式查询优点是精度高缺点是训练慢、显存吃紧。我的选择是混合近距离0 到 20 米用 LSS 显式投影保证精度远距离20 米以外用稀疏 query 查询保证效率。这个分界线不是拍脑袋定的是根据相机标定误差算出来的——20 米外像素级深度误差已经超过 1 米显式投影的收益被误差吃掉了不如交给 query 去学。BEV 网格分辨率我用 0.5 米范围前后 100 米、左右 50 米算下来是 200×200 的栅格特征通道 256这一层特征就是后面所有感知头的公共底座。3.2 查询式感知头目标、地图、占用三类 queryquery 的设计是整个框架的骨架我把它分成三类各自有独立的初始化方式和更新逻辑。目标 query初始化自 BEV 特征上的高响应点数量固定为 300 个负责检测动态目标输出中心点、尺寸、朝向、速度。地图 query数量 100 个负责矢量化的车道线、路沿、停止线初始化用均匀网格撒点再加位置编码因为地图元素分布比较均匀不需要靠特征响应去引导。占用 query数量 64 个不做显式监督只作为稠密几何的压缩桶把 BEV 特征里没法被前两类 query 覆盖的残余信息兜住。三类 query 之间要有交互我用的是交替的 self-attention 加 cross-attentionself-attention 在同一类内部做cross-attention 让目标 query 去查询地图 query 的上下文判断这个目标是不是停在车道里再让所有 query 去查询 BEV 特征。这个顺序很重要反过来先查 BEV 再做类间交互模型会倾向于把地图元素也当成动态目标导致车道线被预测出速度。这个细节文档里不会写但影响很大。3.3 语言主干与跨模态投影层语言主干选 7B 级别的开源模型做底座具体型号看你的许可证约束。关键在于投影层怎么设计。最省事的方案是一个两层 MLP把 query 输出的 256 维特征映射到语言模型的隐藏维度参数量小、训练快但表达能力有限复杂空间关系“第二辆车后面那个骑车的”学不好。更重的方案是 Q-Former 式的可学习查询池用一组固定的 latent query 去“读”感知特征再交给语言模型表达能力强但多一层训练难度。我用的是折中方案MLP 加一层轻量 cross-attentioncross-attention 的 query 是语言 token 的嵌入key/value 是感知 query 的输出。这样语言侧可以按需去“取”几何信息而不是被动接收一堆固定 token。实测下来涉及多目标空间关系的问答准确率比纯 MLP 高约 8 个百分点参数量只多了不到 20M。训练时注意投影层的学习率要比主干高一个数量级否则它收敛太慢主干会先过拟合到语言任务上。3.4 从推理到轨迹输出头的落地形式轨迹输出有两种形式回归和离散 token 分类。回归直接吐连续坐标简单但容易抖离散化把前方可行区域切成格子横向 0.5 米一档、纵向 1 米一档、时间维 0.5 秒一档每一步预测落在哪个格子里稳定但精度受格距限制。OmniDrive 这类框架普遍用离散 token因为要和语言模型的词表统一——轨迹 token 就是词表里额外扩出来的一批特殊 token模型输出它们就像输出文字一样自然。我的配置是预测未来 4 秒每 0.5 秒一个点共 8 个轨迹点每个点用横纵向两个离散 token 表示所以一条完整轨迹是 16 个 token。词表扩展 2048 个横向 32 档 × 纵向 64 档比直接扩几万个连续 bin 要省显存。推理时用受限解码只在轨迹 token 集合里采样避免模型输出“前方 3 米左转 90 度”这种物理上不可能的结果。这里要加一层运动学约束相邻两个轨迹点之间的横向偏移不能超过对应时间内的最大侧向加速度所允许的距离超了就回退到上一帧轨迹做平滑。4. 训练流程与实操复现要点4.1 显存预算估算与硬件配置先把账算清楚不然方案设计得再漂亮也跑不起来。假设视觉主干用 ViT-L约 300M 参数语言主干 7B投影层 20M感知头约 50M总参数量约 7.4B。bf16 精度下纯权重占 14.8GB。优化器用 AdamW一阶二阶动量各占一份又是 29.6GB。梯度占 14.8GB。这三项加起来已经 59GB还没算激活值。激活值的大头在视觉侧六路 1600×900 图像patch size 14每路约 7200 个 patch token六路合计 43000 多个 token经过 24 层 ViT每层都要存 attention 矩阵。用梯度检查点gradient checkpointing可以把激活降到原来的三分之一左右代价是训练速度慢 25% 到 30%。语言侧用 LoRArank 16冻结主干可训练参数降到 40M 左右优化器状态基本可以忽略。这么算下来单卡 80G 跑 batch size 1 是可行的想上 batch 8 至少需要 8 卡配 ZeRO-2或者 16 卡配 ZeRO-3。我实际跑的配置是 8 卡 80G、ZeRO-2、梯度累积 4 步等效 batch 32单步耗时约 2.3 秒。4.2 三阶段训练对齐、联合、指令微调一次性端到端训这套东西几乎必然失败我的经验是拆成三个阶段。第一阶段只训感知冻结语言主干只训视觉主干、感知头和投影层损失用检测的 L1 加 GIoU 加 focal、占用的交叉熵。这一阶段的目标是让 query 学到有物理意义的几何表示大概跑 20 个 epoch检测 mAP 收敛到接近纯感知模型的水平。第二阶段才是联合训练解冻投影层和语言侧的 LoRA让语言损失next-token 交叉熵加进来权重给 1.0感知损失权重降到 0.5。这一步最危险语言损失的梯度很容易把刚训好的几何表示冲垮表现为检测指标突然掉一截。我的应对是视觉主干保持冻结只让感知头和投影层参与联合优化同时监控检测损失一旦连续三个 epoch 上升就回滚学习率。第三阶段做指令微调加入解释类问答和复杂交互指令学习率降到第二阶段的十分之一只训 LoRA 和投影层。这一阶段数据量不用大几万条高质量样本足够重点是把模型的“说话方式”调顺别让它输出一堆标点混乱的检测字段。4.3 损失函数与关键超参配置损失函数是几路加权求和权重怎么定直接影响最终表现。我的配置如下loss_cfg { cls: {weight: 2.0, type: focal, gamma: 2.0, alpha: 0.25}, box_l1: {weight: 0.5, type: l1}, box_iou: {weight: 1.0, type: giou}, map: {weight: 1.0, type: l1_line}, occupancy:{weight: 1.5, type: bce, pos_weight: 3.0}, traj_cls: {weight: 2.0, type: ce, label_smooth: 0.1}, traj_l1: {weight: 0.5, type: l1}, lang: {weight: 1.0, type: ce, ignore_index: -100}, }几个值得说的点分类损失给 2.0 是因为正样本极少权重低了模型会倾向于全预测背景占用损失的 pos_weight 给 3.0 是为了对抗体素级正负样本极度不均衡这个值不要超过 5否则模型会把整片空间都预测成占用看起来召回很高实际没法用轨迹分类损失加 label smooth 0.1 是为了抑制抖动让相邻轨迹 token 的分布别太尖锐。语言损失的 ignore_index 一定要设对padding 位置不屏蔽的话模型会把大量算力浪费在学“怎么输出 padding”上。学习率方面视觉骨干用 1e-5如果是微调预训练权重感知头 1e-4投影层 5e-4LoRA 用 2e-4。整体用 cosine 衰减warmup 比例 0.05。梯度裁剪阈值设 1.0这套多任务联合训练里梯度爆炸是家常便饭裁剪比调学习率更管用。4.4 评测指标与验证方式只看一个 mAP 是自欺欺人。我关注四组指标检测侧看 mAP 和 NDS 类综合分占用侧看 IoU 和特定类别行人、车辆、可行驶区域的分项 IoU规划侧看位移误差、碰撞率、舒适度分项加速度抖动、横摆角速度超限比例语言侧看问答准确率和幻觉率。幻觉率这个指标特别重要——模型有没有编造不存在的物体直接决定了这套系统能不能被信任。我的测法是固定一组包含已知目标数量的场景统计模型描述中出现的不存在目标数超过 5% 就要回去查投影层和数据对齐。验证集一定要按场景切分不能按帧随机切。同一段路的相邻帧如果一半在训练集一半在验证集指标会虚高十几个点这一点在时序模型里尤其明显。我一般按地理位置加时间段做双重切分比如用三个城市的早高峰、两个城市的夜间数据做验证这样测出来的指标才敢拿去汇报。5. 常见问题与排查手记5.1 损失震荡与梯度异常联合训练阶段损失震荡是最常见的问题表现是语言损失正常下降检测损失上下横跳。八成是梯度冲突不是学习率问题。排查方法很简单分别打印感知头和语言侧的梯度范数如果感知侧范数比语言侧高一个数量级以上就是量级失衡。我的解法是给两路损失各加一个可学习的权重uncertainty weighting让模型自己调平衡如果不想引入额外参数就手动把感知损失权重乘上梯度范数的反比做归一化。还有一种情况是 loss 直接变 NaN通常出在占用头的 BCE 上。浮点下溢会导致 log(0)加个 1e-7 的 eps 就好。另外注意混合精度训练时投影层的 cross-attention 里 softmax 容易溢出把那里的 attention 计算强制转成 fp32代价很小但能省掉几天的排查时间。5.2 语言能力退化与“只会报框”现象训到第二阶段模型经常变成“只会报检测结果”的复读机问它为什么减速它回一句“前方有车”。这是灾难性遗忘的典型表现几何梯度过强把语言能力压没了。三个手段组合使用一是在联合训练时混入 10% 到 20% 的纯语言通用数据保持语言模型的基础能力二是 LoRA 的 rank 别调太小16 是下限复杂推理任务建议 32 到 64三是分阶段解冻先只训投影层等语言损失稳定了再开 LoRA。另一个隐蔽的问题是指令跟随失效模型忽略“缓慢”“尽快”这类程度副词。查下来往往是数据里这类词太少。解决办法是在生成问答对时对同一条轨迹配多个不同语气、不同紧急程度的指令描述让模型学会把措辞差异映射到轨迹差异上。5.3 轨迹抖动与物理不合理输出轨迹抖动有两种来源得分开治。一种是 token 级抖动相邻两帧输出的轨迹 token 跳变属于解码不稳定用温度采样加 top-k 限制能缓解或者干脆对输出做时序平滑。另一种是物理抖动轨迹本身合理但二阶导不连续乘客坐着难受。后者要在训练时加约束最简单的做法是加一项加速度惩罚损失把相邻三个轨迹点的加速度算出来超过阈值就罚。还有一种更麻烦的情况模型输出的轨迹在几何上不撞任何东西但明显违反交通规则比如在实线处变道。这类问题靠纯数据驱动很难根治我的做法是加一层轻量的规则校验把车道线和轨迹做几何相交判断越线就重采样。这层校验放在后处理里不参与训练成本低且可控。5.4 常见问题速查表现象可能原因排查手段处理方式检测 loss 正常但 mAP 停滞query 初始化退化全部挤在同一区域可视化 query 的中心点分布加 query 间斥力损失或改用匈牙利匹配占用预测全为占用pos_weight 过大或标签泄漏统计预测正例比例把 pos_weight 降到 2 以内检查标注语言问答全是模板句指令微调数据多样性不足抽样看训练集问句长度分布补数据增加句式变换轨迹整体偏移一个固定量坐标系转换矩阵有误用真值轨迹反投影验证检查外参和时间戳对齐推理时延翻倍KV cache 未复用或图像 token 未裁剪分段计时开启 cache裁掉边缘视角的低价值 token夜间场景性能断崖训练集夜间样本占比过低按光照条件分组统计过采样夜间并加亮度扰动增强6. 车端部署的算力账与时延控制6.1 推理时延的分段拆解与优化手段训练能跑通只是第一步上车才是硬仗。目标定在 10Hz 输出也就是 100 毫秒一帧的预算。拆开来看六路图像预处理加骨干推理大约 35 毫秒用 TensorRT 量化到 INT8ViT-L 在中等算力平台上大概就是这个量级query 更新和感知头 15 毫秒投影层加语言模型解码 40 毫秒轨迹后处理与规则校验 5 毫秒。加起来 95 毫秒卡得死死的没有任何余量。优化重点在语言模型这一侧。7B 模型逐 token 解码光生成 16 个轨迹 token 就要走近十次前向成本很高。我的做法是把轨迹输出从自回归改成一次性并行输出轨迹 token 之间没有强因果关系不需要一个个生成直接用一个轻量 MLP 头并行吐出 16 个位置的概率分布。这样语言模型只需要跑一次 prefilling时延能压到 20 毫秒以内。代价是丢掉了一点 token 间的依赖建模实测对轨迹质量影响在 2% 以内完全可接受。6.2 安全兜底与降级策略再漂亮的模型也得有兜底。我的设计是双通道主通道是 OmniDrive 端到端输出备份通道是一个轻量的规则规划器只吃感知框和车道线。正常情况下主通道结果经过几何合法性校验是否撞障碍、是否越实线、加速度是否超限后下发校验不通过或者模型推理超时立刻切到备份通道切换延迟控制在 10 毫秒以内。降级还要分等级算力紧张时先砍掉语言解释输出乘客侧功能保留轨迹再紧张就降低图像分辨率最极端情况直接退到纯感知加规则。这套分级策略我建议在仿真里就把每一级的触发条件跑一遍别等到实车才发现切换逻辑有死循环。6.3 后续可以继续深挖的方向这套框架目前还有几个明显的短板。一是长时序记忆基本没有模型对三秒前发生过什么只有一个模糊的印象加塞博弈类场景吃亏可行的方向是引入轻量的时序记忆模块把历史 query 做压缩存起来。二是多智能体交互建模粗糙现在只把周围车辆当成静态几何没有建模它们的意图可以尝试在 query 之间加一层意图预测头。三是数据闭环还没打通模型在实车上遇到的新场景怎么自动筛选、自动标注、自动回流这部分工程量比模型本身还大。我在实际项目里的体会是这套东西真正的门槛不在模型结构而在数据管线的规范程度。坐标系、时间戳、标注一致性、语言问答的生成质量这四样里任何一样出问题模型表现都会莫名其妙地差而且极难定位。所以如果你的团队正准备上手我建议先花两周把数据规范文档写死、把自动化校验脚本跑通再动模型代码。磨刀不误砍柴工这句话在这个方向上格外成立。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑