此示例演示如何使用GPU编码器在NVIDIA®GPU上培训和部署完全卷积语义分段网络™.
语义分割网络对图像中的每个像素进行分类,从而生成按类别分割的图像。语义分割的应用包括用于自动驾驶的道路分割和用于医疗诊断的癌细胞分割。要了解更多信息,请参阅使用深度学习开始语义分割(计算机视觉工具箱).
为了说明训练过程,本例训练FCN-8s[1],一种用于语义图像分割的卷积神经网络(CNN)。用于语义分割的其他类型的网络包括完全卷积网络,如SegNet和U-Net。您也可以将此训练过程应用于这些网络。
此示例使用CamVid数据集〔2〕来自剑桥大学的训练。该数据集是包含驾驶时获得的街道级视图的图像的集合。数据集为包括汽车、行人和道路的32个语义类提供像素级标签。
支持CUDA®的NVIDIA GPU和兼容驱动程序。
NVIDIA CUDA工具包。
NVIDIA cuDNN图书馆。
编译器和库的环境变量。有关编译器和库支持的版本的信息,请参见万博1manbetx第三方硬件.有关设置环境变量,请参见设置必备产品s manbetx 845.
使用coder.checkGpuInstall
函数来验证运行此示例所需的编译器和库是否正确设置。
envCfg = coder.gpuEnvConfig (“主持人”);envCfg.DeepLibTarget=“cudnn”;envCfg。DeepCodegen = 1;envCfg。安静= 1;coder.checkGpuInstall (envCfg);
这个例子创建了一个完全卷积语义分割网络,其权重由VGG-16网络初始化。vgg16函数检查VGG-16网络支持包的深度学习工具箱模型是否存在,并返回一个预训练的VGG-16模型。万博1manbetx
vgg16();
下载FCN的预训练版本。此预训练模型使您能够运行整个示例,而无需等待训练完成。doTraining标志控制示例是使用示例的已训练网络还是预训练FCN网络生成代码。
doTraining = false;如果~ doTraining pretrainedURL ='//www.tianjin-qmedu.com/万博1manbetxsupportfiles/gpucoder/cnn_models/fcn/FCN8sCamVid.mat';disp(“下载预先训练的FCN (448mb)……”);websave (“FCN8sCamVid.mat”,训练前;结束
正在下载预训练FCN(448 MB)。。。
从这些url下载CamVid数据集。
图像URL='http://web4.cs.ucl.ac.uk/staff/g.brostow/MotionSegRecData/files/701_StillsRaw_full.zip';拉贝鲁尔='http://web4.cs.ucl.ac.uk/staff/g.brostow/MotionSegRecData/data/LabeledApproved_full.zip';outputFolder = fullfile (pwd,“CamVid”);如果~存在(outputFolder“dir”mkdir(outputFolder) labelsZip = fullfile(outputFolder,“labels.zip”);imagesZip = fullfile (outputFolder,“images.zip”);disp (“下载16mb CamVid数据集标签……”);websave (labelsZip labelURL);解压缩(labelsZip fullfile (outputFolder“标签”));disp ('正在下载557 MB CamVid数据集图像…');websave (imagesZip imageURL);解压缩(imagesZip fullfile (outputFolder“图像”));结束
数据下载时间取决于您的Internet连接。下载操作完成后,示例执行才会继续。或者,使用web浏览器先将数据集下载到本地磁盘。然后,使用outputFolder变量指向下载文件的位置。
使用图像数据存储
加载CamVid图像。imageDatastore使您能够有效地将大量映像集加载到磁盘上。
imgDir = fullfile (outputFolder,“图像”,701 _stillsraw_full); imds=图像数据存储(imgDir);
显示其中一个图像。
I=readimage(imds,25);I=histeq(I);imshow(I)
使用像素标签数据库
(计算机视觉工具箱)加载CamVid像素标签图像数据。像素标签数据存储将像素标签数据和标签ID封装为类名映射。
按照SegNet论文[3]中描述的培训方法,将CamVid中的32个原始类分为11个类。指定这些类。
类别=[“天空”“建筑”“极”“道路”“路面”“树”“符号”“篱笆”“汽车”“行人”“自行车”];
为了将32个类缩减为11个类,将原始数据集中的多个类分组在一起。例如,"Car"是"Car", "SUVPickupTruck", "Truck_Bus", "Train"和"OtherMoving"的组合。属性返回分组标签idcamvidPixelLabelIDs万博1manbetx支持功能。
labelIDs=camvidPixelLabelIDs();
使用类和标签ID创建pixelLabelDatastore。
labelDir = fullfile (outputFolder,“标签”);pxds = pixelLabelDatastore (labelDir、类labelIDs);
读取和显示其中一个像素标记的图像,将其覆盖在图像的顶部。
C=读取图像(pxds,25);cmap=camvidColorMap;B=labeloverlay(I,C,“彩色地图”,提出);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
按类可视化像素计数。
frequency=tbl.PixelCount/sum(tbl.PixelCount);bar(1:numel(classes),frequency)xtick(1:numel(classes))xticklabel(tbl.Name)xtickangle(45)ylabel(“频率”)
理想情况下,所有类都有相同数量的观察。CamVid中的类不平衡,这是街景汽车数据集中普遍存在的问题。这类场景比行人和骑自行车的人有更多的天空、建筑和道路像素,因为在图像中天空、建筑和道路覆盖了更多的区域。如果处理不当,这种不平衡会对学习过程造成不利影响,因为学习偏向于主导阶级。在本例的后面,您将使用类权重来处理这个问题。
CamVid数据集中的图像是720 × 960。为减少训练时间和内存使用,请使用调整摄像机图像的大小和resizeCamVidPixelLabels万博1manbetx支持功能。
imageFolder=fullfile(输出文件夹,“imagesResized”, filesep);imd = resizeCamVidImages (imd, imageFolder);labelFolder = fullfile (outputFolder,“labelsResized”,filesep);pxds=大小调整CamVidPixelLabels(pxds,labelFolder);
使用数据集中60%的图像对SegNet进行训练。其余的图像用于测试。下面的代码将图像和像素标签数据随机分割为训练集和测试集。
[imdsTrain, imdsTest pxdsTrain pxdsTest] = partitionCamVidData (imd, pxds);
60/40分割会产生以下数量的训练和测试图像:
numTrainingImages =元素个数(imdsTrain.Files)
numTrainingImages = 421
numTestingImages =元素个数(imdsTest.Files)
numTestingImages=280
使用fcnLayers
(计算机视觉工具箱)创建使用VGG-16权重初始化的完全卷积网络层fcnLayers
函数执行网络转换,从VGG-16转移权重,并添加语义分割所需的额外层。输出fcnLayers
函数是表示FCN的LayerGraph对象。LayerGraph对象封装网络层和层之间的连接。
imageSize=[360 480];numClasses=numel(类);lgraph=fcnLayers(imageSize,numClasses);
根据数据集中图像的大小选择图像大小。根据CamVid中的类选择类数。
CamVid中的类不平衡。要改进训练,可以使用先前由countEachLabel
(计算机视觉工具箱)函数并计算频率类权重的中位数[3]。
imageFreq =(资源。PixelCount。/ tbl.ImagePixelCount;classWeights =中值(imageFreq) ./ imageFreq;
通过使用像素分类层
(计算机视觉工具箱).
pxLayer = pixelClassificationLayer (“姓名”,“标签”,“类”资源描述。的名字,“类权重”classWeights)
pxLayer=PixelClassificationLayer,具有以下属性:名称:'labels'类:[11×1 Category]类权重:[11×1 double]OutputSize:'auto'超参数LossFunction:'crossentropyex'
通过删除当前的pixelClassificationLayer并添加新层来更新具有新的pixelClassificationLayer的SegNet网络。当前的pixelClassificationLayer命名为“pixelLabels”。用removeLayers
(深度学习工具箱)函数,使用addLayers
(深度学习工具箱)函数,并将新层连接到网络的其余部分connectLayers
(深度学习工具箱)功能。
lgraph = removeLayers (lgraph,“pixelLabels”);lgraph = addLayers(lgraph, pxLayer);lgraph = connectLayers (lgraph,“softmax”,“标签”);
训练的优化算法为Adam,它来源于自适应估计时刻.使用trainingOptions
(深度学习工具箱)函数指定用于Adam的超参数。
选择= trainingOptions (“亚当”,...“初始学习率”1 e - 3,...“MaxEpochs”,100,...“MiniBatchSize”4....“洗牌”,“every-epoch”,...“CheckpointPath”tempdir,...“详细频率”2);
“MiniBatchSize”为4可减少训练时的内存使用。您可以根据系统中的GPU内存量增加或减少此值。
'CheckpointPath'被设置为一个临时位置。这个名称-值对允许在每个训练阶段结束时保存网络检查点。如果培训因系统故障或断电而中断,您可以从保存的检查点恢复培训。确保'CheckpointPath'指定的位置有足够的空间存储网络检查点。
数据扩充用于通过在训练期间随机变换原始数据来提高网络精度。通过使用数据扩充,您可以在不增加标记训练样本数的情况下为训练数据添加更多种类。要对图像和像素标记数据应用相同的随机变换,请使用数据存储合并和t转换。首先,合并imdsTrain
和pxdsTrain
.
dsTrain = combine(imdsTrain, pxdsTrain);
接下来,使用数据存储转换应用在支持函数中定义的所需数据扩展万博1manbetxaugmentImageAndLabel
这里,随机左/右反射和+/-10像素的随机X/Y平移用于数据增强。
xTrans=[-10];yTrans=[-10];dsTrain=转换(dsTrain,@(数据)增强图像和标签(数据,xTrans,yTrans));
注意,数据扩充并不适用于测试和验证数据。理想情况下,测试和验证数据应该能够代表原始数据,并且不作任何修改,以便进行公正的评估。
开始培训使用列车网络
如果溺爱
标志为true。否则,加载预训练网络。
培训是在带有12gb GPU内存的NVIDIA™Titan Xp上验证的。如果你的GPU有更少的内存,你可能会耗尽内存。如果系统中没有足够的内存,请尝试降低MiniBatchSize
财产trainingOptions
为1。训练这个网络需要大约5个小时或更长时间,这取决于你的GPU硬件。
doTraining = false;如果doTraining [net, info] = trainNetwork(dsTrain,lgraph,options);保存(“FCN8sCamVid.mat”,“净”);结束
将DAG网络对象保存为一个名为mat的文件FCN8sCamVid.mat
。此MAT文件在代码生成期间使用。
这个fcn_predict.m函数取图像输入,利用保存在其中的深度学习网络对图像进行预测FCN8sCamVid.mat
文件。函数从FCN8sCamVid.mat
变成一个持久变量mynet并在后续的预测调用中重用持久对象。
类型(“fcn_predict.m”)
function out = fcn_predict(in) %#codegen %版权所有if isempty(mynet) mynet = code . loaddeeplearningnetwork ('FCN8sCamVid.mat');End % pass in input out = predict(mynet,in);
为MeX目标设置目标语言生成一个GPU配置对象,以C++为基础。coder.DeepLearningConfig
函数创建一个cuDNN
的深度学习配置对象,并将其分配给深度学习配置
GPU代码配置对象的属性。运行codegen
指定输入大小[360,480,3]的命令。此大小对应于FCN的输入层。
cfg=coder.gpuConfig(“墨西哥”);cfg。TargetLang =“c++”;cfg。DeepLearningConfig =编码器。DeepLearningConfig (“cudnn”);codegen配置cfg预测-args{one(360480,3,'uint8')}-报告
代码生成成功:查看报告
加载并显示输入图像。
im=imread('testImage.png');imshow (im);
通过调用fcn_predict_mex
在输入图像上。
预测分数=fcn\U预测分数(im);
这个predict_scores
变量是一个三维矩阵,具有11个通道,对应于每个类别的像素级预测分数。使用最大预测分数计算通道以获得像素级标签。
[~,argmax]=max(预测分数,[],3);
将分割标签覆盖在输入图像上并显示分割区域。
类别=[“天空”“建筑”“极”“道路”“路面”“树”“符号”“篱笆”“汽车”“行人”“自行车”];cmap=camvidColorMap();SegmenteImage=labeloverlay(im,argmax,“彩色地图”图形显示(分段图像);像素标签颜色条(cmap,类);
清除加载到内存中的静态网络对象。
清楚的墨西哥人;
函数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”,rout);数据{i,2}=imwarp(数据{i,2},tform,“OutputView”,溃败);结束结束
[1] Long,J.,E.Shelhamer和T.Darrell.“用于语义分割的完全卷积网络”,《IEEE计算机视觉和模式识别会议论文集》,2015年,第3431-3440页。
[2] Brostow,G.J.,J.Fauqueur和R.Cipolla.“视频中的语义对象类:一个高清晰度地面真相数据库。”模式识别的字母.2009年第30卷第2期88-97页。
Badrinarayanan V., A. Kendall, R. Cipolla。“SegNet:一种用于图像分割的深度卷积编码器-解码器体系结构”,arXiv预印本,arXiv:1511.00561, 2015。