做自驾算法这么多年,回头看这个标题,问的其实就是两个事:平时到底在折腾什么,以及模型性能上不去的时候都在干什么。很多人以为自驾算法工程师天天在写高大上的模型结构,实际上大部分时间都在跟数据、评测、bad case 打交道。这篇文章我把自己在这些年的工作习惯、踩过的坑、以及提升模型性能的完整思路整理出来,不敢说绝对正确,但都是亲测有效的东西。
1. 自驾算法的日常工作切片:从数据到模型再到实车验证
1.1 一天的工作从看 bad case 开始
不管你是做感知、预测还是规划,早上到工位的第一件事,我建议不是打开训练脚本看 loss,而是先看昨天的评测结果或者路测反馈里新出现的 bad case。这些坏例子是模型性能最直接的镜子,也是你这一天工作方向的起点。
举个例子,如果你的任务是车道线检测,昨天夜里车队在某座大桥上拍到了一批弯道曲率极大的场景,模型把对向车道线误检成了本车道线,导致舒适性评分下降。这个 bad case 一旦确认,你今天的任务就明确了:分析原因、构造相似样本、评估是否需要调整模型结构或后处理逻辑。这就是自驾算法工程师的日常节奏——不是每天都能推一个新模型出来,但每天都会有一个明确的性能问题要解决。
很多人容易陷入一个误区,觉得提升模型性能就是调参、换网络、加模块。实际上在真实业务场景里,算法的提升往往是从数据开始的。一个 bad case 背后通常不是模型收敛得不够好,而是这个场景在训练数据里压根没见过,或者见过但标注质量拉了胯。所以如果你还停留在“只看指标不看例子”的阶段,那模型性能大概率会卡在某个瓶颈上。
1.2 数据闭环与模型迭代的一次完整循环
自驾算法的工作流程,本质上是一个不断循环的数据闭环。一次完整的迭代周期,通常包含以下几步:
第一步,路测车队采集原始数据,经过脱敏和合规处理后上传到数据平台。第二步,挖掘团队或者算法工程师自己写规则,在海量数据中筛选出有价值的场景,比如罕见交通参与者、极端天气、异形车等,送入标注平台。第三步,标注团队按照你写的标注规范完成标注,你需要抽检标注质量,不合适的打回重标。第四步,完成数据集的构建和划分,触发训练任务。第五步,模型训练完成后进入评测环节,包括离线评测、仿真评测和实车验证,最终输出一份评测报告。第六步,如果收益验证通过,模型被固化到下一个发布版本。
这个循环里最容易被忽略的环节是标注规范的制定。我见过太多算法工程师把标注规范完全甩给标注团队,结果模型训练完发现标签噪声高得离谱。不同传感器、不同天气、不同距离下的标注要求是天差地别的,你必须把模型的输入分布告诉标注团队,他们才知道雨天的遮挡目标该不该标、对向车道被压线车辆遮挡的车尾该不该标。这个环节看似和模型性能没关系,其实关系比换一个注意力模块大得多。
1.3 仿真评测和实车验证:模型性能的最终裁判
有了模型,不能只看离线指标。自驾算法和一般视觉算法最大的不同在于,它最终要跑在车上,所以必须把仿真和实车验证纳入日常工作流程。仿真的价值在于能快速构造大量极端场景,让模型在各种“理论上存在但罕见”的交通流中反复试错;而实车验证则是最后的裁判,因为仿真环境里的传感器模型再逼真,也没法完全复现真实的光照、反射和动态模糊。
在我个人的经验里,一个模型如果只在离线测试集上提升了零点几个点,但仿真和实车表现没有明显变化,那这个提升大概率是过拟合。真正的性能提升,一定会体现在闭环指标上——比如接管率降低、舒适性评分提升、急刹次数减少。所以日常工作中一定要建立一套从离线到仿真再到实车的完整评测链路,让每个模型的收益变化都能量化、可追踪、可回归,而不是靠感觉拍脑袋决定哪个版本上线。
2. 提升模型性能的三驾马车:数据、结构、训练策略
2.1 数据层面的性能提升:最难但收益最实在
先说结论:在自驾场景里,数据质量的上限就是模型性能的上限。你后面改模型结构、调训练策略,本质上都只是在逼近这个上限。所以先别急着换网络,把你的数据分布和标签质量盘明白是性价比最高的事。
第一步是数据分布分析。把训练集里每个场景属性(天气、光照、道路类型、目标尺寸、目标遮挡程度、目标类别占比等)做一次统计,然后和你的实际道路场景分布做对比,找出明显失真的部分。比如你的测试集里小型车辆占了80%,但真实道路上两轮车和行人的出现频率远高于此,那模型在部署后的性能一定打折。这时候你不需要改模型,只需要在数据采集策略里增加两轮车、行人场景的占比,模型性能就会肉眼可见地涨。
第二步是难例挖掘(Hard Example Mining)。很多团队的做法是等模型上线后从路测数据里捞 bad case,再把它们追加到训练集里。这个策略没问题,但有个更高效的做法是使用“teacher model”去挖掘。用当前线上最优模型对大规模未标注数据进行推理,把置信度介于0.3到0.7之间的样本挑出来,人工确认后加入训练集。这些样本通常处于决策边界附近,对模型区分能力的提升帮助极大。
第三步是数据增强策略的精细化。自驾场景不能盲目套用通用的图像增强方式。比如对目标检测任务,随机翻转、裁剪、颜色抖动是常规操作,但要注意翻转会导致交通标志的文字镜像化、车道线方向倒置,这不仅不模拟真实分布,还会污染标签。合理的方式是定义一套自驾场景专属的增强策略,包含几何增强(小角度旋转、有限平移)、光学增强(模拟黄昏、逆光、雨雾)、传感器噪声增强(运动模糊、降采样模糊)等,且每一种增强都要检查对标注框及语义标签的连带影响。
关于数据,最后再强调一遍标签质量。我踩过最大的坑是某次训练中模型的表现突然下降,排查了模型结构、优化器、学习率,都找不到原因。后来抽检了训练样本,发现新一批标注数据里“遮挡目标只标可见部分”和“遮挡目标标全轮廓”两种标准混在了一起,导致回归头在目标尺寸上的输出震荡。从此我对标注质量的抽检比例定死为每天任务量的5%-10%,一旦发现系统性偏差,整批打回重标。
2.2 模型结构层面的性能提升:骨架、模块与多任务设计
模型结构的选择,在自驾算法中是一个持续演进的过程。不要盲目追求大模型和新模块,核心原则是:在算力约束下,把感知、预测、规划各任务的精度和延迟同时优化到可落地状态。
感知部分,常见的提升点包括:backbone 的更换(从 ResNet 到 Swin、ConvNeXt 再到基于 ViT 的变体)、neck 特征融合方式的升级(FPN 到 BiFPN 再到 Transformer-based FPN)、检测头的解耦设计等。但我的建议是不要频繁更换 backbone,尤其在多任务模型里,一次大改动可能带来连锁的性能回退。更稳的做法是逐步替换,比如先在同样 FLOPs 下比较不同 backbone 在目标检测和语义分割子任务上的涨点,确认后再整体切换。
模块层面的提升,值得关注的是注意力机制和多帧时序信息。Lidar 感知里引入基于注意力机制的特征聚合已经基本成为标配,图像感知里引入时序信息则能有效改善遮挡、动态模糊等问题,比如在 BEV 空间里将历史帧特征串起来做时序融合。时序信息的引入不是简单地拼接,而是要设计一个轻量级的时序记忆模块,比如 GRU、LSTM 或 cross-attention,保证推理期时的自回归过程可控,不会因为状态累积导致漂移。
多任务学习是自驾算法提升性能的很有效的方向。把检测、分割、可行驶区域识别、地面高度预测放到同一个共享特征下学习,能显著提升每个子任务的精度,尤其对小目标、远距离目标这类样本量不足的任务,共享特征带来的泛化增益非常明显。多任务的损失函数配置需要精细调节,按照“主任务优先,辅任务波动别太大”的思路设置权重,我常用的方式是在总 loss 中引入 uncertainty weighting,让每个任务的权重随训练动态调整。但要注意,多任务方案会拉长训练时间,如果对单帧推理时延极其敏感,需要评估任务解耦和共享特征之间的取舍。
2.3 训练策略层面的性能提升:损失函数与超参数的细节
训练策略层面的提升往往被低估,但它性价比极高,几乎不增加任何部署成本。损失函数的选择对自驾目标检测、车道线拟合、轨迹预测都会带来显著差异。比如检测任务里,2023年之后基本都转向了基于 attention 的检测头和无锚框设计,损失函数也普遍使用 Focal Loss 系列来缓解正负样本不均衡问题。回归分支则建议使用带有不确定性估计的损失形式,让网络在复杂场景下自己给出一个置信度,这个置信度在后续预测融合模块里能做得很好的输入。
训练超参数方面,有三件事值得认真对待:学习率调度策略、EMA 指数平均滑动、以及梯度裁剪。我见过最经典的错误是训练时把 batch size 翻倍后忘了调学习率,结果是模型始终在一个次优解附近震荡。线性缩放法则在这里很实用:batch size 翻倍,学习率也大致翻倍,但 warmup 需要重新检查。EMA 几乎成了自驾模型训练的标配,它能让最终的模型泛化性提升一到两个点,实测下来对检测框抖动抑制也很明显。
另一个常被忽视的训练细节是“冻结与解冻”策略。如果你在加载一个预训练模型的基础上新引入一个模块,建议先把新模块单独训练几个 epoch,等它的 loss 有下降趋势后,再解冻整个网络一起训练。这个策略能够有效避免预训练知识在新模块随机初始化状态被破坏的问题。我在做 BN 层调整时也栽过跟头:Lidar 模型和图像模型对 BN 的统计量分布极其敏感,如果直接在混合数据集上训练而不管 BN 的 momentum,会出现训练时指标提高、测试时崩溃的现象,后来把 BN 的 momentum 调小并增加 warmup 就解决了。
3. 评测指标和实验管理的实战心得
3.1 评测指标怎么选才不会被表面数字误导
自驾算法涉及的评测指标非常多,不同模块各有侧重。检测任务看 mAP、mAP@0.5、mAP@0.5:0.95 这些常规指标;分割任务看 mIoU、mDice;车道线检测多看 Accuracy、IoU 以及“可行驶区域召回率”;轨迹预测则看 minADE、minFDE 和碰撞率。但指标多不等于你就得全看,关键是建立一套能反映真实道路表现的核心指标集。
以感知为例,我建议除了计算整体 mAP 之外,还需要按难度分层统计。比如把目标按距离分成 0-30 米、30-60 米、60 米以上三档,每档单独算 AP;按天气分成晴天、阴天、雨雾三组,分别看精度变化。为什么要分层?因为整体 mAP 太容易被中近距离的大目标带跑,辛苦提升的远距离 AP 可能被整体数字掩盖。分层统计能让你快速定位到性能瓶颈到底在中距离、近距离还是远距离,以及是否在特定天气下退化严重。
另外,自驾场景中“安全关键指标”比“平均指标”更重要。一个模型如果能把平均精度提升不少,但对行人的召回率下降了,那是绝对不能上线的。我看模型报告时习惯先看严重的失败样本(false negative 里的行人、骑行者、交警手势、施工区域),再看高分误检(把路牌误检成车辆的样本),最后才看 mAP。指标只是帮助你对齐工作方向的工具,最终决策得靠安全性和舒适性导向。
3.2 实验管理:从拍脑袋到规范化迭代
提升模型性能是一个持续迭代的过程,不规范化地做实验会导致大量时间浪费。我从自身的经验教训出发,总结了一套实验管理规范:
每改动一个变量只提交一个实验,未验证前不加新变化。训练和评测每次必须记录完整环境信息,包括数据版本、分支代码 commit、配置参数、随机种子、评测集版本和评测指标脚本版本。所有实验的结果放到统一的表格里,随时可以对比和回溯。如果前后使用了不同的数据切分,需要用相同数据重新验证旧模型,保证公平对比。
这个习惯一开始可能觉得繁琐,但长期收益极高。我遇到过太多次“上次实验不是涨点了嘛,怎么复现不出来”的问题,最后基本都指向了数据版本不一致、评测脚本被改动过、以及随机种子差异。把这些都规范化之后,一些虚假的涨点就不太会出现,实打实的性能提升才会沉淀下来。
另外,每个算法方向应当保留一份完整的 baseline 和对应的评测结果。当你尝试新结构、新损失函数时,任何新方法都应该先超过这份 baseline 再谈上线。没有 baseline 做锚点的实验管理,最后都会变成猴子掰玉米——掰一个丢一个,很难积累出真正可靠的性能提升。
4. 常见问题与排查技巧实录
4.1 模型训练不收敛或震荡怎么办
训练 loss 不下降或者反复震荡,是每个人都会遇到的头号难题。我的排查路径是:先看代码是否存在基础错误(数据加载是否正常、标签是否对齐、loss 计算是否有误、梯度是否回传);再看数据是否存在问题(标签噪声过大、正负样本分布极度不平衡、数据增强是否产生了非法样本);最后看超参数是否合理(学习率是否过大或过小、batch size 是否过小、模型是否过于复杂导致训练不稳定)。
实践中有个非常典型的场景:训练刚开始 loss 下降很快,后来突然飙高然后发散。这种现象大概率来自优化器状态和 BN 统计量的更新冲突。比如训练中期引入了新的数据域,或者某个 batch 里同时出现了极亮和极暗的图像导致 BN 统计量剧烈抖动,就会让 loss 突然上升。解决方案是给 BN 层的统计量更新加一个低通滤波,或者使用更大的 batch size 来稳定统计量。
如果排查了一圈都找不到问题,还有一个保底技巧:把学习率降到原先的十分之一重新跑一遍,如果 loss 能稳定下降,说明之前的问题来自激进的学习率;如果仍不稳定,重新审视数据和标签。
4.2 离线指标涨了,路测表现却变差的一种经典困境
这是自驾算法里最折磨人的问题之一:离线评测 mAP 涨了 2 个点,但上车路测接管率上升,舒适性也下降了。我遇到的多数情况是数据切分太“简单”了,导致离线评测分数虚高。具体地说,训练集和评测集来源于同一批路采数据的不同帧,帧间高度相关,场景分布过于接近,导致模型的真实泛化性能被高估。这种情况下你提升的性能不是泛化能力,而是对特定路段的“记忆能力”。
解决办法是把测试集建设成一个独立的“能力基线测试集”,包含经过挑选的、分布跨度足够大的场景,最好来自不同时段、不同城市、不同天气。对应拆解指标后,才能真正发现路测变差的真正问题。
另一种常见原因是在优化某些指标时引入了副作用。比如为了提高 mAP 在低置信度阈值下的表现,把检测头的分数校准调得过于激进,结果产生了一些高置信度的误检,这类误检在路测中被下游规划模块放大,表现为无故急刹车。解决这类问题,需要在感知模型的评测之外叠加一层“规划接口仿真评测”,观察感知输出变化对规划轨迹的影响,而不是只看感知指标。
4.3 数据分布偏移带来的性能衰减
模型上线后,随着时间推移和地域扩展,性能往往会逐渐下降,这就是数据分布偏移。在实际自驾场景中表现得非常明显:一个在北方城市训练的模型,到南方多雨城市可能就不那么稳定了。解决这个问题的思路不是一次性训练一个大而全的模型,而是建立一个数据领域的监控体系,持续追踪模型在关键子场景上的性能,一旦发现某类场景的指标下滑,就把该场景的数据补进来做增量训练或重训练。
增量训练本身也有风险。直接用新数据在老模型上继续训练,可能会破坏原有能力,即“灾难性遗忘”。我的做法是混合训练,把新数据与代表性旧数据按比例混合,同时在新数据上稍微加大采样权重,保证模型既能学到新场景,又不忘记旧场景。比例通常控制在 1:5 到 1:10 之间,具体视数据量而定。
4.4 标注噪声对模型性能的影响有多大
说到数据,有一个团队常挂嘴边但未必量化过的问题——标注噪声。结合实际观察:如果标签里有 5% 的错误边界框,模型 mAP 可能会直接掉 2 到 4 个点;如果标签存在系统性偏差,比如某个类别的目标全部偏大或偏小,模型还可能出现高置信度的错检。标注噪声对模型的伤害远大于同比例的数据缺失。
应对手段首先是流程上加强对标注规范的审核,其次是训练算法上做一些“抗噪”处理。你可以在损失函数上引入样本权重学习,让模型自动降低高损失样本的贡献,避免被个别错误标注带偏。也可以在人工抽检之外,使用模型预测与标注不一致的样本自动筛选机制,主动找出疑似错标的样本,再做定向复核。这两招都亲测能有效降低标注噪声对性能的干扰。
5. 走向系统化的模型性能优化闭环
5.1 怎么判断性能提升的真实性与稳定性
做了足够多数据和实验之后,你需要回答一个问题:这个提升到底可不可信?我的判断方法是看三样东西:一是在多个随机种子下训练多次,取均值和方差,涨点必须稳定大于方差;二是做消融实验,确认涨点来源于预期模块,而不是随机因素;三是经过完整评测链路验证,离线、仿真、实车闭环表现一致。如果一个提升在单次实验里涨点明显,但在更换随机种子或数据切分后消失,那这个“提升”基本是噪声。
另外,也要警惕“作弊式涨点”。比如训练时偷偷加大了某个难以察觉的数据增强参数,或者改变了评估时的输入分辨率。这类技巧当然也可以算是一种优化,但拿到真实的性能提升要有充分的实验记录支撑,否则上线后很容易露馅。我见过最无语的一次是评测时把图像尺寸调大,mAP 上涨 1.5 个点,但部署延迟也涨了 30%,最后得不偿失。
5.2 从单点优化到多模块协同:一个完整的落地案例视角
单个模型的性能提升,最终要放到整个自驾系统中验证其价值。感知模型的 mAP 提升未必直接转化为更好的驾驶体验,还取决于下游预测规划模块怎么消化这些感知输出。比如感知模块对远处目标的召回率提升了,这个收益在预测模块里如何被利用?是提升了轨迹预测的置信度,还是仅仅增加了计算开销?好的算法工程师不会只关心自己负责的模型指标,还会关注系统级指标的变化。
一个我实践过的流程是:性能改进 → 下游仿真 → 实车测试 → 指标回归 → 灰度发布。当感知的一个模块改动后,除感知评测外,还要跑一遍下游预测和规划的仿真测试。有些感知误检虽然在感知指标上只有轻微波动,但规划模块对“障碍物突然出现”非常敏感,反而会在仿真中被放大成大问题。这种跨模块的反馈是自驾算法优化闭环里最容易被忽视的一环。每次改动模型前都要问自己:这个改动对整个系统是助益还是负担?如果下游模块根本没有能力消费感知提升带来的信息,那这个提升就只是一种虚假繁荣。
5.3 给新入行或者正在转行做自驾算法的人几句实在话
最后给新入行的开发者说几句实在话。自驾算法这个方向门槛确实不低,不仅算法深度要求高,而且需要你有系统工程思维。很多人一上来就扎进最新的论文里,想通过一个惊艳的结构提升模型性能,但真正的工作其实是日复一日地跟数据和评测打交道。你要有心理准备:大部分时间花在数据清洗、标注规范、评测分析、问题复现上,花在“修改神经网络结构”上的时间可能不到五分之一。
但反过来讲,这种工作内容也带来一个独特的优势:它逼着你建立一套严谨的工程方法。从定义问题、分析数据、复现 baseline、跑通闭环、实验对比,到最后验证收益,这套方法论远比任何单个涨点技巧值钱。你在任何一家做自动驾驶或相关感知业务的公司都能用上。
提升模型性能从来没有银弹,只有把数据、结构、训练策略、评测方法这几个环节扎扎实实地打磨到位,性能的上涨才会稳定可持续。我现在看一个模型,第一反应不是它的网络结构有多新,而是它的数据分布定义是否清晰、评测链路是否完备、bad case 定位是否顺滑——这三样做到了,结构上的差距很快就能用迭代补回来。希望这篇文章里写下的经验和误区,能帮你少踩几个我当年踩过的坑。