☰
Transfuser-202205:端到端自动驾驶的Transformer多模态融合实践
2026/10/20 13:00:08 网站建设 项目流程

2022年年中那阵子,我在各种自动驾驶交流群里反复看到一个名字:Transfuser。第一反应是"又一个Transformer落地方案",第二反应是"一段式端到端?这东西还没被吹爆吗?"等我把论文代码完整过了一遍,又亲自在CARLA里把这个流程跑通之后,才意识到它对当时主流技术路线到底意味着什么。

简单说,它直接把相机和多线激光雷达的原始数据丢进同一个网络,在特征层面用Transformer做交叉注意力融合,最终输出未来路点和控制指令,中间不搞独立的物体检测、车道线提取。2022年5月这个版本,正好是项目适配CARLA 0.9.14之后的一次完整训练配置更新,所以很多复现的人会把它简称为"Transfuser-202205"。适合正在跟端到端、传感器融合方向的开发者,也适合想从传统模块化方案往数据驱动方案转的同学,这篇文章把模型原理、训练脚本、复现踩坑一次性讲透。

1. 为什么2022年大家都在看Transfuser:端到端方案的路线之争

1.1 模块化方案和端到端方案的根本矛盾

先说说当时的大背景。2022年之前,业内量产自动驾驶主流还是模块化pipeline:感知模块输出障碍物框、车道线、红绿灯,预测模块算轨迹,规划模块在这些抽象结果上做决策,最后控制模块执行。听起来很合理,但实际工程里最头疼的问题是信息在模块间传递时严重损耗。

举个很常见的例子:相机拍到路面上有一层薄薄的水渍,激光雷达点云里能看出低矮路沿,但感知模型在训练时可能根本没有这类标注,所以输出到规划层的障碍物列表里压根没有它们。规划模块看到的是一个"干净"得有些失真世界。更麻烦的是,感知误差会逐级放大——检测框偏了5厘米,到预测模块变成轨迹偏移,再到规划模块就可能产生一个危险的超车决策。这就像接力赛跑,每一棒交接都有延误,四棒下来跟对手的差距就被拉大了。

端到端方案走的是另一条路:从传感器原始数据直接学习控制指令。没有显式的物体框、车道线中间表示,网络自己决定该看哪、该忽略什么。好处是信息链路最短,坏处是训练难度爆炸。所以在Transfuser出现之前,大部分人对端到端的印象还停留在"小车上跑个模仿学习demo",稍微复杂的城市路况就露馅。

1.2 一段式和两段式的本质区别

其实端到端内部也分两派。一派是两段式:先用检测网络或者语义分割网络把传感器数据变成中级特征,比如BEV语义栅格图,再把这些特征喂给一个控制网络。Bird's Eye View就是典型的"感知编码器+控制器"两段式结构,感知部分单独预训练,控制部分单独训练,两边不共享梯度。

另一派就是Transfuser坚持的一段式:从相机图像、LiDAR点云到最终的方向盘转角、油门刹车,全部在同一个网络里反向传播。传感器编码器、融合Transformer、轨迹预测头、控制头,所有子模块的梯度都共享,训练时所有损失函数直接回传到输入端。

为什么一段式让很多人觉得"不可控"?因为传统工程思维追求中间结果可解释——你得能回答"为什么在这里刹车"。一段式网络中间出来的特征图,你很难指着它说"这是行人""这是红灯"。但Transfuser用实验结果证明了:只要数据规模足够、任务定义清楚,一段式不需要人为设计中间语义,它内部的注意力机制会自己学会"看该看的"。最终效果比两段式更稳,因为梯度贯穿整个学习过程,感知部分也在为最终控制准确性调整自己。

1.3 202205版本到底更新了什么

很多初次接触的人会困惑:Transfuser不是一个模型吗,为什么标题里非要带个"202205"?

这实际上是项目组在迭代过程中的版本习惯。2022年5月这个时间点,他们做了三件比较重要的事:

  • 把整套数据收集流程迁移到了CARLA 0.9.14,新版本模拟器里Town地图的布局、天气系统接口都有变化,旧数据集不能直接复用。
  • 调整了训练配置:场景采样策略里增加了环岛、U型转弯、行人横穿的比例,之前模型在这几类场景下转弯失败率偏高。
  • 修了一版多传感器时间戳对齐的问题,之前相机和LiDAR在高速场景下时序差个一两帧,融合时会"看着以前的点云下现在的方向盘"。

