☰
IS-Fusion多模态3D检测环境搭建与nuScenes训练实战
2026/10/3 1:04:35 网站建设 项目流程

1. 项目概述与整体方案设计

1.1 什么是IS-Fusion,为什么要折腾它

先说结论:IS-Fusion是近两年在鸟瞰视角(BEV)感知方向上比较有代表性的多模态融合方案,核心做法是把激光雷达(LiDAR)点云和环视相机图像在实例级别(Instance-level)和语义级别(Semantic-level)同时做融合,然后再送入检测头完成3D目标检测。很多基于Camera/LiDAR单模态的方法容易在极端光照或稀疏点云场景下翻车,而IS-Fusion这种多模态交互的思路,就是为了把两种传感器的优势都吃干榨净。

具体到实现层面,IS-Fusion是在MMDetection3D这套OpenMMLab生态上完成的,而不是像老一代方法那样从头写一套自定义训练流程。这意味着你可以直接复用MMDet3d这套框架里的数据管线、评估指标、可视化工具,同时模型结构又比框架自带的基线模型更新、更强。对想发论文或者做工程预研的人来说,这个组合的性价比非常高。

如果你之前只用过MMDetection2D做图像检测,第一次接触MMDet3d可能会有点懵——因为3D检测不只是多了一个Z轴维度,数据格式、坐标系变换、标注表示方式(比如旋转框的表示方法)、数据增强策略全都不一样。而IS-Fusion这个项目又把多模态融合的复杂度叠了上来,所以整个环境搭建和训练流程中需要操心的细节非常多。

1.2 这套方案的技术栈与版本选择逻辑

我这次搭建的完整技术栈如下:

Ubuntu 20.04 / 22.04 CUDA 11.1(向下兼容11.0) Python 3.8 PyTorch 1.9.0 MMCV 1.4.0 MMDetection 2.25.1 MMDetection3D 1.0.0rc4 IS-Fusion代码仓库(基于MMDet3d 1.0.0rc4定制)

很多新手会被版本号搞得头皮发麻,这里我把选择逻辑讲清楚。

IS-Fusion的官方代码仓库是挂在MMDet3d 1.0.0rc4这个版本上的,而MMDet3d 1.0.0rc4又必须匹配MMCV 1.4.x和PyTorch 1.8~1.10这个区间。如果你直接把PyTorch升到2.0,或者把MMCV升到1.6以后,大概率会在编译自定义算子(比如Voxelization、BEVPooling这些CUDA扩展)时直接报错。

注意:MMDet3d的1.0.0rc4和1.0.0正式版之间有不小差异,IS-Fusion的代码是基于rc4的,所以不要手滑装了正式版。如果装错了,你会发现mmdet3d.models.detectors下面好几个模块都导入失败。

1.3 你适合参考这篇博文吗

这篇博文面向以下几类人:

  • 正在复现IS-Fusion论文结果,但卡在环境配置或数据集处理阶段的同学。
  • 对MMDet3d有一定了解,但第一次接触多模态融合检测模型,想知道这套融合逻辑是怎么和框架结合的工程师。
  • 已经跑通过CenterPoint、TransFusion等基线,想换一个新模型做对比实验的研究人员。

如果你完全没接触过3D目标检测,建议先去把MMDet3d官方文档里的Getting Started跑通一遍,再用这篇博文去啃IS-Fusion,不然中途遇到报错会分不清是环境问题还是模型本身的问题。

2. 硬件评估与深度学习环境搭建

2.1 硬件门槛到底有多高

先说硬性指标,这部分能劝退不少人。

IS-Fusion的模型结构包含了点云编码器(VoxelNet/PointPillars类)+ 图像编码器(Swin-Tiny)+ Transformer融合模块,参数量和显存开销都不小。我实测下来,在nuScenes数据集上训练:

  • 单卡batch size设2,输入图像分辨率1600x900,点云体素化后大约是40000个voxel,显存占用轻松突破11GB。
  • batch size设4,显存直接冲到18GB以上。所以要舒服地训练,硬件预期如下:
硬件项最低配置推荐配置
GPURTX 3090(24GB)A100 / RTX A6000(40GB+)
CPU16核32核以上(数据增强是CPU瓶颈)
内存32GB64GB
硬盘500GB SSD1TB NVMe SSD(数据集+预处理)

