主要内容

基于深度学习的语义分割

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

语义分割网络对图像中的每个像素进行分类,从而对图像进行分类。语义分割的应用包括用于自动驾驶的道路分割和用于医疗诊断的癌细胞分割。想要了解更多,请看使用深度学习开始语义分割

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

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

设置

此示例创建具有从预先训练的Reset-18网络初始化的权重的Deeplab V3 +网络。Reset-18是一种高效的网络,适用于具有有限处理资源的应用程序。也可以根据应用要求使用其他预磨损网络,例如MobileNet V2或Reset-50。有关更多详细信息,请参阅预先训练的深度神经网络(深度学习工具箱)

获取预制Reset-18,安装resnet18(深度学习工具箱).安装完成后,运行以下代码来验证安装是否正确。

resnet18 ();

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

pretrainedURL =“//www.tatmou.com/金宝appsupportfiles/vision/data/deeplabv3plusResnet18CamVid.mat”;pretrainedFolder = fullfile (tempdir,“pretrainedNetwork”);pretraynetwork = fullfile(pretrinedfolder,“deeplabv3plusResnet18CamVid.mat”);如果~存在(pretrainedNetwork“文件”)MKDIR(PretrinedFolder);DISP('下载预训练网络(58mb)…');Websave(PretRateNetwork,PretRordurl);结束

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

下载Camvid DataSet.

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

注意:数据的下载时间取决于您的Internet连接。在下载完成之前,在块MATLAB中使用的命令。或者,您可以使用Web浏览器首先将数据集下载到本地磁盘。要使用从Web下载的文件,请更改outputFolder变量设置为下载文件的位置。

负载CamVid图片

imageDatastore加载CamVid图像。的imageDatastore使您能够有效地在磁盘上加载大型映像集合。

imgDir = fullfile (outputFolder,“图片”701 _stillsraw_full);imd = imageDatastore (imgDir);

显示其中一个图像。

i = ReadImage(IMDS,559);我=组合(i);imshow(i)

加载CamVid像素标记的图像

pixelLabelDatastore加载CamVid像素标签图像数据。一个pixelLabelDatastore将像素标签数据和标签ID封装到类名映射。

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

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

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

labelids = camvidpixellabelids();

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

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

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

