MMDetection3d对KITT数据集的训练与评估介绍

简介: MMDetection3d对KITT数据集的训练与评估介绍

1. mmdet3d安装过程


其中,推荐安装python=3.7的虚拟环境,因为在kitti数据集可视化过程中需要使用到mayavi包,而这个包的vtk依赖不支持python 3.8版本。


# 创建虚拟环境
conda create --name openmmlab python=3.7 -y
conda activate openmmlab
# 安装深度学习框架
# Linux
conda install pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cudatoolkit=11.3
# Windows
pip install torch==1.11.0+cu102 torchvision==0.12.0+cu102 torchaudio==0.11.0 --extra-index-url https://download.pytorch.org/whl/cu102
# 安装mmdet3d开源算法库
pip install openmim
mim install mmcv-full
mim install mmdet
mim install mmsegmentation
git clone https://github.com/open-mmlab/mmdetection3d.git
cd mmdetection3d
pip install -e .


ps:在linux可能出现的问题不会有太多,但是如果是window中安装,出现pycocotools无法正常安装的问题,原因是没有vc++的编译器,安装一个visual studio 2019的专业版就可以正常安装了mmdet了,而mmdet的依赖就是pycocotools。


这个问题的详细解决方法见:error: Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft C++ Build Tools“


2. KITTI数据集准备


在官网下载对应的数据:http://www.cvlibs.net/datasets/kitti/eval_object.php?obj_benchmark=3d

安装官方文档对数据进行组织:https://mmdetection3d.readthedocs.io/zh_CN/latest/datasets/kitti_det.html