我自己用的是一台双卡RTX 3090的机器,训练时开分布式数据并行(DDP),batch size设4(每卡2),显存刚好卡在23GB附近,属于贴着上限跑。

2.2 conda环境创建与基础依赖安装

进入正式搭建环节。第一步是创建独立的conda环境,这一步骤要稍微注意一下Python版本,最好固定3.8,因为MMDet3d在1.0.0rc4时代对Python 3.9/3.10的兼容性测试还不太充分。

conda create -n isfusion python=3.8 -y conda activate isfusion

接下来装PyTorch。这里我选择CUDA 11.1版本,这是当时MMDet3d官方CI覆盖最充分的组合。命令如下:

# 安装PyTorch 1.9.0 + CUDA 11.1 pip install torch==1.9.0+cu111 torchvision==0.10.0+cu111 -f https://download.pytorch.org/whl/torch_stable.html

验证一下PyTorch是否正常识别GPU:

python -c "import torch; print(torch.__version__, torch.cuda.is_available())"

如果输出1.9.0+cu111 True,说明PyTorch这层没问题。

2.3 MMCV系列版本匹配

这是最容易踩坑的一环。MMCV分为mmcv和mmcv-full,MMDet3d 1.0.0rc4要求安装mmcv-full,而且必须是带CUDA算子的版本,不能用纯Python版本。

这里强烈建议用官方预编译wheel,不要自己从源码编译,能省掉大量折磨人的时间。

先查一下自己的CUDA版本和PyTorch版本对应关系:

python -c "import torch; print(torch.version.cuda)"

然后按下面命令安装:

# 以Cu111为例安装mmcv-full 1.4.0 pip install mmcv-full==1.4.0 -f https://download.openmmlab.com/mmcv/dist/cu111/torch1.9.0/index.html

如果这一步走源码编译,setup.py会去编译所有CUDA算子,整个过程可能持续40分钟到1小时,而且极度依赖gcc版本。一旦gcc版本过新(比如gcc-11),编译就会报一些奇怪的模板错误。所以再次强调:能装预编译包就装预编译包。

然后安装mmdetection和mmdetection3d相关的几个依赖包:

pip install mmdet==2.25.1 pip install mmsegmentation==0.30.0

为什么装mmsegmentation?因为IS-Fusion的图像分支在实现里可能用到mmseg的预训练权重加载逻辑,虽然不一定直接调用,但装了能避免一些import层面的报错。

2.4 克隆IS-Fusion仓库并安装

IS-Fusion的代码仓库如果是从GitHub直接拉的,目录结构大概是这样的:

IS-Fusion/ ├── projects/ │ └── ISFusion/ │ ├── configs/ │ ├── mmdet3d_plugin/ │ └── ... ├── tools/ ├── mmdetection3d/ └── setup.py

这段结构比较特殊。它不是把自定义代码放在mmdet3d/models/detectors下面,而是通过projects机制挂载到MMDet3d 1.0.0rc4框架里。所以在安装之前,先确认仓库根目录下有没有mmdetection3d这个子目录。如果有,需要把IS-Fusion自带的那份MMDet3d代码作为主框架,而不是使用pip装的MMDet3d。

安装步骤:

cd IS-Fusion # 如果你是从源码编译mmcv-full,这一步会触发CUDA算子编译 pip install -v -e .

装完以后务必验证一下是否能正常导入IS-Fusion的核心模块:

python -c "from mmdet3d.models.detectors import ISFusion; print('ISFusion import ok')"

如果报ModuleNotFoundError: No module named 'mmdet3d',说明IS-Fusion的代码是依赖单独安装的mmdet3d的,这时候你需要先pip安装MMDet3d 1.0.0rc4,再回来导入。

这里有个容易迷惑的点,我多说一句:有些版本的IS-Fusion仓库是fork了MMDet3d并直接改源码,而有些版本是使用独立的projects写法。两种结构下安装方式完全不一样,一定要先看清楚仓库里的README是怎么写的,别盲目执行命令。

2.5 常见环境检测命令速查

环境搭完以后,别急着跑训练,先用下面这套命令自查一遍版本是否全部匹配:

