← back

nuScenes 数据集深度解析

0. 前言

📚 本文是一篇关于 nuScenes 数据集的深度技术解析,内容涵盖 15 个章节,建议收藏后慢慢阅读。

nuScenes 是目前学术界和工业界最广泛使用的自动驾驶感知 Benchmark,几乎所有 BEV 感知、3D 检测、Occupancy 方向的论文都以它为评测基准。然而,网上关于 nuScenes 的资料大多停留在「怎么下载」「怎么跑通 demo」的层面,缺乏对数据集本身的系统性梳理。

本文将从工程实践视角,对 nuScenes 进行一次全面拆解:

章节内容适合谁看
1-5数据集概览、传感器规格、标注体系、数据结构、评测指标所有研究者
6-7nuScenes 成为主流的原因、与 Waymo / Argoverse 2 对比选型决策者
8-9官方扩展数据集、E2E 训练局限性与 nuPlan端到端研究者
10Occ3D / OpenOcc / SurroundOcc / OpenOccupancy 四大 Occupancy 数据集深度对比Occupancy 研究者
11-12nuscenes-devkit 可视化详解、经典工作汇总工程落地者
13-14训练 Tricks(CBGS、GT-Aug、Multi-sweep 等)、使用建议“炼丹师”

无论你是自动驾驶的新人还是老人,这篇文章都值得一读


1. 数据集概览

1.1 基本规模

指标数值
场景数量1,000 scenes(每个 20s)
相机图像约 140 万张
LiDAR sweeps约 39 万帧
RADAR sweeps约 140 万帧
关键帧数量4 万帧(2Hz 标注频率)
3D Bounding Boxes约 140 万个
LiDAR 语义标注点数11 亿点(Panoptic nuScenes 扩展)

1.2 采集地点

两地的交通规则差异为算法的泛化能力提供了良好的测试场景

image.png


2. 传感器配置

nuScenes 是首个提供完整 360° 传感器套件的大规模数据集:

nuScenes 传感器套件:6 个相机实现 360° 环视覆盖

2.1 传感器列表

传感器类型数量覆盖范围
Camera6360° 环视
LiDAR1360°(Velodyne HDL-32E)
RADAR5360°
GPS1-
IMU1-

2.2 LiDAR 详细规格

型号:Velodyne HDL-32E

参数规格
线束数32 beams
采集频率20 Hz
水平 FOV360°
垂直 FOV+10° 至 -30°(41.33°)
每圈点数~1080 点
点云速率约 139 万点/秒(双回波模式)
有效距离70m(最大 100m)
精度± 2 cm
激光波长905 nm(Class 1 人眼安全)

与 KITTI 对比:KITTI 使用 Velodyne HDL-64E(64 线),nuScenes 的 32 线点云更稀疏,但成本更低,更接近量产车配置。

2.3 相机详细规格

型号:Basler acA1600-60gc + Evetar Lens N118B05518W

参数规格
传感器1/1.8” CMOS
原始分辨率1600 × 1200
实际输出1600 × 900(ROI 裁剪)
采集频率12 Hz
镜头焦距5.5 mm,F1.8
曝光时间自动曝光,最大 20 ms
图像格式Bayer8 → BGR → JPEG 压缩

2.4 相机 FOV 与布局

image.png

相机FOV方向
CAM_FRONT70°正前方
CAM_FRONT_LEFT70°前左 55°
CAM_FRONT_RIGHT70°前右 55°
CAM_BACK110°正后方
CAM_BACK_LEFT70°后左
CAM_BACK_RIGHT70°后右

前向和侧向相机之间偏移 55°,确保相邻相机视野有重叠,实现完整 360° 覆盖。后视相机 FOV 更大(110°)以弥补后方视野要求。

2.5 传感器同步机制

nuScenes 采用精确的时间同步策略:


3. 标注体系

3.1 目标检测类别(10 类)

nuScenes 原始标注 23 类,检测挑战合并为 10 类:

类别描述
car轿车
truck卡车
bus公交车
trailer拖车
construction_vehicle工程车
pedestrian行人
motorcycle摩托车
bicycle自行车
traffic_cone交通锥
barrier护栏

3.2 目标属性标注

除了 3D Bounding Box,还标注了丰富的属性:

3.3 语义分割类别(32 类)

Panoptic nuScenes 扩展提供点云语义标注,包含:


4. 数据组织结构

4.1 文件目录结构

nuScenes 数据集下载后的推荐组织方式(兼容 mmdetection3d):

nuscenes/
├── maps/                          # 高精地图(4 张栅格化地图)
│   ├── basemap/                   # 底图
│   ├── expansion/                 # 扩展图层
│   ├── prediction/                # 预测用地图
│   ├── 36092f0b03a857c6a3403e25b4b7aab3.png   # boston-seaport
│   ├── 37819e65e09e5547b8a3ceaefba56bb2.png   # singapore-onenorth  
│   ├── 53992ee3023e5494b90c316c183be829.png   # singapore-hollandvillage
│   └── 93406b464a165eaba6d9de76ca09f5da.png   # singapore-queenstown

