ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

KITTI数据集评测实战:从传感器对齐到算法公平对比的完整指南

KITTI数据集评测实战:从传感器对齐到算法公平对比的完整指南 干视觉SLAM或者目标检测这行的应该没人不知道KITTI这个名字。就算你没直接跑过它也一定在论文里看过那几张标志性的车载场景截图还有一堆benchmark榜单上的排名。我从研一开始接触这个数据集中间换了三个方向做视觉里程计、做目标检测、后来调试激光雷达算法绕来绕去居然又回到KITTI上。它确实老了数据是2011年采集的分辨率放到今天也不算高但你不得不承认它是目前极少数能把数据格式、传感器标定、真值生成、评测脚本全部打包好的公开数据集。这篇东西我想聊的实际一点手里有这么一套数据集你到底该怎么用它去评测不同算法从怎么下载、怎么解压、怎么对齐时间戳到怎么设计对比实验、怎么让评测结果不被同行挑毛病一条线讲完少踩我当年踩过的坑。这套内容适合作自动驾驶、移动机器人、计算机视觉方向的研究生、刚入行的算法工程师以及想系统评估自己算法的独立开发者。读完你至少能搞清楚三件事KITTI的各个子任务分别该用什么指标评估怎么在同一套硬件环境下公平对比不同算法以及当你跑出来的精度和论文对不上时问题大概出在哪个环节。1. 认识KITTI它究竟包含什么1.1 传感器配置与数据组织形式KITTI数据集由德国卡尔斯鲁厄理工学院和丰田美国技术研究院联合发起采集平台是一辆改装过的旅行车车顶装了一台Velodyne HDL-64E激光雷达前挡风玻璃位置装了两对灰度相机和两对彩色相机加上一套GPS/IMU导航系统。官方数据里经常用的其实是左侧灰度相机和左侧彩色相机也就是编号0和编号2这两个。四个相机加上雷达、GPS/IMU每次采集都能拿到同步好的多模态数据。原始数据下载下来之后你会看到若干以日期命名的文件夹比如2011_09_26_drive_0001_sync每个文件夹里包含这样几类内容image_00、image_01灰度立体图像对image_02、image_03彩色立体图像对velodyne_points64线激光雷达点云PCD格式oxtsGPS/IMU组合惯导数据包含位置、速度、姿态四元数等这种组织形式对做评测非常友好。所有传感器数据都通过一个统一的时间戳索引对齐过你在代码里只需要把时间戳作为主键就能把某一帧的图像、点云、位姿真值全部取出来。我第一次用的时候没搞懂这个设计自己写了个多线程同步脚本搞了三天最后发现官方本来就存好了同步文件直接用就行。1.2 子任务划分与各自真值KITTI官方把评测分成几个独立的任务常见的有这样几个方向视觉里程计/SLAMOdometry训练序列带了完整的位姿真值测试序列不公开真值用于评测算法的轨迹精度目标检测Object Detection对汽车、行人、骑行者三类目标进行2D和3D检测真值是带截断和遮挡标记的3D框投影到图像上得到的2D框深度补全/深度估计Depth Completion / Depth Prediction激光雷达点云投影生成稀疏深度图作为输入真值是密集深度图来自多帧点云累积语义分割Semantic Segmentation提供了像素级标注但类别比Cityscapes少很多跟踪Tracking多目标跟踪任务提供跨帧的轨迹真值关键点是Odometry的位姿真值不是直接用GPS坐标算的而是通过一个全局优化过程把GPS/IMU数据和点云配准结果融合得到的。所以它的精度比单纯靠GPS差分定位高不少但也不是绝对的厘米级做评测时这个真值本身的误差你心里要有数。1.3 为什么到今天还要用它做基准有人觉得KITTI过时了毕竟现在有nuScenes、Waymo Open Dataset数据规模大得多场景也更丰富。但我个人的看法是KITTI有它不可替代的地方。第一是门槛低。一个训练序列的数据量从几十MB到几百MB不等下载几个序列就能开始干活不像Waymo一个TFRecord就几个GB没个固态硬盘和大内存都转不动。第二是评测体系成熟。官方devkit提供了完整的评测脚本从分割结果到3D框的IoU计算都有现成代码省了你从零写评测逻辑的时间。第三是论文对比容易。你做一个新算法想说服审稿人最直接的方式就是在KITTI上和其他方法做对比。既然所有基线方法都报了KITTI上的结果你也用同一套指标对比才有说服力。我自己更看重的还有一点KITTI数据集的标注质量非常稳定。它在目标检测上的3D框标注虽然有争议但至少在评测集上经过了反复校正做对比实验时不会因为真值本身的问题导致结果忽高忽低。2. 测试什么算法选型与测试维度2.1 按任务划分算法类别评测不是把算法下载下来跑一遍就完事你先得想清楚自己到底要测什么。在KITTI上常见的算法评测可以分这么几类。视觉里程计方向代表性的有ORB-SLAM3特征点法、VINS-Mono滑动窗口优化、DSO直接法。如果你测的是定位精度就用Odometry的00到10序列跑完整轨迹计算预测轨迹和真值之间的误差。这类算法对光照敏感KITTI的公路场景光照变化不算剧烈但遇到隧道、树荫切换时表现差异很明显。激光SLAM方向代表性算法有LOAM、Lego-LOAM、LIO-SAM。它们依赖点云的几何结构KITTI的郊区道路场景里建筑、车辆、树木特征丰富能比较好地体现特征匹配的质量。激光算法对初值敏感如果只给雷达数据不给IMULIO-SAM这类依赖预积分的算法会退化得比较厉害评测的时候要把输入条件写清楚。目标检测方向如果用图像做2D检测可以测YOLOv8、Faster R-CNN、DETR系列如果用点云做3D检测可以测PointPillars、SECOND、CenterPoint。不同算法对硬件的要求差异极大必须在同一块GPU上做速度对比才有意义。深度估计方向自监督深度估计的代表有Monodepth2它在KITTI上做过大量消融实验非常适合作为基准。评测时常用绝对相对误差、均方根误差、阈值准确率这几个指标。2.2 测试的核心维度设计在我实际评测经验里单看精度是最容易自欺欺人的。你说你的算法ATE比ORB-SLAM3低了5%但如果只在一个序列上跑出来的那什么都不说明。设计测试维度至少要覆盖下面几项精度不同序列上的平均性能。比如视觉里程计看ATE绝对轨迹误差和RPE相对位姿误差目标检测看mAP。单帧耗时同一个环境下运行统计每帧平均处理时间。注意要把数据加载时间排除掉不然I/O瓶颈会污染你的速度数据。硬件资源占用CPU、GPU、内存的峰值占用。有的算法精度好但是内存占用爆炸在嵌入式设备上直接不可用。鲁棒性这个容易被人忽略。同一算法在不同序列上的精度方差大不大在快速转弯、多车流、树荫场景下有没有突然漂移这些在论文里不直观但实际部署时才是生死线。我习惯上会先做一个小步快跑的预测试每个算法只跑一两个序列看输出结果有没有明显异常确认正常后再跑完整评测集。这样能省下大量时间不然像ORB-SLAM3跑完全部11个序列可能要数小时跑完发现参数没调对心态直接炸裂。2.3 评测脚本和指标对齐各任务的官方测评指标要搞清楚不然很容易自己算出来一个数跟官方完全对不上。视觉里程计官方评测用的是平移误差和旋转误差按子序列长度100m到800m分段统计。论文里常见的ATE/RPE指标并不是Odometry榜单上的官方指标这意味着你用ATE和官方榜单排名对比没有直接可比性。目标检测2D检测用APAverage Precision3D检测用AP值时还额外划分了易、中、难三个等级其中难等级对遮挡严重的小目标要求极高。如果不按官方的匹配规则算自己写一个IoU阈值结果基本没法横向对比。深度估计官方提供的是一个在线评测服务你把预测深度图打包上传它给你算指标。很多论文里报的指标是自己算的所以你会发现同一方法在不同论文里数值不同。读论文时先看清作者到底怎么算的。我自己踩过最大的坑就是深度估计指标的操作空间。有的论文用深度范围0到80米有的用1到50米有的用带遮蔽的掩码过滤掉某些像素不同操作得到的RMSE能差出一大截。做对比时一定要把评估掩码和深度范围写清楚。3. 实操全流程从下载到跑通一次完整评测3.1 数据下载与目录组织KITTI的数据下载不像现在的一些数据集那样一个链接全量拉取它是按任务和序列分开的。以视觉里程计为例你需要下载的有这些灰度图序列数据集中的Odometry data包含彩色图可选位姿真值Odometry ground truth标定文件Calibration files下载要注意的是官方服务器在国外速度不稳定这个只能换网络环境或者用下载工具搞。有时候下载一半断掉重新下又得排队建议用支持断点续传的下载工具。下载完的目录我建议这样组织kitti_dataset/ └── odometry/ ├── poses/ │ ├── 00.txt │ └── 01.txt ├── sequences/ │ ├── 00/ │ │ ├── image_0/ │ │ ├── image_1/ │ │ ├── calib.txt │ │ └── times.txt │ └── 01/ └── devkit/这里有个很多人容易忽略的点Odometry任务里calib.txt里面不仅有相机内参还包括了相机到激光雷达的外参。如果你要做图像和点云的融合算法这个外参是必须的而且这个外参是序列级别的不是每一个序列都相同的拷贝文件时要对应好。3.2 时间戳对齐与坐标系变换细节KITTI的times.txt给出的是每帧图像的采集时间单位是秒但很多序列不是严格等间隔采样的偶尔会有几毫秒的抖动。如果你做的是多传感器融合这种抖动可能导致激光雷达和图像的内容错位。解决办法通常是找最近邻时间戳把激光雷达点云变换到图像采集时刻的雷达坐标系下。这里涉及两个变换雷达坐标系到相机坐标系的变换直接用calib.txt里的Tr矩阵当前帧到参考帧的位姿变换用插值GPS/IMU数据实现如果做纯视觉SLAM不需要考虑激光雷达的时间同步但做视觉惯性系统时IMU频率高100Hz以上图像频率低10Hz需要把IMU测量值在图像帧之间做预积分。我在VINS-Mono的评测中就遇到过IMU频率设置错误导致位姿估计发散的问题最后查出来是数据集的IMU坐标系和算法默认坐标系不一致一个简单的坐标轴交换就解决了。3.3 用官方devkit跑一次评测以视觉里程计评测为例官方devkit的用法是这样./evaluation/odometry/evaluate_odometry(预测位姿文件路径)位姿文件每行有12个数字对应3x4变换矩阵格式是第一行是第0帧到世界坐标系的变换后面每一行是当前帧到世界坐标系的变换。注意不是相邻帧之间的相对变换是全局位姿。我第一次跑的时候以为要提供相对位姿结果输出结果全是乱码。后来读了源码才发现官方脚本是拿你的全局位姿和真值全局位姿做SE(3)上的对齐后计算误差。这里有一个隐含步骤评测之前官方会做一个位姿对齐用Umeyama算法也就是Sim(3)相似变换把预测轨迹和真值轨迹对齐消除坐标系基准不同导致的误差。如果你自己写评测代码不看源码很容易少掉这一步。跑完之后devkit会输出一个表格按序列长度分段统计平移误差和旋转误差还会把所有序列的平均误差算出来这个平均值才是你写论文时要报的数。3.4 记录实验日志的习惯跑算法的时候建议把每个实验运行时的软硬件环境、参数配置、启动时间、运行时长、输出结果全程记录下来。不一定用多复杂的工具一个Markdown文件就行。比如这样记录实验编号EXP-007 算法ORB-SLAM3 序列KITTI Odometry 07 环境RTX 4090Ubuntu 22.04Docker镜像xxx 参数ORB特征点数1500金字塔尺度1.2 输出keyframe_traj.txt ATE0.41m 备注07序列有较多直线路段退化场景不明显这种习惯看起来笨但当你同时跑七八个算法、每个算法调了好几版参数后你会感谢自己当初的随手记录。人脑的记忆力在高密度对比实验面前完全不靠谱。4. 不同算法公平对比的关键技巧4.1 硬件与运行环境的一致性控制公平性是做算法对比实验时最敏感的话题。同行审稿或者组内汇报别人第一个问题就是你测的这几个算法是在同一台机器上跑的吗是不是分别用了不同型号的GPU我的经验是所有算法必须在同一物理机上跑操作系统、驱动版本、依赖库比如PyTorch版本、CUDA版本要完全一致。因为这些因素对性能影响很大CUDA版本不同可能导致同一模型的推理速度差出30%以上。控制硬件环境是最基本的底线。在此基础上建议把算法封装成统一的评测接口输入相同的数据路径和输出路径。可以考虑写一个统一的评测脚本比如用Python的子进程去调用不同算法的主程序然后统一读取输出结果做指标计算。这样能极大减少人为操作的失误。4.2 输入配置的统一不同算法对输入数据的要求不一样视觉SLAM算法只需要灰度图或彩色图激光SLAM算法只需要点云视觉惯性算法需要图像IMU。你不能因为某个算法只用了点云就给它额外提供GPS数据这会让它占便宜。正确做法是测什么模态就只提供什么模态。比如测VINS-Mono就只给图像和IMU测ORB-SLAM3单目模式就只给单目图像。如果你做的是多模态融合算法那对比对象也要选用了相同传感器输入的算法。在数据预处理上也尽量别加私货。比如目标检测如果你对图像做了自适应直方图均衡化那对比方法也应该用同样处理后的图像做推理。你在论文里必须明确说明是否对输入做了预处理不然别人复现你的实验时会完全对不上。4.3 参数调整的边界这里要聊一个比较微妙的问题。算法对比实验时参数到底能不能调我的经验是在评测前先按论文默认参数跑一遍然后只允许在有限范围内做调参比如ORB特征点数量从1000调到2000这属于合理调参但你要是为了某个特定序列专门调一套参数那评测结果就有选择性报告cherry picking的嫌疑了。一个靠谱的流程是先在训练集序列上调参到满意然后在测试集序列上跑最终指标。KITTI Odometry的00到10序列并没有严格划分哪些是训练集哪些是测试集一般大家把00到07当验证集08到10当测试集。你在组里自己跑评测时也遵循这个约定报告统一的结果。4.4 可视化对比从数字到图纯数字指标看不出算法的问题在哪。我强烈建议在每次评测后输出轨迹对比图、逐帧误差曲线和关键帧图像叠加图。轨迹图可以用Python的matplotlib直接绘制。把真值轨迹、算法A轨迹、算法B轨迹画在同一张图上哪里偏移了、哪里整体旋转了一眼就能看出来。误差曲线能看出算法在哪一段时间内性能恶化是遇到了快速转弯还是进入了隧道。关键帧的叠加图最直观但工作量也最大我是在写论文时才逐帧挑图的。这些可视化材料不仅方便你自己排查问题也是论文和汇报中说服力的来源。审稿人看到一张干净的轨迹对比图比看十张参数表格更容易相信你的算法确实更优。5. 常见问题与排查技巧实录5.1 评测结果和论文差太多这可能是在KITTI上做评测时最让人崩溃的问题。你跑了某个开源算法论文里ATE是0.5米你跑出来2米差出一大截。排查顺序我建议是先看输入数据对不对是不是用了不同序列再看启动参数是不是和论文一致然后看算法是否有随机性比如RANSAC多次运行结果不同最后看评测代码是不是有问题——你算的ATE和官方评测的ATE定义可能不同。以ORB-SLAM3为例它带有Loop Closing线程跑KITTI 00序列有回环和跑07序列也有回环结果差很多。如果你跑的是不带回环的模式跟论文的完整模式比差距是正常的。另外ORB-SLAM3的ORB_SLAM3/Examples/Stereo和Monocular的默认参数不一样用错模式会退化得很厉害。5.2 时间戳不对齐导致图像和点云错位如果你做的是多传感器算法一个高频出现的问题是图像和点云没对齐。症状是投影到图像上的点云边缘和图像内容错开半个身位。解决思路是先把点云按雷达坐标系到相机坐标系的变换投影到图像平面计算重投影误差。如果误差大于几个像素说明外参或时间戳有问题。KITTI的标定文件是序列级的不会随时间变化所以问题大概率出在时间戳对齐上。VELO到CAM的投影公式是P_cam T_velo_to_cam * P_velo然后通过相机内参把3D点投影到2D像素坐标。你可以随便找一个点云的近距离点检查投影后的坐标和图像上对应物体是否吻合。如果所有点都整体偏移一般就是外参有问题如果有些点对不上而另一些点能对上一般是时间戳不对齐导致的运动畸变。5.3 程序偶发崩溃与内存问题跑KITTI长序列时长时间运行的算法经常会莫名其妙崩溃。以我自己的经历ORB-SLAM3在跑00序列的第两千多帧时偶尔会段错误排查了很久发现是词汇表文件加载的一次性问题和线程同步导致的偶发冲突。遇到这种问题建议先复现多跑几次看是不是稳定复现。稳定复现的话就好解决了加日志断点逐步定位。偶发复现的话多半是并发问题尝试缩小线程池或者换低延迟的同步机制。也可能和内存碎片有关长序列跑完会产生大量局部变量和临时对象某些实现不好的代码会有潜在内存泄漏跑久了直接OOM。5.4 数据下载不完整导致评测报错KITTI每个序列的数据量都不小一个视觉里程计的00序列的灰度图数据大约有几百张00到4540张左右的图下载中断后不容易发现缺失帧。我遇到过的情况是跑完算法后在评测阶段提示某帧真值缺失或文件不存在。排查后发现是当时下载时漏了几个文件。建议在下载后立即检查文件数量ls | wc -l看是否和张数一致。KITTI的Odometry序列帧数表网上能搜到比如00序列是4540帧01序列是1100帧07序列是1100帧记不太准确切值但每次都会核对一遍。6. KITTI之外的延伸思考6.1 单数据集评测的局限性KITTI再经典也免不了有几个明显的局限。场景单一。它基本是在德国卡尔斯鲁厄的城市和郊区道路采集的没有雪天、没有大雨、没有夜间高速公路长直道占比高目标检测任务中的物体尺度分布和国内城市交通场景差异不小。传感器老了。Velodyne HDL-64E是上一代机械雷达点云稀疏、有运动畸变。今天的固态雷达和补盲雷达的测距模式和点云密度完全不同在KITTI上调好的参数换到现代传感器上不一定能迁移。数据量其实没那么大。做深度学习目标检测时KITTI的训练集只有不到八千张图在今天动辄百万级的数据集面前它更像一个算法开发调试集而不是拿来训练大模型的数据集。6.2 与现代数据集的互补使用我现在做评测的习惯是KITTI当作入门验证 快速迭代新颖数据集当作扩展验证 泛化测试。先用KITTI把算法调到能稳定跑通然后再在nuScenes或者自己采集的数据上做一轮验证。这样既可以利用KITTI工具链成熟的优势又能避免单数据集过拟合的陷阱。还有一个容易踩的坑是KITTI上的性能不代表在新场景上的性能。视觉SLAM算法在KITTI这种结构化道路上效果很好但到了室内杂乱环境或者越野环境可能会出现完全退化。展示算法在KITTI上的良好表现只是讲了一个完整的故事实际落地还要做更多场景的测试。6.3 未来方向多传感器融合评测KITTI的传感器配置在今天看起来反而成了它的一个优势——它有图像、有激光雷达、有GPS/IMU。越来越多的人在KITTI上做多传感器融合的评测比如视觉激光雷达的SLAM、图像点云的目标检测。做这类评测时你既要保证各个传感器的时间同步又要做好外参标定。目前KITTI官方提供的标定文件已经够用但如果你自己重新标定结果会不太一样。有些论文报告的结果之所以比别家好是因为他们重新优化了外参后做评测的——这属于评测协议的问题不算算法本身的提升。我的建议是除非你论文的核心创新点就是外参标定否则直接用官方标定文件保证公平对比。最后再分享一个小技巧。做任何KITTI评测前先把官方的devkit源码从头到尾读一遍尤其是评测指标的计算细节。很多你认为理所当然的算法结论其实是因为评测方式不同导致的假象。读懂了评测代码你对实验结果的信任程度会高很多也更容易发现论文里那些藏得很深的评测细节差异。这个习惯说实话比我在这篇文章里写的任何算法经验都值钱。
返回列表