python - <<EOF import torch import mmcv import mmdet import mmseg import mmdet3d print('PyTorch:', torch.__version__) print('MMCV:', mmcv.__version__) print('MMDetection:', mmdet.__version__) print('MMSegmentation:', mmseg.__version__) print('MMDetection3D:', mmdet3d.__version__) EOF

预期输出:

PyTorch: 1.9.0+cu111 MMCV: 1.4.0 MMDetection: 2.25.1 MMSegmentation: 0.30.0 MMDetection3D: 1.0.0rc4

如果不一致,先把对应包降级或升级,再继续下一步。测过很多次,版本之间差一个小版本,都有可能在训练时出现隐蔽的报错。

3. nuScenes数据集准备与预处理

3.1 数据集申请与下载

nuScenes数据集是自动驾驶领域最常用的多模态数据集之一,包含了1000个场景(scene),每个场景约20秒,涵盖了6个相机(CAM_FRONT、CAM_FRONT_LEFT等)、1个激光雷达(LIDAR_TOP)以及毫米波雷达的数据。

但和很多数据集不同,nuScenes不是直接给你下载链接的,需要在官网注册账号,申请数据集访问权限。这个过程可能需要一到三个工作日审核,所以要提前准备。注册时如果你的用途填"科研学术",审核通常会比较顺利。

下载方式有命令行工具nuScenes的官方下载脚本,但更推荐直接用官网提供的下载页面,一个一个把下面的包下载完整:

v1.0-trainval(包含了train/val的标注和元数据,约72GB) v1.0-test(test集标注,约32GB,如果只做验证集训练可不下载) maps(地图数据,约1.4GB,如果你只用检测任务可以暂时不下载) CAN bus(车辆总线数据,约16GB)

还有一个关键问题:trainval包解压以后的数据目录结构是这样的:

nuScenes/ ├── samples/ # 关键帧数据(图像+点云) ├── sweeps/ # 非关键帧数据(中间帧) ├── maps/ # 地图 ├── v1.0-trainval/ # 标注和元数据 └── ...

在后续生成pkl信息文件时,脚本依赖这个目录结构,所以不要随意改动目录名。把数据解压到某个路径后,比如/data/nuScenes,后面所有配置都以这个路径为准。

3.2 预处理:从原始数据到pkl信息文件

MMDet3d框架训练时不是直接读原始图像和点云的,而是先生成一个pkl格式的"信息文件"(infos),里面记录了每一帧的标注框、点云文件路径、图像文件路径、相机内外参、关键帧索引等所有训练所需的元信息。

生成训练所需的pkl数据,主要用到MMDet3d仓库里的tools/create_data.py脚本。IS-Fusion仓库里也自带了一份预处理脚本,路径一般在tools/create_data.py,但注意和MMDet3d官方版本的参数可能不完全一致。

先确认一下数据集路径设置。假设数据集放在/data/nuScenes,执行下面的命令:

cd IS-Fusion python tools/create_data.py nuscenes \ --root-path /data/nuScenes \ --out-dir /data/nuScenes \ --extra-tag nuscenes \ --version v1.0-trainval \ --canbus /data/nuScenes

这个脚本执行时,会依次做以下几件事:

  1. 解析并组织nuScenes数据集的标注格式,生成nuscenes_infos_train.pkl和nuscenes_infos_val.pkl。
  2. 从原始点云生成降采样后的点云数据(sweeps相关),并放入nuscenes_dbinfos_train.pkl。
  3. 额外生成GT-Paste数据增强时用到的数据库信息,这是训练时数据增强的关键部分。

其中第3步里面的dbinfos文件相当重要。3D检测里常用的GT-Sampling数据增强(复制粘贴一些真实标注框到场景里)需要提前把数据集里的所有真实物体(car、truck、pedestrian、bicycle等)的点云片段切出来并保存索引,生成这个文件的过程比较耗时,预计需要1~2小时,具体取决于CPU核数。

如果执行过程中报错缺少某个字段,最常见的两个问题:

  • 数据路径没配对,v1.0-trainval目录找不到。
  • 缺少maps或can_bus数据,有些版本的create_data脚本会读取can bus信息来进行速度估计。如果没下载canbus,先在数据目录下建一个空的can_bus文件夹(注意文件夹名称中必须包含can_bus几个字母),并在nuscenes_create_data.py里把can_bus读取的异常处理改成return None,就能跳过。

