这个例子展示了如何使用函数而不是层图或层次图来创建和训练一个深度学习网络dlnetwork
。使用函数的优点是可以灵活地描述各种网络。缺点是您必须完成更多步骤并仔细准备数据。此示例使用手写数字图像,其双重目标是对数字进行分类并确定每个数字与垂直方向的角度。
的digitTrain4DArrayData
函数加载图像、它们的数字标签以及它们从垂直方向的旋转角度。创建arrayDatastore
对象的图像、标签和角度,然后使用结合
函数创建一个包含所有训练数据的单一数据存储。提取类名和非离散响应的数量。
[XTrain, YTrain anglesTrain] = digitTrain4DArrayData;dsXTrain = arrayDatastore (XTrain,“IterationDimension”,4);dsYTrain=arrayDatastore(YTrain);dsAnglesTrain=arrayDatastore(anglesTrain);dsTrain=combine(dsXTrain,dsYTrain,dsAnglesTrain);classNames=categories(YTrain);numClasses=numel(classNames);numResponses=size(anglesTrain,2);numObservations=numel(YTrain);
从训练数据中查看一些图像。
idx=randperm(numObservations,64);I=imtile(XTrain(:,:,:,idx));图imshow(I)
定义下面的网络来预测标签和旋转角度。
带有16个5 × 5滤波器的卷积-批数- relu块。
两个卷积批量范数块的一个分支,每个块都有32个3 × 3滤波器,中间有一个ReLU操作
带有带有32个1 × 1卷积的卷积-批norm块的跳过连接。
使用添加和ReLU操作组合两个分支
对于回归输出,一个具有完全连接操作的分支,大小为1(响应的数量)。
对于分类输出,具有大小为10(类数)的完全连接操作和softmax操作的分支。
定义每个操作的参数,并将它们包含在结构中。使用格式parameters.OperationName.ParameterName
哪里参数
结构是,OperationName
操作的名称(例如“conv1”)和ParameterName
是参数的名称(例如,“Weights”)。
创建一个结构体参数
包含模型参数。初始化可学习层权重和偏差使用initializeGlorot
和initializeZeros
例子函数,分别。属性初始化批处理归一化偏移量和比例参数initializeZeros
和initializeOnes
例子函数,分别。
要使用批处理规范化层执行训练和推断,还必须管理网络状态。在进行预测之前,您必须指定来自训练数据的数据集均值和方差。创建一个结构体状态
包含状态参数。批处理归一化统计信息不能为dlarray
对象。初始化批处理归一化训练均值和训练方差状态使用0
和的
函数,分别。
初始化示例函数作为支持文件附加到此示例。金宝app
初始化第一卷积层的参数。
filterSize = [5 5];numChannels = 1;numFilters = 16;sz = [filterSize numChannels numFilters];numOut = prod(filterSize) * numFilters;numIn = prod(filterSize) * numFilters;parameters.conv1。重量= initializeGlorot(深圳、numOut numIn);parameters.conv1。Bias = initializeZeros([numFilters 1]);
初始化第一个批处理规范化层的参数和状态。
parameters.batchnorm1.Offset=初始化zezeros([numFilters 1]);parameters.batchnorm1.Scale=初始值([numFilters 1]);state.batchNormal1.TrainedMean=零(numFilters,1,“单一”);state.batchnorm1。TrainedVariance = 1 (numFilters 1“单一”);
初始化第二个卷积层的参数。
filterSize=[3];numChannels=16;numFilters=32;sz=[filterSize numChannels numFilters];numOut=产品(过滤器规格)*NUM过滤器;numIn=产品(过滤器规格)*NUM过滤器;parameters.conv2.Weights=初始值groot(sz、numOut、numIn);parameters.conv2.Bias=initializeZeros([numFilters 1]);
初始化第二个批处理规范化层的参数和状态。
parameters.batchnorm2。Offset = initializeZeros([numFilters 1]);parameters.batchnorm2。Scale = initializeOnes([numFilters 1]);state.batchnorm2。TrainedMean = 0 (numFilters 1“单一”);state.batchnorm2。TrainedVariance = 1 (numFilters 1“单一”);
初始化第三个卷积层的参数。
filterSize = [3 3];numChannels = 32;numFilters = 32;sz = [filterSize numChannels numFilters];numOut = prod(filterSize) * numFilters;numIn = prod(filterSize) * numFilters;parameters.conv3。重量= initializeGlorot(深圳、numOut numIn);parameters.conv3。Bias = initializeZeros([numFilters 1]);
初始化第三批标准化层的参数和状态。
parameters.batchnorm3。Offset = initializeZeros([numFilters 1]);parameters.batchnorm3。Scale = initializeOnes([numFilters 1]);state.batchnorm3。TrainedMean = 0 (numFilters 1“单一”); state.batchNormal3.TrainedVariance=个(numFilters,1,“单一”);
在跳过连接中初始化卷积层的参数。
filterSize = [1 1];numChannels = 16;numFilters = 32;sz = [filterSize numChannels numFilters];numOut = prod(filterSize) * numFilters;numIn = prod(filterSize) * numFilters;parameters.convSkip.Weights = initializeGlorot(深圳、numOut numIn);parameters.convSkip.Bias = initializeZeros([numFilters 1]);
在跳过连接中初始化批处理规范化层的参数和状态。
parameters.batchnormSkip.Offset = initializeZeros([numFilters 1]);parameters.batchnormSkip.Scale = initializeOnes([numFilters 1]);state.batchnormSkip.TrainedMean = 0 ([numFilters 1],“单一”);state.batchnormSkip.TrainedVariance = ones([numFilters 1],“单一”);
初始化与分类输出相对应的全连接层的参数。
sz = [numClasses 6272]; / / / /numOut = numClasses;numIn = 6272;parameters.fc1。重量= initializeGlorot(深圳、numOut numIn);parameters.fc1。Bias = initializeZeros([numClasses 1]);
初始化回归输出对应的全连接层的参数。
sz = [numResponses 6272]; / /numOut = numResponses;numIn = 6272;parameters.fc2。重量= initializeGlorot(深圳、numOut numIn);parameters.fc2。Bias = initializeZeros([numResponses 1]);
查看参数的结构。
参数
参数=结构体字段:conv1:[1×1结构]batchnorm1:[1×1结构]conv2:[1×1结构]batchnorm2:[1×1结构]conv3:[1×1结构]batchnorm3:[1×1结构]convSkip:[1×1结构]batchnormSkip:[1×1结构]fc1:[1×1结构]fc2:[1×1结构]
查看“conv1”操作的参数。
parameters.conv1
ans =结构体字段:权重:[5×5×1×16 dlarray]偏差:[16×1 dlarray]
查看状态的结构。
状态
陈述=结构体字段:[1×1 struct] batchnorm2: [1×1 struct] batchnorm3: [1×1 struct] batchnormSkip: [1×1 struct]
查看batchnorm1操作的状态参数。
state.batchnorm1
ans =结构体字段:TrainedMean: [16×1 single] TrainedVariance: [16×1 single]
创建函数模型
,计算前面描述的深度学习模型的输出。
这个函数模型
取模型参数参数
,输入数据dlX
的国旗doTraining
哪个指定了模型是否应该返回训练或预测的输出,以及网络状态状态
.网络输出标签的预测、角度的预测和更新后的网络状态。
创建函数modelGradients
,它接受模型参数,即一小批输入数据dlX
与相应的目标T1
和T2
分别包含标签和角度,并返回损耗相对于可学习参数的梯度、更新后的网络状态和相应的损耗。
指定培训选项。训练20个时代,小批量128个。
numEpochs=20;miniBatchSize=128;
要监视培训进度,可以在每次迭代后绘制培训损失。创建包含“培训进度”的变量图。如果不想绘制培训进度,请将此值设置为“无”。
情节=“培训进度”;
使用小型批处理队列
处理和管理小批量图像。为每个mini-batch:
使用自定义小批量预处理功能preprocessMiniBatch
(在本例的最后定义)一次性对类标签进行编码。
使用标注标签格式化图像数据“SSCB”
(空间、空间、通道、批次)。默认情况下小型批处理队列
对象将数据转换为dlarray
具有底层类型的对象仅有一个的
.不要向类标签或角度添加格式。
在可用的GPU上进行训练。默认情况下,小型批处理队列
对象将每个输出转换为gpuArray
如果有可用的GPU。使用GPU需要并行计算工具箱™和支持的GPU设备。金宝app有关支持的设备的信息,请参见金宝appGPU支金宝app持情况(并行计算工具箱).
兆贝可= minibatchqueue (dsTrain,...“MiniBatchSize”miniBatchSize,...“MiniBatchFcn”,@minibatch,...“MiniBatchFormat”, {“SSCB”,'',''});
对于每个epoch,洗牌数据并在小批数据上循环。在每次迭代结束时,显示训练进度。为每个mini-batch:
使用以下方法评估模型坡度和损失:德尔费瓦尔
和modelGradients
函数。
使用adamupdate
函数。
初始化Adam的参数。
trailingAvg = [];trailingAvgSq = [];
初始化训练进度图。
如果情节= =“培训进度”figure lineLossTrain=动画线(“颜色”[0.85 0.325 0.098]);ylim([0正])包含(“迭代”) ylabel (“损失”网格)在结束
火车模型。
迭代= 0;开始=抽搐;%环游各个时代。为历元=1:numEpochs%洗牌数据。洗牌(兆贝可)%循环小批而Hasdata (mbq) iteration = iteration + 1;[dlX, dlY1 dlY2] =下一个(兆贝可);使用dlfeval和% modelGradients函数。[gradient,state,loss] = dlfeval(@modelGradients, parameters, dlX, dlY1, dlY2, state);%使用Adam优化器更新网络参数。(参数、trailingAvg trailingAvgSq) = adamupdate(参数、渐变...trailingAvg trailingAvgSq,迭代);%显示训练进度。如果情节= =“培训进度”D =持续时间(0,0,toc(开始),“格式”,“hh:mm:ss”);addpoints (lineLossTrain、迭代、双(收集(extractdata(损失))))标题(“时代:”+时代+”,过去:“+ drawnow字符串(D))结束结束结束
通过将测试集上的预测与真实标签和角度进行比较,检验模型的分类精度。使用控件管理测试数据集小型批处理队列
对象的设置与训练数据相同。
[XTest,欧美,anglesTest] = digitTest4DArrayData;dsXTest = arrayDatastore (XTest,“IterationDimension”4);dsYTest = arrayDatastore(欧美);dsAnglesTest = arrayDatastore (anglesTest);dst =结合(dsXTest dsYTest dsAnglesTest);mbqTest = minibatchqueue (dst,...“MiniBatchSize”miniBatchSize,...“MiniBatchFcn”,@minibatch,...“MiniBatchFormat”, {“SSCB”,'',''});
为了预测验证数据的标签和角度,对小批量进行循环,并使用模型函数doTraining
选项设置为假
.存储预测的类和角度。比较预测的和真实的类和角度,并存储结果。
doTraining = false;classesPredictions = [];anglesPredictions = [];classCorr = [];angleDiff = [];%循环小批。而hasdata (mbqTest)%读取小批量数据。[dlXTest, dlY1Test dlY2Test] =下一个(mbqTest);%使用predict函数进行预测。[dlY1Pred, dlY2Pred] =模型(参数、dlXTest doTraining、状态);%确定预测类。Y1PredBatch = onehotdecode (dlY1Pred一会1);classesPredictions = [classesPredictions Y1PredBatch];Dermine预测角度Y2PredBatch = extractdata (dlY2Pred);anglesPredictions = [anglesPredictions Y2PredBatch];%比较预测类和真实类Y1Test = onehotdecode (dlY1Test一会1);classCorr = [classCorr Y1PredBatch == Y1Test];%比较预测角度和真实角度angleDiffBatch = Y2PredBatch - dlY2Test;angleDiff = [angleDiff extractdata(gather(angleDiffBatch))];结束
评估分类精度。
精度=意味着(classCorr)
精度= 0.9730
评估回归精度。
angleRMSE =√意味着(angleDiff ^ 2))
垂钓者=仅有一个的6.6909
查看一些图像及其预测。以红色显示预测的角度,以绿色显示正确的标签。
idx=randperm(大小(XTest,4),9);图为i=1:9子批次(3,3,i)i=XTest(:,:,:,idx(i));imshow(I)hold在sz=尺寸(I,1);偏移量=sz/2;角度预测(idx(I));绘图(偏移量*[1-tand(thetaPred)1+tand(thetaPred)],[sz 0],“r——”) = anglesTest(idx(i));情节(抵消* [1-tand (thetaValidation) 1 +罐内(thetaValidation)], [sz 0],“g——”)举行从标签=字符串(classesPredictions (idx (i)));标题(”的标签:“+标签)结束
这个函数模型
取模型参数参数
,输入数据dlX
的国旗doTraining
哪个指定了模型是否应该返回训练或预测的输出,以及网络状态状态
.网络输出标签的预测、角度的预测和更新后的网络状态。
函数[dlY1、dlY2] =模型(参数、dlX doTraining,状态)%卷积重量= parameters.conv1.Weights;偏见= parameters.conv1.Bias;海底= dlconv (dlX、权重、偏见,“填充”,“相同”);%批处理规范化,ReLU抵消= parameters.batchnorm1.Offset;规模= parameters.batchnorm1.Scale;trainedMean = state.batchnorm1.TrainedMean;trainedVariance = state.batchnorm1.TrainedVariance;如果doTraining[Dy,trainedMean,trainedVariance]=批次标准(Dy,偏移量,比例,trainedMean,trainedVariance);%更新状态state.batchnorm1。TrainedMean = TrainedMean;state.batchnorm1。TrainedVariance = TrainedVariance;其他的海底= batchnorm(海底、抵消、规模、trainedMean trainedVariance);结束海底= relu(海底);%卷积,批处理归一化(跳过连接)重量= parameters.convSkip.Weights;偏见= parameters.convSkip.Bias;dlYSkip = dlconv(海底,重量、偏见,“步”2);抵消= parameters.batchnormSkip.Offset;规模= parameters.batchnormSkip.Scale;trainedMean = state.batchnormSkip.TrainedMean;trainedVariance = state.batchnormSkip.TrainedVariance;如果doTraining [dlskip,trainedMean,trainedVariance] = batchnorm(dlskip,offset,scale,trainedMean,trainedVariance);%更新状态state.batchnormSkip.TrainedMean = trainedMean;state.batchnormSkip.TrainedVariance = trainedVariance;其他的dlYSkip = batchnorm (dlYSkip、抵消、规模、trainedMean trainedVariance);结束%卷积重量= parameters.conv2.Weights;偏见= parameters.conv2.Bias;海底= dlconv(海底,重量、偏见,“填充”,“相同”,“步”2);%批处理规范化,ReLU抵消= parameters.batchnorm2.Offset;规模= parameters.batchnorm2.Scale;trainedMean = state.batchnorm2.TrainedMean;trainedVariance = state.batchnorm2.TrainedVariance;如果doTraining[Dy,trainedMean,trainedVariance]=批次标准(Dy,偏移量,比例,trainedMean,trainedVariance);%更新状态state.batchnorm2。TrainedMean = TrainedMean;state.batchnorm2。TrainedVariance = TrainedVariance;其他的海底= batchnorm(海底、抵消、规模、trainedMean trainedVariance);结束海底= relu(海底);%卷积重量= parameters.conv3.Weights;偏见= parameters.conv3.Bias;海底= dlconv(海底,重量、偏见,“填充”,“相同”);%批正常化抵消= parameters.batchnorm3.Offset;规模= parameters.batchnorm3.Scale;trainedMean = state.batchnorm3.TrainedMean;trainedVariance = state.batchnorm3.TrainedVariance;如果doTraining[Dy,trainedMean,trainedVariance]=批次标准(Dy,偏移量,比例,trainedMean,trainedVariance);%更新状态state.batchnorm3。TrainedMean = TrainedMean;state.batchnorm3。TrainedVariance = TrainedVariance;其他的海底= batchnorm(海底、抵消、规模、trainedMean trainedVariance);结束%, ReLUly = dlskip + ly;海底= relu(海底);%完全连接,softmax(标签)权重=parameters.fc1.weights;bias=parameters.fc1.bias;dlY1=fullyconnect(dlY,权重,bias);dlY1=softmax(dlY1);%完全连接(角度)重量= parameters.fc2.Weights;偏见= parameters.fc2.Bias;dlY2 = fullyconnect(海底,重量、偏见);结束
的modelGradients
函数,获取模型参数,即一小批输入数据dlX
与相应的目标T1
和T2
分别包含标签和角度,并返回损耗相对于可学习参数的梯度、更新后的网络状态和相应的损耗。
函数[gradients,state,loss]=modelGradients(参数dlX,T1,T2,state)doTraining=true;[dlY1,dlY2,state]=model(参数dlX,doTraining,state);lossLabels=crossentropy(dlY1,T1);lossAngles=mse(参数dlY2,T2);loss=lossLabels+0.1*lossAngles;gradients=dlgradient(损失,参数);结束
的preprocessMiniBatch
函数使用以下步骤对数据进行预处理:
从传入的单元格数组中提取图像数据并连接到一个数字数组中。将图像数据连接到第四个维度上,为每个图像添加了第三个维度,用作单通道维度。
从传入的单元数组中提取标签和角度数据,并分别沿第二维度连接到分类数组和数字数组中。
一次性将分类标签编码为数字数组。编码到第一个维度会生成一个与网络输出形状匹配的编码数组。
函数(X, Y,角)= preprocessMiniBatch(伊势亚、YCell angleCell)%从单元格提取图像数据并连接猫(X = 4,伊势亚{:});%从单元格中提取标签数据并连接Y =猫(2,YCell {:});%从单元格中提取角度数据并连接角=猫(2,angleCell {:});%一次性编码标签Y, Y = onehotencode (1);结束
batchnorm
|crossentropy
|dlarray
|dlconv
|德尔费瓦尔
|dlgradient
|完全连接
|小型批处理队列
|onehotdecode
|onehotencode
|雷卢
|sgdmupdate
|softmax