主要内容

基于深度学习的语义分割

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

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

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

本示例使用摄像机数据集[2]来自剑桥大学接受培训。这个数据集是一个图像集合,包含驾驶时获得的街道视图。该数据集提供了32个语义类的像素级标签,包括汽车、行人和道路。

安装程序

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

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

resnet18();

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

pretrainedURL =“//www.tianjin-qmedu.com/万博1manbetxsupportfiles/vision/data/deeplabv3plusResnet18CamVid.mat”;pretrainedFolder=fullfile(tempdir,“pretrainedNetwork”);pretrainedNetwork = fullfile (pretrainedFolder,“deeplabv3plusResnet18CamVid.mat”);如果~存在(pretrainedNetwork“文件”mkdir (pretrainedFolder);disp ('下载预训练网络(58mb)…');websave (pretrainedNetwork pretrainedURL);结束

具有CUDA能力的NVIDIA™ 强烈建议使用GPU来运行此示例。使用GPU需要并行计算工具箱™. 有关支持的计算功能的信息,请参阅万博1manbetxGPU版万博1manbetx本支持(并行计算工具箱)

下载CamVid数据集

从以下URL下载CamVid数据集。

imageURL =“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,“摄像机”);labelsZip=fullfile(outputFolder,“labels.zip”);imagesZip = fullfile (outputFolder,“images.zip”);如果~存在(labelsZip“文件”) | | ~存在(imagesZip“文件”mkdir (outputFolder) disp (“下载16mb CamVid数据集标签……”);websave (labelsZip labelURL);解压缩(labelsZip fullfile (outputFolder“标签”));disp(“下载557 MB CamVid数据集图像……”);websave (imagesZip imageURL);解压缩(imagesZip fullfile (outputFolder'图片'));结束

注意:资料下载时间视乎阁下的互联网连接情况而定。上面使用的命令阻塞MATLAB,直到下载完成。或者,您可以使用web浏览器先将数据集下载到本地磁盘。要使用从网上下载的文件,请更改outputFolder变量设置为下载文件的位置。

负载CamVid图片

使用imageageAtastore.要加载CamVid图像,请执行以下操作:imageageAtastore.使您能够有效地在磁盘上加载大型映像集合。

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

显示其中一个图像。

I = readimage (imd, 559);I = histeq(我);imshow(我)

加载CamVid像素标记图像

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

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

类= [“天空”“建筑”“杆子”“路”“路面”“树”“SignSymbol”“围栏”“车”“行人”“骑自行车的”];

为了将32个类减少到11个,将来自原始数据集的多个类分组在一起。例如,"Car"是"Car", "SUVPickupTruck", "Truck_Bus", "Train"和"OtherMoving"的组合。使用支持函数返回分组标签id万博1manbetxcamvidPixelLabelIDs,在本例末尾列出。

labelIDs = camvidPixelLabelIDs ();

使用类和标签id来创建pixelLabelDatastore。

labelDir = fullfile (outputFolder,“标签”);pxds = pixelLabelDatastore (labelDir、类labelIDs);

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

C = ReadImage(PXDS,559);cmap = camvidcolormap;B=labeloverlay(I,C,“彩色地图”,提出);imshow (B) pixelLabelColorbar(提出、类);

没有颜色覆盖的区域没有像素标签,也不会在训练期间使用。

统计分析数据集

要查看CamVid数据集中类标签的分布,请使用countEachLabel。此函数按类别标签统计像素数。

tbl=计数标签(pxds)
台=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);BAR(1:NUMER(类),频率)XTICKS(1:NUMER(类))XTickLabels(TBL.NAME)XTickangle(45)Ylabel(“频率”

理想情况下,所有的类都有相同数量的观察。然而,CamVid中的类不平衡,这是汽车街景数据集中普遍存在的问题。这类场景比行人和骑自行车的人有更多的天空、建筑和道路像素,因为在图像中天空、建筑和道路覆盖了更多的区域。如果处理不当,这种不平衡会对学习过程造成不利影响,因为学习偏向于主导阶级。在本例的后面,您将使用类权重来处理这个问题。

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

准备培训、验证和测试集

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

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

60/20/20的分割结果为如下数量的训练、验证和测试图像:

numTrainingImages=numel(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。

%指定网络镜像大小。这通常与训练图像的大小相同。imageSize = [720 960 3];%指定类的数量。numClasses =元素个数(类);%创建deeplabv3+。LGRAPHE=deeplabv3plusLayers(图像大小、NumClass、,“resnet18”);

使用类权重来平衡类

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

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

属性指定类权重pixelClassificationLayer

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

选择培训选项

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

定义验证数据。dsVal =结合(imdsVal pxdsVal);定义培训选项。选择= trainingOptions (“sgdm”...“LearnRateSchedule”“分段”...“LearnRateDropPeriod”10...“LearnRateDropFactor”, 0.3,...“动量”, 0.9,...“InitialLearnRate”1 e - 3,...“L2规范化”,0.005,...“ValidationData”dsVal,...“MaxEpochs”30岁的...“MiniBatchSize”8...“洗牌”“every-epoch”...“CheckpointPath”,tempdir,...'verbosefrequency'2....“阴谋”“训练进步”...“验证耐心”4);

学习率采用分段计划。学习率每10个纪元降低0.3倍。这使得网络能够以较高的初始学习率快速学习,同时一旦学习率下降,就能够找到接近局部最优的解。

通过设置,每个epoch都对网络进行验证数据测试“ValidationData”参数。的“验证耐心”设置为4,以便在验证精度收敛时尽早停止训练。这可以防止网络对训练数据集进行过拟合。

最小批量大小8用于减少培训时的内存使用。您可以根据系统上的GPU内存量增加或减少此值。

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

数据增加

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

dsTrain = combine(imdsTrain, pxdsTrain);

接下来,使用数据存储变换应用支持函数中定义的所需数据扩充万博1manbetxaugmentImageAndLabel.这里,随机左/右反射和随机X/Y平移+/- 10像素用于数据增强。

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

请注意,数据扩充不适用于测试和验证数据。理想情况下,测试和验证数据应代表原始数据,且未经修改,以便进行无偏评估。

开始训练

开始使用trainNetwork(深度学习工具箱)如果doTraining国旗是真的。否则,加载备用网络。

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

doTraining = false;如果doTraining [net, info] = trainNetwork(dsTrain,lgraph,options);其他的data =负载(pretrainedNetwork);网= data.net;结束

在一个图像上测试网络

作为快速的健全性检查,在一个测试映像上运行经过培训的网络。

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

显示结果。

B=labeloverlay(I,C,“彩色地图”提出,“透明”imshow(B)pixelLabelColorbar(cmap,类);

比较C储存的预期地面真相pxdsTest.绿色和洋红色区域突出了分割结果与预期的基础事实不同的区域。

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

从视觉上看,道路、天空和建筑等类的语义分割结果重叠得很好。然而,像行人和汽车这样较小的物体就不那么准确了。每个类的重叠量可以使用交叉联合(IoU)度量,也称为Jaccard指数。使用jaccard功能来衡量欠条。

iou = jaccard(c,ceneceseResult);表(课程,iou)
ans=11×2表“天空”0.91837“建筑物”0.84479“杆子”0.31203“道路”0.93698“路面”0.82838“树木”0.89636“标志符号”0.57644“栅栏”0.71046“汽车”0.66688“行人”0.48417“自行车”0.68431

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

评估培训的网络

要测量多个测试图像的准确性,请运行semanticseg在整个测试集中。一个小批大小为4用于减少内存使用,而分割图像。你可以根据你系统上的GPU内存数量增加或减少这个值。

pxdsResults = semanticseg (imdsTest净,...“MiniBatchSize”,4,...“WriteLocation”,Tempdir,...“冗长”、假);

semanticseg将测试集的结果返回为PixellabeldAtastore.对象。中的每个测试图像的实际像素标签数据imdsTest写入磁盘的位置由“WriteLocation”参数。使用evaluateSemanticSegmentation测量测试集结果上的语义分段度量。

指标= evaluateSemanticSegmentation (pxdsResults pxdsTest,“冗长”、假);

evaluateSemanticSegmentation为单个类别返回整个数据集的各种度量,以及每个测试图像。查看数据集级别度量,检查指标。DataSetMetrics

指标。DataSetMetrics
ans=1×5表GlobalAccuracy意味着意思意味着意思是敏感_____________________________________ 0.85392 0.6302 0.85392 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

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

万博1manbetx支持功能

函数labelIDs = camvidPixelLabelIDs ()返回每个类对应的标签id。%CamVid数据集有32个类。将它们分为以下11个类%原赛格网培训方法[1]。%这11个类是:%“天空”“建筑”,“杆”,“道路”,“路面”,“树”,“SignSymbol”,%“栅栏”,“汽车”,“行人”和“自行车”。% CamVid像素标签id作为RGB颜色值提供。集团成%11类并将其作为M×3矩阵的单元格数组返回。的%原始CamVid类名与每个RGB值一起列出。注意其他/空白类别在下面排除。labelIDs = {...%“天空”[128 128 128;...%“天空”%“建设”[000 128 064;...%“桥”128 000 000;...%“建设”064 192 000;...% “墙”064 000 064;...%“隧道”192 000 128;...%的“拱门”%“极”[19219128;...%“立柱”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;...%”RoadShoulder”%“树”[ 128 128 000;...%“树”192 192 000;...%“植被杂项”%“符号”[192 128 128;...%“符号”128 128 064;...%”Misc_Text”000 064 064;...%“交通灯”%“栅栏”[064 064 128;...%“栅栏”% “车”[064 000 128;...% “车”064 128 192;...%”SUVPickupTruck”192 128 192;...%”Truck_Bus”192 064 128;...%“火车”128 064 064;...%”OtherMoving”%“行人”[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=色条('同伴'甘氨胆酸,);%使用类名作为标记。C.Ticklabels = ClassNames;numclasses = size(cmap,1);%居中标记标签。c.Ticks = 1 / (numClasses * 2): 1 / numClasses: 1;%删除勾号。c、 长度=0;结束
函数提出= camvidColorMap ()定义CamVid数据集使用的颜色映射。cmap=[128%的天空128 0 0%的建筑192 192 192%极点128 64 128%道路60 40 222%的人行道上128 128 0% 树192 128 128.% SignSymbol64 64 128% 栅栏64 0 128.%汽车64 64 0%行人0 128 192%骑自行车];%在[0]和[1]之间进行规格化。Cmap = Cmap ./ 255;结束
函数[imdsTrain, imdsVal, imdsTest, pxdsTrain, pxdsVal, pxdsTest] = partioncamviddata (imds,pxds)%对CamVid数据进行分区,随机选取60%的数据进行训练。的%rest用于测试。%设置初始随机状态,例如再现性。rng(0);numFiles=numel(imds.Files);shuffleddinces=randperm(numFiles);%使用60%的图像进行训练。numTrain=圆形(0.60*numFiles);trainingIdx=洗牌骰子(1:numTrain);%使用20%的图像进行验证numVal=round(0.20*numFiles);valIdx=shuffledDices(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信息。类= pxds.ClassNames;labelIDs = camvidPixelLabelIDs ();%创建用于训练和测试的像素标签数据存储。trainingLabels = pxds.Files (trainingIdx);valLabels = pxds.Files (valIdx);testLabels = pxds.Files (testIdx);pxdsTrain = pixelLabelDatastore(trainingLabels, classes, labelid);pxdsVal = pixelLabelDatastore(valLabels, classes, labelid);pxdsTest = pixelLabelDatastore(testLabels, classes, labelid);结束
函数数据=增强图像和标签(数据、xTrans、yTrans)%增强图像和像素标签图像使用随机反射和% 翻译。i = 1:size(data,1) tform = randomAffine2d(...“XReflection”,真的,...“XTranslation”xTrans,...“YTranslation”,yTrans);%将视图置于输出空间中图像的中心%允许平移将输出图像移出视图。rout=affineOutputView(大小(数据{i,1})),tform,“邦兹风格”“centerOutput”);使用相同的变换扭曲图像和像素标签。Data {i,1} = imwarp(Data {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年第2期第30卷,第88-97页。

另请参阅

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

相关的话题