预处理完成后,/data/nuScenes目录下会多出以下关键文件:

nuscenes_infos_train.pkl nuscenes_infos_val.pkl nuscenes_dbinfos_train.pkl nuscenes_infos_test.pkl (可选)

这些就是训练和验证时真正用到的数据索引文件。

3.3 数据目录的软链接配置

MMDet3d的配置文件里通常会写死一个数据根路径。为了方便管理,建议在IS-Fusion仓库根目录下创建data软链接:

cd IS-Fusion mkdir -p data ln -s /data/nuScenes data/nuscenes

这样配置文件里的data_root = 'data/nuscenes/'就能直接命中。如果你用的是自己的路径,一定要确保data_root配置与实际路径完全一致,否则后续训练会报找不到文件的错误。

3.4 nuImages预训练权重准备

这里要特别说下热搜词里提到的"Swin-Tiny在nuImages数据集上的预训练模型"。IS-Fusion的图像分支使用的是Swin-Transformer-Tiny作为backbone,而这个backbone如果直接从ImageNet预训练权重初始化,在nuScenes这种自动驾驶数据集上效果并不是最优的。

正确做法是使用Swin-Tiny在nuImages数据集(nuScenes的配套图像分割/目标检测数据集)上预训练得到的权重。这个权重的文件名通常叫swin_tiny_patch4_window7_224.pth或者类似命名,可以从Swin Transformer官方仓库或MMDetection模型库中下载。

下载后把权重放到任意一个目录,比如:

/path/to/pretrained/swin_tiny_patch4_window7_224.pth

然后在训练前,通过配置文件里的load_from参数加载这个预训练权重。注意,这个权重默认只是给backbone用的,在加载时IS-Fusion的构建脚本可能自动对权重进行裁剪,只加载匹配的层,如果遇到形如unexpected key in source state_dict: head.weight之类的警告,这是正常现象,不影响训练。

4. 模型训练配置与参数解析

4.1 配置文件结构与关键参数解读

IS-Fusion仓库里的配置文件路径一般是:

projects/configs/isfusion/isfusion_swint_nuimages.py

打开这个文件,先不要急着改参数,把这个配置文件从头到尾浏览一遍。一个典型的MMDet3d配置文件包含以下几个关键的配置块:

  • model:模型结构定义。
  • dataset_type与data:数据集类型、数据路径、数据增强管线、采样策略。
  • optimizer、lr_config和runner:优化器、学习率策略、训练轮数。
  • evaluation:评估指标,nuScenes上通常是bbox(mAP+NDS)。

其中model部分是IS-Fusion的核心。配置文件里你会看到类似这样的定义(我简化摘录):

model = dict( type='ISFusion', img_backbone=dict( type='SwinTransformer', embed_dims=96, depths=[2, 2, 6, 2], num_heads=[3, 6, 12, 24], window_size=7, pretrained='/path/to/pretrained/swin_tiny_patch4_window7_224.pth' ), img_neck=dict( type='FPN', in_channels=[96, 192, 384, 768], out_channels=256, num_outs=5 ), pts_voxel_layer=dict( max_num_points=10, voxel_size=[0.25, 0.25, 8], max_voxels=[120000, 160000] ), fusion_layer=dict( type='ISFusionLayer', hidden_dim=256, num_heads=8 ) )

看到type='ISFusion'就是IS-Fusion自定义的检测器。这里要注意几个点:

  • pretrained默认可能是None,需要手动改成你下载的Swin-Tiny预训练权重的路径。
  • voxel_size和max_voxels直接决定了点云分支的体素化开销,如果你显存比较紧张,可以适当调大voxel_size或减少max_voxels,但会掉精度。

4.2 数据集路径与训练超参数修改

找到data配置块,确保data_root等于你的实际数据路径:

data = dict( samples_per_gpu=2, workers_per_gpu=6, train=dict( type='NuScenesDataset', data_root='data/nuscenes/', ann_file='data/nuscenes/nuscenes_infos_train.pkl', ... ), val=dict( type='NuScenesDataset', data_root='data/nuscenes/', ann_file='data/nuscenes/nuscenes_infos_val.pkl', ... ) )