├── samples/                       # 关键帧数据(2Hz,带标注)
│   ├── CAM_FRONT/                 # 前向相机图像
│   │   ├── n015-2018-07-18-11-07-57+0800__CAM_FRONT__1531883530412470.jpg
│   │   └── ...
│   ├── CAM_FRONT_LEFT/            # 前左相机图像
│   ├── CAM_FRONT_RIGHT/           # 前右相机图像
│   ├── CAM_BACK/                  # 后向相机图像
│   ├── CAM_BACK_LEFT/             # 后左相机图像
│   ├── CAM_BACK_RIGHT/            # 后右相机图像
│   ├── LIDAR_TOP/                 # 顶部 LiDAR 点云(.pcd.bin)
│   ├── RADAR_FRONT/               # 前向毫米波雷达
│   ├── RADAR_FRONT_LEFT/          # 前左毫米波雷达
│   ├── RADAR_FRONT_RIGHT/         # 前右毫米波雷达
│   ├── RADAR_BACK_LEFT/           # 后左毫米波雷达
│   └── RADAR_BACK_RIGHT/          # 后右毫米波雷达

├── sweeps/                        # 非关键帧数据(原始频率,无标注)
│   ├── CAM_FRONT/                 # 同 samples,12Hz
│   ├── CAM_FRONT_LEFT/
│   ├── ...
│   ├── LIDAR_TOP/                 # 20Hz 点云
│   └── RADAR_*/                   # 13Hz 雷达数据

├── lidarseg/                      # 点云语义分割标签(可选)
│   └── v1.0-{mini,trainval,test}/
│       ├── {sample_data_token}_lidarseg.bin   # 逐点类别标签
│       └── ...

├── v1.0-mini/                     # Mini 子集元数据(10 scenes)
├── v1.0-trainval/                 # 训练+验证集元数据(850 scenes)
└── v1.0-test/                     # 测试集元数据(150 scenes,无标注)
    ├── attribute.json             # 目标属性定义
    ├── calibrated_sensor.json     # 传感器标定(内外参)
    ├── category.json              # 类别定义(23 类)
    ├── ego_pose.json              # 车辆位姿(全局坐标)
    ├── instance.json              # 目标实例(跨帧 tracking ID
    ├── log.json                   # 采集日志(车辆、日期、地点)
    ├── map.json                   # 地图引用
    ├── sample.json                # 关键帧定义(2Hz)
    ├── sample_annotation.json     # 3D Box 标注
    ├── sample_data.json           # 传感器数据索引
    ├── scene.json                 # 场景定义(20s 连续段)
    ├── sensor.json                # 传感器定义
    └── visibility.json            # 可见性定义

4.2 核心概念关系

scene (场景)
  └── sample (关键帧, 2Hz)
        ├── sample_data (传感器数据指针)
        │     ├── CAM_FRONT → samples/CAM_FRONT/xxx.jpg
        │     ├── LIDAR_TOP → samples/LIDAR_TOP/xxx.pcd.bin
        │     └── ...
        └── sample_annotation (3D Box 标注)
              ├── instance_token → 跨帧目标 ID
              ├── category_token → 类别
              ├── attribute_tokens → 属性(可见性、姿态等)
              └── translation, size, rotation → 3D 位姿

4.3 关键帧 vs 非关键帧

类型目录频率标注用途
关键帧samples/2 Hz✅ 有 3D Box训练 & 评测
非关键帧sweeps/原始频率❌ 无时序建模、点云累积

4.4 元数据 JSON 文件说明

文件内容主要字段
scene.json场景定义token, name, first/last_sample_token
sample.json关键帧token, timestamp, scene_token, data
sample_data.json传感器数据token, filename, ego_pose_token, calibrated_sensor_token
sample_annotation.json3D 标注token, instance_token, translation, size, rotation
instance.json目标实例token, category_token, first/last_annotation_token
calibrated_sensor.json标定参数camera_intrinsic, translation, rotation
ego_pose.json车辆位姿translation, rotation, timestamp

4.5 数据划分

子集元数据目录场景数用途
miniv1.0-mini/10代码调试、快速验证
trainv1.0-trainval/700训练
valv1.0-trainval/150验证
testv1.0-test/150测试(标注不公开)

5. 评测指标

5.1 3D 目标检测指标

NDS(nuScenes Detection Score) 是综合评价指标:

$$ NDS = \frac{1}{10}[5 \times mAP + \sum_{i=1}^{5}(1 - \min(1, TP_i))] $$

其中 $TP_i$ 包含 5 个 True Positive 指标:

指标描述
ATEAverage Translation Error(平移误差)
ASEAverage Scale Error(尺度误差)
AOEAverage Orientation Error(朝向误差)
AVEAverage Velocity Error(速度误差)
AAEAverage Attribute Error(属性误差)
指标描述
ATEAverage Translation Error(平移误差)
ASEAverage Scale Error(尺度误差)
AOEAverage Orientation Error(朝向误差)
AVEAverage Velocity Error(速度误差)
AAEAverage Attribute Error(属性误差)

mAP 计算特点

5.2 跟踪指标

5.3 预测指标


6. 为何 nuScenes 成为主流 Benchmark

