主要内容

训练分类网络在三维点云分类中的应用

此示例演示了中概述的方法[1,点云数据预处理为体素化编码,然后直接使用一个简单的3-D卷积神经网络结构进行对象分类。在最近的一些方法中,如[2,点云数据的编码可能更复杂,可以通过网络进行端到端训练来完成分类/目标检测/分割任务。然而,在所有这些评价中,从不规则的无序点移动到可以馈入卷积网络的网格结构的一般模式仍然是相似的。

导入和分析数据

在本例中,我们使用悉尼城市对象数据集。在本例中,我们使用数据中的折叠1-3作为训练集,折叠4作为验证集。

dataPath公司= downloadSydneyUrbanObjects (tempdir);dsTrain = loadSydneyUrbanObjectsData(数据路径,[1 2 3]);dsVal = loadSydneyUrbanObjectsData (dataPath公司,4);

分析训练集,了解数据中存在的标签以及标签的总体分布情况。

dsLabels=transform(dsTrain,@(数据)数据{2});labels=readall(dsLabels);图形直方图(标签)

从直方图中可以明显看出,在训练数据中存在某些对象类喜欢的类不平衡问题行人比不那么频繁的课程更常见吗乌特

数据扩充管道

为了避免过度拟合并增加分类器的稳健性,在训练网络时,一定数量的随机数据扩充通常是一个好主意。功能随机仿射E2Dpctransform使得在点云数据上定义随机仿射变换变得容易。我们还为每个点云中的每个点添加了一些随机的逐点抖动。这个函数augmentPointCloudData包含在下面的支持功能一节中。金宝app

dsTrain =变换(dsTrain @augmentPointCloudData);

验证点云数据的增强看起来是合理的。

dataOut=preview(dsTrain);figure-pcshow(dataOut{1});title(dataOut{2});

接下来,我们向每个输入点云添加一个简单的体素化变换,如前一个示例中所述,将输入点云变换为可与卷积神经网络一起使用的伪图像。

dsTrain =变换(dsTrain @formOccupancyGrid);dsVal =变换(dsVal @formOccupancyGrid);

检查最终体素化体积的样本,我们将其输入网络,以验证体素化是否正常工作。

数据=预览(dsTrain);图p=面片(等值面(数据{1},0.5));p.FaceColor=“红色”;p.EdgeColor =“没有”;daspect([1])视图(45,45)camlight;照明phong标题(数据{2});

定义网络架构

在本例中,我们使用[1]中描述的简单3-D分类体系结构。

[image3dInputLayer([32 32 32],]),“名字”“inputLayer”“正常化”“没有”),...卷积3层(5,32,“步”2.“名字”“Conv1”),...leakyReluLayer (0.1,“名字”“leakyRelu1”),...32岁的convolution3dLayer (3“步”1.“名字”“Conv2”),...leakyReluLayer (0.1,“名字”“Leakyrul2”),...maxPooling3dLayer (2“步”2.“名字”“maxPool”),...完全连接层(128,“名字”“fc1”),...reluLayer (“名字”“relu”),...dropoutLayer (0.5,“名字”“辍学1”),...fullyConnectedLayer(14日“名字”“取得”),...软MaxLayer(“名字”“softmax”),...分类层(“名字”“无交叉熵”));voxnet = layerGraph(层);图绘制(voxnet);

设置培训选项

使用带动量的随机梯度下降,并对学习率计划进行分段调整。这个例子是在TitanX GPU上运行的,对于内存更少的GPU,可能需要减少批大小。尽管3D卷积网络具有概念简单的优点,但它们在训练时使用大量内存的缺点。

miniBatchSize = 32;dsLength =长度(dsTrain.UnderlyingDatastore.Files);iterationsPerEpoch =地板(dsLength / miniBatchSize);dropPeriod =地板(8000 / iterationsPerEpoch);选择= trainingOptions (“sgdm”“初始学习率”,0.01,“MiniBatchSize”,小批量,...“LearnRateSchedule”“分段”...“LearnRateDropPeriod”,下降期,...“ValidationData”,dsVal,“MaxEpochs”,60,...“DispatchInBackground”假的,...“洗牌”“永远”);

列车网络的

