主要内容

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

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

导入和分析数据

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

datapath = downloadsydneybanobjects(tempdir);dstrain = loadsydneyurnanobjectsdata(DataPath,[1 2 3]);dsval = loadsydneyurnanobjectsdata(DataPath,4);

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

dsLabels = transform(dsTrain,@(data) data{2});标签= readall (dsLabels);图直方图(标签)

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

数据增加管道

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

dsTrain=transform(dsTrain,@augmentPointCloudData);

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

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

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

dstrain =变换(dstrain,@ formoccupancygrid);DSVAL =变换(DSVAL,@ FormoCcupancyGrid);

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

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

定义网络体系结构

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

层=[image3dInputLayer([32],'姓名''InputLayer'“正常化”“没有”),......卷积3层(5,32,'走吧'2,'姓名'“Conv1”),......Liquidyrel3(0.1,'姓名'“leakyRelu1”),......卷积3dlayer(3,32,'走吧',1,'姓名'“Conv2”),......Liquidyrel3(0.1,'姓名'“Leakyrul2”),......maxpooling3dlayer(2,'走吧'2,'姓名''maxpool'),......fullyConnectedLayer (128'姓名''fc1'),......Rululayer('姓名'“relu”),......DropoutLayer(0.5,'姓名'“dropout1”),......完全连接层(14,'姓名''fc2'),......softmaxLayer ('姓名'“softmax”),......classificationLayer ('姓名'“无交叉熵”));voxnet = layerGraph(层);图绘制(voxnet);

设置培训选项

使用带有动量的随机梯度下降,并分段调整学习速率计划。此示例在TitanX GPU上运行,对于内存较少的GPU,可能需要减少批处理大小。虽然3D ConvNet具有概念简单的优点,但其缺点是在训练时使用大量内存输入法。

miniBatchSize = 32;dsLength =长度(dsTrain.UnderlyingDatastore.Files);iterationsPerEpoch =地板(dsLength / miniBatchSize);dropPeriod =地板(8000 / iterationsPerEpoch);选择= trainingOptions (“sgdm”“初始学习率”,0.01,“MiniBatchSize”miniBatchSize,......“LearnRateSchedule”'分段'......'学习ropperiod'dropPeriod,......“ValidationData”,dsVal,'maxepochs',60,......“DispatchInBackground”假的,......“洗牌”'绝不');

列车网络的

VoxNet = Trainnetwork(Dstrain,Voxnet,选项);
单个GPU培训。| ====================================================================================================================== ||时代|迭代|经过时间的时间迷你批量|验证|迷你批量|验证| Base Learning | | | | (hh:mm:ss) | Accuracy | Accuracy | Loss | Loss | Rate | |======================================================================================================================| | 1 | 1 | 00:00:03 | 9.38% | 20.65% | 2.6408 | 2.6300 | 0.0100 | | 4 | 50 | 00:00:25 | 31.25% | 29.03% | 2.2892 | 2.2954 | 0.0100 | | 8 | 100 | 00:00:45 | 37.50% | 37.42% | 1.9256 | 2.0372 | 0.0100 | | 12 | 150 | 00:01:05 | 53.12% | 47.10% | 1.6398 | 1.7396 | 0.0100 | | 16 | 200 | 00:01:24 | 43.75% | 55.48% | 1.9551 | 1.5172 | 0.0100 | | 20 | 250 | 00:01:44 | 40.62% | 61.29% | 1.7413 | 1.3598 | 0.0100 | | 24 | 300 | 00:02:04 | 50.00% | 60.00% | 1.4652 | 1.2962 | 0.0100 | | 27 | 350 | 00:02:23 | 43.75% | 64.52% | 1.5017 | 1.1762 | 0.0100 | | 31 | 400 | 00:02:42 | 53.12% | 69.03% | 1.2488 | 1.1132 | 0.0100 | | 35 | 450 | 00:03:02 | 50.00% | 69.03% | 1.3160 | 1.0272 | 0.0100 | | 39 | 500 | 00:03:23 | 59.38% | 69.03% | 1.1753 | 1.1366 | 0.0100 | | 43 | 550 | 00:03:44 | 56.25% | 65.81% | 1.1546 | 1.1086 | 0.0100 | | 47 | 600 | 00:04:03 | 68.75% | 65.81% | 0.9808 | 1.0251 | 0.0100 | | 50 | 650 | 00:04:22 | 65.62% | 69.68% | 1.1245 | 1.0136 | 0.0100 | | 54 | 700 | 00:04:42 | 62.50% | 65.16% | 1.2860 | 1.0934 | 0.0100 | | 58 | 750 | 00:05:01 | 59.38% | 68.39% | 1.2466 | 1.0271 | 0.0100 | | 60 | 780 | 00:05:13 | 56.25% | 64.52% | 1.1676 | 1.0798 | 0.0100 | |======================================================================================================================|