nuScenes 在自动驾驶感知领域的主导地位并非偶然,而是多重因素的综合结果:

6.1 传感器配置最接近量产车

nuScenes 是首个提供完整 360° 环视传感器套件的公开数据集。6 个相机的配置与特斯拉、蔚来、理想等量产车高度一致。相比之下,KITTI 只有前向双目相机,研究成果难以迁移到实际产品。

6.2 数据规模与标注质量的平衡

6.3 评测体系设计合理

NDS 指标综合考虑了 mAP + 5 个 TP 误差(位置、尺度、朝向、速度、属性),比 KITTI 单纯用 IoU 阈值更全面,能更好区分算法的实际性能差异。

6.4 开发工具完善

nuscenes-devkit 提供开箱即用的数据加载、可视化、评测脚本,降低了研究者的工程负担。

6.5 先发优势与网络效应

2019 年发布后被 BEVDet、BEVFormer 等开创性工作采用,形成了事实标准。新论文为了与前人对比,只能沿用同一 Benchmark。

6.6 场景多样性

波士顿(右舶)+ 新加坡(左舶)的组合提供了交通规则差异,有利于评估算法泛化能力。


7. 与其他高质量数据集对比

7.1 主流数据集概览

数据集场景数相机LiDAR3D Box 标注地域
nuScenes1,0006(360°)1140 万波士顿、新加坡
KITTI222(前向)18 万德国
Waymo1,150551200 万美国多城市
Argoverse 21,0007(360°)2-美国多城市

nuScenes 优势

7.2 Waymo Open Dataset

发布方:Waymo(Google 旗下自动驾驶公司)

发布时间:2019 年

指标规格
场景数1,150(每个 20s)
相机5 个(1 前 + 2 前侧 + 2 侧)
LiDAR5 个(1 顶部 64 线 + 4 短距)
3D Box 标注约 1200 万
标注频率10 Hz
采集地域美国多城市(旧金山、凤凰城等)

优势

局限

7.3 Argoverse 2

发布方:Argo AI(福特 & 大众投资,2022 年已解散)

发布时间:2021 年

指标规格
场景数1,000(传感器数据集)
相机7 个环视 + 2 个立体前视
LiDAR2 个 32 线
高精地图6 个城市,覆盖 2,000+ km
标注频率10 Hz
采集地域美国 6 城市

核心特色

适用场景

7.4 数据集选择建议

研究方向推荐数据集理由
BEV 感知入门nuScenes社区成熟、复现方便
追求 SOTAWaymo数据量大、标注精度高
在线建图Argoverse 2HD Map 标注最完善
轨迹预测Argoverse 2Motion Forecasting 子集专为预测设计
端到端规划nuPlan唯一大规模 Planning 数据集

8. nuScenes 官方扩展数据集

8.1 nuScenes-lidarseg

8.2 Panoptic nuScenes

8.3 nuImages


9. nuScenes 在端到端训练中的局限性

nuScenes 虽然是感知 Benchmark 的事实标准,但在端到端自动驾驶(E2E) 研究中存在明显不足:

9.1 核心局限

维度局限性影响
数据量仅 5.5 小时有效驾驶数据难以学习复杂驾驶策略
场景数1000 个场景,每个仅 20s长尾场景覆盖不足
规划标注无 Planning 标注(仅有 ego pose)只能用 ego 轨迹作为伪标签
评测方式仅支持开环评测无法评估闭环决策能力
交互场景缺乏复杂交互标注难以评估博弈行为

9.2 nuPlan:面向规划的数据集

为弥补上述不足,Motional 于 2021 年发布了 nuPlan——首个大规模自动驾驶规划数据集:

指标nuScenesnuPlan
数据量5.5 小时1500+ 小时
场景数1,000120 万+
标注类型感知标注感知 + 规划轨迹
评测方式开环开环 + 闭环仿真
采集地域2 城市4 城市(波士顿、匹兹堡、新加坡、拉斯维加斯)

nuPlan 特色

9.3 nuPlan 的局限性

尽管 nuPlan 在数据规模上有巨大提升,但仍存在根本性问题:

  1. 仿真保真度不足
    • 其他交通参与者采用简单的 replay 或规则驱动
    • 无法模拟真实的人类驾驶反应
    • 仿真与真实世界存在 sim-to-real gap
  2. 场景多样性有限
    • 仍以常规驾驶为主
    • 高风险 corner case(如紧急避让、复杂路口博弈)覆盖不足
  3. 传感器数据缺失
    • nuPlan 主要提供向量化数据(检测结果、地图)
    • 原始传感器数据(图像、点云)需额外下载,体积巨大

9.4 闭环仿真:依然是开放难题

端到端自动驾驶的评测核心在于闭环仿真——让模型的决策影响环境,环境再反馈给模型。目前的主要挑战:

⚠️ 核心矛盾:高保真仿真需要精确建模人类行为,但人类行为本身难以预测。

有前景的闭环仿真方案