voxnet = trainNetwork (dsTrain、voxnet选项);
单CPU训练。|======================================================================================================================| | 时代| |迭代时间| Mini-batch | |验证Mini-batch | |验证基地学习  | | | | ( hh: mm: ss) | | |精度精度损失| | |率损失|======================================================================================================================| | 1 | 1 | 00:00:12 | | 0.00% 3.23% | 2.6579 | 2.6466 | 0.0100 | | 4 | 50 | 00:01:53 | | 31.25% 29.03% | 2.1520 | 2.3095 | 0.0100 | | 100 | | 00:03:33 | | 28.12% 36.77% | 2.2633 | 2.1510 | 0.0100 | | 150 | | 00:05:11 | 43.75%| 46.45% | 2.0506 | 1.9057 | 0.0100 | | 16 | 200 | 00:06:49 | 37.50% | 52.26% | 1.8627 | 1.6161 | 0.0100 | | 20 | 250 | 00:08:35 | 50.00% | 59.35% | 1.8573 | 1.4587 | 0.0100 | | 24 | 300 | 00:10:14 | 34.38% | 58.06% | 1.8636 | 1.4360 | 0.0100 | | 27 | 350 | 00:11:51 | 62.50% | 61.94% | 1.4174 | 1.3093 | 0.0100 | | 31 | 400 | 00:13:31 | 65.62% | 64.52% | 1.1966 | 1.2727 | 0.0100 | | 35 | 450 | 00:15:09 | 56.25% | 61.94% | 1.3562 | 1.2473 | 0.0100 | | 39 | 500 | 00:16:49 | 62.50% | 66.45% | 1.2819 | 1.1354 | 0.0100 | | 43 | 550 | 00:18:27 | 56.25% | 65.16% | 1.4563 | 1.1351 | 0.0100 | | 47 | 600 | 00:20:05 | 56.25% | 66.45% | 1.3096 | 1.1142 | 0.0100 | | 50 | 650 | 00:21:40 | 56.25% | 65.16% | 1.0104 | 1.1023 | 0.0100 | | 54 | 700 | 00:23:21 | 75.00% | 70.32% | 0.9403 | 1.0848 | 0.0100 | | 58 | 750 | 00:25:00 | 65.62% | 71.61% | 1.0909 | 1.1003 | 0.0100 | | 60 | 780 | 00:25:59 | 65.62% | 72.26% | 0.9628 | 1.0406 | 0.0100 | |======================================================================================================================|

评估网络

按照[1,本例仅从悉尼城市对象中形成训练和验证集。使用验证来评估经过训练的网络的性能,因为它没有被用来训练网络。

valLabelSet=transform(dsVal,@(数据)数据{2});valLabels=readall(valLabelSet);outputLabels=Classification(voxnet,dsVal);Accurance=nnz(outputLabels==valLabels)/numel(outputLabels);disp(Accurance)
0.7226

查看混淆矩阵,研究各种标签类别的准确性

混淆图(valLabels、outputLabels)

训练集中注意到的标签不平衡是分类准确度的一个问题。混淆图说明了行人(最常见的类别)的准确度和召回率高于不太常见的类别(如van)。因为本示例的目的是演示使用点云数据的基本分类网络训练方法,将不探讨为提高分类性能而可能采取的后续步骤,例如对训练集重新采样或实现更好的标签平衡,或使用对标签不平衡更为鲁棒的损失函数(例如加权交叉熵)。

参考文献

1)用于实时物体识别的三维卷积神经网络,Daniel Maturana,Sebastian Scherer,2015 IEEE/RSJ智能机器人和系统国际会议(IROS)

2)PointPillars:用于点云对象检测的快速编码器,Alex H.Lang,Sourabh Vora等,CVPR 2019

3)悉尼城市对象数据集,阿拉斯泰尔·夸德罗斯,詹姆斯·安德伍德,伯特兰·杜拉德,悉尼城市对象

金宝app支持功能