ps:官方提供的数据切分指令如果wget无法正常下载访问,可以在/etc/hosts中自行添加网页的IP地址(IP地址的查询服务链接:https://www.ip138.com/),例如:


wget -c  https://raw.githubusercontent.com/traveller59/second.pytorch/master/second/data/ImageSets/test.txt --no-check-certificate --content-disposition -O ./data/kitti/ImageSets/test.txt


这个问题的详细解决方法,我也用博客贴出:Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|0.0.0.0|:443… failed


处理后的文件夹结构应该如下:


kitti
├── ImageSets
│   ├── test.txt
│   ├── train.txt
│   ├── trainval.txt
│   ├── val.txt
├── testing
│   ├── calib
│   ├── image_2
│   ├── velodyne
│   ├── velodyne_reduced
├── training
│   ├── calib
│   ├── image_2
│   ├── label_2
│   ├── velodyne
│   ├── velodyne_reduced
│   ├── planes (optional)
├── kitti_gt_database
│   ├── xxxxx.bin
├── kitti_infos_train.pkl
├── kitti_infos_val.pkl
├── kitti_dbinfos_train.pkl
├── kitti_infos_test.pkl
├── kitti_infos_trainval.pkl
├── kitti_infos_train_mono3d.coco.json
├── kitti_infos_trainval_mono3d.coco.json
├── kitti_infos_test_mono3d.coco.json
├── kitti_infos_val_mono3d.coco.json


这里我不太理解mmdet3d转换出来的这些.pkl与.coco.json文件,所以下面写了个测试代码来对其进行详细了解。


2.1 了解 .coco.json 文件

对于 .coco.json 后缀的文件,可以通过两种方式对其进行读取,如下所示:


# 方法1:
json_path = r'../data/kitti/kitti_infos_train_mono3d.coco.json'
with open(json_path, 'r') as fr:
    json_file = json.load(fr)
# 方法2:
cocojson_path = '../data/kitti/kitti_infos_train_mono3d.coco.json'
cocojson_file = mmcv.load(cocojson_path)


ps:如果由于某些原因导致json文件的内容被情况,也就是变成了一个空的.coco.json文件,这时候使用以上的两种方法读取数据是会报错的,这一点需要尤其注意。(在测试过程中我就是出现了这个题,还排查了许久的原因)


其中,查看kitti_infos_train_mono3d.coco.json 和 kitti_infos_test_mono3d.coco.json内容如下所示,有固定字段组成的字典形式,由annotation、images、categories组成,其中训练集有标注信息,而验证集没有标注信息,其字段信息如下所示:

image.png


其中的images又是由多个字典组成,如下所示:

image.png


不过在训练的时候,我看见配置文件中其实使用的pkl文件,所以这里生成的.coco.json文件更多的可能是使用一些2D的经典目标检测算法来训练kitti数据集的。也就是说,生成的.coco.json文件,使得我们可以使用mmdetection的开源算法库(检测2d的算法)来训练kitti数据集。


2.2 了解 .pkl 文件

使用一般的手段是不能正常读取.pkl文件的,np.fromfile 与 json.load 都不能正常读取,因为这是mmdet中独特的数据存储格式。对于网上没有这种文件的详细介绍,此时就可以转换思路通过如何生成 .pkl 文件入手,知道了其如何生成就应该知道其存储的内容是什么。


在代码层面,首先在 tools/create_data.py 中的 kitti_data_pre 函数中,作为数据处理的入口。之后可以发现,代码中是通过 mmcv.dump 与 mmcv.load 来进行pkl格式数据与.coco.json格式数据的写入与导出,但是数据本身就是一个字典形式。具体的构造在 get_kitti_image_info 函数中,函数的相关注释如下:


KITTI annotation format version 2:
{
    [optional]points: [N, 3+] point cloud
    [optional, for kitti]image: {
        image_idx: ...
        image_path: ...
        image_shape: ...
    }
    point_cloud: {
        num_features: 4
        velodyne_path: ...
    }
    [optional, for kitti]calib: {
        R0_rect: ...
        Tr_velo_to_cam: ...
        P2: ...
    }
    annos: {
        location: [num_gt, 3] array
        dimensions: [num_gt, 3] array
        rotation_y: [num_gt] angle array
        name: [num_gt] ground truth name array
        [optional]difficulty: kitti difficulty
        [optional]group_ids: used for multi-part object
    }
}


这里,直接利用 mmcv.load 来读取 kitti_test.pkl 数据,pkl_file = mmcv.load(file=pkl_path) ,其内容如下所示:

4a28139dd5e44f1abb2d21e6a8285c55.png


可以发现,其作为一个列表元素,每个训练数据都被构建成了一个字典。每个字典由4大部分组成:inage、point_cloud、calib、annos。其与注释内容是相符合的,其中可以使用 mmcv.track_iter_progress 可以按顺序对字典进行提取:for info in mmcv.track_iter_progress(kitti_infos)


其中,对于这4个部分,官方资料中有解释到:https://mmdetection3d.readthedocs.io/zh_CN/latest/datasets/kitti_det.html

57f4b2c46feb45e7abe99cef5a596af4.png


可以发现,其实这里的annos就是kitti中的label文件的数据。而对于label_2的介绍,可以参考https://blog.csdn.net/qq_37534947/article/details/106628308,label文件是kitti中object的标签和评估数据,以“000001.txt”文件为例,包含样式如下:

image.png


每一行代表一个object,每一行都有16列分别表示不同的含义,具体如下:


  • 第1列(字符串):代表物体类别(type)

总共有9类,分别是:Car、Van、Truck、Pedestrian、Person_sitting、Cyclist、Tram、Misc、DontCare。其中DontCare标签表示该区域没有被标注,比如由于目标物体距离激光雷达太远。为了防止在评估过程中(主要是计算precision),将本来是目标物体但是因为某些原因而没有标注的区域统计为假阳性(false positives),评估脚本会自动忽略DontCare区域的预测结果。

  • 第2列(浮点数):代表物体是否被截断(truncated)

数值在0(非截断)到1(截断)之间浮动,数字表示指离开图像边界对象的程度。

  • 第3列(整数):代表物体是否被遮挡(occluded)

整数0、1、2、3分别表示被遮挡的程度。

  • 第4列(弧度数):物体的观察角度(alpha)

取值范围为:-pi ~ pi(单位:rad),它表示在相机坐标系下,以相机原点为中心,相机原点到物体中心的连线为半径,将物体绕相机y轴旋转至相机z轴,此时物体方向与相机x轴的夹角,如图1所示。

  • 第5~8列(浮点数):物体的2D边界框大小(bbox)

四个数分别是xmin、ymin、xmax、ymax(单位:pixel),表示2维边界框的左上角和右下角的坐标。

  • 第9~11列(浮点数):3D物体的尺寸(dimensions)分别是高、宽、长(单位:米)
  • 第12-14列(整数):3D物体的位置(location)分别是x、y、z(单位:米),特别注意的是,这里的xyz是在相机坐标系下3D物体的中心点位置。
  • 第15列(弧度数):3D物体的空间方向(rotation_y)取值范围为:-pi ~ pi(单位:rad),它表示,在照相机坐标系下,物体的全局方向角(物体前进方向与相机坐标系x轴的夹角)
  • 第16列(整数):检测的置信度(score)要特别注意的是,这个数据只在测试集的数据中有。


2.3 .bin文件、.pkl文件、.coco.json文件的查看代码

如何查看KITTI数据集涉及的这些.bin文件,以及mmdetection3d统一的.pkl与.coco.json格式,以下我写了个代码已实现对这些文件的查看。


参考代码:


import numpy as np
import os
import json
import mmcv
# os.chdir(path='')
root = os.getcwd()
print(root)
bin_path = '../data/kitti/kitti_gt_database/1000_Car_0.bin'
pkl_path = '../data/kitti/kitti_infos_train.pkl'
# 原来是 test_mono3d.coco.json由于名称的问题,读取不了数据
json_path = r'../data/kitti/test.json'
os.path.exists(bin_path), "{} is not exists".format(bin_path)
os.path.exists(json_path), "{} is not exists".format(json_path)
bin_file = np.fromfile(file=bin_path, dtype=np.float32, count=-1)
pkl_file = np.fromfile(file=pkl_path, dtype=np.float32, count=-1)
print(bin_file.shape)
print(pkl_file.shape)
# with open(json_path, 'r') as fr:
#     json_file = json.load(fr)
# print(json_file)
pkl_path = '../data/kitti/kitti_infos_train.pkl'
kitti_infos = mmcv.load(file=pkl_path)
# print(pkl_file)
json_path = r'../data/kitti/kitti_infos_train_mono3d.coco.json'
with open(json_path, 'r') as fr:
    json_train_file = json.load(fr)
# print(json_file)
cocojson_path = '../data/kitti/kitti_infos_test_mono3d.coco.json'
json_test_file = mmcv.load(cocojson_path)


补充:使用 mmcv.load 不仅仅可以读取,coco.json和.pkl文件,其一共支持5种格式的数据格式。如下所示:


file_handlers = {
    'json': JsonHandler(),
    'yaml': YamlHandler(),
    'yml': YamlHandler(),
    'pickle': PickleHandler(),
    'pkl': PickleHandler()
}


3. KITTI数据集训练


如果你在单个机器上启动多个任务,比如,在具有8块显卡的机器上进行2个4块显卡训练的任务,你需要为每个任务指定不同的端口(默认为29500)以避免通信冲突。


如果你使用 dist_train.sh 启动训练任务,可以在命令中设置端口:


CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh ${CONFIG_FILE} 4
CUDA_VISIBLE_DEVICES=4,5,6,7 PORT=29501 ./tools/dist_train.sh ${CONFIG_FILE} 4


端口的设置还有另外的两种方法:


# 方法1:通过 --options 设置端口
CUDA_VISIBLE_DEVICES=0,1,2,3 GPUS=4 ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} config1.py ${WORK_DIR} --options 'dist_params.port=29500'
CUDA_VISIBLE_DEVICES=4,5,6,7 GPUS=4 ./tools/slurm_train.sh ${PARTITION} ${JOB_NAME} config2.py ${WORK_DIR} --options 'dist_params.port=29501'
# 方法2:通过修改配置文件(来设置不同的通信端口
dist_params = dict(backend='nccl', port=29500)
dist_params = dict(backend='nccl', port=29501)