方案代表工作核心思路局限
数据驱动仿真TrafficSim、BITS从真实数据学习交通参与者行为模型泛化到未见场景困难
生成式仿真GAIA-1、DriveDreamer、MagicDrive用 Diffusion/World Model 生成逼真驾驶视频物理一致性难以保证
神经渲染仿真UniSim、MARS、StreetGaussians用 NeRF/3DGS 重建真实场景,支持视角合成动态物体建模困难
混合仿真Waymax、DriveArena结合数据驱动 + 规则 + 可控生成工程复杂度高

当前研究趋势

💡 小结:nuScenes 适合感知研究,nuPlan 是 Planning 研究的起点,但真正的闭环端到端评测仍需依赖下一代仿真技术。


10. 基于 nuScenes 的 3D Occupancy 数据集深度对比

随着 Tesla 提出 Occupancy Network 概念,3D 占据感知成为自动驾驶感知的热门方向。由于 nuScenes 官方未提供 Occupancy 标注,学术界陆续构建了多个基于 nuScenes 的 Occupancy 数据集。

10.1 主流 Occupancy 数据集概览

数据集发布时间会议类别数Flow 标注分辨率
Occ3D-nuScenes2023NeurIPS160.4m
OpenOcc2023ICCV160.5m
SurroundOcc2023ICCV160.5m
OpenOccupancy2023ICCV160.2m

10.2 标注生成流程对比

所有 Occupancy 数据集的核心挑战是:如何从稀疏的 LiDAR 点云生成稠密的体素标注?

各数据集采用了相似但有差异的自动标注流水线:

通用流程(三步走)

1. LiDAR 点云累积 (Point Cloud Accumulation)
   └─ 聚合多帧 LiDAR 扫描,增加点云密度

2. 遮挡推理 (Occlusion Reasoning / Ray Casting)
   └─ 判断每个体素是「占据」「空闲」还是「不可见」

3. 场景补全 (Scene Completion / Refinement)
   └─ 填补点云稀疏区域的语义标注

各数据集差异

步骤Occ3D-nuScenesOpenOccSurroundOccOpenOccupancy
点云累积多帧聚合 + Poisson 重建多帧聚合多帧聚合 + NeRF 隐式重建多帧聚合 + 多传感器融合
遮挡推理基于可见性的 Ray CastingRay CastingRay Casting + 图像引导动态物体单独处理
场景补全图像引导的体素细化语义先验补全多尺度特征融合LiDAR-Camera 交叉验证

10.3 Occ3D-nuScenes 详解

来源:清华 MARS Lab

标注流程

  1. 点云稠密化:累积前后多帧 LiDAR 点云,使用 Poisson 表面重建生成连续 Mesh
  2. 语义迁移:将 nuScenes 3D Box 标注和 Panoptic nuScenes 语义标注迁移到体素
  3. 可见性建模:通过 Ray Casting 判断每个体素对各相机的可见性
  4. 体素细化:利用图像特征修正边界区域的语义类别

特点

体素范围

X: [-40m, 40m]  →  200
Y: [-40m, 40m]  →  200
Z: [-1m, 5.4m]  →  16
分辨率: 0.4m

10.4 OpenOcc 详解

来源:OpenDriveLab(与 OccNet / Scene as Occupancy 论文配套)

核心差异

  1. 提供 Flow 标注:为 8 类前景物体(车、人、骑行者等)标注了运动流向量
  2. 支持 4D 感知:可用于 Motion Prediction 和 Planning 任务

标注流程

  1. 多帧点云对齐(动静态分离处理)
  2. 基于 nuScenes 3D Box 的实例关联
  3. 计算相邻帧之间的物体位移作为 Flow GT

体素范围

X: [-50m, 50m]  →  200
Y: [-50m, 50m]  →  200
Z: [-5m, 3m]    →  16
分辨率: 0.5m

适用场景:端到端自动驾驶研究(如 UniAD、VAD 使用 OpenOcc 评测 Planning)


10.5 SurroundOcc 详解

来源:清华大学

核心创新:引入 NeRF 隐式重建 辅助标注生成

标注流程

  1. 训练场景级 NeRF 模型重建连续 3D 场景
  2. 从 NeRF 中采样得到稠密的占据信息
  3. 结合 LiDAR 点云和图像语义进行标签融合

特点


10.6 OpenOccupancy 详解

来源:上海交通大学

核心差异

  1. 最高分辨率:0.2m(其他数据集为 0.4-0.5m)
  2. 多传感器融合标注:同时利用 LiDAR 和 Camera 进行交叉验证

标注流程

  1. 累积前后 10 帧 LiDAR 点云
  2. 动态物体使用 3D Box 跟踪结果独立对齐
  3. 静态场景使用位姿变换累积
  4. 图像语义分割结果用于验证和补全边界

体素范围

X: [-51.2m, 51.2m]  →  512
Y: [-51.2m, 51.2m]  →  512
Z: [-5m, 3m]        →  40
分辨率: 0.2m

10.7 关键差异总结