所以如果你在GitHub上看到"202205"这个标记,意味着拿这套代码和配置重跑,可以直接复现出那一版在公开仿真评测里的表现。对于做对比实验的人来说,这个时间戳就是一把刻度尺。

2. Transfuser的架构秘密:Transformer和CNN不是二选一,是互相打补丁

2.1 相机和LiDAR在CARLA里分别怎么进网络

先看单模态的部分。

相机这边,Transfuser取的不只一个视角。它会用前视、左前、右前等多路RGB图像,每一路都过同一个共享的CNN骨干网络(ResNet的某种变体)提取空间语义特征。CNN在这个位置的作用很纯粹:把图像里"哪里有轮廓、哪里有纹理、哪里像障碍物"这种局部信息压缩成特征图。因为CNN的卷积感受野是局部的,天然适合处理图像的二维空间结构。

LiDAR那边,处理方式比相机更讲究。原始点云是一堆散乱的三维坐标点,没法直接进CNN。项目里的做法是先把点云转到BEV俯视图,按x-y平面划分成网格,每个网格里统计高度值、点密度、强度等通道,得到一张"长什么样很像栅格地图"的多通道俯视特征图。这张特征图再过另一个CNN骨干,得到LiDAR分支的特征。

到这里为止,两个模态还是各走各的,像两个部门分别写了份报告。接下来的问题就是:怎么把这两份报告合起来,而且合完不能打架。

2.2 Transformer注意力在这里不是语言模型里的自注意力

很多刚上手的人会误以为Transfuser的Transformer用的是语言模型那种"序列中每个位置相互看"的自注意力。其实不是。这里面用的是交叉注意力(cross-attention),操作逻辑完全不同。

我打个比方:自注意力是开会时所有人互相讨论,每个人都发言、都听别人的;而交叉注意力像是"A部门带着问题去B部门查资料"——A部门的每个查询(query)去B部门的键值(key-value)库里检索自己需要的信息,拿回来融合。

在Transfuser的融合Transformer里,相机特征和BEV特征互为查询和键值库。相机图像里有丰富的纹理细节,比如骑车人的轮廓、路沿的颜色变化,这些信息去BEV特征里查"这个位置在俯视图上对应的区域长什么样";BEV特征拿着全局的几何布局,去图像特征里确认"这个位置是不是真的有东西"。经过多层交叉注意力之后,两个模态的特征在空间上对齐了。

关键点在于叫"transformer"但没用位置编码是行不通的。项目里会显式地把空间坐标信息叠进注意力里,否则模型分不清"左上角的图像块"对应"BEV的哪个栅格"。这个几何对齐能力是纯CNN融合做不到的——卷积只能在局部窗口内找对应关系,遇到跨传感器、跨视角的对应,它没有全局建模能力。

2.3 从融合特征到驾驶指令的具体流程

融合后的特征图会被压成一段固定维度的向量,这相当于"整个场景的摘要"。在这个向量后面,Transfuser接了两个输出头:

  • 路点预测头:输出未来若干秒内车辆要经过的一系列坐标点,通常以车体当前位置为原点,每个点带横向偏移和纵向距离,时间上从前到后排列。有了路点序列,就相当于有了一条期望轨迹。
  • 控制头:直接回归方向盘转角、油门开度、刹车踏板的数值。训练的时候还额外做了一层离散化分类,把转向预测拆成"向左、直行、向右"的分类任务和连续角度回归任务,双管齐下,让模型学到的控制信号更平滑。

推理的时候有个细节:模型先用自己的路点头给出期望轨迹,然后交给一个下游的横纵向控制器去追踪。这个控制器可以用简单的PID,也可以用带动力学约束的模型预测控制(MPC)。之所以不直接用模型输出的控制量,是因为光靠神经网络直接输出刹车油门的抖动比较大,跑在真实车上乘客会晕。先给轨迹再让轻量控制器去跟踪,整个系统更稳。

2.4 为什么选了Transformer而不是纯CNN多层融合