详细的训练过程这里就不贴出来的,和mmdetection、mmfewshot等的训练过程是一样的。详细可以参考:MMOpenLab使用专栏


经过测试,出现的使用问题:


1)训练MVXNET:弹出非法访问的问题(解决方法是降低学习率,以实现单卡运行的学习率配置)

2)训练Point RCNN:占用显存不断增加,最终溢出(官方还没有修复这个问题)


成功测试的算法:SECOND、3D-SSD、PointPillars、Part-A2、SASSD


4. KITTI数据集评估标准


以PointPillars为例,训练完之后会有一个评估结果(以下结果是截取了Car这个类的结果,还有另外两个类的结果没有放上来)


----------- AP11 Results ------------
Car AP11@0.70, 0.70, 0.70:
bbox AP11:90.5385, 89.3699, 86.2703
bev  AP11:89.6290, 86.8373, 79.6047
3d   AP11:85.9857, 76.4022, 73.5934
aos  AP11:90.38, 88.89, 85.46
Car AP11@0.70, 0.50, 0.50:
bbox AP11:90.5385, 89.3699, 86.2703
bev  AP11:90.6688, 89.9088, 89.0676
3d   AP11:90.6654, 89.8380, 88.8712
aos  AP11:90.38, 88.89, 85.46
Overall AP11@easy, moderate, hard:
bbox AP11:79.9252, 74.4630, 71.3123
bev  AP11:77.1720, 68.2989, 63.5469
3d   AP11:73.1700, 62.1137, 58.4967
aos  AP11:74.50, 68.65, 65.49
----------- AP40 Results ------------
Car AP40@0.70, 0.70, 0.70:
bbox AP40:95.6966, 92.1547, 87.4279
bev  AP40:92.4469, 88.1739, 83.6487
3d   AP40:87.8139, 76.5133, 73.3604
aos  AP40:95.51, 91.61, 86.58
Car AP40@0.70, 0.50, 0.50:
bbox AP40:95.6966, 92.1547, 87.4279
bev  AP40:95.9824, 94.8116, 91.7013
3d   AP40:95.9314, 94.6114, 90.0106
aos  AP40:95.51, 91.61, 86.58
Overall AP40@easy, moderate, hard:
bbox AP40:82.7911, 75.4843, 71.5740
bev  AP40:78.7391, 68.7362, 64.2875
3d   AP40:74.1775, 61.6529, 57.5156
aos  AP40:76.47, 68.73, 64.88