对比维度Occ3D-nuScenesOpenOccSurroundOccOpenOccupancy
分辨率0.4m(中等)0.5m(较粗)0.5m(较粗)0.2m(最细)
Flow 标注✅(8 类前景)
标注方法Poisson 重建多帧累积NeRF 隐式重建多传感器融合
动态物体处理基于 Box 跟踪独立对齐较弱独立对齐(最完善)
学术影响力最广泛使用E2E 研究首选中等高精度研究
适用任务3D SSC3D SSC + Planning3D SSC高精度 SSC

10.8 Occupancy 数据集格式与使用指南

各数据集虽然标注流程不同,但最终提供的数据格式大致相似,核心是 3D 体素网格 + 语义标签

通用数据格式

occ_data/
├── gts/                           # Ground Truth 标签
│   ├── {scene_name}/
│   │   ├── {sample_token}.npz     # 体素标签文件
│   │   └── ...
│   └── ...
└── infos/                         # 元数据索引
    ├── occ_infos_train.pkl
    └── occ_infos_val.pkl

单帧标签文件结构(.npz)

import numpy as np

# 加载标签文件
data = np.load('xxx.npz')

# 核心字段
voxel_label = data['semantics']     # shape: (X, Y, Z), dtype: uint8
#   - 值 0~15: 语义类别 ID
#   - 值 255: 忽略/不可见区域

mask_lidar = data['mask_lidar']     # shape: (X, Y, Z), dtype: bool
#   - True: LiDAR 可见区域
#   - False: 遮挡/超出范围

mask_camera = data['mask_camera']   # shape: (X, Y, Z), dtype: bool
#   - True: 至少一个相机可见
#   - False: 相机不可见

# OpenOcc 额外提供
flow = data['flow']                 # shape: (X, Y, Z, 3), dtype: float16
#   - 前景体素的运动向量 (vx, vy, vz)

各数据集具体格式差异

数据集标签文件格式体素尺寸 (X×Y×Z)额外字段
Occ3D-nuScenes.npz200×200×16mask_lidar, mask_camera
OpenOcc.npz200×200×16flow (运动向量)
SurroundOcc.npy200×200×16
OpenOccupancy.npz512×512×40mask_lidar, mask_camera

语义类别映射(16 类)

OCC_CLASSES = [
    'others',             # 0: 其他/未知
    'barrier',            # 1: 护栏
    'bicycle',            # 2: 自行车
    'bus',                # 3: 公交车
    'car',                # 4: 轿车
    'construction_vehicle', # 5: 工程车
    'motorcycle',         # 6: 摩托车
    'pedestrian',         # 7: 行人
    'traffic_cone',       # 8: 交通锥
    'trailer',            # 9: 拖车
    'truck',              # 10: 卡车
    'driveable_surface',  # 11: 可行驶区域
    'other_flat',         # 12: 其他平面
    'sidewalk',           # 13: 人行道
    'terrain',            # 14: 地形
    'manmade',            # 15: 人造结构
    'vegetation',         # 16: 植被
]
IGNORE_LABEL = 255

坐标系与体素索引

以 Occ3D-nuScenes 为例:

# 体素空间定义
VOXEL_SIZE = [0.4, 0.4, 0.4]        # 单位: 米
POINT_CLOUD_RANGE = [-40, -40, -1, 40, 40, 5.4]  # [x_min, y_min, z_min, x_max, y_max, z_max]

# 从世界坐标 (x, y, z) 转换到体素索引 (i, j, k)
def world_to_voxel(x, y, z):
    i = int((x - POINT_CLOUD_RANGE[0]) / VOXEL_SIZE[0])
    j = int((y - POINT_CLOUD_RANGE[1]) / VOXEL_SIZE[1])
    k = int((z - POINT_CLOUD_RANGE[2]) / VOXEL_SIZE[2])
    return i, j, k

# 从体素索引转换回世界坐标(体素中心)
def voxel_to_world(i, j, k):
    x = POINT_CLOUD_RANGE[0] + (i + 0.5) * VOXEL_SIZE[0]
    y = POINT_CLOUD_RANGE[1] + (j + 0.5) * VOXEL_SIZE[1]
    z = POINT_CLOUD_RANGE[2] + (k + 0.5) * VOXEL_SIZE[2]
    return x, y, z

数据加载示例

Occ3D-nuScenes 加载

import numpy as np
import pickle

# 加载元数据
with open('data/occ3d/occ_infos_train.pkl', 'rb') as f:
    infos = pickle.load(f)

# 遍历样本
for info in infos:
    sample_token = info['token']
    scene_name = info['scene_name']
    
    # 加载 Occupancy GT
    occ_path = f'data/occ3d/gts/{scene_name}/{sample_token}.npz'
    occ_data = np.load(occ_path)
    
    semantics = occ_data['semantics']       # (200, 200, 16)
    mask_lidar = occ_data['mask_lidar']     # (200, 200, 16)
    mask_camera = occ_data['mask_camera']   # (200, 200, 16)
    
    # 仅评估相机可见区域
    valid_mask = mask_camera
    valid_semantics = semantics[valid_mask]

OpenOcc 加载(含 Flow)

import numpy as np

# 加载标签
occ_data = np.load('data/openocc/gts/scene-0001/xxx.npz')

semantics = occ_data['semantics']  # (200, 200, 16)
flow = occ_data['flow']            # (200, 200, 16, 3)

