主要内容

基于深度学习的语义分割

这个例子展示了如何使用深度学习训练语义分割网络。

语义分割网络对图像中的每个像素进行分类,导致由类分割的图像。语义分割的应用包括用于自主驾驶和癌细胞分段的道路分割,用于医学诊断。要了解更多信息,请参阅使用深度学习开始语义分割

为了说明训练过程,本示例训练Deeplab v3+[1],一种用于语义图像分割的卷积神经网络(CNN)。其他类型的语义分割网络包括完全卷积网络(FCN)、SegNet和U-Net。这里显示的训练过程也可以应用于这些网络。

此示例使用CamVid数据集(2)来自剑桥大学的训练。该数据集是一个包含在驾驶时获得的街道级视图的图像集合。该数据集为包括汽车、行人和道路的32个语义类提供像素级标签。

设置

此示例创建了Deeplab v3+网络,其权重由预先训练的Resnet-18网络初始化。Resnet-18是一个高效的网络,非常适合处理资源有限的应用程序。根据应用程序要求,还可以使用其他预训练网络,如MobileNet v2或Resnet-50。有关更多详细信息,请参阅ee预先训练的深度神经网络(深度学习工具箱)

要获得预训练的Resnet-18,请安装resnet18(深度学习工具箱).安装完成后,运行以下代码以验证安装是否正确。

resnet18 ();

此外,下载预训练版本的DeepLab v3+。预训练模型允许您运行整个示例,而无需等待训练完成。

pretrainedURL =“//www.tatmou.com/金宝appsupportfiles/vision/data/deeplabv3plusResnet18CamVid.mat”;pretrainedFolder = fullfile (tempdir,“pretrainedNetwork”);pretrainedNetwork=fullfile(pretrainedFolder,“deeplabv3plusResnet18CamVid.mat”);如果~存在(pretrainedNetwork“文件”)mkdir(预训练文件夹);disp('下载预训练网络(58mb)…');websave(pretrainedNetwork,pretrainedrl);终止

强烈推荐使用支持cuda的NVIDIA™GPU来运行此示例。使用GPU需要并行计算工具箱™。有关支持的计算能力的信息,请参见金宝appGPU支金宝app持情况(并行计算工具箱)

下载CamVid数据集

从以下url下载CamVid数据集。

图像URL='http://web4.cs.ucl.ac.uk/staff/g.brostow/MotionSegRecData/files/701_StillsRaw_full.zip';LabelURL =.'http://web4.cs.ucl.ac.uk/staff/g.brostow/MotionSegRecData/data/LabeledApproved_full.zip';outputFolder = fullfile (tempdir,“CamVid”);labelsZip = fullfile (outputFolder,“labels.zip”);imagesZip=fullfile(outputFolder,“images.zip”);如果~存在(labelsZip“文件”)| | ~存在(imagesZip,“文件”)mkdir(输出文件夹)显示(“下载16mb CamVid数据集标签……”);websave(labelsZip,labelURL);解压缩(labelsZip,fullfile)(outputFolder,“标签”));disp ('正在下载557 MB CamVid数据集图像…');websave(imagesZip,imageURL);解压(imagesZip,fullfile)(outputFolder,'图片'));终止

注意:数据的下载时间取决于您的Internet连接。上面使用的命令将阻止MATLAB,直到下载完成。或者,您可以使用web浏览器先将数据集下载到本地磁盘。若要使用从web下载的文件,请更改输出文件夹变量设置为下载文件的位置。

负载CamVid图片

使用ImageageAtastore.加载CamVid图像。的ImageageAtastore.使您能够在磁盘上高效地加载大量图像。

imgDir = fullfile (outputFolder,'图片',701 _stillsraw_full);IMDS = IMAGEDATASTORE(IMGDIR);

显示其中一个图像。

I=readimage(imds,559);I=histeq(I);imshow(I)

加载CamVid像素标记的图像

使用PixellabeldAtastore.加载Camvid像素标签图像数据。一种PixellabeldAtastore.将像素标签数据和标签ID封装为类名映射。

我们使培训更容易,我们将CamVid中的32个原始课程分为11个课程。指定这些类。

类= [“天空”“建筑”“极”“道路”“路面”“树”“符号”“篱笆”“车”“行人”“自行车”];