函数数据集路径=下载SydneyUrbanObjects(dataLoc)如果nargin==0 dataLoc=pwd();终止dataLoc=字符串(dataLoc);url="http://www.acfr.usyd.edu.au/papers/data/";name =“sydney-urban-objects-dataset.tar.gz”如果~ (fullfile (dataLoc,存在“sydney-urban-objects-dataset”),“dir”)disp(“正在下载悉尼城市对象数据集……”);解压(url +名字,dataLoc);终止datasetPath=dataLoc.append(“sydney-urban-objects-dataset”);终止函数ds = loadSydneyUrbanObjectsData (datapath公司、折叠)% loadSydneyUrbanObjectsData数据存储与点云和悉尼城市对象数据集的相关分类标签。% ds = loadSydneyUrbanObjectsData(datapath)构造一个数据存储%代表悉尼城市的点云和相关类别%对象数据集。输入数据路径是一个字符串或字符数组%表示到悉尼城市对象根目录的路径%的数据集。% ds = loadSydneyUrbanObjectsData(___,折叠)可选允许%您希望包含在列表中的所需折叠的规格%输出ds。例如,[1 2 4]指定您想要第一个,%第二次和第四次折叠数据集。默认值:[1 2 3 4]。如果Nargin < 2 fold = 1:4;终止datapath公司=字符串(datapath公司);路径= fullfile (datapath公司,“对象”, filesep);%现在,将所有折叠都包括在数据存储中foldNames {1} = importdata (fullfile (datapath公司,“折叠”“fold0.txt”));foldNames {2} = importdata (fullfile (datapath公司,“折叠”“fold1.txt”));foldNames {3} = importdata (fullfile (datapath公司,“折叠”“fold2.txt”));foldNames{4}=importdata(完整文件(数据路径,“折叠”“fold3.txt”));名称= foldNames(折叠);名称= vertcat(名字{:});fullFilenames = append(路径、名称);ds = fileDatastore (fullFilenames,“ReadFcn”,@ExtrainingData,“FileExtensions”“。斌”);%洗牌ds.Files=ds.Files(randperm(长度(ds.Files)));终止函数dataOut=extractTrainingData(fname)[pointData,intensity]=readbin(fname);[~,name]=fileparts(fname);name=string(name);name=extractBefore(name,“。”);name =取代(名称、“_”' ');labelNames = [“四轮驱动”“建筑”“公共汽车”“汽车”“行人”“支柱”...“杆子”“红绿灯”“交通标志”“树”“卡车”“树干”“哑巴”“范”];标签=分类(名称、labelNames);dataOut = {pointCloud (pointData“强度”,强度),标签};终止函数(pointData、强度)= readbin(帧)% readbin从悉尼城市目标二进制中读取点和强度数据%的文件。%名称=['t'、'intensity'、'id'、,。。。%‘x’、‘y’、‘z’、,。。。%“方位角”、“距离”、“pid”]% formats = ['int64', 'uint8', 'uint8',…%“float32”、“float32”、“float32”、,。。。% ` float32 `, ` float32 `, ` int32 `]fid=fopen(fname,“r”);c = onCleanup(@() fclose(fid));fseek(支撑材10 1);从开始移动到第一个X点位置10个字节X=fread(fid,inf,“单身”, 30);fseek (fid, 14日1);Y =从文件中读(fid,正无穷,“单身”, 30);fseek(支撑材,18岁,1);Z =从文件中读(fid,正无穷,“单身”, 30);fseek(支撑材8 1);强度=从文件中读(fid,正无穷,“uint8”点数据=[X,Y,Z];终止函数dataOut = formOccupancyGrid(data) grid = pcbin(data{1},[32 32 32]);occupancyGrid = 0(大小(网格),“单身”);ii=1:numel(grid)occuncygrid(ii)=~isempty(grid{ii});终止标签={2}数据;dataOut = {occupancyGrid、标签};终止函数dataOut = augmentPointCloudData(data) ptCloud = data{1};标签={2}数据;%围绕Z轴应用随机旋转。tform = randomAffine3d (“旋转”,@() deal([0 0 1],360*rand),“规模”,[0.98,1.02],“XReflection”,真的,“YReflection”,真正的);%关于z轴的随机旋转ptCloud = pctransform (ptCloud tform);%对点云中的每个点应用抖动amountOfJitter = 0.01;numPoints =大小(ptCloud.Location, 1);D = 0(大小(ptCloud.Location),“喜欢”, ptCloud.Location);D (: 1) = diff (ptCloud.XLimits) *兰德(numPoints, 1);D (:, 2) = diff (ptCloud.YLimits) *兰德(numPoints, 1);D (: 3) = diff (ptCloud.ZLimits) *兰德(numPoints, 1);D = amountOfJitter。* D;ptCloud = pctransform (ptCloud D);dataOut = {ptCloud、标签};终止