这个例子展示了如何建立一个自定义的训练循环来并行地训练一个网络。在本例中,并行工作人员对整个小批处理的部分进行培训。如果你有一个GPU,那么训练就会在GPU上进行。在培训期间,DataQueue
对象将训练进度信息发送回MATLAB客户端。
加载数字数据集并为数据集创建图像数据存储。以随机方式将数据存储拆分为训练和测试数据存储。
digitDatasetPath = fullfile (matlabroot,“工具箱”,“nnet”,“nndemos”,...“nndatasets”,“DigitDataset”);imd = imageDatastore (digitDatasetPath,...“IncludeSubfolders”,真的,...“LabelSource”,“foldernames”);[imdsTrain, imdsTest] = splitEachLabel (imd, 0.9,“随机”);
确定训练集中的不同类。
类=类别(imdsTrain.Labels);numClasses =元素个数(类);
定义您的网络架构,并通过使用layerGraph
函数。这种网络结构包括批处理归一化层,跟踪数据集的均值和方差统计量。并行训练时,在每个迭代步骤结束时,结合所有工作者的统计信息,以确保网络状态反映整个小批。否则,网络状态可能会在各个worker之间发散。例如,如果您正在训练有状态递归神经网络(rnn),使用被分割成更小序列的序列数据来训练包含LSTM或GRU层的网络,您还必须管理工作人员之间的状态。
层=[imageInputLayer([28 1],“名字”,“输入”,“归一化”,“没有”20岁的)convolution2dLayer (5“名字”,“conv1”) batchNormalizationLayer (“名字”,“bn1”) reluLayer (“名字”,“relu1”20岁的)convolution2dLayer (3“填充”,1,“名字”,“conv2”) batchNormalizationLayer (“名字”,“bn2”) reluLayer (“名字”,“relu2”20岁的)convolution2dLayer (3“填充”,1,“名字”,“conv3”) batchNormalizationLayer (“名字”,“bn3”) reluLayer (“名字”,“relu3”) fullyConnectedLayer (numClasses“名字”,“俱乐部”));lgraph = layerGraph(层);
创建一个dlnetwork
对象从层图。dlnetwork
对象允许使用自定义循环进行训练。
dlnet = dlnetwork (lgraph)
dlnet =带有属性的dlnetwork: Layers: [11×1 nnet.cnn.layer.Layer] Connections: [10×2 table] Learnables: [14×3 table] State: [6×3 table] InputNames: {'input'} OutputNames: {'fc'} Initialized: 1
确定MATLAB是否可以使用图形处理器canUseGPU
函数。
如果有可用的图形处理器,那么在图形处理器上进行训练。创建一个和gpu一样多的并行池。
如果没有可用的gpu,那么在cpu上进行培训。创建一个具有默认工作人员数量的并行池。
如果canUseGPU executionEnvironment =“图形”;numberOfGPUs = gpuDeviceCount (“可用”);池= parpool (numberOfGPUs);其他的executionEnvironment =“cpu”;池= parpool;结束
获取并行池中工作人员的数量。在本例的后面,您将根据这个数字划分工作负载。
N = pool.NumWorkers;
指定培训选项。
numEpochs = 20;miniBatchSize = 128;速度= [];
对于GPU训练,推荐的做法是随GPU的数量线性增加小批量的大小,以保持每个GPU上的工作量不变。有关更多相关建议,请参见使用多个gpu进行培训.
如果执行环境==“图形”miniBatchSize = miniBatchSize .* N结束
miniBatchSize = 512
计算每个工人的小批量大小,方法是将整个小批量大小在工人之间平均分割。把剩下的分配给第一个工人。
workerMiniBatchSize = floor(miniBatchSize ./ repmat(N,1,N));余数= workerMiniBatchSize - sum(workerMiniBatchSize);workerMiniBatchSize = workerMiniBatchSize + [ones(1,remainder) 0 (1,N-remainder)]
workerMiniBatchSize =1×4128 128 128 128
初始化培训进度图。
建立训练区figure lineosstrain = animatedline(“颜色”[0.85 0.325 0.098]);ylim([0正])包含(“迭代”) ylabel (“损失”网格)在
为了在培训期间从工人那里发回数据,创建一个DataQueue
对象。使用afterEach
为了建立一个函数,displayTrainingProgress
,在每次工作人员发送数据时调用。displayTrainingProgress
是一个支持金宝app函数,在本示例的最后定义,它显示来自工人的培训进度信息。
Q = parallel.pool.DataQueue;displayFcn = @(x) displayTrainingProgress(x,lineLossTrain);afterEach (Q, displayFcn);
使用自定义并行训练循环训练模型,具体步骤如下。要在所有的工作人员上同时执行代码,使用spmd
块。在spmd
块,labindex
给出当前执行代码的工作程序的索引。
在培训之前,使用分区
功能,并设置ReadSize
到工人的小批量大小。
对于每个epoch,使用重置
和洗牌
功能。对于epoch中的每个迭代:
在开始并行处理之前,请确保所有工作人员都有可用的数据和
操作(共和党
)的结果hasdata
函数。
方法从数据存储中读取一个迷你批处理读
函数,并将检索到的图像连接成一个四维图像数组。对图像进行归一化,使像素取之间的值0
和1
.
将标签转换为虚拟变量矩阵,该矩阵将标签与观测值相对。虚拟变量包含1
观察的标签和0
否则。
将小批量数据转换为dlarray
对象,并指定维度标签“SSCB”
(spatial, spatial, channel, batch)。对于GPU训练,将数据转换为gpuArray
.
通过调用,计算每个worker上的梯度和网络损失dlfeval
在模型梯度
函数。的dlfeval
函数计算helper函数模型梯度
有了自动区分,所以模型梯度
可以自动计算与损失相关的梯度。模型梯度
在示例的最后定义,并在给定网络、小批量数据和真实标签的情况下返回损失和梯度。
要得到整体损失,就要把所有工人的损失加起来。这个例子使用交叉熵作为损失函数,而累计损失是所有损失的总和。在聚合之前,将每个损失乘上工作者正在处理的整个小批的比例进行归一化。使用gplus
将所有损失加在一起,并在员工中复制结果。
要聚合和更新所有工作人员的梯度,请使用dlupdate
与aggregateGradients
函数。aggregateGradients
是在本示例金宝app最后定义的支持函数。这个函数使用gplus
根据每个worker正在处理的整体小批量的比例进行归一化,在worker之间添加和复制梯度。
聚合使用的所有工作者的网络状态aggregateState
函数。aggregateState
是在本示例金宝app最后定义的支持函数。网络中的批处理归一化层跟踪数据的均值和方差。由于完整的mini-batch分散在多个worker中,所以在每次迭代后聚合网络状态来计算整个mini-batch的均值和方差。
计算最终梯度后,使用sgdmupdate
函数。
将培训进度信息发送给客户发送
与DataQueue
.只使用一个工作人员发送数据,因为所有工作人员都有相同的丢失信息。为了确保数据在CPU上,以便没有GPU的客户端机器可以访问它,使用收集
在dlarray
在发送之前。
开始=抽搐;spmd%分区数据存储。workerImds =分区(imdsTrain N labindex);workerImds。ReadSize=workerMiniBatchSize(labindex); workerVelocity = velocity; iteration = 0;为时代= 1:numEpochs%重置并洗牌数据存储。重置(workerImds);workerImds = shuffle (workerImds);%循环小批。而@and,hasdata(workerImds)) iteration = iteration + 1;%读取一小批数据。[workerXBatch, workerTBatch] =阅读(workerImds);workerXBatch =猫(4,workerXBatch {:});workerNumObservations =元素个数(workerTBatch.Label);将图像归一化。workerXBatch = single(workerXBatch) ./ 255;%将标签转换为虚拟变量。workerY = 0 (numClasses workerNumObservations,“单一”);为c=1:numClasses workerY(c,workerBatch.Label==classes(c))=1;结束%将小批数据转换为dlarray。dlworkerX = dlarray (workerXBatch,“SSCB”);%如果在GPU上训练,则将数据转换为gpuArray。如果执行环境==“图形”dlworkerX = gpuArray (dlworkerX);结束评估模型的梯度和工人的损失。[workerGradients, dlworkerLoss workerState] = dlfeval (@modelGradients、dlnet dlworkerX, workerY);合计所有工人的损失。workerNormalizationFactor=workerMiniBatchSize(labindex)。/miniBatchSize;loss=gplus(workerNormalizationFactor*extractdata(dlworkerLoss));%聚合所有worker的网络状态dlnet。状态= aggregateState (workerState workerNormalizationFactor);汇总所有工人的梯度。workerGradients。值= dlupdate (@aggregateGradients workerGradients.Value, {workerNormalizationFactor});%使用SGDM优化器更新网络参数。[dlnet.Learnables,workerVelocity]=sgdmupdate(dlnet.Learnables,workerGradients,workerVelocity);结束%显示培训进度信息。如果Labindex == 1 data = [epoch loss iteration toc(start)];发送(Q,收集(数据));结束结束结束
训练网络后,可以测试其准确性。
使用readall
在测试数据存储中,连接它们并将它们规范化。
XTest = readall (imdsTest);XTest =猫(4 XTest {:});XTest = single(XTest) ./ 255;欧美= imdsTest.Labels;
培训完成后,所有员工都拥有相同的完整的培训网络。找回他们中的任何一个。
dlnetFinal = dlnet {1};
对图像进行分类dlnetwork
对象,使用预测
函数在一个dlarray
.
dlYPredScores =预测(dlnetFinal dlarray (XTest“SSCB”));
从预测的分数中,找出得分最高的班级马克斯
函数。在此之前,从dlarray
与extractdata
函数。
[~, idx] = max (extractdata (dlYPredScores), [], 1);YPred =类(idx);
为了获得模型的分类精度,将测试集上的预测与真实标签进行比较。
精度=意味着(YPred = =次)
精度= 0.9910
定义一个函数,模型梯度
,以计算损失相对于网络的可学习参数的梯度。这个函数为一个小批量计算网络输出X
与向前
和softmax
并计算损失,给出真实的输出,使用交叉熵。当你用dlfeval
,启用自动区分,并且dlgradient
可自动计算与可学习值相关的损失梯度。
函数[dlgradients,dlloss,state] = modelGradients(dlnet,dlX,dlY) [dlpred,state] = forward(dlnet,dlX);dlYPred = softmax (dlYPred);dlloss = crossentropy (dlYPred、海底);dlgradients = dlgradient (dlloss dlnet.Learnables);结束
定义一个函数来显示来自工人的培训进度信息。的DataQueue
在这个例子中,每当一个worker发送数据时调用这个函数。
函数displayTrainingProgress (data,line) addpoints(line,double(data(3)),double(data(2)))) D = duration(0,0,data(4)),“格式”,“hh: mm: ss”); 头衔(”时代:“+数据(1)+”,过去:“+ drawnow字符串(D))结束
定义一个函数,将所有工作人员的渐变叠加在一起。gplus
将所有渐变加在一起,并在工人身上复制。在将它们相加之前,将它们标准化,方法是将它们乘以一个表示工作者正在处理的整个小批处理的比例的因子。检索。的内容dlarray
,u
seextractdata
.
函数gradient = aggregateGradients(dlgradients,factor)梯度= gplus(因子*渐变)公关;结束
定义一个函数,用于聚合所有工作进程上的网络状态。网络状态包含经过训练的数据集批量规范化统计信息。由于每个工作者只看到小批量的一部分,因此聚合网络状态,以便统计数据代表所有数据的统计数据。对于每个小批量,组合平均值计算为每个迭代的工人平均值的加权平均值。根据以下公式计算组合方差:
在哪里 为工人总数, 为小批处理中观察的总数, 是多少个观测值处理的 th工人, 和 均值和方差统计数据是计算在那个工人身上的吗 是所有工人的总和平均值。
函数state = aggregateState(state,factor) numrows = size(state,1);为isBatchNormalizationState = state.Parameter(j) ==“受训男子”...& & state.Parameter (j + 1) = =“TrainedVariance”...&& state.Layer(j) == state.Layer(j+1);如果isBatchNormalizationState meanVal = state.Value{j};varVal = state.Value {j + 1};计算综合平均值combinedMean = gplus(因子* meanVal)公关;计算合并方差项的总和combinedVarTerm =因素。*(varVal + (meanVal - combinedMean).^2);%更新状态state.Value (j) = {combinedMean};state.Value (j + 1) = {gplus (combinedVarTerm)公关};结束结束结束
crossentropy
|dlarray
|dlfeval
|dlgradient
|dlnetwork
|dlupdate
|向前
|预测
|sgdmupdate
|softmax