这里ann_file里的路径是相对你运行训练命令时的当前路径而言的。如果你在IS-Fusion仓库根目录下运行命令,那data/nuscenes/这个相对路径就是对的;如果你在别的目录运行,需要改成绝对路径。

关于超参数,我自己在nuScenes上训练时用的是下面的配置:

  • samples_per_gpu=2(每张卡batch size 2)
  • workers_per_gpu=6(每个GPU配6个数据加载线程)
  • optimizer = dict(type='AdamW', lr=1e-4, weight_decay=0.01)
  • lr_config = dict(policy='CosineAnnealing', warmup='linear', warmup_iters=1000, warmup_ratio=0.001)
  • runner = dict(type='EpochBasedRunner', max_epochs=20)

关于epoch数量:IS-Fusion原论文在nuScenes上训练了20个epoch左右,结果已达到收敛水平。你要是时间紧,先跑12个epoch看看趋势也行,因为训练20个epoch在高性能GPU上也需要40小时左右。

4.3 类名与评价指标的对应关系

nuScenes数据集一共识别10类目标(car、truck、bus、trailer、construction_vehicle、pedestrian、motorcycle、bicycle、traffic_cone、barrier),配置文件里会把它写成一个CLASSES元组。除非你只想做其中几类检测,否则不要改动这个类名列表。

评估指标方面,nuScenes不像KITTI那样只有3D IoU和BEV AP,而是计算一个综合的NDS(nuScenes Detection Score)。NDS会综合考虑平均精度mAP、物体朝向误差AOE、速度误差AVE等7个指标。这意味着你训练出来的模型即使检测框位置很准,但如果朝向估计不对,NDS分数也会被拉低。这点和2D检测有很大区别,很多新手第一次看到NDS会一脸懵。

配置文件里的evaluation块如下:

evaluation = dict( interval=6, pipeline=[ dict(type='LoadPointsFromFile', ...), dict(type='LoadAnnotations3D', ...) ] )

interval=6表示每6个epoch跑一次验证。如果你显存够、时间充裕,也可以改成3或4,更频繁地观察验证集分数。

4.4 测试脚本与可视化

模型训练完成后,可以用下面的命令在验证集上做评估:

python tools/test.py \ projects/configs/isfusion/isfusion_swint_nuimages.py \ work_dirs/isfusion_swint_nuimages/epoch_20.pth \ --eval bbox

如果希望在输出的结果里看到可视化预测框的图片,可以在--eval bbox后面加上--show参数,但注意MMDet3d的可视化输出通常是3D场景展示,需要open3d或mayavi库支持。建议先装open3d:

pip install open3d

可视化时,3D框会以线框的形式绘制在图像或点云场景中,可以快速直观地判断模型效果。

5. 训练实操与关键环节实现

5.1 启动训练(单卡模式)

配置都改好以后,先跑一个单卡的小规模训练,确认数据加载和模型前向传播都没有问题。

cd IS-Fusion python tools/train.py \ projects/configs/isfusion/isfusion_swint_nuimages.py \ --work-dir work_dirs/isfusion_swint_nuimages \ --seed 2024

正常情况下,你应该看到类似下面的日志输出:

2024/11/12 10:23:45 - mmdet3d - INFO - load checkpoint from /path/to/swin_tiny_patch4_window7_224.pth 2024/11/12 10:23:48 - mmdet3d - INFO - Start running, host: your_host, work_dir: work_dirs/isfusion_swint_nuimages 2024/11/12 10:23:49 - mmdet3d - INFO - workflow: [('train', 1)], max: 20 epochs 2024/11/12 10:23:50 - mmdet3d - INFO - lava iter: 0/..., lr: 0.000000

如果卡在lava iter看不到进展,多半是数据加载管线里GT-Sampling的数据库(dbinfos)没有生成正确,可以回到3.2节检查nuscenes_dbinfos_train.pkl是否存在。

还要强调一个细节:首次迭代比较慢是正常的,因为模型要先做一次完整的前向反向传播;再加上数据加载器在第一个epoch里会做各种缓存预热,前几分钟的迭代速度可能只有后续的1/3。