评估网络

按照[1此示例仅形成从悉尼城市对象的培训和验证。使用验证评估训练网络的性能,因为它不用于培训网络。

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

查看混淆矩阵来研究不同标签类别的准确性

figure打印混乱(valLabels、outputLabels)

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

参考文献

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

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

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

万博1manbetx支持功能

函数数据集路径=下载SydneyUrbanObjects(dataLoc)如果nargin == 0 dataLoc = pwd();终止dataLoc=字符串(dataLoc);url="http://www.acfr.usyd.edu.au/papers/data/";name =“悉尼城市 - 对象-TATASET.TAR.GZ”如果〜存在(fullfile(dataLoc,“sydney-urban-objects-dataset”),“dir”)disp('下载悉尼城市对象数据集......');untar(完整文件(url、名称)、dataLoc);终止datasetPath = dataLoc.append (“sydney-urban-objects-dataset”);终止函数ds = loadSydneyUrbanObjectsData (datapath公司、折叠)%loadydneybanobjectsdata数据存储与点云和%悉尼城市对象数据集的关联分类标签。% ds = loadSydneyUrbanObjectsData(datapath)构造一个数据存储%代表悉尼城市的点云和相关类别%对象数据集。输入datapath是一个字符串或char数组%表示到悉尼城市对象根目录的路径%的数据集。%ds = loadsydneyurnanobjectsdata(___,folds)可选择允许%您希望包含在列表中的所需折叠的规格%输出DS。例如,[1 2 4]指定您想要的第一个,%秒和数据集的第四个折叠。默认值:[1 2 3 4]。如果nargin <2折= 1:4;终止数据路径=字符串(数据路径);路径=完整文件(数据路径,“对象”,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”'.bin');%洗牌ds.Files=ds.Files(randperm(长度(ds.Files)));终止函数dataOut=extractTrainingData(fname)[pointData,intensity]=readbin(fname);[~,name]=fileparts(fname);name=string(name);name=extractBefore(name,'。');名称=替换(名称,'_''');labelNames = [“4WD”“建筑”“公共汽车”“汽车”“行人”“支柱”......“杆子”“红绿灯”“交通标志”“树”“卡车”“树干”“ute”“van”];label=categorical(名称,labelNames);dataOut={pointCloud(pointData,“强度”,强度),标签};终止函数[Pointdata,强度] = reavbin(fname)悉尼城市对象二进制的%储存读点和强度数据%档案。%名称=['t'、'intensity'、'id'、,。。。%‘x’、‘y’、‘z’、,。。。%“方位角”、“距离”、“pid”]% formats = ['int64', 'uint8', 'uint8',…% ` float32 `, ` float32 `, ` float32 `,…%'float32','float32','int32']fid = fopen(帧,'r');c = onCleanup(@() fclose(fid));fseek(支撑材10 1);%从头开始移动到第一个X点位置10个字节X=fread(fid,inf,“单身”, 30);fseek (fid, 14日1);Y =从文件中读(fid,正无穷,“单身”, 30);FSEEK(FID,18,-1);z = fread(fid,inf,“单身”, 30);FSEEK(FID,8,-1);强度=欺诈(FID,INF,'uint8'点数据=[X,Y,Z];终止函数dataout = formoccupancygrid(data)grid = pcbin(数据{1},[32 32 32]);占用=零(大小(栅格),“单身”);对于ii=1:numel(grid)occuncygrid(ii)=~isempty(grid{ii});终止标签={2}数据;dataOut = {occupancyGrid、标签};终止函数dataOut = augmentPointCloudData(data) ptCloud = data{1};标签={2}数据;%围绕Z轴应用随机旋转。tform = ronsomaffine3d('回转',@() deal([0 0 1],360*rand),“规模”[0.98, 1.02],'Xreflection',真的,“YReflection”,真的);%关于z轴的随机旋转ptCloud=pctransform(ptCloud,tform);%对点云中的每个点应用抖动amountOfJitter=0.01;numPoints=size(ptCloud.Location,1);D=zeros(size(ptCloud.Location),“喜欢”,ptcloud.location);d(:,1)= diff(ptcloud.xlimits)* rand(nuitpoints,1);d(:,2)= diff(ptcloud.ylimits)* rand(nuitpoints,1);d(:,3)= diff(ptcloud.zlimits)* rand(nuitpoints,1);d = QuanteOfjitter。* D;ptcloud = pctransform(ptcloud,d);dataout = {ptcloud,label};终止