对于上述的结果,下面分别对特定的名词进行解释说明:


4.1 bbox、bev、3d、aos

深度学习算法的检测指标通常由bbox、bev、3d、aos四个检测指标,其含义分别如下所示:


  • bbox:2D检测框的准确率
  • bev:BEV视图下检测框的准确率
  • 3d:3D检测框的准确率
  • aos:检测目标旋转角度的准确率


4.2 AP11与AP40

  • AP11:表示11点插值平均精度,在kitti 3D中R11={0,0.1,0.2,……,1},是等间距的recall level
  • AP40:表示40点插值平均精度,将R11修改为R40={1/40,2/40,3/40,……,1},同样是等间距的recall level


ps:论文《Disentangling Monocular 3D Object Detection》证明AP11是不准确的,因为当模型可以提供一个精度极小,仅仅是>0的一个单一目标,此时R=0时的精度即为1,那么AP11的平均精度即为1/11,这个精度已经超过了很多的方法,所以是不合理的。所以后续修改为AP40。


4.3 Car AP11@0.70, 0.70, 0.70与Car AP11@0.70, 0.50, 0.50

  • AP11@0.70, 0.70, 0.70分别代表bbox,bev,3d在0.70阈值下的平均精度
  • AP11@0.70, 0.50, 0.50分别代表bbox,bev,3d在0.70,0.50,0.50不同阈值下的平均精度


这里可以发现,评估bbox只有0.70这个阈值,所以可以发现bbox的两行数据都是一样的,而对于bev与3d来说,0.50的阈值比0.70的阈值要宽松,所以第二组的结果(阈值0.50)一般要比第一组的结果(阈值0.70)要高。


4.4 bbox AP11:90.5385, 89.3699, 86.2703

无论是bbox,还是bev、3d、aos,每个评价指标在某一个阈值下都会有3组结果,这三组结果分别对应的是easy、moderate和hard下的评估结果。难度越来越大,所以数值也越来越小,所以这三组数值一般是呈递减状态。


4.5 mAP

image.png

一般论文中的实验结果都会贴上一个mAP的最终结果,这个结果就是moderate mAP的结果。比如,在刚刚的PointPillars实验结果中,对于car类别的AP11结果如下所示,其中76.4022就是作为car这个类基准排名的主要指标。


Car AP11@0.70, 0.70, 0.70:
3d   AP11:85.9857, 76.4022, 73.5934


而对于全部3个类别的AP11结果如下所示,那么62.1137就是作为3类(3 Class)基准排名的主要指标。


Overall AP11@easy, moderate, hard:
3d   AP11:73.1700, 62.1137, 58.4967


现在,来查看mmdetection3d中PointPillars的结果:

image.png


可以发现,其实刚刚我跑出来的结果Class的AP是76.4022,而3 Class的AP是62.137。这个结果和官方跑出来的77.6和64.07差不多。使用以下指令,来测试刚刚训练好的PointPillars的最新模型:


python tools/test.py configs/pointpillars/hv_pointpillars_secfpn_6x8_160e_kitti-3d-3class.py \
                     work_dirs/hv_pointpillars_secfpn_6x8_160e_kitti-3d-3class/latest.pth \
                     --eval mAP


输出结果:

image.png


可以看见,无论是Car=76.4022还是3 Class=62.1137,都与训练时期的验证结果差不多,所以训练期间的验证结果还是可信的。


4.6 aos(Average Orientation Similarity)

aos的名称为平均方向相似性(这里是利用了AP11来进行计算),计算公式如下:

image.png


其中,r代表物体检测的召回率。在因变量r下,方向相似性s∈[0,1]被定义为所有预测样本与ground truth余弦距离的归一化:

image.png


