使用模型函数更新批归一化统计信息
此示例显示如何更新定义为函数的网络中的网络状态。
批处理归一化操作将跨小批处理的每个输入通道归一化。为了加快卷积神经网络的训练并降低对网络初始化的敏感性,可以在卷积和非线性之间使用批量归一化操作,例如ReLU层。
在训练过程中,批归一化操作首先通过减去小批平均值并除以小批标准差来归一化每个通道的激活。然后,该操作将输入移位一个可学习偏移量β然后用一个可学习的比例因子来衡量γ.
当使用训练过的网络对新数据进行预测时,批归一化操作使用训练过的数据集均值和方差,而不是小批均值和方差来归一化激活。
要计算数据集统计信息,必须使用不断更新的状态来跟踪小批统计信息。
如果在模型函数中使用批处理归一化操作,则必须为训练和预测定义行为。例如,您可以指定一个布尔选项doTraining
控制模型是使用小批量统计数据进行训练,还是使用数据集统计数据进行预测。
这段来自模型函数的示例代码展示了如何应用批处理规范化操作,并在训练期间仅更新数据集统计信息。
如果doTraining [Y,trainedMean,trainedVariance] = batchnorm(Y,offset,scale,trainedMean,trainedVariance);%更新状态state.batchnorm1。受过训练的人;state.batchnorm1。trained方差= trained方差;其他的Y = batchnorm(Y,offset,scale,trainedMean,trainedVariance);结束
负荷训练数据
的digitTrain4DArrayData
函数加载图像、它们的数字标签以及它们从垂直方向旋转的角度。创建一个arrayDatastore
对象获取图像、标签和角度,然后使用结合
函数创建一个包含所有训练数据的单个数据存储。提取类名和非离散响应的数量。
[XTrain,TTrain,anglesTrain] = digitTrain4DArrayData;dsXTrain = arrayDatastore(XTrain,IterationDimension=4);dsTTrain = arrayDatastore(TTrain);dsAnglesTrain = arrayDatastore(anglesTrain);dsTrain = combine(dsXTrain,dsTTrain,dsAnglesTrain);classNames =类别(TTrain);numClasses = numel(classNames);numResponses = size(anglesTrain,2);numObservations = numel(TTrain);
查看训练数据中的一些图像。
idx = randperm(numObservations,64);I = imtile(XTrain(:,:,:,idx));图imshow(我)
定义深度学习模型
定义以下预测标签和旋转角度的网络。
带有16个5 × 5滤波器的卷积-batchnorm- relu块。
两个卷积批模块的分支,每个块有32个3 × 3滤波器,中间有一个ReLU操作
一个带有32个1乘1卷积的卷积批量模块的跳过连接。
使用加法和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。Weights = initializeGlorot(sz,numOut,numIn);parameters.conv1。偏差= initializeZeros([numFilters 1]);
初始化第一批规格化层的参数和状态。
parameters.batchnorm1。Offset = initializeZeros([numFilters 1]);parameters.batchnorm1。Scale = initializeOnes([numFilters 1]);state.batchnorm1。TrainedMean = initializezero ([numFilters 1]);state.batchnorm1。TrainedVariance = initializeOnes([numFilters 1]);
初始化第二个卷积层的参数。
filterSize = [3 3];numChannels = 16;numFilters = 32;sz = [filterSize numChannels numFilters];numOut = prod(filterSize) * numFilters;numIn = prod(filterSize) * numFilters;parameters.conv2。Weights = initializeGlorot(sz,numOut,numIn);parameters.conv2。偏差= initializeZeros([numFilters 1]);
初始化第二个批处理规范化层的参数和状态。
parameters.batchnorm2。Offset = initializeZeros([numFilters 1]);parameters.batchnorm2。Scale = initializeOnes([numFilters 1]);state.batchnorm2。TrainedMean = initializezero ([numFilters 1]);state.batchnorm2。TrainedVariance = initializeOnes([numFilters 1]);
初始化第三个卷积层的参数。
filterSize = [3 3];numChannels = 32;numFilters = 32;sz = [filterSize numChannels numFilters];numOut = prod(filterSize) * numFilters;numIn = prod(filterSize) * numFilters;parameters.conv3。Weights = initializeGlorot(sz,numOut,numIn);parameters.conv3。偏差= initializeZeros([numFilters 1]);
初始化第三批规范化层的参数和状态。
parameters.batchnorm3。Offset = initializeZeros([numFilters 1]);parameters.batchnorm3。Scale = initializeOnes([numFilters 1]);state.batchnorm3。TrainedMean = initializezero ([numFilters 1]);state.batchnorm3。TrainedVariance = initializeOnes([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(sz,numOut,numIn);parameters.convSkip.Bias = initializeZeros([numFilters 1]);
在跳过连接中初始化批处理规范化层的参数和状态。
parameters.batchnormSkip.Offset = initializeZeros([numFilters 1]);parameters.batchnormSkip.Scale = initializeOnes([numFilters 1]);state.batchnormSkip.TrainedMean = initializeZeros([numFilters 1]);state.batchnormSkip.TrainedVariance = initializeOnes([numFilters 1]);
初始化分类输出对应的全连接层的参数。
sz = [numClasses 6272];numOut = numClasses;numIn = 6272;parameters.fc1。Weights = initializeGlorot(sz,numOut,numIn);parameters.fc1。偏差= initializeZeros([numClasses 1]);
初始化与回归输出相对应的全连接层的参数。
sz = [numResponses 6272];numOut = numResponses;numIn = 6272;parameters.fc2。Weights = initializeGlorot(sz,numOut,numIn);parameters.fc2。偏差= initializeZeros([numResponses 1]);
查看状态的结构。
状态
状态=带字段的结构:batchnorm1: [1×1 struct] batchnorm2: [1×1 struct] batchnorm3: [1×1 struct] batchnormSkip: [1×1 struct]
属性的状态参数batchnorm1
操作。
state.batchnorm1
ans =带字段的结构:TrainedMean: [16×1 dlarray] TrainedVariance: [16×1 dlarray]
定义模型函数
创建函数模型
,列在示例末尾,它计算前面描述的深度学习模型的输出。
这个函数模型
将模型参数作为输入参数
,输入数据,标志doTraining
,它指定模型是否返回用于训练或预测的输出,以及网络状态状态
.网络输出标签的预测、角度的预测和更新的网络状态。
定义模型损失函数
创建函数modelLoss
,在示例末尾列出,它将带有相应目标的一小批输入数据作为输入T1
而且T2
分别包含标签和角度,并返回损失、损失相对于可学习参数的梯度以及更新的网络状态。
指定培训项目
指定培训选项。
numEpochs = 20;miniBatchSize = 128;
火车模型
使用自定义训练循环训练模型。使用minibatchqueue
处理和管理小批量的图像。对于每个小批量:
使用自定义小批量预处理功能
preprocessMiniBatch
(在本例末尾定义)来对类标签进行一次性编码。用尺寸标签格式化图像数据
“SSCB”
(空间,空间,通道,批次)。默认情况下,minibatchqueue
对象将数据转换为dlarray
具有基础类型的对象单
.不要为类标签或角度添加格式。如果有GPU,可以在GPU上进行训练。默认情况下,
minibatchqueue
对象将每个输出转换为gpuArray
如果GPU可用。使用GPU需要并行计算工具箱™和受支持的GPU设备。金宝app有关受支持设备的信息,请参见金宝appGPU支金宝app持版本(并行计算工具箱).
mbq = minibatchqueue(dsTrain,...MiniBatchSize = MiniBatchSize,...MiniBatchFcn = @preprocessMiniBatch,...MiniBatchFormat = [“SSCB”""""]);
对于每个纪元,洗牌数据并在小批量数据上循环。在每个纪元结束时,显示训练进度。对于每个小批量:
评估模型损失和梯度使用
dlfeval
和modelLoss
函数。方法更新网络参数
adamupdate
函数。
初始化亚当解算器的参数。
trailingAvg = [];trailingAvgSq = [];
初始化培训进度图。
图C = colororder;lineLossTrain = animatedline(Color=C(2,:));Ylim ([0 inf]) xlabel(“迭代”) ylabel (“损失”网格)在
训练模型。
迭代= 0;开始= tic;%遍历epoch。为epoch = 1:numEpochs% Shuffle数据。洗牌(兆贝可)在小批上循环而Hasdata (mbq)迭代=迭代+ 1;[X,T1,T2] = next(mbq);计算模型损失、梯度和状态,使用dlfeval和% modelLoss函数。[loss,gradients,state] = dlfeval(@modelLoss,parameters,X,T1,T2,state);使用Adam优化器更新网络参数。。[parameters,trailingAvg,trailingAvgSq] = adamupdate(参数,梯度,...trailingAvg trailingAvgSq,迭代);%显示培训进度。D = duration(0,0,toc(start),Format=“hh: mm: ss”);损失=双倍(损失);addpoints (lineLossTrain、迭代、失去)标题(”时代:“+ epoch +,消失:"+字符串(D))现在绘制结束结束
测试模型
通过将测试集上的预测结果与真实标签和角度进行比较,测试模型的分类精度。方法管理测试数据集minibatchqueue
对象使用与训练数据相同的设置。
[XTest,T1Test,anglesTest] = digitTest4DArrayData;dsXTest = arrayDatastore(XTest,IterationDimension=4);dsTTest = arrayDatastore(T1Test);dsAnglesTest = arrayDatastore(anglesTest);dsTest = combine(dsXTest,dsTTest,dsAnglesTest);mbqTest = minibatchqueue(dsTest...MiniBatchSize = MiniBatchSize,...MiniBatchFcn = @preprocessMiniBatch,...MiniBatchFormat = [“SSCB”""""]);
若要预测验证数据的标签和角度,请使用modelPredictions
函数,在示例末尾列出。该函数返回预测的类别和角度,以及与真实值的比较。
[classesforecasts, anglesforecasts,classCorr,angleDiff] = modelforecasts (parameters,state,mbqTest,classNames);
评估分类准确率。
精确度=平均值(classCorr)
准确度= 0.9824
评估回归精度。
angleRMSE =√(mean(angleDiff.^2))
angleRMSE =单7.9194
查看一些带有预测的图片。红色显示预测角度,绿色显示正确角度。
idx = randperm(size(XTest,4),9);数字为i = 1:9 subplot(3,3,i) i = XTest(:,:,:,idx(i));imshow (I)在sz = size(I,1);Offset = sz/2;thetaPred =角预测(idx(i));plot(offset*[1-tand(thetaPred) 1+tand(thetaPred)],[sz 0],“r——”) thetaValidation = anglesTest(idx(i));plot(offset*[1-tand(thetaValidation) 1+tand(thetaValidation)],[sz 0],,“g——”)举行从label = string(classesforecasts (idx(i)));标题(”的标签:“+标签)结束
模型函数
这个函数模型
将模型参数作为输入参数
,输入数据X
,旗帜doTraining
,它指定模型是否返回用于训练或预测的输出,以及网络状态状态
.该函数返回标签的预测、角度的预测以及更新后的网络状态。
函数[Y1,Y2,state] = model(parameters,X,doTraining,state)%卷积weights = parameters.conv1.Weights;bias = parameters.conv1.Bias;Y = dlconv(X,权重,偏差,Padding=2);批处理归一化,ReLUoffset = parameters.batchnorm1.Offset;scale = parameters.batchnorm1.Scale;trainedMean = state.batchnorm1.TrainedMean;trainedVariance = state.batchnorm1.TrainedVariance;如果doTraining [Y,trainedMean,trainedVariance] = batchnorm(Y,offset,scale,trainedMean,trainedVariance);%更新状态state.batchnorm1。受过训练的人;state.batchnorm1。trained方差= trained方差;其他的Y = batchnorm(Y,offset,scale,trainedMean,trainedVariance);结束Y = relu(Y);%卷积,批量归一化(跳过连接)weights = parameters.convSkip.Weights;bias = parameters.convSkip.Bias;YSkip = dlconv(Y,权重,偏差,Stride=2);offset = parameters.batchnormSkip.Offset;scale = parameters.batchnormSkip.Scale;trainedMean = state.batchnormSkip.TrainedMean;trainedVariance = state.batchnormSkip.TrainedVariance;如果doTraining [YSkip,trainedMean,trainedVariance] = batchnorm(YSkip,offset,scale,trainedMean,trainedVariance);%更新状态state.batchnormSkip.TrainedMean = trainedMean;state.batchnormSkip.TrainedVariance = trainedVariance;其他的YSkip = batchnorm(YSkip,offset,scale,trainedMean,trainedVariance);结束%卷积weights = parameters.conv2.Weights;bias = parameters.conv2.Bias;Y = dlconv(Y,weights,bias,Padding=1,Stride=2);批处理归一化,ReLUoffset = parameters.batchnorm2.Offset;scale = parameters.batchnorm2.Scale;trainedMean = state.batchnorm2.TrainedMean;trainedVariance = state.batchnorm2.TrainedVariance;如果doTraining [Y,trainedMean,trainedVariance] = batchnorm(Y,offset,scale,trainedMean,trainedVariance);%更新状态state.batchnorm2。受过训练的人;state.batchnorm2。trained方差= trained方差;其他的Y = batchnorm(Y,offset,scale,trainedMean,trainedVariance);结束Y = relu(Y);%卷积weights = parameters.conv3.Weights;bias = parameters.conv3.Bias;Y = dlconv(Y,权重,偏差,Padding=1);批归一化offset = parameters.batchnorm3.Offset;scale = parameters.batchnorm3.Scale;trainedMean = state.batchnorm3.TrainedMean;trainedVariance = state.batchnorm3.TrainedVariance;如果doTraining [Y,trainedMean,trainedVariance] = batchnorm(Y,offset,scale,trainedMean,trainedVariance);%更新状态state.batchnorm3。受过训练的人;state.batchnorm3。trained方差= trained方差;其他的Y = batchnorm(Y,offset,scale,trainedMean,trainedVariance);结束%加法,ReLUY = YSkip + Y;Y = relu(Y);%完全连接,softmax(标签)weights = parameters.fc1.Weights;bias = parameters.fc1.Bias;Y1 =完全连接(Y,权重,偏差);Y1 = softmax(Y1);%完全连接(角度)weights = parameters.fc2.Weights;bias = parameters.fc2.Bias;Y2 =完全连接(Y,权重,偏差);结束
模型损失函数
的modelLoss
函数将模型参数作为输入,是输入数据的一个小批量X
有相应的目标T1
而且T2
分别包含标签和角度,并返回损失、损失相对于可学习参数的梯度以及更新的网络状态。
函数[loss,gradients,state] = modelLoss(parameters,X,T1,T2,state) doTraining = true;[Y1,Y2,state] = model(parameters,X,doTraining,state);lossLabels = crossentropy(Y1,T1);lossAngles = mse(Y2,T2);loss = lossLabels + 0.1*lossAngles;Gradients = dlgradient(损失,参数);结束
模型预测函数
的modelPredictions
函数取模型参数,网络状态,aminibatchqueue
输入数据的兆贝可
类中的所有数据进行迭代,从而返回模型预测minibatchqueue
使用模型
函数与doTraining
选项设置为假
.该函数返回预测的类别和角度,以及与真实值的比较。对于类,比较是一个1和0的向量,表示正确和不正确的预测。对于角度,比较是预测角度与真实值之间的差值。
函数[classesforecasts, anglesforecasts,classCorr,angleDiff] = modelforecasts (parameters,state,mbq,classes) doTraining = false;classesforecasts = [];anglesforecasts = [];classCorr = [];angleDiff = [];而hasdata(mbq) [X,T1,T2] = next(mbq);使用模型函数进行预测。[Y1,Y2] = model(parameters,X,doTraining,state);确定预测的类。Y1PredBatch = onehotdecode(Y1,classes,1);classesforecasts = [classesforecasts Y1PredBatch];% Dermine预测角度Y2PredBatch = extractdata(Y2);anglesforecasts = [anglesforecasts Y2PredBatch];比较预测的和真实的类。Y1 = onehotdecode(T1,classes,1);classCorr = [classCorr Y1PredBatch == Y1];比较预测角度和真实角度。angleDiffBatch = Y2PredBatch - T2;angleDiff = [angleDiff extractdata(gather(angleDiffBatch))];结束结束
小批量预处理功能
的preprocessMiniBatch
函数按照以下步骤对数据进行预处理:
从传入单元格数组中提取图像数据并连接到数值数组中。将图像数据连接到第四个维度将为每个图像添加第三个维度,用作单通道维度。
从传入单元格数组中提取标签和角度数据,并分别连接到分类数组和数值数组中。
One-hot将分类标签编码为数字数组。编码到第一个维度会产生一个与网络输出形状匹配的编码数组。
函数[X,T,angle] = preprocessMiniBatch(dataX,dataT,dataAngle)从单元格和拼接中提取图像数据X = cat(4,dataX{:});从单元格和级联中提取标签数据T = cat(2,dataT{:});从单元格和拼接中提取角度数据angle = cat(2,dataAngle{:});单热编码标签T = onehotencode(T,1);结束
另请参阅
dlarray
|sgdmupdate
|dlfeval
|dlgradient
|fullyconnect
|dlconv
|softmax
|线性整流函数(Rectified Linear Unit)
|batchnorm
|crossentropy
|minibatchqueue
|onehotencode
|onehotdecode