训练残差网络用于图像分类
这个例子展示了如何创建一个具有残余连接的深度学习神经网络,并在CIFAR-10数据上训练它。残差连接是卷积神经网络结构中一个很受欢迎的元素。使用残差连接可以改善网络中的梯度流,并且可以训练更深层的网络。
对于许多应用程序,使用由简单的层序列组成的网络就足够了。然而,一些应用程序需要具有更复杂图结构的网络,其中各层可以有来自多个层的输入和到多个层的输出。这些类型的网络通常被称为有向无环图(DAG)网络。残余网络是DAG网络的一种类型,它具有绕过主网络层的残余(或快捷)连接。残差连接使参数梯度更容易从输出层传播到网络的早期层,这使得训练更深的网络成为可能。这种增加的网络深度可以在更困难的任务上获得更高的准确性。
要创建和训练具有图结构的网络,请遵循以下步骤。
创建一个
LayerGraph
对象使用layerGraph
.层图指定了网络体系结构。你可以创建一个空的图层图,然后给它添加图层。您还可以直接从网络层数组创建层图。在这种情况下,layerGraph
连接数组中的层一个接一个。添加图层到图层图使用
addLayers
,并从图中删除图层removeLayers
.连接层到其他层使用
connectLayers
,并将层与其他层断开连接disconnectLayers
.绘制网络架构使用
情节
.使用以下方法训练网络
trainNetwork
.训练后的网络是DAGNetwork
对象。对新数据进行分类和预测
分类
和预测
.
您还可以加载预训练的网络进行图像分类。有关更多信息,请参见预训练深度神经网络.
准备数据
下载CIFAR-10数据集[1]。该数据集包含60,000张图像。每张图像大小为32 × 32,有三个颜色通道(RGB)。数据集的大小为175 MB。根据您的互联网连接,下载过程可能会花费一些时间。
Datadir = tempdir;downloadCIFARData (datadir);
将CIFAR-10训练和测试图像加载为4-D数组。训练集包含50,000张图像,测试集包含10,000张图像。使用CIFAR-10测试图像进行网络验证。
[XTrain,YTrain,XValidation,YValidation] = loadCIFARData(datadir);
您可以使用以下代码显示训练图像的随机样本。
图;idx = randperm(size(XTrain,4),20);im = imtile(XTrain(:,:,:,idx),“ThumbnailSize”(96、96));imshow (im)
创建一个augmentedImageDatastore
对象用于网络训练。在训练过程中,数据存储沿垂直轴随机翻转训练图像,并在水平和垂直方向上随机翻译最多4个像素。数据增强有助于防止网络过度拟合和记忆训练图像的确切细节。
imagessize = [32 32 3];pixelRange = [-4 4];imageAugmenter = imageDataAugmenter(…“RandXReflection”,真的,…“RandXTranslation”pixelRange,…“RandYTranslation”, pixelRange);augimdsTrain = augmentedImageDatastore(imageSize,XTrain,YTrain,…“DataAugmentation”imageAugmenter,…“OutputSizeMode”,“randcrop”);
定义网络架构
剩余网络架构由以下组件组成:
一个主要分支与卷积,批规范化,和ReLU层连接顺序。
剩余的连接绕过了主干的卷积单元。残差连接和卷积单元的输出按元素方式添加。当激活的大小发生变化时,残余连接也必须包含1 × 1的卷积层。剩余连接使参数梯度更容易从输出层流向网络的早期层,这使得训练更深的网络成为可能。
创建主分支
首先创建网络的主分支。主要分支包括五个部分。
包含图像输入层和具有激活的初始卷积的初始部分。
三个阶段的卷积层具有不同的特征大小(32 × 32, 16 × 16和8 × 8)。每个阶段包含N卷积的单位。在这一部分的例子中,N = 2.每个卷积单元包含两个具有激活的3 × 3卷积层。的
netWidth
参数为网络宽度,定义为网络第一阶段卷积层中滤波器的个数。第二和第三阶段的第一个卷积单元对空间维度进行了两倍的采样。为了在整个网络中保持每个卷积层所需的计算量大致相同,每次执行空间下采样时,将过滤器的数量增加两倍。最后一个部分是全局平均池化、完全连接、softmax和分类层。
使用convolutionalUnit (numF、跨步、标签)
来创建一个卷积单元。numF
是每层卷积滤波器的个数,步
单位的第一个卷积层的步幅是多少标签
是一个字符数组,用于添加到图层名称之前。的convolutionalUnit
函数在示例末尾定义。
给所有图层起唯一的名字。卷积单元中的层的名称以“SjUk”
,在那里j
阶段指数是和吗k
是那个阶段的卷积单元的索引。例如,“S2U1”
表示阶段2,单元1。
netWidth = 16;layers = [imageInputLayer([32 32 3],“名字”,“输入”) convolution2dLayer (3 netWidth“填充”,“相同”,“名字”,“convInp”) batchNormalizationLayer (“名字”,“BNInp”) reluLayer (“名字”,“reluInp”) convolutionalUnit (netWidth 1“S1U1”) additionLayer (2“名字”,“add11”) reluLayer (“名字”,“relu11”) convolutionalUnit (netWidth 1“S1U2”) additionLayer (2“名字”,“add12”) reluLayer (“名字”,“relu12”) convolutionalUnit (2 * netWidth 2“S2U1”) additionLayer (2“名字”,“add21”) reluLayer (“名字”,“relu21”) convolutionalUnit (2 * netWidth 1“S2U2”) additionLayer (2“名字”,“add22”) reluLayer (“名字”,“relu22”) convolutionalUnit (4 * netWidth 2“S3U1”) additionLayer (2“名字”,“add31”) reluLayer (“名字”,“relu31”) convolutionalUnit (4 * netWidth 1“S3U2”) additionLayer (2“名字”,“add32”) reluLayer (“名字”,“relu32”) averagePooling2dLayer (8,“名字”,“globalPool”) fullyConnectedLayer (10“名字”,“fcFinal”) softmaxLayer (“名字”,“softmax”) classificationLayer (“名字”,“classoutput”));
从层数组中创建一个层图。layerGraph
连接所有的图层层
按顺序。绘制层图。
lgraph = layerGraph(layers);图(“单位”,“归一化”,“位置”,[0.2 0.2 0.6 0.6]);情节(lgraph);
创建剩余连接
在卷积单元周围添加残差连接。大多数剩余连接不执行任何操作,只是简单地向卷积单元的输出添加元素。
创建剩余连接“reluInp”
到“add11”
层。因为您在创建层时指定了添加层的输入数为两个,所以该层有两个带有名称的输入“三机”
和“in2”
.第一个卷积单元的最后一层已经连接到“三机”
输入。然后,附加层对第一个卷积单元和第二个卷积单元的输出求和“reluInp”
层。
以同样的方式,连接“relu11”
层的第二个输入“add12”
层。通过绘制图层图来检查你是否正确地连接了图层。
lgraph = connectLayers(lgraph,“reluInp”,“add11 / in2”);lgraph = connectLayers(lgraph,“relu11”,“add12 / in2”);图(“单位”,“归一化”,“位置”,[0.2 0.2 0.6 0.6]);情节(lgraph);
当卷积单元中的层激活改变大小时(即当它们在空间上被下采样而在通道维度上被上采样时),残差连接中的激活也必须改变大小。通过使用1 × 1卷积层及其批处理归一化层来改变剩余连接中的激活大小。
skip1 = [convolution2dLayer(1,2*netWidth,“步”2,“名字”,“skipConv1”) batchNormalizationLayer (“名字”,“skipBN1”));lgraph = addLayers(lgraph,skip1);lgraph = connectLayers(lgraph,“relu12”,“skipConv1”);lgraph = connectLayers(lgraph,“skipBN1”,“add21 / in2”);
在网络的第二阶段添加身份连接。
lgraph = connectLayers(lgraph,“relu21”,“add22 / in2”);
通过另一个1 × 1卷积层及其批处理归一化层改变第二和第三阶段之间残留连接中的激活大小。
skip2 = [convolution2dLayer(1,4*netWidth,“步”2,“名字”,“skipConv2”) batchNormalizationLayer (“名字”,“skipBN2”));lgraph = addLayers(lgraph,skip2);lgraph = connectLayers(lgraph,“relu22”,“skipConv2”);lgraph = connectLayers(lgraph,“skipBN2”,“add31 / in2”);
添加最后一个身份连接并绘制最后一个层图。
lgraph = connectLayers(lgraph,“relu31”,“add32 / in2”);图(“单位”,“归一化”,“位置”,[0.2 0.2 0.6 0.6]);情节(lgraph)
建立更深层次的人际关系
对于任意深度和宽度的CIFAR-10数据,使用支持函数创建带有剩余连接的层图金宝appresidualCIFARlgraph.
lgraph = residalcifarlgraph (netWidth,numUnits,unitType)
为带有剩余连接的CIFAR-10数据创建层图。
netWidth
为网络宽度,定义为网络前3 × 3卷积层中滤波器的数量。numUnits
为网络主分支中卷积单元的个数。因为网络由三个阶段组成,每个阶段都有相同数量的卷积单元,numUnits
必须是3的整数倍。unitType
卷积单元的类型是否指定为“标准”
或“瓶颈”
.一个标准的卷积单元由两个3 × 3的卷积层组成。瓶颈卷积单元由三个卷积层组成:1 × 1层用于通道维度的下采样,3 × 3卷积层和1 × 1层用于通道维度的上采样。因此,瓶颈卷积单元的卷积层数比标准单元多50%,但空间3 × 3卷积的数量只有标准单元的一半。这两种单元类型具有相似的计算复杂度,但是当使用瓶颈单元时,在剩余连接中传播的特征总数是瓶颈单元的四倍。总深度,定义为顺序卷积层和完全连接层的最大数量,为2*numUnits
带标准单元的网络+ 2和3*numUnits
带有瓶颈单元的网络+ 2。
创建一个具有9个标准卷积单元(每个阶段3个单元)的残差网络,宽度为16。网络总深度为2*9+2 = 20。
numUnits = 9;netWidth = 16;lgraph = residalcifarlgraph (netWidth,numUnits,“标准”);图(“单位”,“归一化”,“位置”,[0.1 0.1 0.8 0.8]);情节(lgraph)
列车网络的
指定培训选项。训练网络80次。选择一个与mini-batch大小成比例的学习率,并在60次epoch后将学习率降低10倍。使用验证数据每个epoch验证一次网络。
miniBatchSize = 128;learnRate = 0.1*miniBatchSize/128;valFrequency = floor(size(XTrain,4)/miniBatchSize);options = trainingOptions(“个”,…“InitialLearnRate”learnRate,…“MaxEpochs”, 80,…“MiniBatchSize”miniBatchSize,…“VerboseFrequency”valFrequency,…“洗牌”,“every-epoch”,…“阴谋”,“训练进步”,…“详细”假的,…“ValidationData”{XValidation, YValidation},…“ValidationFrequency”valFrequency,…“LearnRateSchedule”,“分段”,…“LearnRateDropFactor”, 0.1,…“LearnRateDropPeriod”、60);
来训练网络使用trainNetwork
,设置doTraining
旗帜真正的
.否则,加载一个预训练的网络。在一个好的GPU上训练网络大约需要两个小时。如果你没有GPU,那么训练需要更长的时间。
doTraining = false;如果doTraining trainedNet = trainNetwork(augimdsTrain,lgraph,options);其他的负载(“cifarnet - 20 - 16. -垫”,“trainedNet”);结束
评估训练过的网络
在训练集(不含数据增强)和验证集上计算网络的最终精度。
[YValPred,probs] = classification (trainedNet,XValidation);validationError = mean(YValPred ~= YValidation);YTrainPred =分类(trainedNet,XTrain);trainError = mean(YTrainPred ~= YTrain);disp (“训练错误:”+ trainError*100 +“%”)
训练误差:2.862%
disp ("验证错误:"+ validationError*100 +“%”)
验证误差:9.76%
绘制混淆矩阵。通过使用列和行摘要显示每个类的精度和召回率。这个网络最常混淆猫和狗。
图(“单位”,“归一化”,“位置”,[0.2 0.2 0.4 0.4]);cm = confusionchart(YValidation,YValPred);厘米。Title =验证数据的混淆矩阵;厘米。ColumnSummary =“column-normalized”;厘米。RowSummary =“row-normalized”;
您可以使用以下代码显示9个测试图像的随机样本以及它们的预测类和这些类的概率。
figure idx = randperm(size(XValidation,4),9);为i = 1:元素个数(idx)次要情节(3 3 i) imshow (XValidation (:,:,:, idx(我)));Prob = num2str(100*max(pros (idx(i),:)),3);predClass = char(YValPred(x(i)));标题([predClass,”、“概率,“%”])结束
convolutionalUnit (numF、跨步、标签)
创建一个包含两个卷积层和相应的批处理规范化层和ReLU层的层数组。numF
是卷积滤波器的个数,步
第一个卷积层的步幅是多少标签
是一个附加在所有层名前的标签。
函数layers = convolutionalUnit(numF,stride,tag) layers =[卷积2dlayer (3,numF,“填充”,“相同”,“步”步,“名字”,标签,“conv1”]) batchNormalizationLayer (“名字”,标签,“BN1”]) reluLayer (“名字”,标签,“relu1”numF]) convolution2dLayer(3日,“填充”,“相同”,“名字”,标签,“conv2”]) batchNormalizationLayer (“名字”,标签,“BN2”)));结束
参考文献
[1] Krizhevsky, Alex。“从微小的图像中学习多层特征。”(2009)。https://www.cs.toronto.edu/~kriz/learning-features-2009-TR.pdf
[10]何凯,张翔宇,任少卿,孙健。“图像识别的深度残差学习。”在计算机视觉与模式识别IEEE会议论文集,第770-778页。2016.
另请参阅
analyzeNetwork
|layerGraph
|trainNetwork
|trainingOptions