这是我一开始最想问的问题。既然CNN也能做融合——两个分支的特征图在某个中间层做concat,然后再堆几层卷积不就行了?

答案是纯CNN融合在复杂场景下会掉链子。从实验对比来看,在简单直道和低速转弯路段,CNN融合和Transformer融合差距不大,但一旦进入有多个交通参与者、有遮挡、有强逆光的城市场景,CNN融合的路线完成率断崖式下跌。原因不复杂:CNN的感受野是局部的,一个卷积核最多看周围K×K个像素范围,两个传感器特征要在空间上建立远距离依赖关系非常吃力。而注意力机制让每个位置都能"隔空取物",直接看到另一个模态里的关键区域。

另外一个很实用优点:Transformer把特征当作一组token来处理,对传感器数量变化不那么敏感。今天你可能只装了一个前视相机,明天加装了四个环视相机,只要把token数量加上去,注意力模块能自适应处理,不用大幅修改网络结构。

3. 一段式训练的目标函数设计:多任务监督和模仿学习是怎么拧成一股绳的

3.1 数据从哪里来:CARLA专家驾驶采集

端到端训练最要命的是数据。Transfuser的数据全部来自CARLA模拟器里的专家驾驶系统(autopilot)。这个内置专家会给出安全、符合交规的驾驶行为,在设定好的路线里不断开。

采集的时候有几个关键点:

  • 多地图多天气:不是在单一地图里闷头跑,而是在多个城镇布局、不同光照、不同天气(晴天/雨天/大雾/夜晚)下都采集,让模型见过足够多变的场景。
  • 相机和LiDAR同步记录:每一帧保存多视角相机图像、原始点云、路由目标点以及专家给出的方向盘/油门/刹车真值。
  • 路由目标怎么编码:端到端不能真的"零地图"裸奔。每个路口往左、往右还是直行,这个路由指令是外部给定的。Transfuser把路由目标点做成了embedding向量,跟融合特征在高层拼接起来,告诉模型"接下来我要往哪走"。这是很多一上来就搞端到端的人容易漏掉的部分——没有路由信息,模型在一个多岔路口就会茫然。

3.2 Loss函数到底拆成几块

一段式训练不是简单"输出和控制真值做个MSE"。实际训练目标函数拆得很细,我记得大致是这么几块:

  • 转向预测:一个离散化分类损失(方向盘角度被切成有限个桶,比如左、中、右),加上一个连续回归损失。这样模型既知道"大概该往哪边打",又能学到精确角度。
  • 速度预测:油门和刹车的回归,用L1损失。
  • 轨迹点预测:对每个路点坐标做平滑L1损失,时间越靠后的点权重越低,因为远期轨迹本身不确定性更大。
  • 辅助监督:在特征输出上额外接了一些语义辅助头,比如做物体检测或者可行驶区域分割。这些头只在训练时存在,推理时丢掉。它起的作用是逼着编码器保留跟驾驶决策相关的结构化信息,不至于为了拟合控制信号而把中间特征压缩成一个没有意义的黑盒。

这套多任务设计对一段式训练意义重大:整个网络从传感器原始数据到控制指令都是可微的,所有任务损失会通过共享的编码器层和融合Transformer回传。也就是说,路径点预测的错误、转向角度的误差、辅助语义分割的误差,全部会调整融合注意力模块的权重。相比"感知任务先训练好再固定住、控制任务单独跑"的两段式,Transfuser的每个模块都在为整体驾驶表现负责。

3.3 训练避坑:增广、平衡和灾难性遗忘

训练过程里比较隐蔽的坑有三个。

第一个是数据增广的语义一致性。相机图像可以做颜色抖动、随机裁剪、水平翻转,这个简单。但BEV特征图如果也做随机旋转和平移,必须保证它跟相机图像里的空间变换是一一对应的。两边的增广操作要同时做、参数一致,否则等于是给模型喂了两份对不齐的矛盾数据,融合模块直接学歪。

第二个是场景采样比例。如果数据里90%都是直道,模型很快学会"反正直着开就行",变道、环岛这类罕见但关键的行为一概不会。Transfuser的做法是设置场景采样概率,人为提高复杂路口的出现比例。这也是为什么有人直接拿公开数据集重训一个,效果不如原版——它们可能没注意到数据集里场景比例本身是调过的。