# 获取前景物体的运动向量
foreground_mask = (semantics >= 1) & (semantics <= 10)  # 前景类别
foreground_flow = flow[foreground_mask]  # (N, 3)

与 nuScenes 原始数据对齐

from nuscenes.nuscenes import NuScenes
import numpy as np

nusc = NuScenes(version='v1.0-trainval', dataroot='data/nuscenes')

# 获取 sample
sample = nusc.get('sample', sample_token)

# 获取 LiDAR 点云
lidar_data = nusc.get('sample_data', sample['data']['LIDAR_TOP'])
lidar_path = nusc.dataroot + '/' + lidar_data['filename']
points = np.fromfile(lidar_path, dtype=np.float32).reshape(-1, 5)

# 获取 ego pose(用于坐标变换)
ego_pose = nusc.get('ego_pose', lidar_data['ego_pose_token'])

# 获取相机图像
for cam_name in ['CAM_FRONT', 'CAM_FRONT_LEFT', 'CAM_FRONT_RIGHT', 
                  'CAM_BACK', 'CAM_BACK_LEFT', 'CAM_BACK_RIGHT']:
    cam_data = nusc.get('sample_data', sample['data'][cam_name])
    cam_path = nusc.dataroot + '/' + cam_data['filename']
    # 加载图像...

目录组织建议(兼容 mmdet3d)

data/
├── nuscenes/                      # nuScenes 原始数据
│   ├── maps/
│   ├── samples/
│   ├── sweeps/
│   ├── v1.0-trainval/
│   └── v1.0-test/

├── occ3d-nuscenes/                # Occ3D 标注
│   ├── gts/
│   │   ├── scene-0001/
│   │   │   ├── {sample_token}.npz
│   │   │   └── ...
│   │   └── ...
│   └── occ3d_infos_{train,val}.pkl

└── openocc/                       # OpenOcc 标注
    ├── gts/
    └── openocc_infos_{train,val}.pkl

常见代码库支持

数据集官方 Repommdet3d 支持
Occ3DTsinghua-MARS-Lab/Occ3D✅ 官方提供 config
OpenOccOpenDriveLab/OpenScene✅ UniAD/VAD 兼容
SurroundOccweiyithu/SurroundOcc✅ BEVFormer 风格
OpenOccupancyJeffWang987/OpenOccupancy✅ 独立框架

10.9 选择建议

研究目标推荐数据集理由
入门 / Benchmark 复现Occ3D-nuScenes使用最广泛,论文对比方便
端到端自动驾驶OpenOcc提供 Flow 标注,支持 Planning 评测
高精度占据感知OpenOccupancy0.2m 分辨率,细节更丰富
隐式重建研究SurroundOccNeRF-based 标注方法可参考

10.10 Occupancy 评测指标

mIoU(mean Intersection over Union) 是标准评测指标:

$$ mIoU = \frac{1}{C} \sum_{c=1}^{C} \frac{TP_c}{TP_c + FP_c + FN_c} $$

其中 $C$ 为类别数(通常 16 类)。

IoU(Scene Completion IoU):仅评估「占据 vs 空闲」的二分类准确率,不考虑语义类别。


10.11 Occupancy 数据集的局限性

  1. 标注噪声:自动标注流程不可避免引入噪声,尤其是远距离和遮挡区域
  2. 动态物体边界:高速运动物体的边界模糊
  3. 语义歧义:部分类别(如 vegetation vs terrain)边界定义模糊
  4. 分辨率限制:0.2-0.5m 分辨率对小物体(行人、锥桶)表达能力有限

11. 开发工具与可视化

11.1 nuscenes-devkit 概览

官方 Python SDK,提供完整的数据加载、可视化、评测工具链:

pip install nuscenes-devkit

核心功能模块:

模块功能典型用途
nuscenes.nuscenes数据加载与查询获取 scene/sample/annotation
nuscenes.utils坐标变换、数据类LiDAR→Camera 投影
nuscenes.eval评测脚本计算 NDS/mAP
nuscenes.map_expansion高精地图 API车道线、人行横道查询
nuscenes.prediction轨迹预测工具Agent 历史轨迹提取
模块功能典型用途
nuscenes.nuscenes数据加载与查询获取 scene/sample/annotation
nuscenes.utils坐标变换、数据类LiDAR→Camera 投影
nuscenes.eval评测脚本计算 NDS/mAP
nuscenes.map_expansion高精地图 API车道线、人行横道查询
nuscenes.prediction轨迹预测工具Agent 历史轨迹提取

11.2 常用 API

from nuscenes.nuscenes import NuScenes

# 初始化
nusc = NuScenes(version='v1.0-trainval', dataroot='/data/nuscenes')

# 获取场景
scene = nusc.scene[0]

# 获取 sample
sample = nusc.get('sample', scene['first_sample_token'])

# 获取传感器数据
cam_data = nusc.get('sample_data', sample['data']['CAM_FRONT'])

# 可视化
nusc.render_sample(sample['token'])

11.3 可视化能力详解

nuscenes-devkit 提供了丰富的可视化功能,覆盖从单帧渲染到完整场景视频的各种需求:

