从零构建3D场景理解:OpenOcc与MMDetection3D实战指南
当自动驾驶汽车穿梭于复杂城市道路时,它如何"看见"并理解周围被遮挡的物体?这正是3D Occupancy预测技术要解决的核心问题。不同于传统3D检测仅识别物体包围框,Occupancy模型将空间划分为体素网格,预测每个网格是否被占据及语义类别,能更精细地描述复杂场景。本文将手把手带您用OpenOcc数据集和MMDetection3D框架,构建首个能理解三维空间占用状态的AI模型。
1. 环境配置与数据准备
1.1 搭建基础开发环境
推荐使用conda创建隔离的Python环境,避免依赖冲突。以下命令将安装PyTorch和CUDA工具包:
conda create -n openocc python=3.8 -y conda activate openocc pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 -f https://download.pytorch.org/whl/torch_stable.htmlMMDetection3D框架需要额外安装mmcv和mmdetection3d:
pip install openmim mim install mmcv-full==1.7.0 mim install mmdet==2.28.1 mim install mmsegmentation==0.30.0 git clone https://github.com/open-mmlab/mmdetection3d.git cd mmdetection3d && pip install -v -e .注意:CUDA版本需与PyTorch匹配,若使用3090等安培架构显卡,建议选择CUDA 11.3以上版本
1.2 获取并解析OpenOcc数据集
OpenOcc在nuScenes基础上扩展了3D体素标注,数据集目录结构如下:
OpenOcc/ ├── occ_gt_release_v1_0 │ ├── train │ │ ├── scene-0001__frame-0001.npz │ │ └── ... │ ├── val │ ├── occ_gt_train.json │ └── occ_gt_val.json └── nuscenes ├── samples ├── sweeps ├── v1.0-trainval └── v1.0-test关键文件说明:
*.npz:体素网格真值,包含200×200×16的网格,每个体素存储语义标签和占据状态occ_gt_*.json:标注元数据,包含相机参数、时间戳等场景信息nuscenes_infos_*.pkl:MMDetection3D所需的预处理数据索引
2. 数据预处理实战
2.1 转换标注格式
OpenOcc的标注需要转换为MMDetection3D兼容的格式。使用以下脚本处理原始数据:
from mmdet3d.datasets import OpenOccDataset dataset = OpenOccDataset( data_root='data/OpenOcc', ann_file='data/OpenOcc/occ_gt_release_v1_0/occ_gt_train.json', pipeline=None, test_mode=False ) dataset.create_data_infos('data/OpenOcc/nuscenes_infos_train.pkl')该过程会生成包含以下关键字段的.pkl文件:
| 字段名 | 类型 | 描述 |
|---|---|---|
| sample_idx | int | 样本唯一ID |
| lidar_points | dict | 激光雷达点云路径及变换矩阵 |
| images | dict | 六路相机图像路径及内外参 |
| occ_gt_path | str | 体素标注文件路径 |
2.2 构建数据流水线
MMDetection3D通过Pipeline处理数据加载和增强。典型配置如下:
train_pipeline = [ dict(type='LoadMultiViewImagesFromFiles', to_float32=True), dict(type='LoadOccupancyGT', grid_size=[200, 200, 16]), dict(type='PhotoMetricDistortionMultiViewImage'), dict(type='NormalizeMultiviewImage', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375]), dict(type='PadMultiViewImage', size_divisor=32), dict(type='DefaultFormatBundle3D', class_names=CLASSES), dict(type='Collect3D', keys=['img', 'gt_occ']) ]提示:体素网格尺寸(grid_size)需与模型head配置保持一致,过大可能导致显存溢出
3. 模型构建与训练
3.1 配置Baseline模型
我们采用基于摄像头的BEVFormer-Occ方案,配置文件关键部分如下:
model = dict( type='OccFormer', img_backbone=dict( type='ResNet', depth=101, num_stages=4, out_indices=(1, 2, 3)), bev_encoder=dict( type='BEVFormerEncoder', num_layers=6, pc_range=[-51.2, -51.2, -5.0, 51.2, 51.2, 3.0]), occ_head=dict( type='OccHead', in_channels=256, out_channels=18, # 16语义类 + 1占据 + 1空 grid_size=[200, 200, 16], loss_occ=dict( type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0)) )主要参数说明:
pc_range:点云范围(xmin, ymin, zmin, xmax, ymax, zmax)grid_size:体素网格的W/H/D维度out_channels:输出通道数=语义类别数+占据状态
3.2 启动分布式训练
使用8卡GPU进行分布式训练的命令:
./tools/dist_train.sh configs/occ/occformer_r101.py 8 --work-dir work_dirs/occformer训练过程监控指标:
| 指标名称 | 正常范围 | 说明 |
|---|---|---|
| loss_occ | 1.5-3.0 | 体素分类损失 |
| acc | 0.7-0.85 | 体素预测准确率 |
| miou | 0.4-0.6 | 语义分割mIoU |
遇到显存不足时,可减小batch_size或降低grid_size分辨率
4. 可视化与性能评估
4.1 结果可视化工具
MMDetection3D提供体素可视化工具,运行以下命令生成预测结果:
from mmdet3d.apis import init_model, inference_detector model = init_model('configs/occ/occformer_r101.py', 'work_dirs/occformer/latest.pth') result = inference_detector(model, 'demo/data/nuscenes/sample_CAM_FRONT.jpg') model.show_results(result, 'demo/result.ply')生成的.ply文件可用CloudCompare或MeshLab查看,不同颜色代表不同语义类别:
- 红色:车辆
- 绿色:植被
- 蓝色:道路
- 黄色:行人
4.2 定量评估指标
评估脚本会自动计算以下关键指标:
./tools/dist_test.sh configs/occ/occformer_r101.py work_dirs/occformer/latest.pth 8 --eval mIoUOpenOcc官方评估协议包含:
| 指标 | 计算公式 | 权重 |
|---|---|---|
| mIoU | Σ(TP)/(Σ(TP+FP+FN)) | 0.5 |
| mAcc | Σ(TP)/Σ(TP+FP) | 0.3 |
| IoU_occ | 占据体素的IoU | 0.2 |
在验证集上,典型baseline模型的性能应达到:
- mIoU: 42-46%
- mAcc: 65-70%
- IoU_occ: 55-60%
5. 进阶优化技巧
5.1 数据增强策略
提升小物体识别效果的多尺度增强配置:
train_pipeline = [ ... dict(type='RandomScaleImageMultiViewImage', scales=[0.5, 0.8, 1.0, 1.2]), dict(type='RandomFlip3D', flip_ratio=0.5), dict(type='OccupancyAug', rot_range=[-0.785, 0.785], scale_ratio=[0.9, 1.1]), ... ]5.2 模型微调技巧
当显存受限时,可采用以下策略:
- 梯度累积:设置
optimizer_config = dict(type='Fp16OptimizerHook', accumulative_counts=2) - 混合精度:添加
fp16 = dict(loss_scale=512.)到配置 - 稀疏卷积:将密集体素预测改为稀疏预测,可减少70%显存占用
occ_head=dict( type='SparseOccHead', voxel_size=0.4, max_num_points=500000)5.3 多模态融合方案
结合激光雷达点云提升性能的配置示例:
model = dict( type='MultiModalOcc', pts_voxel_layer=dict( max_num_points=10, voxel_size=[0.2, 0.2, 0.2], max_voxels=[120000, 160000]), pts_middle_encoder=dict( type='PointPillarsScatter', in_channels=64, output_shape=[512, 512]), fusion_neck=dict( type='CrossModalTransformer', num_heads=8, embed_dims=256) )在实际项目中,这种融合方案能使mIoU提升3-5个百分点,尤其改善遮挡区域的预测效果。