第三个是灾难性遗忘。多地图数据混在一起训练时,模型很容易学了新地图忘了旧地图的路况特征。解决办法是数据加载时做shuffle,并且训练过程中用小的学习率退火(cosine decay),别一次性把学习率拉太低,给特征提取层留出持续更新空间。

4. 复现Transfuser的实操链路:从CARLA数据到Benchmark分数

4.1 环境准备和版本配套

如果现在就想去复现,先把环境配齐。我踩过一遍之后,推荐这套组合:

  • 操作系统:Ubuntu 20.04或22.04都行,Windows上CARLA也能跑但后面多进程并行处理会很别扭,别自找麻烦。
  • Python环境:3.8或3.9,配合PyTorch 1.12以上版本即可,不必追最新版。
  • CARLA版本:严格匹配0.9.14。版本不对会直接导致数据集采集脚本报错,或者加载地图接口不兼容。
  • 硬件:我一开始用的单张24GB显存的显卡,batch size调到16勉强能跑。如果手头有40GB或80GB的卡,一个默认配置的batch size 32能直接跑起来,省很多心。

目录结构建议清爽一点:CARLA服务器程序单独放一个文件夹,项目代码单独放一个文件夹,数据集单独放一个大硬盘目录。别把数据集和代码混在同一个目录里,后面预处理的BEV缓存文件体积会很大。

4.2 官方训练管线那一套脚本的顺序

整个复现流程像流水线一样,按固定顺序执行,别跳步:

  1. 启动CARLA服务端:用subprocess方式从Python里拉起CARLA服务器,而不是手动开两个窗口。手动开容易遇到进程假死,而且无人值守跑十几个小时采集时,窗口一崩全白干。
  2. 数据采集:运行数据收集脚本,指定目标城镇、天气列表、交通流量参数。这个过程会生成HDF5格式的原始数据集,每个场景一个文件,里面打包了相机图像、点云、路由点和控制真值。
  3. BEV预处理:把原始点云转成BEV栅格特征,这一步很吃CPU和内存。如果你在采集完直接训练,数据加载环节CPU会一直满载,GPU反而闲着。我建议把预处理好的BEV特征单独缓存成numpy数组,训练时直接读缓存,速度能快好几倍。
  4. 训练主模型:加载HDF5和预处理好的BEV缓存,开始跑多任务损失训练。训练脚本会周期性保存checkpoint,记录loss曲线。
  5. Benchmark验证:用官方验证脚本在保留的测试场景上跑闭环评测,看车辆能不能完整到达终点、有没有违反交规、有没有碰撞。这就是最后发论文时用的指标。
  6. 可视化:用route plotting脚本把预测的路点序列画出来,跟真值轨迹叠在一起看偏差。

每一步耗时都不短。我自己的经验是:数据采集一晚上能收几百个场景,预处理再花几个小时,训练在中端单卡上要两三天起步。所以这个项目不适合"今天拉下来明天出结果",要复现就留出至少一周时间。

4.3 最容易踩的三个坑

我复现过程中踩掉三层皮,先说最疼的三个:

坑一是CARLA服务端和Python客户端版本错位。如果你系统的Python环境里多装了一个别的地图的CARLA库,会导致运行数据采集时卡死。最后我是把CARLA安装在干净目录、用绝对路径启动,并且专门给项目建了一个独立conda环境才解决。

坑二是BEV预处理内存爆炸。原始点云数量大,多进程预处理时如果每批次攒太多帧,内存直接拉满,机器进入swap地狱。解决办法是限制同时预处理的场景数,分批次写入磁盘,释放中间变量。

坑三是验证指标随机性大。单条路线跑一次失败,不能立刻断定模型有问题。CARLA世界里的车辆、行人行为本身有随机性,同一个模型同一条路线跑五遍,结果可能三成五成。标准做法是用多seed、多个不同起点终点组合,算平均路线完成率和平均碰撞率,再下结论。

4.4 从指标回推模型哪里出了问题