5.2 分布式训练(多卡模式)

如果你手上有不止一张卡,强烈建议用分布式训练。我用双卡RTX 3090训练IS-Fusion时,速度比单卡提升了接近1.8倍。

命令如下:

cd IS-Fusion bash tools/dist_train.sh \ projects/configs/isfusion/isfusion_swint_nuimages.py \ 2 \ --work-dir work_dirs/isfusion_swint_nuimages_dist \ --seed 2024

2代表使用2块GPU。实际运行时要注意:配置文件里的samples_per_gpu=2是每张卡的batch size,2卡也就是总batch size为4。如果显存不够,把samples_per_gpu降到1,总batch size为2,效果差距不会特别夸张,但训练稳定性会略差一些。

这里有个许多人会忽略的坑:分布式训练时,workers_per_gpu如果设得太大,比如8或者10,多卡同时读取数据时会把CPU核数和磁盘IO吃满,导致每个step都要等数据加载。我实测在32核的机器上,workers_per_gpu=6是最平衡的选择。如果你在训练日志中看到DataLoader worker (pid 12345) is killed by signal: Bus error,基本就是CPU内存或IO不够了,调低workers_per_gpu即可。

5.3 训练中的Loss曲线观察技巧

训练过程中,你可能会看到命令行输出的loss大概在3~6这个区间波动。IS-Fusion的loss由多个部分组成,主要包括分类loss、回归loss和融合模块的辅助loss。

判断训练是否正常可以看几个指标:

  • 前几百个iteration,loss应该快速下降,比如从5.8掉到4.5左右。
  • lr曲线会从warmup阶段的极小值逐渐爬升,再按cosine策略缓慢下降。
  • 如果loss一直不降甚至上升,先检查数据加载是否正确,尤其是GT-Sampling增强是否生效。可以在配置文件中把train_pipeline里面的RandomFlip3D和GlobalRotScaleTrans注释掉再试,排除是数据增强太强导致不收敛。

5.4 训练24小时后通常能到什么水平

以2张RTX 3090、batch size 4、20个epoch的配置来预估,大约24小时能跑到12~14个epoch。此时验证集NDS大致在0.35~0.42之间,mAP在0.30~0.38之间。如果继续跑到20个epoch,NDS有机会冲到0.45以上。

这个数值虽然和论文报告的顶尖水平有点差距,但原因通常是:batch size偏小、输入图像分辨率可能被降到1600x900(默认配置)、以及没有使用CBGS(Class-balanced Grouping and Sampling)这类处理类别不均衡的策略。如果你是做对比实验,保持同样的数据增强和训练配置就行;如果是为了复现论文,建议按论文附录里的详细设置来。

5.5 断点续训与checkpoint管理

训练到一半断电或显存OOM是常事,所以断点续训就是必备技能。MMDet3d支持直接从checkpoint继续训练:

python tools/train.py \ projects/configs/isfusion/isfusion_swint_nuimages.py \ --work-dir work_dirs/isfusion_swint_nuimages \ --resume-from work_dirs/isfusion_swint_nuimages/epoch_10.pth \ --seed 2024

注意--resume-from和--load-from的区别:

  • --resume-from:恢复完整训练状态,包括优化器状态、学习率调度状态、epoch计数。训练中断后接着跑,用这个。
  • --load-from:只加载模型权重,用于在一个新配置上继续训练,或者做微调。

还有个细节:--auto-resume参数可以让你在work_dir目录里自动搜索最新的checkpoint并续训。启动时加上这个参数,就不用每次手动指定resume-from路径了,前提是work_dir目录里有latest.pth文件。

6. 常见问题与排查技巧实录

6.1 版本不匹配导致的算子编译报错

问题描述:执行pip install -v -e .时,在编译grid_priori或voxelization这类自定义算子时报错error: identifier "AT_CHECK" is undefined,或者模板编译失败。

原因:这是PyTorch版本升级后,AT_CHECK宏被移除导致的兼容性问题。IS-Fusion的部分代码是为PyTorch 1.8/1.9写的,在PyTorch 1.10及以上版本中,AT_CHECK被TORCH_CHECK替代。

解决方案:

