1. 日志分析
1.1 曲线绘制
- 绘制某次运行的损失loss
python tools/analysis_tools/analyze_logs.py plot_curve work_dirs/3dssd_4x4_kitti-3d-car/20221013_094855.log.json --keys loss --legend 3dssd --mode train --interval 1
输出:
- 绘制某次运行的学习率lr,并且保存图片为pdf格式
python tools/analysis_tools/analyze_logs.py plot_curve work_dirs/3dssd_4x4_kitti-3d-car/20221013_094855.log.json --keys lr --legend 3dssd --mode train --interval 1 --out lr.pdf
保存的pdf文件:
- 同一张图像绘制两个模型运行时的损失loss,并且保存图片为pdf格式
python tools/analysis_tools/analyze_logs.py plot_curve work_dirs/3dssd_4x4_kitti-3d-car/20221013_094855.log.json work_dirs/hv_pointpillars_secfpn_6x8_160e_kitti-3d-3class/20221012_114205.log.json --keys loss --legend 3dssd pointpillars --mode train --interval 1 --out lr.pdf
保存的pdf文件:
在model=val也就是在验证模式下,log会输出一些精度信息,类似于:"KITTI/Car_3D_AP11_easy_strict": 26.5527,"KITTI/Car_BEV_AP11_easy_strict": 69.40167,"KITTI/Car_2D_AP11_easy_strict": 69.93827。这些信息的keys正常来说应该就是KITTI/Car_3D_AP11_easy_strict,但是在代码中是无法正常读取的。也就说,只能读取train中包含的keys,如下所示:
除了以上的keys之外的信息是没有办法绘制图像的,不过既然有了json文件,如果想要对val的精度信息绘制曲线,也可以自行编码实现。
1.2 平均训练速度绘制
python tools/analysis_tools/analyze_logs.py cal_train_time work_dirs/3dssd_4x4_kitti-3d-car/20221013_094855.log.json
结果输出:
-----Analyze train time of work_dirs/3dssd_4x4_kitti-3d-car/20221013_094855.log.json----- slowest epoch 11, average time is 0.2238 fastest epoch 72, average time is 0.1832 time std over epochs is 0.0049 average iter time: 0.1873 s/iter
2. 可视化
2.1 结果可视化
- 观察模型预测结果,同时获取评测结果
python tools/test.py ${CONFIG_FILE} ${CKPT_PATH} --eval 'mAP' --eval-options 'show=True' 'out_dir=${SHOW_DIR}'
ps:
1)3D 单模态检测任务中的 ***_points.obj 和 ***_pred.obj 将会被保存在 ${SHOW_DIR} 中
2)多模态检测任务中的 ***_points.obj,***_pred.obj,***_gt.obj,***_img.png 和 ***_pred.png 将会被保存在 ${SHOW_DIR} 中
当您在没有 GUI 的远程服务器上运行测试的时候,无法进行在线可视化,您可以设定 show=False。对于离线可视化可以选择利用Open3D来可视化结果,但是远程服务器一般无法使用。所以可以选择将结果保存到本地,然后使用3D 可视化软件,例如 MeshLab 来打开这些在 ${SHOW_DIR} 目录下的文件,从而查看 3D 检测输出。具体来说,打开 ***_points.obj 查看输入点云,打开 ***_pred.obj 查看预测的 3D 边界框。
2.2 数据集可视化
- 浏览KITTI数据集
可以使用 tools/misc/browse_dataset.py 来在线显示载入的数据和真值标签,并且保存进磁盘。为了浏览 KITTI 数据集,您可以运行下面的指令:
python tools/misc/browse_dataset.py configs/base/datasets/kitti-3d-3class.py --task det --output-dir ${OUTPUT_DIR} --online
ps:如果没有显示器,直接移除 --online 标志,从而仅仅保存可视化结果并且进行离线浏览
测试样例(以下样例均来自000003.png):
- 浏览数据增强后的KITTI数据集
为了验证数据的一致性和数据增强的效果,您还可以使用以下命令添加 --aug 标志来可视化数据增强后的数据
python tools/misc/browse_dataset.py configs/base/datasets/kitti-3d-3class.py --task det --aug --output-dir ${OUTPUT_DIR} --online
测试样例:
- 浏览支持多模态的KITTI数据集
显示 2D 图像以及投影的 3D 边界框,则需要找到支持多模态数据加载的配置文件,然后将 --task 参数更改为 multi_modality-det
python tools/misc/browse_dataset.py configs/mvxnet/dv_mvx-fpn_second_secfpn_adamw_2x8_80e_kitti-3d-3class.py --task multi_modality-det --output-dir ${OUTPUT_DIR} --online
测试样例:
不仅仅可以浏览KITTI数据集,也可以简单的使用不同的配置文件来浏览不同的数据集:
- 在 3D 语义分割任务中可视化 ScanNet 数据集
python tools/misc/browse_dataset.py configs/_base_/datasets/scannet_seg-3d-20class.py --task seg --output-dir ${OUTPUT_DIR} --online
- 在单目 3D 检测任务中浏览 nuScenes 数据集
python tools/misc/browse_dataset.py configs/_base_/datasets/nus-mono3d.py --task mono-det --output-dir ${OUTPUT_DIR} --online
2.3 单点云结果推理
在mmdet3d开源算法库中,其实还提供了一些API的接口以供我们使用。对于KITTI数据集的单个bin样本,可以使用 demo/ pcd_demo.py 脚本来测试。配置文件可以自行选择,预训练模型可以从模型库中下载,运行如下命令可以去测试点云场景下一个单模态的 3D 检测算法。
python demo/pcd_demo.py ${PCD_FILE} ${CONFIG_FILE} ${CHECKPOINT_FILE} [--device ${GPU_ID}] [--score-thr ${SCORE_THR}] [--out-dir ${OUT_DIR}]
测试样例:
python demo/pcd_demo.py demo/data/kitti/kitti_000008.bin \ configs/second/hv_second_secfpn_6x8_80e_kitti-3d-car.py \ checkpoints/hv_second_secfpn_6x8_80e_kitti-3d-car_20200620_230238-393f000c.pth \ --out-dir demo/data/single_modelity
同样的,在输出的目录下,就会出现单个点云场景***_points.obj 和 ***_pred.obj文件。这两个文件可以直接通过一些3D软件来查看。
2.4 点云api接口处理
这里有一个例子去说明如何构建模型以及测试给出的点云:
from mmdet3d.apis import init_model, inference_detector config_file = '../configs/pointpillars/hv_pointpillars_secfpn_6x8_160e_kitti-3d-3class.py' checkpoint_file = '../checkpoints/pointpillars/hv_pointpillars_secfpn_6x8_160e_kitti-3d-3class_20220301_150306-37dc2420.pth' # 从配置文件和预训练的模型文件中构建模型 model = init_model(config_file, checkpoint_file, device='cuda:1') # 测试单个文件并可视化结果 point_cloud = '../data/kitti/training/velodyne/000100.bin' result, data = inference_detector(model, point_cloud) # 可视化结果并且将结果保存到 'results' 文件夹 model.show_results(data, result, out_dir='result_dirs')
同样的,在输出的目录下,就会出现单个点云场景***_points.obj 和 ***_pred.obj文件。这两个文件可以直接通过一些3D软件来查看。
3. 模型复杂度
mmdet3d中提供了 tools/analysis_tools/get_flops.py 脚本来计算一个模型的计算量 (FLOPS) 和参数量 (params),具体是通过 mmcv.cnn.get_model_complexity_info() 这个函数来计算得到的。
- 测试PointPillars模型
python tools/analysis_tools/get_flops.py configs/pointpillars/hv_pointpillars_secfpn_6x8_160e_kitti-3d-3class.py
输出:
============================== Input shape: (40000, 4) Flops: 34.33 GFLOPs Params: 4.83 M ==============================
- 测试3D-SSD模型
python tools/analysis_tools/get_flops.py configs/3dssd/3dssd_4x4_kitti-3d-car.py
输出:
============================== Input shape: (40000, 4) Flops: 16.03 GFLOPs Params: 2.51 M ==============================
ps:计算量 (FLOPs) 和输入形状有关,但是参数量 (params) 则和输入形状无关。默认的输入形状为 (1, 40000, 4),而且现在脚本现在仅仅支持单模态输入(点云或者图片)的单阶段模型的计算量 (FLOPs) 计算。暂时不支持两阶段和多模态模型的计算,比如sassd、mvxnet这些模型的计算量都无法计算得到。
4. 模型转换
4.1 发布模型
tools/model_converters/publish_model.py 帮助用户准备他们用于发布的模型。在上传一个模型到云服务器 (AWS) 之前,您需要做以下几步:
将模型权重转换为 CPU 张量
删除记录优化器状态 (optimizer states) 的相关信息
计算检查点 (checkpoint)文件的哈希编码 (hash id) 并且把哈希编码加到文件名里
测试样例:
python tools/model_converters/publish_model.py work_dirs/3dssd_4x4_kitti-3d-car/epoch_1.pth 3dssd_kitti_1epoch_20221015.pth
最终的输出文件名将会是 3dssd_kitti_1epoch_20221015-b4ec4689.pth。其中b4ec4689就是哈希编码,作为这个权重的唯一ID。
5. 数据集转换
对于自动驾驶场景下标注信息,一般比较复杂,而其中是包含了2d的边界框信息的。那么,其实可以将这些2d信息转化为coco的标注格式,就可以使用一些经典的目标检测网络来训练自动驾驶的数据集,比如KITTI,nuscense,Waymo等。
- 转换 nuImages 数据集为 COCO 格式
python -u tools/data_converter/nuimage_converter.py --data-root ${DATA_ROOT} --version ${VERSIONS} --out-dir ${OUT_DIR} --nproc ${NUM_WORKERS} --extra-tag ${TAG}
6. 其他内容
6.1 配置文件打印
测试样例:
python tools/misc/print_config.py configs/3dssd/3dssd_4x4_kitti-3d-car.py
输出:
Config: model = dict( type='SSD3DNet', backbone=dict( type='PointNet2SAMSG', in_channels=4, num_points=(4096, 512, (256, 256)), radii=((0.2, 0.4, 0.8), (0.4, 0.8, 1.6), (1.6, 3.2, 4.8)), num_samples=((32, 32, 64), (32, 32, 64), (32, 32, 32)), sa_channels=(((16, 16, 32), (16, 16, 32), (32, 32, 64)), ((64, 64, 128), (64, 64, 128), (64, 96, 128)), ((128, 128, 256), (128, 192, 256), (128, 256, 256))), aggregation_channels=(64, 128, 256), fps_mods=('D-FPS', 'FS', ('F-FPS', 'D-FPS')), fps_sample_range_lists=(-1, -1, (512, -1)), norm_cfg=dict(type='BN2d', eps=0.001, momentum=0.1), sa_cfg=dict( type='PointSAModuleMSG', pool_mod='max', use_xyz=True, normalize_xyz=False)), ...... checkpoint_config = dict(interval=1) log_config = dict( interval=30, hooks=[dict(type='TextLoggerHook'), dict(type='TensorboardLoggerHook')]) ...... optimizer = dict(type='AdamW', lr=0.002, weight_decay=0) optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2)) lr_config = dict(policy='step', warmup=None, step=[45, 60]) runner = dict(type='EpochBasedRunner', max_epochs=80)
参考资料:
https://mmdetection3d.readthedocs.io/zh_CN/latest/useful_tools.html