跑完benchmark拿到分数不等于完事,关键是要知道"差在哪"。我自己总结了一套排查逻辑,很土但很管用:

  • 如果总在变道时失败,比如骑线压线甚至冲出车道,优先去可视化融合Transformer的注意力图,看模型的注意力有没有对BEV目标产生足够的关注。注意力权重的热力图能直接告诉你是重在了图像还是重在了LiDAR。
  • 如果总在路口转错方向,大概率是路由embedding和目标点融合出了问题,检查路由信息有没有被后续层稀释。
  • 如果总撞静止的障碍物,比如路边停靠的车辆、施工锥,问题集中在LiDAR分支对静态障碍物的感知缺失。可以调高BEV高度通道的权重,或者在辅助语义头里增加"静态障碍物"分类的监督。
  • 如果速度控制特别抖,说明控制头回归的尺度没学稳,可以把控制头的分类分支权重调大,让控制器输出更偏向离散桶的中心,轨迹会更平滑。

这些排查手段在纯两段式系统里不太用得上,因为你可以直接去调检测模块的阈值。但端到端模型就只能通过可视化特征和输出来定位,看指标的"病灶"在哪里。

5. 2025年回头看Transfuser:它给端到端自动驾驶留下了什么

5.1 一段式从"非主流"变成了主流之一

把时间拉回到现在,再回头看2022年的Transfuser,它的历史位置比当时看起来重要得多。它之后出现的很多新模型——比如BEV感知系列、VAD这类向量化端到端方案——走的路子基本都能看到Transfuser的影子:多模态输入进特征融合网络、输出结构化轨迹、后端接控制交互。

那个时代大家对一段式的最大顾虑是"训练的不可解释性",所以当时两段式在量产车里还是主流。随着后续数据采集手段和数据量大幅提升,端到端模型的可训练性和泛化能力已经今非昔比。现在新提出的方案里,一段式已经不是什么需要特别解释的异类了。你可以批评它数据需求大、闭环验证难,但已经很少有人质疑"传感器原始输入能不能直接学出控制指令"这个基本命题——Transfuser把这个命题从"口号"变成了"有完整工程实现的东西"。

5.2 在CARLA平台上的副作用:刷榜问题是把双刃剑

另一个值得说的点是,Transfuser的广泛传播和CARLA排行榜的流行是互相成就的。它在排行榜上的亮眼表现让这个模型被大量引用,也让CARLA benchmark变成了端到端方向的默认试验场。

但这里有个副作用:很多后续工作开始盯着排行榜指标做优化。有些模型把规划的reward单独拿出来做强化学习调整,在特定地图和天气状态下表现很好,换一个新的城镇布局就露馅。我在实际项目里看过一些在CARLA上刷到高分的模型,跑到真实感更强的场景里,转弯明显保守、对动态障碍物的反应迟钝。所以说,CARLA分数是重要参照,但别把它当成"这个模型能上路"的证明。仿真环境和真实世界的domain gap永远存在。

5.3 我在后续项目里的三点体会

Transfuser跑完之后,我又陆陆续续做了好几个端到端相关项目,回过头来想想,有三件事是真正沉淀下来的:

多模态融合不是堆一个Transformer就完事,查询和键值的设计要跟数据形态匹配。相机特征和BEV特征的分布差异极大,硬拼在一起不如明确让一个当"提问者"、另一个当"资料库"。这个思路后来我用到点云和毫米波雷达融合上,一样管用。

端到端模型的debug方式要换一套。传统感知可以画框、可以数准确率,端到端想定位问题只能靠可视化特征和设计消融实验。我当时是把几个模块的中间输出全部导出来做成网页交互界面,才能一个个排除问题。想做端到端方向的人,建议提早把可视化工具链搭起来,不然后面调优寸步难行。

最后是闭环仿真测试的必要性。单帧预测准确实在说明不了太多,很多模型转向预测挺准、路点也挺准,但放进闭环里一跑,一个小偏差就累积成大事故。Transfuser从一开始就把闭环benchmark当核心指标,这是个非常好的工程习惯。做端到端项目,千万别只看离线指标沾沾自喜。

如果现在有人问我入坑端到端自动驾驶该从哪开始,我还是会首推复现一次Transfuser。它的代码量不算小,但每个模块都清晰可读,数据链路、训练链路、评测链路完整,是一套少有的"三段全齐"的参考实现。把那套流程跑通,你对多模态融合、模仿学习、闭环评测的理解会有一次实质性的提升。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询