其中D®表示在召回率r下所有预测为正样本的集合,∆θ(i) 表示检出物体i的预测角度与ground truth的差。为了惩罚多个检出匹配到同一个ground truth,如果检出i已经匹配到ground truth设置δi = 1,否则δi = 0。


简要分析:我们希望aos的值越大越好,越大也就说明预测角度与ground truth的值越相似,那么这个是如何实现的呢。在余弦函数中,如果预测角度与ground turth的值越接近,那么它们差值就越接近0,余弦值是越靠近1,也就是余弦越大,那么整个公式的求和平均也是越大的。而如果预测值与ground truth不像,严重预测错误,那么其差值就会变大,一个比较大的差值在余弦公式中是比较小的,甚至可能是负数,导致1+cos的结果很小,从而使得整体的结果偏小。所以aos公式可以一定程度的判断方向的预测正确性。


4.7 easy、moderate、hard的定义

KITTI数据集中easy、moderate、hard根据标注框是否被遮挡、遮挡程度和框的高度进行定义的,具体数据如下:


  • 简单:最小边界框高度:40像素,最大遮挡级别:完全可见,最大截断:15%
  • 中等:最小边界框高度:25像素,最大遮挡水平:部分遮挡,最大截断:30%
  • 困难:最小边界框高度:25像素,最大遮挡级别:难以看到,最大截断:50%


参考资料:


1. MMDet3d官方文档


2. What is the resuls meaning? #185


3. KITTI数据集3d目标检测的评价的含义


4. 机器学习算法评估指标——3D目标检测


5. 点云感知算法面试知识点(一)


目录
相关文章
|
6月前
|
机器学习/深度学习 测试技术
大模型开发:描述交叉验证以及为什么在模型评估中使用它。
【4月更文挑战第24天】交叉验证是评估机器学习模型性能的方法,通过将数据集分成训练集和多个子集(折叠)进行多次训练验证。它能减少过拟合风险,提供更可靠的性能估计,用于参数调优,并减少小数据集或噪声带来的随机性影响。通过汇总多轮验证结果,得到模型的整体性能估计。
63 7
|
6月前
|
机器学习/深度学习 数据采集 PyTorch
使用PyTorch解决多分类问题:构建、训练和评估深度学习模型
使用PyTorch解决多分类问题:构建、训练和评估深度学习模型
使用PyTorch解决多分类问题:构建、训练和评估深度学习模型
|
3月前
|
Python
模型训练
【8月更文挑战第20天】模型训练。
50 0
|
1月前
|
数据可视化 计算机视觉
训练数据集(一):真实场景下采集的煤矸石目标检测数据集,可直接用于YOLOv5/v6/v7/v8训练
本文介绍了一个用于煤炭与矸石分类的煤矸石目标检测数据集,包含891张训练图片和404张验证图片,分为煤炭、矸石和混合物三类。数据集已标注并划分为训练和验证集,适用于YOLOv5/v6/v7/v8训练。数据集可通过提供的链接下载。
53 1
训练数据集(一):真实场景下采集的煤矸石目标检测数据集,可直接用于YOLOv5/v6/v7/v8训练
|
3月前
|
数据采集 人工智能 小程序
如何制作数据集并基于yolov5训练成模型并部署
这篇文章介绍了如何为YOLOv5制作数据集、训练模型、进行模型部署的整个流程,包括搜集和标注图片、创建数据集文件夹结构、编写配置文件、训练和评估模型,以及将训练好的模型部署到不同平台如ROS机器人、微信小程序和移动应用等。
如何制作数据集并基于yolov5训练成模型并部署
|
6月前
|
机器学习/深度学习 编解码 PyTorch
训练Sora模型,你可能需要这些(开源代码,模型,数据集及算力评估)
在之前的文章《复刻Sora有多难?一张图带你读懂Sora的技术路径》,《一文看Sora技术推演》我们总结了Sora模型上用到的一些核心技术和论文,今天这篇文章我们将整理和总结现有的一些开源代码、模型、数据集,以及初步训练的算力评估,希望可以帮助到国内的创业公司和个人开发者展开更深的研究。
|
3月前
|
机器学习/深度学习 自然语言处理 数据可视化
训练模型
【8月更文挑战第1天】
48 2
|
XML 数据挖掘 数据格式
|
5月前
|
算法 计算机视觉
【YOLOv8训练结果评估】YOLOv8如何使用训练好的模型对验证集进行评估及评估参数详解
【YOLOv8训练结果评估】YOLOv8如何使用训练好的模型对验证集进行评估及评估参数详解
|
6月前
|
机器学习/深度学习 算法 小程序
垃圾分类算法训练及部署
垃圾分类算法训练及部署
57 1