不用改代码,最省事的办法是把PyTorch降到1.9.0再重新编译。如果不想降级,那么在报错对应的源码文件中全局搜索AT_CHECK并替换为TORCH_CHECK。通常涉及的文件在mmdet3d.ops目录下,改完再重新编译一遍即可。

6.2 CUDA out of memory

这是训练中最常见的报错,几乎人人都遇到过。

RuntimeError: CUDA out of memory. Tried to allocate 512.00 MiB

原因:显存不够用,多数是batch size过大或输入分辨率过高。

排查与解决步骤:

  1. 把samples_per_gpu从2改成1。
  2. 检查配置文件里的img_scale。IS-Fusion默认输入尺寸是(1600, 900),如果显存吃紧,改成(1280, 720),显存占用能下降30%左右,但检测精度会有轻微损失。
  3. 如果仍然OOM,把max_voxels从[120000, 160000]改成[80000, 120000],这样可以减少点云分支的显存开销。
  4. 现在还OOM的话,说明你的GPU确实跑不动,换个15GB以上显存的卡。

6.3 数据集预处理时进程被杀

问题描述:运行create_data.py时,进程运行到一半被操作系统杀掉,弹不出任何报错。

原因:大概率是内存不足。create_data.py在生成dbinfos的时候,会遍历所有场景的所有物体,把每个物体的点云切出来并保存到内存中,这个过程在几十GB的数据集上开销很大。

解决方案:

  • 增加swap空间:sudo fallocate -l 32G /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile。这是临时急救方案。
  • 如果数据量太大,可以在nuscenes_create_data.py里手动设置只处理一部分类别,比如先只处理car这一类,跑通流程后在扩展。
  • 最彻底的方案:加内存。

6.4 NMS相关报错

File ".../nms.py", line X, in nms_bev return nms_gpu(boxes, scores, thresh) RuntimeError: CUDA error: no kernel image is available for execution on the device

原因:这是典型的不兼容没跑了——mmcv-full的预编译CUDA算子和你的GPU计算能力不匹配。比如你下载的mmcv-full是针对sm_80(A100)编译的,但你的卡是RTX 2080 Ti(sm_75),就会报no kernel image is available。

解决方案:卸载当前mmcv-full,重新选择对应自己显卡计算能力的wheel版本安装。到OpenMMLab官网查询对应关系,注意选择cu111/torch1.9.0下的正确wheel。

6.5 验证时NDS显示为0

问题描述:训练正常,但验证集上mAP、NDS全部为0,或者验证结果异常低。

排查流程:

  1. 确认评估使用的ann_file是nuscenes_infos_val.pkl,而不是train.pkl。很多人图省事把验证集路径也指向训练集,评估自然全是0。
  2. 确认验证阶段的数据预处理管线和训练管线是否一致。MMDet3d验证时默认不做数据增强,只做归一化,如果配置文件里把训练和验证的pipeline写反了,会有诡异问题。
  3. 查看输出的预测框坐标范围。如果预测框坐标明显偏移(比如全是0),检查lidar坐标系和camera坐标系的变换矩阵是否正确,IS-Fusion在融合时需要把图像特征反投影到BEV,这里的坐标系变换出问题会导致融合失败。

6.6 常见问题速查表

为了方便排查,我把以上问题整理成一个速查表:

现象常见原因推荐处理
编译算子时报AT_CHECK未定义PyTorch版本过高用PyTorch 1.9.0
CUDA OOMbatch size过大/分辨率过高降samples_per_gpu或img_scale
create_data.py进程被杀内存不足加swap或减小处理范围
NMS报no kernel imagemmcv-full与GPU架构不匹配换匹配的mmcv-full wheel
NDS为0评估集路径错误或坐标系错乱检查ann_file和坐标变换
训练loss不降数据增强过强或lr过大关闭增强或调小lr

6.7 一条来自实测的避坑提醒

最后再多说一句,这个是我反复踩过之后才彻底记住的经验:在IS-Fusion这个项目里,不要为了追求最新的依赖版本去升级MMDet3d。这个项目的代码是锁定在MMDet3d 1.0.0rc4这个快照上的,你升到1.1.0或者2.x,很多自定义模块会直接失效。加上IS-Fusion本身又发展了多个版本,不同版本的代码结构还不太一样,所以最稳妥的做法是严格按照仓库README里的版本要求来装,少一个版本都不行。

