自动驾驶纯视觉感知这几年卷得厉害,BEVFormer算是绕不开的一个经典方案。但真正动手在AutoDL上把它跑起来,很多人第一步就被环境、数据、显存这些坎拦住了。我这次从零开始,把Nuscenes数据集完整训练BEVFormer的全流程走了一遍,踩了不少坑,也总结出一套能在AutoDL上快速复现的可靠路径,分享出来给后面要入坑的朋友参考。
先说清楚这套方案能解决什么问题:AutoDL平台按小时计费,GPU资源灵活,非常适合做BEVFormer这种大模型的训练验证;但平台自带环境是通用镜像,要跑BEVFormer,还得自己处理数据格式、依赖版本、训练配置这些细节。这篇文章覆盖从数据集申请下载、环境搭建、配置文件修改到完整训练、报错排查的整个过程,适合已经跑通基础目标检测、准备转入BEV感知方向的研究生或算法工程师。
1. 整体思路与方案选型
1.1 为什么选AutoDL作为训练平台
BEVFormer训练对硬件要求不低,Nuscenes全量数据集单卡训练,显存基本要24GB以上,如果本地没有多卡A100或者RTX 3090/4090,光准备机器就是一笔不小的开销。AutoDL这类云GPU平台的优势在于可以按需租用,训练完就释放,成本相对可控。
我在AutoDL上选择的是RTX 4090(24GB显存)规格的实例,搭配平台提供的PyTorch 2.0 + CUDA 11.8基础镜像。之所以不选A100,一方面是因为4090性价比更高,另一方是因为BEVFormer官方实现基于mmdetection3d框架,对GPU型号并没有特殊依赖,24GB显存跑base版本足够,不需要上80GB的大卡。
1.2 环境版本组合的底层逻辑
BEVFormer最麻烦的地方在于依赖版本耦合非常紧,尤其是mmcv、mmdet、mmseg、mmdet3d这四件套的版本必须严格对齐,版本不匹配会直接导致导入报错或算子编译失败。我最终采用的版本组合如下:
| 依赖包 | 版本 | 说明 |
|---|---|---|
| Python | 3.8 | 3.10以下兼容性最好 |
| PyTorch | 1.13.1 | 官方推荐版本 |
| CUDA | 11.7 | 与PyTorch配套 |
| mmcv-full | 1.7.0 | 必须1.6以上,BEVFormer用到了其中的Deformable Attention |
| mmdet | 2.28.1 | 3.x版本接口变动太大,不推荐 |
| mmseg | 0.30.0 | 和mmdet版本配套 |
| mmdet3d | 1.0.0rc6 | 官方分支指定版本 |
这个组合不是我拍脑袋定的,BEVFormer官方仓库的requirements.txt里写得很清楚,但直接pip install大概率会装上最新版本导致冲突。稳妥做法是先创建conda环境,再按固定顺序安装,后面第3章会详细说。
1.3 方案对比:从头训练还是加载预训练权重
这个问题我纠结了很久。BEVFormer有两种启动方式:一种是完全从头训练,另一种是加载官方提供的nuScenes预训练权重继续训练或微调。从实验角度看,如果只是为了验证代码能跑通、熟悉训练流程,从头训练几百个iteration就够了;如果要做精度对比或下游任务,建议直接加载预训练权重。
我在AutoDL上先做了200 iter的冒烟测试确认流程无问题,再启动完整训练。这样能避免数据或配置问题在长训练跑到一半才暴露,白白烧掉几十个小时的GPU费用。
2. 环境搭建与依赖安装避坑要点
2.1 conda环境创建与PyTorch安装
AutoDL镜像自带conda,我建议创建一个独立环境,不要污染基础环境。
# 创建conda环境 conda create -n bevformer python=3.8 -y conda activate bevformer # 安装PyTorch 1.13.1 + CUDA 11.7 pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 --extra-index-url https://download.pytorch.org/whl/cu117这里注意不要用AutoDL自带的PyTorch 2.0镜像,因为后续编译mmcv-full时可能出现算子兼容性问题。实测下来PyTorch 1.13.1是BEVFormer全链路最稳的版本,这也是官方CI测试用的版本。
2.2 mmcv-full编译的两种方式与取舍
mmcv-full是BEVFormer里最关键的依赖,负责提供CUDA算子。BEVFormer官方要求mmcv-full版本在1.6.0以上,我用的是1.7.0。安装有两种方式:
方式一:直接安装预编译包(推荐)
pip install mmcv-full==1.7.0 -f https://download.openmmlab.com/mmcv/dist/cu117/torch1.13.1/index.html这种方式不需要本地编译,几分钟就能装完。前提是PyTorch和CUDA版本要和链接里的对应。
方式二:源码编译安装(备用方案)
如果预编译包安装后出现算子缺失问题,比如ImportError: libcudart.so.11.0: cannot open shared object file,则需要源码编译:
git clone https://github.com/open-mmlab/mmcv.git -b v1.7.0 cd mmcv MMCV_WITH_OPS=1 pip install -e .源码编译耗时视机器性能而定,AutoDL上大约20到40分钟。这里要提醒的是,编译前确认gcc版本不低于7.0,否则会报internal compiler error。
2.3 mmdet、mmseg、mmdet3d安装顺序
三个包安装顺序不能乱,因为mmdet3d的安装会依赖mmdet和mmseg,且版本必须匹配。我按以下顺序执行:
# 先安装mmdet和mmseg pip install mmdet==2.28.1 mmseg==0.30.0 # 再安装mmdet3d,从源码安装指定版本 git clone https://github.com/open-mmlab/mmdetection3d.git -b v1.0.0rc6 cd mmdetection3d pip install -e .这里的坑在于,如果先装mmdet3d再装mmdet,pip会主动把mmdet升级到3.x版本,导致BEVFormer无法启动。装完后建议用pip list验证一下四个核心包的版本都符合上表。
2.4 其他依赖与常见编译报错
BEVFormer还依赖一些其他库,比如timm、einops、numpy等。有一个关键点:numpy版本必须锁定在1.23.5以下,新版numpy在PyTorch 1.13下会出现module 'numpy' has no attribute 'bool'一类的报错。执行:
pip install numpy==1.23.5 timm einops yapf==0.40.1另外还有一个很隐蔽的坑:mmdet3d 1.0.0rc6在编译时会检查torchvision的版本,如果版本过高会出现AssertionError: TorchVision not found之类误报。上面安装的0.14.1版本是安全的。
3. Nuscenes数据集获取与处理全流程
3.1 数据下载:官方渠道与磁盘空间规划
Nuscenes完整数据集比较大,包含1000个场景,每个场景约20秒,总共约300GB以上。在AutoDL上下载时,要格外注意两点:第一是AutoDL系统盘一般只有50GB,数据必须放到数据盘(一般挂载在/root/autodl-tmp),第二是数据下载速度受官网限制,从官网直接下载非常慢。
建议先在本地官网注册并申请下载权限,然后获取下载链接,再到AutoDL上用wget或aria2c并行下载。整个数据集包括:
| 数据内容 | 大小 | 说明 |
|---|---|---|
| trainval | 约70GB | 训练集和验证集图像 |
| test | 约46GB | 测试集图像(可选) |
| CAN bus | 约9GB | 车辆CAN总线数据 |
| map | 约7GB | 高精地图扩展包 |
| 标注文件 | 约8GB | json标注 |
如果只是做训练验证,trainval加上map和CAN bus就够用了,test可以不下载。我在AutoDL数据盘上预留了300GB空间,实际使用约120GB,包括后续生成的中间文件。
3.2 数据集目录结构规范
Nuscenes数据必须按照mmdet3d规定的目录结构存放,否则后续生成info文件时找不到路径。规范结构如下:
nuscenes/ ├── maps/ ├── samples/ ├── sweeps/ ├── v1.0-trainval/ ├── can_bus/ ├── lidarseg/ └── (test目录可选)下载完成后,先建立一个软链接指向你的数据目录,方便多个项目共用同一份数据:
mkdir -p data/nuscenes ln -s /root/autodl-tmp/nuscenes data/nuscenes3.3 使用官方工具生成pkl标注文件
mmdet3d训练需要把Nuscenes的json标注转换成pkl格式,这里用到的工具是官方仓库里的create_data.py。在BEVFormer仓库的tools目录下执行:
python tools/create_data.py nuscenes \ --root-path ./data/nuscenes \ --out-dir ./data/nuscenes \ --extra-tag nuscenes \ --version v1.0-trainval \ --canbus ./data/nuscenes这一步生成的文件包括:
nuscenes_infos_train.pkl:训练集所有帧的传感器标注信息nuscenes_infos_val.pkl:验证集标注信息nuscenes_dbinfos_train.pkl:用于data augmentation的数据库信息nuscenes_infos_test.pkl:测试集信息(如果下载了test数据)nuscenes_infos_train_mono3d.coco.json:单目3D标注格式,BEVFormer不强制使用,但可以顺带生成
生成过程大约需要30到60分钟,取决于数据盘IO性能。如果中途报缺失文件,多半是下载时漏了某个子目录,回到3.1检查。
3.4 数据加载验证:确认pkl文件可正确读取
在正式训练之前,先验证数据是否能被正确加载。我写了一个简单的测试脚本:
import pickle with open('./data/nuscenes/nuscenes_infos_train.pkl', 'rb') as f: data = pickle.load(f) print(len(data['infos'])) # 训练集大约28130条 sample = data['infos'][0] print(sample['lidar_path']) print(sample['cam_sweeps'].keys())如果正常输出路径和相机sweep的键名,说明数据文件没问题。这里如果报KeyError: 'cam_sweeps',说明你用的create_data.py版本和BEVFormer仓库不一致,需要从BEVFormer官方仓库里拉取对应的data_converter脚本。
4. 配置文件修改与训练启动
4.1 配置文件结构与关键参数解读
BEVFormer的训练配置在projects/configs/bevformer/目录下,核心文件是bevformer_base.py。这个文件是继承结构,先加载基础配置,再叠加数据集和模型配置。看懂这个文件是调通训练的前提。
几个关键参数的作用如下:
| 参数名 | 默认值 | 作用 |
|---|---|---|
voxel_size | [0.512, 0.512, 8] | 体素分辨率,影响BEV网格大小 |
point_cloud_range | [-51.2, -51.2, -5, 51.2, 51.2, 3] | 感知范围,正负51.2米 |
bev_h/bev_w | 200 / 200 | BEV特征图尺寸 |
num_query | 900 | 可学习query数量 |
num_classes | 10 | 检测类别数,Nuscenes是10类 |
use_ema | False | 是否启用指数滑动平均 |
save_epoch | 1 | 每隔多少个epoch保存一次ckpt |
训练策略方面,BEVFormer base版本默认训练24个epoch,学习率初始为2e-4,采用了余弦退火调度。如果只想验证流程,建议直接把total_epochs改成1,log_config的间隔调小到每10次迭代打印一次。
4.2 针对单卡训练的资源配置调整
AutoDL租用单张4090时,不能直接用官方默认的多卡配置,需要手动调整以下参数:
# 在bevformer_base.py中修改 data = dict( samples_per_gpu=1, # 单卡batch size设为1,4090 24GB只能跑1 workers_per_gpu=4, ) optimizer = dict( type='AdamW', lr=2e-4, paramwise_cfg=dict(custom_keys={'backbone': dict(lr_mult=0.1)}), )batch size是最关键的,BEVFormer的显存占用大头在BEV特征图和可变形注意力模块上,24GB显存跑batch size=1已经是极限,如果想跑大batch,需要A100 80GB或者多卡并行。
另外,由于用了单卡,需要去掉配置文件里的find_unused_parameters相关设置,并确保gpu_ids为[0]:
gpu_ids = [0]4.3 启动完整训练:命令与日志分析
环境配置无误后,进入BEVFormer仓库根目录,执行训练命令:
cd /root/autodl-tmp/BEVFormer python tools/train.py projects/configs/bevformer/bevformer_base.py \ --work-dir ./work_dirs/bevformer_base \ --gpus 1启动后观察日志输出,重点看以下几个方面:
- 模型结构加载:确认各模块参数量,总参数量约69MB(BEVFormer-Base),如果显示为0或无法加载多为依赖缺失
- 数据集初始化:正常情况下会输出
Loading 28130 annotations之类信息,耗时约10分钟 - 显存占用:用
nvidia-smi实时查看,训练稳定后显存应在20-23GB之间,如果超24GB就会OOM
正常启动后,日志每10步输出一次loss,期望数值在初始阶段大约5到8之间,随着训练逐渐下降。如果初始loss直接飙升到几百,优先检查学习率是否过大或数据label是否有问题。
4.4 checkpoint保存与中断恢复
长训练过程中因网络抖动、机器抢占等原因导致中断是很常见的事。BEVFormer支持从ckpt恢复训练:
python tools/train.py projects/configs/bevformer/bevformer_base.py \ --work-dir ./work_dirs/bevformer_base \ --resume-from ./work_dirs/bevformer_base/epoch_10.pth这里建议把AutoDL的自动快照功能打开,但快照只保存系统盘,数据盘里的数据不受影响。如果实例被释放了,重新创建一个同配置实例、挂载同一数据盘,再手动把代码和work_dir同步过来即可,不需要重新处理数据。
5. 常见问题与排查技巧实录
5.1 显存不足导致OOM
OOM是最常见的问题,尤其是在生成BEV特征时。报错通常长这样:
RuntimeError: CUDA out of memory. Tried to allocate 2.00 GiB (GPU 0; 23.70 GiB total capacity; ...)排查顺序:先用nvidia-smi看显存是否被其他进程占用,然后用fuser -v /dev/nvidia*杀掉多余进程;如果确认是训练本身超限,依次尝试以下方案:
samples_per_gpu从1改为1且开启cudnn.benchmark=False- 降低
bev_h和bev_w到150×150(这是最后手段,会牺牲精度) - 检查mmcv-full是否开启了磁盘缓存,
MKL_SERVICE_FORCE_INTEL=1等环境变量有时能小幅降低显存
4090在batch size=1下基本能跑满24GB,如果还OOM,优先怀疑是不是其他地方改了配置文件导致特征图尺寸变大。
5.2 加载预训练权重时的shape mismatch
使用官方提供的BEVFormer预训练模型做微调时,经常遇到以下报错:
size mismatch for img_backbone.backbone.conv1.weight: copying a param with shape torch.Size([64, 3, 7, 7]) from checkpoint, the shape in current model is torch.Size([128, 3, 7, 7])这个原因是预训练模型的backbone输入通道数(3通道RGB图)和配置文件里的num_cams或图像尺寸设置不一致。遇到这个情况,用tools/convert_bevformer_checkpoints.py脚本转换权重,或者直接忽略backbone权重只加载neck和head部分:
load_from = 'path/to/checkpoint.pth' # 在配置文件中加一行 load_from = None # 改为None表示不加载预训练权重如果是刻意忽略backbone,用mmcv.runner的load_checkpoint接口并设置strict=False即可。
5.3 CUDA算子版本相关报错
BEVFormer的核心算子Deformable Attention在mmcv-full里编译,如果版本不对,会出现:
ModuleNotFoundError: No module named 'mmcv.ops.multi_scale_deformable_attn'这是mmcv-full没有正确编译GPU算子导致的。解决方法是执行3.2节的源码编译方式,确认编译日志中出现Compiling ops... done字样。还有一种情况是mmcv和mmcv-full装重了,需要先卸载再安装:
pip uninstall mmcv mmcv-full -y pip install mmcv-full==1.7.0 -f https://download.openmmlab.com/mmcv/dist/cu117/torch1.13.1/index.html5.4 训练结束后评估精度异常
训练24个epoch后在验证集上评估,如果mAP非常低(比如不到0.1),而loss已经收敛,问题多半出在数据加载或后处理上。排查方向有:
- 确认
test配置里的ann_file指向的是nuscenes_infos_val.pkl,而不是训练集 - 确认
class_names顺序和Nuscenes官方顺序一致(默认顺序是car, truck, trailer, bus, construction_vehicle, bicycle, motorcycle, pedestrian, barrier, traffic_cone) - 确认是否加载了ema权重,BEVFormer官方实验里开启EMA后精度更高
我在调试时发现一个隐蔽问题:验证时NMS阈值设太高(0.7以上),导致大量预测框被滤除,mAP掉得厉害。把nms_iou_thr调到0.5后恢复了正常水平。
5.5 常见问题速查表
| 症状 | 原因 | 解决方案 |
|---|---|---|
启动即报No module named 'mmcv.ops' | mmcv-full未正确编译 | 源码重编译mmcv-full |
size mismatch加载权重失败 | 配置文件与ckpt结构不一致 | 设置strict=False或convert脚本 |
| CUDA OOM | batch size过大或显存被占用 | 调小batch,清理进程 |
numpy bool报错 | numpy版本过新 | 锁定numpy==1.23.5 |
| 训练loss为NaN | 学习率过大或数据有脏值 | 降低lr,检查标注有无无穷值 |
验证时KeyError: 'pts_bbox' | mmdet3d版本与配置文件不匹配 | 升级/降级mmdet3d到rc6 |
| pkl文件加载慢 | 磁盘IO瓶颈 | 数据放到SSD数据盘,不要放系统盘 |
6. 训练效率优化与后续扩展建议
6.1 开启混合精度训练
BEVFormer base版本使用FP32训练,24GB显存只能跑batch size=1,但开启AMP(自动混合精度)后,显存占用可以降到18GB左右,还能小幅提升训练速度。配置文件里增加:
fp16 = dict(loss_scale='dynamic')但需要确认模型中有部分算子不支持FP16,尤其是multi_scale_deformable_attn,实测下来BEVFormer官方代码是支持AMP的,只是精度会有轻微波动。对实验验证场景完全够用。
6.2 使用分布式训练加速
AutoDL上可以租用多卡实例,比如4×4090。修改启动命令:
bash tools/dist_train.sh projects/configs/bevformer/bevformer_base.py 4 \ --work-dir ./work_dirs/bevformer_base同时把配置里的data.samples_per_gpu改成1,这样总batch size变为4。BEVFormer官方在8卡A100上训练24个epoch大约需要40小时,单张4090上要明显更久,多卡能缩短到可控范围。代价是loss曲线可能会略有波动,这是正常的。
6.3 数据增强与超参数微调实验
如果想进一步提升模型效果,可以从几个方向入手:
use_cbgs=True:开启类别平衡采样,对Nuscenes这种类别分布不均的数据集有明显增益rotate_prev_bev:对上一帧BEV特征做随机旋转,增强时序鲁棒性- 增大
num_query从900到1200:能提升密集场景下的小目标召回率,但显存会增加
做实验时建议用--auto-resume配合的可视化工具追踪不同配置在验证集上的NDS(nuScenes检测分数)和mAP曲线,只留最优配置做长训练。
6.4 部署到真实场景的路径
训练完模型之后,如果要做实车或实机部署,BEVFormer官方TensorRT转换需要把模型导出为ONNX再转engine。需要注意的是BEVFormer包含了时序融合的buffer,导出时需要把use_temporal标志位设成False或固定bev_embedding维度。这块相对复杂,建议先跑通pytorch推理,再考虑TensorRT优化。我在实际部署时发现Nuscenes训练出的模型在real-world数据上泛化性需要评估,建议针对目标场景采集数据做finetune。
根据我的经验,如果在AutoDL上从零开始,环境搭建大约2小时,数据处理1到2小时,冒烟测试半小时,后续全量训练就是时间问题。关键是把环境版本锁死、数据目录规范处理好,后面踩坑的概率会大幅下降。这套流程我已经跑通多次,希望对准备入坑BEVFormer的朋友有帮助。