单帧多模态渲染

# 渲染单个 sample 的所有传感器数据(6 相机 + LiDAR BEV + 3D Box)
nusc.render_sample(sample['token'])

单传感器渲染

# 渲染单个相机图像 + 3D Box 投影
nusc.render_sample_data(sample['data']['CAM_FRONT'], with_anns=True)

# 渲染 LiDAR 点云(BEV 视角)
nusc.render_sample_data(sample['data']['LIDAR_TOP'], with_anns=True)

点云累积可视化

# 累积多帧点云,获得更稠密的 BEV 图
nusc.render_sample_data(
    sample['data']['LIDAR_TOP'], 
    nsweeps=10,           # 累积 10 帧
    underlay_map=True     # 叠加地图底图
)

特定标注渲染

# 渲染单个 3D Box 标注
ann_token = sample['anns'][0]
nusc.render_annotation(ann_token)

场景视频渲染

# 渲染整个场景的视频(所有相机通道)
nusc.render_scene(scene['token'])

# 渲染单个通道的视频
nusc.render_scene_channel(scene['token'], 'CAM_FRONT')

语义分割可视化(Lidarseg/Panoptic)

from nuscenes.nuscenes import NuScenes

# 初始化时加载 lidarseg 数据
nusc = NuScenes(version='v1.0-trainval', dataroot='/data/nuscenes', verbose=True)

# 渲染带语义标签的点云 BEV
nusc.render_sample_data(
    sample['data']['LIDAR_TOP'],
    show_lidarseg=True,           # 显示语义标签
    filter_lidarseg_labels=[10, 11]  # 仅显示 truck 和 trailer 类别
)

LiDAR 到相机投影

from nuscenes.utils.data_classes import LidarPointCloud
from nuscenes.utils.geometry_utils import view_points

# 加载点云
lidar_data = nusc.get('sample_data', sample['data']['LIDAR_TOP'])
pc = LidarPointCloud.from_file(nusc.dataroot + lidar_data['filename'])

# 获取标定参数
cam_data = nusc.get('sample_data', sample['data']['CAM_FRONT'])
cs_record = nusc.get('calibrated_sensor', cam_data['calibrated_sensor_token'])

# 投影到图像平面
points_2d = view_points(pc.points[:3, :], np.array(cs_record['camera_intrinsic']), normalize=True)

高精地图可视化

from nuscenes.map_expansion.map_api import NuScenesMap

# 加载地图
nusc_map = NuScenesMap(dataroot='/data/nuscenes', map_name='singapore-onenorth')

# 渲染地图图层
fig, ax = nusc_map.render_layers(['road_segment', 'lane', 'ped_crossing'], figsize=(10, 10))

# 在指定位置渲染周围地图
nusc_map.render_map_patch(
    box_coords=(300, 1000, 500, 1200),  # (x_min, y_min, x_max, y_max)
    layer_names=['drivable_area', 'lane_divider', 'ped_crossing']
)

image.png

11.4 可视化函数速查表

函数功能输入
render_sample()渲染完整 sample(6 相机 + BEV)sample_token
render_sample_data()渲染单个传感器数据sample_data_token
render_annotation()渲染单个 3D Boxannotation_token
render_scene()渲染场景视频(所有相机)scene_token
render_scene_channel()渲染场景视频(单通道)scene_token, channel
render_ego_pose()渲染自车轨迹-
render_instance()渲染目标实例的跟踪轨迹instance_token

12. 基于 nuScenes 的经典工作

12.1 3D 目标检测

方法模态NDSmAP特点
PointPillarsL45.330.5快速 LiDAR 检测
CenterPointL67.360.3Center-based
TransFusionL+C71.768.9Transformer 融合
BEVFusionL+C72.970.2BEV 空间融合

12.2 纯视觉 BEV 感知

方法NDSmAP特点
DETR3D42.534.93D query
BEVDet48.039.4LSS 架构
BEVFormer56.948.1Transformer
SparseBEV62.955.8稀疏 query

12.3 端到端自动驾驶

方法L2 Error特点
UniAD0.48m统一架构
VAD0.41m向量化表示

13. 常见训练 Tricks / Best Practice

基于 nuScenes 训练 3D 检测模型时,以下技巧被广泛验证有效,可带来显著的性能提升:

13.1 数据增强

多帧点云累积(Multi-sweep Fusion)

nuScenes 单帧点云仅约 3.4 万点(32 线),远低于 Waymo 的 64 线点云密度。累积多帧 sweeps 可有效增加点云密度:

# 常用配置:累积 10 帧(约 0.5 秒)
sweeps = 10  # 官方 baseline 推荐值

# mmdetection3d 配置示例
point_cloud_range = [-51.2, -51.2, -5.0, 51.2, 51.2, 3.0]
data = dict(
    train=dict(
        pipeline=[
            dict(type='LoadPointsFromFile', ...),
            dict(type='LoadPointsFromMultiSweeps', sweeps_num=10),  # 累积 10 帧
            ...
        ]
    )
)

效果:累积 10 帧可使有效点数提升 5-8 倍,mAP 通常提升 3-5 个点。