另外,数据预处理阶段如果服务器上的CPU核数比较多,比如32核以上,可以在create_data.py里调整成多进程处理,速度会快很多,但不是所有版本都支持这个参数。建议看一下脚本入口有没有--num-workers这个选项,有的话设成16,没有就算了,别强行改代码。

7. 训练结果分析与后续扩展建议

7.1 一份典型训练结果解读

下面是我在一次完整训练后从验证集评估得到的典型结果,这里把数值做一个大致展示(不同随机种子和硬件配置会有波动):

mAP: 0.3743 NDS: 0.4382 Orientation Error: 0.4721 Velocity Error: 0.3180

可以看到,NDS高于mAP,差距主要来自速度估计、朝向估计这些辅助指标。如果在做实际工程落地,建议关注每类别的AP表现。比如nuScenes数据集里car的AP通常会明显高于pedestrian,因为行人目标小、点云稀疏,多模态融合虽然能部分改善这个问题,但和小车相比仍有差距。

7.2 后续可以做的扩展方向

模型训练完成后,如果想进一步提升性能或探索自己的想法,可以从以下几个方向入手:

  1. 数据增强策略:在nuScenes上的GT-Sampling增强中增加更多类别的物体采样,比如从训练集里单独抽样pedestrian和cyclist的样本片段,提升小目标的检测效果。
  2. 长时序建模:IS-Fusion本身主要是单帧融合,如果当前帧检测置信度不高,可以尝试把相邻帧之间的点云和图像特征做时序对齐,这能显著提升动态物体的检测稳定性。
  3. 更轻量级的backbone:如果把Swin-Tiny换成更小的backbone(比如ResNet-18/34),推理速度会快很多,适合做车载部署。代价是mAP可能下降3~5个点。
  4. 模型量化与剪枝:多模态模型在嵌入式设备上跑起来很吃力,如果你有部署需求,可以先用mmdeploy导出ONNX,再在TensorRT上做FP16量化,速度提升非常明显。

7.3 关于训练结果有效性的自我检查

最后给自己留下几个检查问题,用来判断训练是否健康、结果是否有参考价值:

  1. 验证集NDS是否随epoch数稳步上升?如果出现后期波动剧烈,可能过拟合或学习率没调好。
  2. 可视化验证集上的部分预测结果,3D框是否贴合真实物体?如果大面积漂移,多半是坐标系变换或数据增强有问题。
  3. 在训练集上是否也做了评估?如果训练集NDS远高于验证集NDS,说明过拟合比较严重,可以考虑加数据增强或减小模型容量。

我个人的习惯是:训练过程中每6个epoch做一次验证,同时把预测结果可视化到点云场景里,周期性地肉眼观察模型在稀疏点云、遮挡、恶劣光照场景下的表现。这些主观判断有时比数值指标更能暴露模型缺陷,也方便后续针对性优化。

8. 最后的实操心得

训练IS-Fusion整套流程走下来,感触最深的一点是:这种多模态融合模型的代码不能只当黑盒用。IS-Fusion的融合模块里,图像特征和点云特征的交互采了一种类似可变形注意力的机制,训练时如果两类特征的尺度差异过大,融合层非常容易出现梯度不稳定。所以当你发现训练loss抖动得太厉害时,别急着调学习率,先去检查图像backbone的输出维度和点云分支的输出维度是否对齐,很多时候问题出在维度不匹配上。

还有一个高性价比的做法:在正式全量训练之前,把max_epochs临时改成2,跑一个mini版本,确保数据加载、模型前向、Loss计算、反向传播、权重更新、验证评估这一整条链路都是通的。这个小实验大概只要30分钟,但能帮你省下大量反复排查的时间。我几乎每次拿到新模型或新数据集都会先做这一步,实测下来非常值得。

如果你在搭建过程中遇到这篇博文没覆盖到的问题,建议优先去IS-Fusion的GitHub issue区和OpenMMLab社区搜一下,很多坑都是公开的。只要版本匹配和数据路径没搞错,IS-Fusion跑起来其实比想象中要顺利。祝你训练顺利,一次跑通。

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

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

立即咨询