为了将32个类减少为11个,将原始数据集中的多个类分组在一起。例如,“Car”是“Car”、“SUVPickupTruck”、“Truck_Bus”、“Train”和“OtherMoving”的组合。使用支持函数返回分组的标签ID金宝app摄像机像素标签,在本例的最后列出。

labelIDs=camvidPixelLabelIDs();

使用类和标签ID创建像素标签数据库。

labelDir=fullfile(outputFolder,“标签”);pxds=像素LabelDataStore(labelDir,类,LabelId);

读取和显示其中一个像素标记的图像,将其覆盖在图像的顶部。

C = ReadImage(PXDS,559);cmap = camvidcolormap;我= labeloverlay (C“ColorMap”,提出);imshow (B) pixelLabelColorbar(提出、类);

没有颜色覆盖的区域没有像素标签,并且在培训期间不使用。

统计分析数据集

要查看CamVid数据集中类标签的分布,请使用countEachLabel.这个函数根据类标签计算像素的数量。

台= countEachLabel (pxds)
tbl=11×3表名字PixelCount ImagePixelCount  ______________ __________ _______________ {' 天空}7.6801 4.8315 e + e + 07年08年{“建筑”}1.1737 e + 08年4.8315 e + 08年{“极点”}4.7987 4.8315 e + e + 06年08年{‘路’}1.4054 e + 08年4.8453 e + 08年{“路面”}3.3614 4.7209 e + e + 07年08年{‘树’}5.4259 4.479 e + e + 07年08年{‘SignSymbol} 5.2242 4.6863 e + e + 06年08年{“栅栏”}6.9211 2.516 e + e + 06年08年{'汽车'}{'行人'}3.4029e+06 4.4444e+08{'自行车'}2.5912e+06 2.6196e+08

按类可视化像素计数。

频率= tbl.pixelcount / sum(tbl.pixelcount);吧(1:NUMER(类),频率)XTICKS(1:NUMER(类))XTickLabels(TBL.NAME)XTickangle(45)Ylabel(“频率”)

理想情况下,所有类别的观测值都是相等的。但是,CamVid中的类别是不平衡的,这是街道场景的汽车数据集中的一个常见问题。此类场景比行人和骑自行车的像素具有更多的天空、建筑和道路像素,因为天空、建筑和道路在图像中覆盖更多的区域。如果不进行处理,则坦率地说,这种不平衡可能对学习过程有害,因为学习偏向于占主导地位的类。在本例后面,您将使用类权重来处理此问题。

Camvid数据集中的图像尺寸为720×960。选择图像尺寸,使得在带有12 GB内存的NVIDIA™Titan X上的训练期间,大量批次图像可以适合内存。如果GPU没有足够的内存或减少训练批量大小,您可能需要调整图像的大小以更小的尺寸。

准备培训、验证和测试集

Deeplab v3+使用数据集中60%的图像进行训练。其余图像分别以20%和20%的比例均匀分割,以进行验证和测试。以下代码将图像和像素标签数据随机分割为训练、验证和测试集。

[IMDStrain,IMDSVAL,IMDSTEST,PXDSTRAIN,PXDSVAL,PXDSTEST] = PartitionCamViddata(IMDS,PXD);

60/20/20分割会产生以下数量的培训、验证和测试图像:

numTrainingImages =元素个数(imdsTrain.Files)
numTrainingImages = 421
numValImages =元素个数(imdsVal.Files)
numValImages = 140
numTestingImages =元素个数(imdsTest.Files)
numTestingImages=140

创建网络

使用deeplabv3plusLayers函数创建基于ResNet-18的DeepLab v3+网络。为应用程序选择最佳网络需要经验分析,这是另一种超参数调优。例如,您可以尝试使用不同的基础网络,如ResNet-50或MobileNet v2,或者您可以尝试其他语义分割网络架构,如SegNet、完全卷积网络(FCN)或U-Net。

%指定网络映像大小。这通常与列车映像大小相同。图像大小=[720 960 3];%指定类的数量。numClasses=numel(类);%创建DeepLab v3+。lgraph = deeplabv3plusLayers(imageSize, numClasses,“resnet18”);

使用类权重平衡类

如前面所示,CamVid中的类是不平衡的。为了提高训练,你可以使用课程权重来平衡课程。使用前面计算的像素标签计数countEachLabel并计算频率类权重的中位数。

imageFreq =(资源。PixelCount。/ tbl.ImagePixelCount;classWeights = median(imageFreq) ./ imageFreq ./ imageFreq ./ imageFreq ./
classWeights =11×10.3182 0.2082 5.0924 0.1744 0.7103 0.4175 4.5371 1.8386 1.0000 6.6059⋮

属性指定类权重像素分类层

pxLayer = pixelClassificationLayer (“姓名”,“标签”,“类”资源描述。的名字,“类权重”, classWeights);lgraph = replaceLayer (lgraph,“分类”,px层);

选择培训选项

用于训练的优化算法是带动量的随机梯度下降(SGDM)。使用trainingOptions(深度学习工具箱)来指定用于SGDM的超参数。

%定义验证数据。dsVal=联合收割机(imdsVal、pxdsVal);%定义培训选项。选择= trainingOptions (“个”,...“LearnRateSchedule”,“分段”,...“LearnRateDropPeriod”10...“LearnRateDropFactor”,0.3,...“动力”,0.9,...“初始学习率”1 e - 3,...“L2Regularization”, 0.005,...“ValidationData”,dsVal,...“MaxEpochs”30岁的...“MiniBatchSize”8....“洗牌”,“every-epoch”,...“CheckpointPath”tempdir,...'verbosefrequency'2,...“情节”,“训练进步”,...“ValidationPatience”, 4);

学习率采用分段计划。学习率每10个历元降低0.3倍。这允许网络以更高的初始学习率快速学习,同时能够在学习率下降时找到接近局部最优的解决方案。

通过设置,每个epoch都对网络进行验证数据测试“ValidationData”范围。的“ValidationPatience”设置为4以在验证精度收敛时提前停止训练。这可防止网络在训练数据集上过度拟合。

8个小批量用于减少训练时的内存使用。你可以根据你系统上的GPU内存数量增加或减少这个值。

此外“CheckpointPath”设置为临时位置。这个名称-值对允许在每个训练阶段结束时保存网络检查点。如果培训因系统故障或断电而中断,您可以从保存的检查点恢复培训。确保指定的位置“CheckpointPath”有足够的空间来存储网络检查点。例如,保存100个Deeplab v3+检查点需要约6 GB的磁盘空间,因为每个检查点有61 MB。

数据扩充

数据增强用于通过在训练期间随机转换原始数据来提高网络精度。通过使用数据增强,您可以在不增加标记培训样本的数量的情况下为培训数据添加更多品种。要将相同的随机转换应用于图像和像素标签数据使用数据存储结合变换.首先,联合收割机imdsTrainpxdsTrain

dsTrain = combine(imdsTrain, pxdsTrain);

接下来,使用数据存储变换应用在支持功能中定义的所需数据增强金宝appaugmentImageAndLabel这里,随机左/右反射和+/-10像素的随机X/Y平移用于数据增强。

XTrans = [-10 10];ytrans = [-10 10];dstrain =变换(dstrain,@(data)augmentimageandlabel(数据,xtrans,ytrans));

注意,数据扩充并不适用于测试和验证数据。理想情况下,测试和验证数据应该能够代表原始数据,并且不作任何修改,以便进行公正的评估。

开始训练

开始培训使用列车网络(深度学习工具箱)如果溺爱国旗是真的。否则,加载备用网络。

注意:培训是在带有12gb GPU内存的NVIDIA™Titan X上验证的。如果你的GPU内存更少,你可能会在训练期间耗尽内存。如果出现这种情况,请尝试设置“MiniBatchSize”1在trainingOptions,或减少网络输入并调整训练数据的大小。训练这个网络大约需要5个小时。根据你的GPU硬件,可能需要更长的时间。

doTraining = false;如果doTraining[net,info]=列车网络(dsTrain,lgraph,options);其他的数据=负荷(预训练网络);net=data.net;终止

在一个图像上测试网络

作为一个快速的完整性检查,在一个测试图像上运行训练过的网络。

I=readimage(imdsTest,35);C=semanticseg(I,net);

显示结果。

我= labeloverlay (C“Colormap”,cmap,“透明度”, 0.4);imshow (B) pixelLabelColorbar(提出、类);

比较中的结果C储存的预期地面真相pxdsTest.绿色和洋红色区域强调分割结果与预期的原始事实不同的区域。

expectedResult = readimage (pxdsTest 35);实际= uint8 (C);预期= uint8 (expectedResult);预计imshowpair(实际)

视觉上,对于道路、天空和建筑等类别,语义分割结果重叠良好。但是,行人和汽车等较小的对象则不那么准确。每个类别的重叠量可以使用联合交叉点(IoU)度量,也称为Jaccard索引。使用杰卡德用于测量IoU的函数。

iou = jaccard(c,ceneceseResult);表(课程,iou)
ans =11×2表class iou ____________ _______“Sky”0.91837“Building”0.84479“Pole”0.31203“Road”0.93698“Pavement”0.82838“Tree”0.89636“SignSymbol”0.57644“Fence”0.71046“Car”0.66688“Pedestrian”0.48417“Bicyclist”0.68431

iOU均衡确认了视觉结果。道路,天空和建筑课程的IOU得分高,而行人和汽车等课程得分低。其他常见的分割指标包括骰子分数轮廓匹配分数。

评估培训的网络

要测量多个测试图像的准确性,请运行语义词组在整个测试集上。分割图像时,使用最小批量大小4来减少内存使用。您可以根据系统上的GPU内存量增加或减少此值。

pxdsResults=semanticseg(imdsTest,net,...“MiniBatchSize”,4,...“写位置”,Tempdir,...“详细”、假);

语义词组将测试集的结果作为PixellabeldAtastore.对象。中的每个测试图像的实际像素标签数据IMD测试将写入磁盘中由指定的位置“写位置”参数使用评价语义切分度量测试集结果上的语义分割度量。

度量=评估语义分段(pxdsResults,pxdsTest,“详细”、假);

评价语义切分为单个类别返回整个数据集的各种度量标准,以及每个测试图像。查看数据集级别指标,检查metrics.DataSetMetrics

metrics.DataSetMetrics
ans =表1×5GlobalAccuracy意味着意思意味着意思是致命__________________________ ___________ 0.85392 0.6302 0.65051 0.65051

数据集指标提供了网络性能的高级概述。要查看每个类别对总体性能的影响,请使用指标。ClassMetrics

指标。ClassMetrics
ans =11×3表精度IoU MeanBFScore ________ _______ ___________ Sky建筑0.778453 0.76098 0.58511杆0.71586 0.21477 0.56639道路0.73024 0.91465 0.76696路面0.730466树0.776377树标志0.779358护栏0.71507 0.46484 0.48566汽车0.790956 0.76799 0.69233行人0.876290.4366 0.60792自行车0.87844 0.60829 0.55089

虽然整体数据集性能相当高,但类度量标准显示了代表性的类(如)行人,骑自行车的,不像班级那样细分吗,,建筑物.包含更多代表性不足班级的样本的额外数据可能有助于改善结果。

金宝app支持功能

函数labelIDs=camvidPixelLabelIDs()返回每个类对应的标签id。%CamVid数据集有32个类。将他们分成11个班%原始的SegNet培训方法[1]。%%这11个类是:%“天空”“建筑”,“杆”,“道路”,“路面”,“树”,“SignSymbol”,%“围栏”、“汽车”、“行人”和“自行车手”。%%CamVid像素标签ID作为RGB颜色值提供。把他们分成几个小组%11类并将其返回为MY-3矩阵的单元格数组。的%原始CamVid类名在每个RGB值旁边列出。请注意百分比另一个/空白类被排除在下面。labelIDs = {...%的“天空”[ 128 128 128;...%的“天空”]%“建设”[000 128 064;...%“桥”128 000 000;...%“建设”064 192 000;...% “墙”064 000 064;...%的“隧道”192 000 128;...%“拱门”]%“极”[19219128;...%”Column_Pole”000 000 064;...%”TrafficCone”]%的道路[128 064 128;...%“道路”128 000 192;...%”LaneMkgsDriv”192 000 064;...%“lanemkgsnondriv”]%“路面”[ 000 000 192;...%“人行道”064 192 128;...%”ParkingBlock”128 128 192;...%“路肩”]%的“树”[128 128 000;...%的“树”192 192 000;...%”VegetationMisc”]%”SignSymbol”[ 192 128 128;...%”SignSymbol”128 128 064;...%“杂项文本”000 064 064;...%”TrafficLight”]%“栅栏”[064 064 128;...%“栅栏”]% “车”[ 064 000 128;...% “车”064 128 192;...%“SUVPickupTruck”192 128 192;...%“卡车和公共汽车”192 064 128;...%“训练”128 064 064;...%“其他移动”]%“行人”[064 064 000;...%“行人”192 128 064;...%“孩子”064 000 192;...%”CartLuggagePram”064 128 064;...% “动物”]%“骑自行车的”[000 128 192;...%“骑自行车的”192 000 192;...%”MotorcycleScooter”]};终止
函数PixellabelColorbar(CMAP,ClassNames)%添加一个颜色条到当前轴。颜色栏被格式化%以显示带有颜色的类名。甘氨胆酸colormap(提出)%将颜色栏添加到当前图形。c = colorbar ('同伴'甘氨胆酸,);%使用类名作为标记。C.Ticklabels = ClassNames;numclasses = size(cmap,1);%中心打勾标签。c、 Ticks=1/(numclass*2):1/numclass:1;%删除勾号。c.TickLength = 0;终止
函数cmap=camvidColorMap()%定义CamVid数据集使用的颜色映射。Cmap = [128 128 128 .%天空128 0 0%的建筑192 192 192%极点128 64 128%的道路60 40 222%铺路128 128 0% 树192 128 128.%符号64 64 128% 栅栏64 0 128.%的车64 64 0%行人0 128 192%骑自行车的];% Normalize between[0 1]。cmap=cmap./255;终止
函数[imdsTrain,imdsVal,imdsTest,pxdsTrain,pxdsVal,pxdsTest]=分区摄像机数据(imds,pxds)%通过随机选择60%的数据进行训练,对CamVid数据进行分区% rest用于测试。%设置初始随机状态,例如重现性。rng (0);numFiles =元素个数(imds.Files);shuffledIndices = randperm (numFiles);%使用60%的图像进行训练。numTrain = round(0.60 * numFiles);trainingIdx = shuffledIndices (1: numTrain);%使用20%的图像进行验证numVal = round(0.20 * numFiles);valIdx = shuffledIndices (numTrain + 1: numTrain + numVal);%使用其余的测试。testIdx = shuffledIndices (numTrain + numVal + 1:结束);%创建用于培训和测试的图像数据存储。trainingImages=imds.Files(trainingIdx);valImages=imds.Files(valIdx);testImages=imds.Files(testIdx);imdsTrain=imageDatastore(trainingImages);imdsVal=imageDatastore(valImages);imdsTest=imageDatastore(testImages);%提取类和标签ID信息。classes=pxds.ClassNames;labelIDs=camvidPixelLabelIDs();%创建用于培训和测试的像素标签数据存储。trainingLabels=pxds.Files(trainingIdx);valLabels=pxds.Files(valIdx);testLabels=pxds.Files(testIdx);pxdsTrain=像素标签数据存储(培训标签、类、标签ID);pxdsVal=像素标签数据存储(标签、类、标签ID);pXDTest=像素标签数据存储(测试标签、类、标签ID);终止
函数data = augmentImageAndLabel(data, xTrans, yTrans)%增强图像和像素标签图像使用随机反射和% 翻译。对于i=1:大小(数据,1)t形式=随机仿射2d(...“XReflection”,真的,...“XTranslation”,xTrans,...“YTranslation”, yTrans);%将视图居中放置在输出空间的图像中心,同时%允许平移将输出图像移出视图。rout = affineOutputView(size(data{i,1})), tform,“BoundsStyle”,“中心输出”);%使用相同的变换扭曲图像和像素标签。数据{i,1}=imwarp(数据{i,1},tform,“OutputView”,溃败);数据{i,2} = imwarp(数据{i,2},tform,“OutputView”,溃败);终止终止

参考

[1] Chen Liang-Chieh et al.“基于Atrous可分离卷积的编码器-解码器语义图像分割”。大会(2018)。

[2]荆棘,G.J.,J.Faueueur和R. Cipolla。“视频中的语义对象类:高清地面真相数据库。”模式识别的字母.2009年第30卷第2期88-97页。

另见

|||||||(深度学习工具箱)|(深度学习工具箱)|(深度学习工具箱)|

相关的话题