C = readimage (pxds, 559);提出= 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 /笔(tbl.PixelCount);bar(1:numel(classes),frequency) xticks(1:numel(classes)) xticklabels(tbl.Name) xtickangle(45) ylabel(“频率”

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

CamVid数据集中的图像大小为720 × 960。图像大小的选择是这样的:在NVIDIA™Titan X上使用12gb内存进行训练时,可以容纳足够大的一批图像。如果您的GPU没有足够的内存或减少训练批大小,您可能需要将图像调整为更小的尺寸。

准备培训、验证和测试集

DEEPLAB V3 +使用来自数据集的60%的图像进行培训。其余图像分别以20%和20%的验证和测试均匀分开。以下代码随机将图像和像素标记数据随机分割为培训,验证和测试集。

[imdsTrain, imdsVal, imdsTest, pxdsTrain, pxdsVal, pxdsTest] = partioncamviddata (imds,pxds);

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。

%指定网络图像大小。这通常与Raing Image Size相同。imageSize = [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⋮

属性指定类权重pixelClassificationLayer

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

选择培训选项

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

定义验证数据。dsVal =结合(imdsVal pxdsVal);%定义培训选项。选择= trainingOptions (“个”...“LearnRateSchedule”“分段”...“LearnRateDropPeriod”10...“LearnRateDropFactor”, 0.3,...“动量”, 0.9,...“InitialLearnRate”1 e - 3,...“L2Regularization”, 0.005,...“ValidationData”dsVal,...“MaxEpochs”30岁的...“MiniBatchSize”,8,...“洗牌”“every-epoch”...“CheckpointPath”tempdir,...“VerboseFrequency”2,...'plots'“训练进步”...“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.这里,随机左/右反射和随机X/Y平移+/- 10像素用于数据增强。

xTrans = [-10 10];yTrans = [-10 10];dsTrain = transform(dsTrain, @(数据)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);

显示结果。

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

比较C与预期的地面真理pxdsTest.绿色和品红区域突出了分割结果与预期地面真实值不同的区域。

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

在视觉上,语义分割结果对于诸如道路,天空和建筑物等课程重叠。然而,像行人和汽车这样的较小物体并不准确。可以使用交叉联盟(iou)度量标准来测量每个类的重叠量,也称为Jaccard索引。使用jaccard功能来衡量欠条。

借据= jaccard (C, expectedResult);表(类、借据)
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指标证实了可视结果。道路、天空和建筑类的欠条分数较高,而行人和汽车等类的欠条分数较低。其他常见的细分指标包括骰子bfscore.轮廓匹配分数。

评估培训网络

要测量多个测试图像的准确性,请运行semanticseg在整个测试集上。迷你批次大小为4用于在分割图像时降低内存使用情况。您可以根据您在系统上的GPU内存量增加或减少此值。

pxdsresults = semanticseg(IMDST,NET,...“MiniBatchSize”,4,...'writeelocation'tempdir,...“详细”、假);

semanticseg将测试集的结果作为pixelLabelDatastore对象。中的每个测试图像的实际像素标签数据imdsTest在由此指定的位置写入磁盘'writeelocation'参数。用评估评估度量测试集结果上的语义分割度量。

指标= evaluateSemanticSegmentation (pxdsResults pxdsTest,“详细”、假);

评估评估为整个数据集、单个类和每个测试映像返回各种指标。要查看数据集级别度量,请检查指标。DataSetMetrics

指标。DataSetMetrics
ans =表1×5GlobalAccuracy MeanAccuracy MeanIoU WeightedIoU MeanBFScore  ______________ ____________ _______ ___________ ___________ 0.87695 0.85392 0.6302 0.80851 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个班%原赛格网培训方法[1]。%这11个类是:%的“天空”“建筑”,“极”,“路”,“路面”、“树”、“SignSymbol”,%“围栏”,“汽车”,“行人”和“骑自行车的”。% CamVid像素标签id作为RGB颜色值提供。集团成% 11类并将它们作为m × 3矩阵的单元格数组返回。的%原始CamVid类名在每个RGB值旁边列出。请注意%表示Other/Void类被排除在下面。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;...%“Roadshoulder”]%的“树”[128 128 000;...%的“树”192 192 000;...%”VegetationMisc”]%”SignSymbol”[192 128 128;...%”SignSymbol”128 128 064;...%“misc_text”000 064 064;...%”TrafficLight”]%“栅栏”[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(提出)%添加一个颜色条到当前轴。颜色栏被格式化%以显示带有颜色的类名。甘氨胆酸colormap(提出)%添加颜色栏到当前的数字。c = colorbar (“对等”甘氨胆酸,);%使用类名作为标记。c.TickLabels =一会;numClasses =大小(提出,1);%中心打勾标签。c.Ticks = 1 / (numClasses * 2): 1 / numClasses: 1;%删除勾号。c.TickLength = 0;结束
函数提出= camvidColorMap ()%定义Camvid DataSet使用的ColorMap。Cmap = [128 128 128 .%天空128 0 0%的建筑192 192 192.%极128 64 128%的道路60 40 222%路面128 128 0%的树192 128 128%signsymbol.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] = partioncamviddata (imds,pxds)%对CamVid数据进行分区,随机选取60%的数据进行训练。的% 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:结束);%创建图像数据存储以进行培训和测试。trafterimages = imds.files(trafferidx);Valimages = IMDS.FILES(VANVEX);testimages = imds.files(testIdx);imdstrain = imageageatastore(stabledimages);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 = pixelLabelDatastore(trainingLabels, classes, labelid);pxdsVal = pixelLabelDatastore(valLabels, classes, labelid);pxdsTest = pixelLabelDatastore(testLabels, classes, labelid);结束
函数data = augmentImageAndLabel(data, xTrans, yTrans)%增加图像和像素标签图像使用随机反射和%的翻译。i = 1:size(data,1) tform = randomAffine2d(...“XReflection”,真的,...“XTranslation”,XTrans,...“YTranslation”, yTrans);%中心在输出空间中图像中心的视图%允许平移将输出图像移出视图。rout = affineOutputView(size(data{i,1})), tform,“BoundsStyle”“centerOutput”);使用相同的变换扭曲图像和像素标签。数据{i,1} = imwarp(数据{i,1},tform,“OutputView”,溃败);Data {i,2} = imwarp(Data {i,2}, tform,)“OutputView”,溃败);结束结束

参考文献

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

Brostow, G. J., J. Fauqueur, R. Cipolla。"视频中的语义对象类:高清晰度地面真实数据库"模式识别的字母.2009年第30卷第2期88-97页。

也可以看看

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

相关的话题