GT-Aug(Ground Truth Augmentation)

从数据库中随机采样 GT Box 及其内部点云,粘贴到当前场景中:

# 生成 GT 数据库
python tools/create_data.py nuscenes --root-path ./data/nuscenes --out-dir ./data/nuscenes
# 输出: nuscenes_dbinfos_train.pkl

# 配置示例
db_sampler = dict(
    data_root='data/nuscenes/',
    info_path='data/nuscenes/nuscenes_dbinfos_train.pkl',
    rate=1.0,
    prepare=dict(
        filter_by_difficulty=[-1],
        filter_by_min_points=dict(
            car=5, truck=5, bus=5, trailer=5,
            construction_vehicle=5, traffic_cone=5,
            barrier=5, motorcycle=5, bicycle=5, pedestrian=5
        )
    ),
    classes=['car', 'truck', ...],
    sample_groups=dict(
        car=2, truck=3, bus=4, trailer=6,
        construction_vehicle=7, traffic_cone=2,
        barrier=2, motorcycle=6, bicycle=6, pedestrian=2
    )
)

常规增强

# 点云增强
dict(type='GlobalRotScaleTrans',
     rot_range=[-0.3925, 0.3925],  # ±22.5°
     scale_ratio_range=[0.95, 1.05],
     translation_std=[0.5, 0.5, 0.5]),
dict(type='RandomFlip3D', flip_ratio_bev_horizontal=0.5),
dict(type='PointsRangeFilter', point_cloud_range=point_cloud_range),
dict(type='ObjectRangeFilter', point_cloud_range=point_cloud_range),

13.2 类别平衡采样(CBGS)

nuScenes 类别分布极度不均衡:car 占 40%+,而 bicycle、motorcycle 不足 1%。CBGS 通过重采样平衡各类别梯度:

# CBGS 核心思想
# 1. 统计每个类别的实例数
# 2. 按类别数量对 sample 进行重采样,使各类别采样概率接近
# 3. 每个 epoch 相当于对稀有类别过采样

# mmdetection3d 配置
dataset = dict(
    type='CBGSDataset',  # 启用 CBGS
    dataset=dict(
        type='NuScenesDataset',
        ...
    )
)

效果:CBGS 对稀有类别(bicycle、motorcycle、construction_vehicle)提升显著,mAP 通常提升 2-4 个点。

13.3 类别分组多头(Multi-group Head)

将形状相近的类别分组,每组使用独立的检测头:

# 推荐分组(来自 CBGS 论文)
class_groups = [
    ['car'],                              # 主流类别单独一组
    ['truck', 'construction_vehicle'],    # 大型车辆
    ['bus', 'trailer'],                   # 超大型车辆
    ['barrier'],                          # 静态障碍物
    ['motorcycle', 'bicycle'],            # 两轮车
    ['pedestrian', 'traffic_cone'],       # 小型目标
]

13.4 优化器与学习率

# AdamW + One Cycle Policy(常用配置)
optimizer = dict(
    type='AdamW',
    lr=1e-4,
    weight_decay=0.01
)

lr_config = dict(
    policy='cyclic',
    target_ratio=(10, 1e-4),
    cyclic_times=1,
    step_ratio_up=0.4
)

# 或使用 Cosine Annealing
lr_config = dict(
    policy='CosineAnnealing',
    warmup='linear',
    warmup_iters=1000,
    warmup_ratio=1.0 / 10,
    min_lr_ratio=1e-5
)

13.5 训练周期

# 常用配置
total_epochs = 20  # LiDAR-only
total_epochs = 24  # 多模态融合(需要更多 epoch 收敛)

# BEVDet 系列通常使用 24 epochs
# CenterPoint 使用 20 epochs

13.6 Tricks 效果汇总

TrickmAP 提升NDS 提升
Multi-sweep (10帧)+3~5+2~4
GT-Aug+2~4+1~3
CBGS+2~4+1~2
Multi-group Head+1~2+1
Fade Strategy+0.5~1+0.5
Test Time Aug+1~2+1

13.7 推荐训练流程

1. 数据准备
   └─ 生成 pkl 信息文件 + GT 数据库

2. Baseline 训练
   └─ 10-sweep + GT-Aug + 基础增强
   └─ AdamW + Cosine/OneCycle
   └─ 20 epochs

3. 加入 CBGS
   └─ 观察稀有类别指标变化

4. 超参调优
   └─ 学习率、增强强度、sweep 数量

5. 最终提交
   └─ TTA(Test Time Augmentation)
   └─ Model Ensemble(如需冲榜)

14. 使用建议

14.1 数据下载

官网下载地址:https://www.nuscenes.org/nuscenes#download

完整数据约 300GB,建议:

14.2 常见数据预处理

# 生成数据库信息文件
python tools/create_data.py nuscenes --root-path ./data/nuscenes --out-dir ./data/nuscenes

# 输出文件
# - nuscenes_infos_train.pkl
# - nuscenes_infos_val.pkl
# - nuscenes_dbinfos_train.pkl(用于数据增强)

14.3 坐标系说明


15. 许可证


参考资料