主要内容

图像分类网络的参数修剪和量化

这个例子显示了如何删除的参数训练神经网络使用两个参数得分指标:分数级[1][2]和突触流分数。

在许多应用程序转移学习用于图像分类网络接受一个新任务或从头开始一个新的网络训练,最优网络结构不清楚,网络可能overparameterized。一个overparameterized网络冗余的连接。结构化的修剪,也称为sparsification,压缩技术,旨在识别冗余,您可以删除不必要的连接而不影响网络的准确性。当你使用修剪结合网络量化,可以减少网络的推理时间和内存占用更容易部署。

这个例子展示了如何:

  • 执行的岗位培训、迭代、非结构化修剪不需要训练数据

  • 两个不同的修剪算法的性能进行评估

  • 调查layer-wise稀疏修剪后诱导

  • 评估修剪对分类精度的影响

  • 评价量化的影响分类精度的修剪网络

这个例子使用一个简单的卷积神经网络分类手写数字从0到9。有关设置的更多信息的数据用于训练和验证,看看创建简单的深度学习神经网络分类

负载Pretrained网络和数据

负荷训练和验证数据。火车的卷积神经网络分类的任务。

[imdsTrain, imdsValidation] = loadDigitDataset;网= trainDigitDataNetwork (imdsTrain imdsValidation);trueLabels = imdsValidation.Labels;类=类别(trueLabels);

创建一个minibatchqueue对象包含验证数据。集executionEnvironment汽车评估网络在GPU上,如果一个是可用的。默认情况下,minibatchqueue将每个输出转换为对象gpuArray如果一个GPU是可用的。使用GPU需要并行计算工具箱™和支持GPU设备。万博1manbetx支持设备的信息,请参阅万博1manbetxGPU计算的需求(并行计算工具箱)

executionEnvironment =“汽车”;miniBatchSize = 128;imdsValidation。ReadSize = miniBatchSize;mbqValidation = minibatchqueue (imdsValidation 1“MiniBatchSize”miniBatchSize,“MiniBatchFormat”,“SSCB”,“MiniBatchFcn”@preprocessMiniBatch,“OutputEnvironment”,executionEnvironment);

神经网络剪枝

神经网络剪枝的目标是识别和删除不重要的连接来减少网络的大小,而不影响网络的准确性。在下图中,左边,网络连接,每个神经元映射到下一层的神经元。修剪后,网络连接少于最初的网络。

pruneImage.bmp

修剪算法分配网络中的每个参数的分数。分数排名的重要性每个连接的网络。您可以使用两种实现目标稀疏修剪的方法:

  • 只有一次的修剪,删除一个指定的百分比的连接在一个步骤根据他们的分数。这种方法容易层崩溃时指定一个稀疏价值高。

  • 迭代修剪——实现目标稀疏的一系列迭代步骤。您可以使用这个方法当网络结构评估分数敏感。分数是评估在每一个迭代,所以使用一系列步骤允许网络逐步走向稀疏。

下面的例子使用了迭代剪枝方法实现目标稀疏。

迭代修剪

pruningWF.png

转换为dlnetwork对象

在本例中,您使用突触流算法,要求您创建一个定制的成本函数和评价梯度对代价函数来计算参数的分数。要创建一个定制的成本函数,首先pretrained网络转换为一个dlnetwork

转换层的网络图和删除层用于分类使用removeLayers

lgraph = layerGraph (net.Layers);lgraph = removeLayers (lgraph, (“softmax”,“classoutput”]);dlnet = dlnetwork (lgraph);

使用analyzeNetwork分析网络体系结构和可学的参数。

analyzeNetwork (dlnet)

评估网络修剪前的准确性。

accuracyOriginalNet = evaluateAccuracy (dlnet mbqValidation、类trueLabels)
accuracyOriginalNet = 0.9908

可学的参数的层3卷积层和一层完全连接。网络最初由21578可学的参数。

numTotalParams =总和(cellfun (@numel dlnet.Learnables.Value))
numTotalParams = 21578
numNonZeroPerParam = cellfun (@ (w) nnz (extractdata (w)), dlnet.Learnables.Value)
numNonZeroPerParam =8×172 15680 1152 4608 32 10

稀疏网络中被定义为参数的百分比值为零。检查网络的稀疏。

initialSparsity = 1 - (sum (numNonZeroPerParam) / numTotalParams)
initialSparsity = 0

修剪之前,网络有稀疏的零。

创建迭代计划

定义一个迭代修剪方案,指定目标稀疏和迭代次数。对于这个示例,使用间隔线性迭代实现目标稀疏。

numIterations = 10;targetSparsity = 0.90;iterationScheme = linspace (0 targetSparsity numIterations);

修剪循环

对于每一次迭代,定制修剪循环在本例中执行以下步骤:

  • 计算分数为每个连接。

  • 等级分数为所有连接网络中基于选择的修剪算法。

  • 确定删除连接的门槛最低的分数。

  • 使用阈值创建修剪面具。

  • 应用网络的修剪面具可学的参数。

网络掩码

相反的设置项权重数组直接为零,修剪算法为每个可学的创建二进制掩模参数,指明是否修剪一个连接。面具让你探索的行为修剪修剪网络和尝试不同的方案不改变底层网络结构。

例如,考虑下面的重量。

testWeight = (10.4 5.6 0.8 9);

创建一个二进制面具testWeight每个参数。

testMask = [1 0 1 0];

应用的面具testWeight修剪重量。

testWeightsPruned = testWeight。* testMask
testWeightsPruned =1×40.8000 10.4000 0 0

在迭代修剪中,您创建一个二进制掩模为每个迭代包含修剪信息。应用权重数组的面具不会改变数组的大小或神经网络的结构。因此,修剪步骤并不直接导致任何加速在推理或压缩网络大小的磁盘上。

初始化一个阴谋而修剪网络原始网络的准确性。

图绘制(100 * iterationScheme([1]结束),100 * accuracyOriginalNet * [1],“* - b”,“线宽”2,“颜色”,“b”100年)ylim ([0]) xlim (100 * iterationScheme([1,结束]))包含(“稀疏(%)”)ylabel (“精度(%)”)传说(“原来的准确性”,“位置”,“西南”)标题(“修剪准确性”网格)

级修剪

级修剪[1]分配一个分数每个参数等于它的绝对值。假设一个参数对应的绝对值的相对重要性的准确性训练网络。

初始化的面具。对于第一个迭代,您不要删除任何参数和稀疏是0%。

pruningMaskMagnitude =细胞(1、numIterations);pruningMaskMagnitude {1} = dlupdate (@ (p)真正的(大小(p)), dlnet.Learnables);

下面是修剪级的实现。各种目标稀疏的网络修剪一个循环提供灵活地选择一个修剪网络基于其准确性。

lineAccuracyPruningMagnitude = animatedline (“颜色”,‘g’,“标记”,“o”,“线宽”,1.5);传奇(“原来的准确性”,“修剪精度级”,“位置”,“西南”)%计算级分数scoresMagnitude = calculateMagnitudeScore (dlnet);idx = 1:元素个数(iterationScheme) prunedNetMagnitude = dlnet;%更新修剪面具pruningMaskMagnitude {idx} = calculateMask (scoresMagnitude iterationScheme (idx));%检查零修剪面具中的条目的数量numPrunedParams =总和(cellfun (@ (m) nnz (~ extractdata (m)), pruningMaskMagnitude {idx} value));稀疏= numPrunedParams / numTotalParams;%修剪面膜适用于网络参数prunedNetMagnitude。可学的= dlupdate (@ (W M) W。* M, prunedNetMagnitude。可学的,pruningMaskMagnitude {idx});%计算验证删除网络上的准确性accuracyMagnitude = evaluateAccuracy (prunedNetMagnitude, mbqValidation、类trueLabels);%显示修剪的进步addpoints (lineAccuracyPruningMagnitude 100 *稀疏,100 * accuracyMagnitude) drawnow结束

SynFlow修剪

突触流保护(SynFlow)[2]分数用于修剪。您可以使用此方法来删除网络,使用线性激活ReLU等功能。

初始化的面具。第一次迭代,不修剪参数,稀疏是0%。

pruningMaskSynFlow =细胞(1、numIterations);pruningMaskSynFlow {1} = dlupdate (@ (p)真正的(大小(p)), dlnet.Learnables);

你使用的输入数据来计算分数是一个图像包含的。如果您正在使用GPU,将数据转换成gpuArray

dlX = dlarray ((net.Layers (1) .InputSize),SSC的);如果(executionEnvironment = =“汽车”& & canUseGPU) | | executionEnvironment = =“图形”dlX = gpuArray (dlX);结束

以下循环实现迭代突触流分数修剪[2],一个定制的成本函数评估SynFlow得分为每个参数用于网络修剪。

lineAccuracyPruningSynflow = animatedline (“颜色”,“r”,“标记”,“o”,“线宽”,1.5);传奇(“原来的准确性”,“修剪精度级”,“突触流精度”,“位置”,“西南”)prunedNetSynFlow = dlnet;%迭代增加稀疏idx = 1:元素个数(iterationScheme)%计算SynFlow分数scoresSynFlow = calculateSynFlowScore (prunedNetSynFlow dlX);%更新修剪面具pruningMaskSynFlow {idx} = calculateMask (scoresSynFlow iterationScheme (idx));%检查零修剪面具中的条目的数量numPrunedParams =总和(cellfun (@ (m) nnz (~ extractdata (m)), pruningMaskSynFlow {idx} value));稀疏= numPrunedParams / numTotalParams;%修剪面膜适用于网络参数prunedNetSynFlow。可学的= dlupdate (@ (W M) W。* M, prunedNetSynFlow。可学的,pruningMaskSynFlow {idx});%计算验证删除网络上的准确性accuracySynFlow = evaluateAccuracy (prunedNetSynFlow, mbqValidation、类trueLabels);%显示修剪的进步addpoints (lineAccuracyPruningSynflow 100 *稀疏,100 * accuracySynFlow) drawnow结束

调查修剪网络结构

选择删除多少网络精度之间做出权衡和稀疏。使用稀疏和准确性情节选择迭代所需的稀疏程度和可接受的精度。

pruningMethod =“SynFlow”;selectedIteration =8;prunedDLNet = createPrunedNet (dlnet selectedIteration、pruningMaskSynFlow pruningMaskMagnitude, pruningMethod);[sparsityPerLayer, prunedChannelsPerLayer numOutChannelsPerLayer layerNames] = pruningStatistics (prunedDLNet);

早些时候卷积层通常修剪更少,因为他们含有更多的相关信息的核心底层结构的图像(如边缘和角落)解释图像至关重要。

情节的每层稀疏选择修剪方法和迭代。

图栏(sparsityPerLayer * 100)标题(“每层稀疏”)包含(“层”)ylabel (“稀疏(%)”)xticks(1:元素个数(sparsityPerLayer) xticklabels (layerNames) xtickangle(45)组(gca,“TickLabelInterpreter”,“没有”)

修剪算法梅干单一连接时指定一个低目标稀疏。当你指定一个高目标稀疏,修剪算法在卷积或完全可以删除整个过滤器和神经元连接层。

图酒吧([prunedChannelsPerLayer, numOutChannelsPerLayer-prunedChannelsPerLayer],“堆叠”)包含(“层”)ylabel (“过滤器”)标题(“每层数量的过滤器”)xticks(1:(元素个数(layerNames))) xticklabels (layerNames) xtickangle(45)传说(“削减”频道/神经元的数量,“原来数量的渠道/神经元”,“位置”,“southoutside”甘氨胆酸)组(,“TickLabelInterpreter”,“没有”)

评估网络的准确性

比较网络剪枝前后的准确性。

YPredOriginal = modelPredictions (dlnet、mbqValidation、类);accOriginal =意味着(YPredOriginal = = trueLabels)
accOriginal = 0.9908
YPredPruned = modelPredictions (prunedDLNet、mbqValidation、类);accPruned =意味着(YPredPruned = = trueLabels)
accPruned = 0.9328

创建一个混合矩阵图来探索真正的类标签预测类标签的原始和修剪网络。

图confusionchart (trueLabels YPredOriginal);标题(“原始网络”)

验证的数字数据包含250张图片为每个类,如果网络预测每个形象完美的类,对角线上的所有分数等于250,没有值之外的对角线。

confusionchart (trueLabels YPredPruned);标题(“删除网络”)

修剪网络时,比较困惑图表的原始网络和修剪网络检查每个类标签的准确性如何改变所选稀疏的水平。如果所有数字对角线上减少大致相等,没有偏见。但是,如果减少是不平等的,您可能需要选择一个修剪网络从早期迭代通过减少变量的值selectedIteration

数字转换修剪网络

深在MATLAB神经网络训练使用单精度浮点数据类型。即使网络小需要大量的内存和硬件执行浮点算术运算。这些限制可以抑制深度学习的部署模型,计算能力低和更少的内存资源。通过使用低精度存储重量和激活,你可以减少网络的内存需求。您可以使用深度学习工具箱与深度学习模型量化库支持包减少内存占用的深层神经网络通过量化权重,偏见,和卷积的激活层8位整数数据类型。万博1manbetx

修剪网络影响的范围统计参数和激活在每一层,所以量化网络的准确性可以改变。探索这种差异,使量子化修剪网络和使用量化网络进行推理。

把数据分割成校准和验证数据集。

calibrationDataStore = splitEachLabel (imdsTrain, 0.1,“随机”);validationDataStore = imdsValidation;

创建一个dlquantizer对象和指定修剪网络作为网络数字转换。

prunedNet = assembleNetwork ([prunedDLNet。层;net.Layers (end-1:结束)]);quantObjPrunedNetwork = dlquantizer (prunedNet,“ExecutionEnvironment”,“图形”);

使用校准功能锻炼与标定数据和网络收集范围统计权重,偏见,和激活在每一层。

calResults =校准(quantObjPrunedNetwork calibrationDataStore)

使用验证函数比较网络之前和之后的结果量化使用验证数据集。

valResults =验证(quantObjPrunedNetwork validationDataStore);

检查MetricResults.Result字段的验证输出量化网络的准确性

valResults.MetricResults。结果valResults.Statistics

小批预处理功能

preprocessMiniBatch函数进行预处理mini-batch预测因子的提取图像数据从输入单元阵列和连接到一个数字数组。对灰度输入,连接在第四维度的数据添加一个三维图像使用作为一个单通道尺寸。

函数X = preprocessMiniBatch(伊势亚)%从细胞中提取图像数据和连接。猫(X = 4,伊势亚{:});结束

模型精度函数

评估的分类精度dlnetwork。准确的比例是由网络标签正确分类。

函数精度= evaluateAccuracy (dlnet mbqValidation、类trueLabels) YPred = modelPredictions (dlnet、mbqValidation、类);精度=意味着(YPred = = trueLabels);结束

SynFlow得分函数

calculateSynFlowScore函数计算突触流(SynFlow)分数。突触显著[2]被描述为定义的基于类的梯度分数梯度的产品损失乘以参数值:

synFlowScore = d ( 损失 ) d θ * θ

SynFlow分数是一个突触卓越成绩,使用网络输出的总和作为损失函数:

损失 = f ( 腹肌 ( θ ) , X )

f 神经网络所代表的功能吗

θ 网络的参数吗

X 输入数组到网络吗

计算参数梯度对这个损失函数,使用dlfeval和一个梯度函数模型。

函数dlnet得分= calculateSynFlowScore (dlnet dlX)。可学的= dlupdate (@abs dlnet.Learnables);梯度= dlfeval (@modelGradients dlnet dlX);分数= dlupdate (@ g (g, w)。*w, gradients, dlnet.Learnables);结束

模型梯度SynFlow得分

函数梯度= modelGradients (dlNet inputArray)%计算梯度在给定dlnetwork的输入dlYPred =预测(dlNet inputArray);pseudoloss =总和(dlYPred,“所有”);梯度= dlgradient (pseudoloss dlNet.Learnables);结束

级得分函数

calculateMagnitudeScore函数返回分数大小,定义为element-wise参数的绝对值。

函数分数= calculateMagnitudeScore (dlnet)得分= dlupdate (@abs dlnet.Learnables);结束

掩码生成函数

calculateMask函数返回一个二进制掩模的网络参数基于给定的分数和目标稀疏。

函数掩码= calculateMask (scoresMagnitude稀疏)%计算二进制掩码基于parameter-wise分数等,面具包含0的比例规定稀疏。%平单元阵列的分数都在得分向量flattenedScores = cell2mat (cellfun (@ (S) extractdata(收集(S (:))), scoresMagnitude.Value,“UniformOutput”、假));%的分数和排名确定的阈值删除连接%给稀疏flattenedScores = (flattenedScores)进行排序;k =圆(稀疏*元素个数(flattenedScores));如果k = = 0打= 0;其他的打= flattenedScores (k);结束%创建一个二进制的面具掩码= dlupdate (@ (S)年代>打,scoresMagnitude);结束

模型的预测函数

modelPredictions函数作为输入dlnetwork对象dlnet,minibatchqueue的输入数据兆贝可网络类,计算模型预测minibatchqueue遍历所有数据的对象。这个函数使用onehotdecode函数找到预测类最高的分数。

函数预测= modelPredictions (dlnet、兆贝可类)预测= [];hasdata(兆贝可)dlXTest =下一个(兆贝可);dlYPred = softmax(预测(dlnet dlXTest));YPred = onehotdecode (dlYPred、类1)';预测=[预测;YPred];结束重置(兆贝可)结束

应用剪枝函数

createPrunedNet函数的作用是:返回指定修剪修剪dlnetwork算法和迭代。

函数prunedNet = createPrunedNet (dlnet selectedIteration、pruningMaskSynFlow pruningMaskMagnitude, pruningMethod)开关pruningMethod情况下“级”prunedNet = dlupdate (@ (W M) W。*M, dlnet, pruningMaskMagnitude{selectedIteration});情况下“SynFlow”prunedNet = dlupdate (@ (W M) W。*M, dlnet, pruningMaskSynFlow{selectedIteration});结束结束

修剪统计函数

pruningStatistics函数提取详细的层,修剪等统计数据层稀疏和过滤器或神经元的数量被修剪。

sparsityPerLayer -在每个层的比例参数修剪

prunedChannelsPerLayer -渠道数量/在每一层神经元可以删除的修剪

numOutChannelsPerLayer -渠道数量/每一层的神经元

函数[sparsityPerLayer, prunedChannelsPerLayer numOutChannelsPerLayer layerNames] = pruningStatistics (dlnet) layerNames =独特(dlnet.Learnables.Layer,“稳定”);numLayers =元素个数(layerNames);layerIDs = 0 (numLayers, 1);idx = 1:元素个数(layerNames) layerIDs (idx) =找到(layerNames (idx) = = {dlnet.Layers.Name});结束sparsityPerLayer = 0 (numLayers, 1);prunedChannelsPerLayer = 0 (numLayers, 1);numOutChannelsPerLayer = 0 (numLayers, 1);numParams = 0 (numLayers, 1);numPrunedParams = 0 (numLayers, 1);idx = 1: numLayers层= dlnet.Layers (layerIDs (idx));%计算稀疏paramIDs = strcmp (dlnet.Learnables.Layer layerNames (idx));paramValue = dlnet.Learnables.Value (paramIDs);p = 1:元素个数(paramValue) numParams (idx) = numParams (idx) +元素个数(paramValue {p});numPrunedParams (idx) = numPrunedParams (idx) + nnz (extractdata (paramValue {p}) = = 0);结束%计算信道统计信息sparsityPerLayer (idx) = numPrunedParams (idx) / numParams (idx);开关类(层)情况下“nnet.cnn.layer.FullyConnectedLayer”numOutChannelsPerLayer (idx) = layer.OutputSize;prunedChannelsPerLayer (idx) = nnz(所有(layer.Weights = = 0, 2) &layer.Bias (:) = = 0);情况下“nnet.cnn.layer.Convolution2DLayer”numOutChannelsPerLayer (idx) = layer.NumFilters;prunedChannelsPerLayer (idx) = nnz(重塑(所有(layer.Weights = = 0, [1, 2, 3]), [], 1) &layer.Bias (:) = = 0);情况下“nnet.cnn.layer.GroupedConvolution2DLayer”numOutChannelsPerLayer (idx) = layer.NumGroups * layer.NumFiltersPerGroup;prunedChannelsPerLayer (idx) = nnz(重塑(所有(layer.Weights = = 0, [1, 2, 3]), [], 1) &layer.Bias (:) = = 0);否则错误(“未知层:“+类(层))结束结束结束

负载数字数据集函数

loadDigitDataset函数加载数据集的数字,将数据分为训练和验证数据。

函数[imdsTrain, imdsValidation] = loadDigitDataset () digitDatasetPath = fullfile (matlabroot,“工具箱”,“nnet”,“nndemos”,“nndatasets”,“DigitDataset”);imd = imageDatastore (digitDatasetPath,“IncludeSubfolders”,真的,“LabelSource”,“foldernames”);[imdsTrain, imdsValidation] = splitEachLabel (imd, 0.75,“随机”);结束

火车数字识别网络功能

trainDigitDataNetwork函数火车一个卷积神经网络对数字灰度图像进行分类。

函数网= trainDigitDataNetwork (imdsTrain imdsValidation)层= [imageInputLayer ([28 28 1],“归一化”,“rescale-zero-one”)convolution2dLayer (3 8“填充”,“相同”)reluLayer maxPooling2dLayer (2“步”2)convolution2dLayer(16日“填充”,“相同”)reluLayer maxPooling2dLayer (2“步”32岁的,2)convolution2dLayer (3“填充”,“相同”)reluLayer fullyConnectedLayer (10) softmaxLayer classificationLayer];%指定培训选项选择= trainingOptions (“个”,“InitialLearnRate”,0.01,“MaxEpochs”10“洗牌”,“every-epoch”,“ValidationData”imdsValidation,“ValidationFrequency”30岁的“详细”假的,“阴谋”,“没有”,“ExecutionEnvironment”,“汽车”);%的列车网络的网= trainNetwork (imdsTrain层,选项);结束

引用

[1]歌汉,杰夫池,和威廉·j·约翰·Tran玩弄》2015。“学习权重和高效的神经网络连接。”Advances in Neural Information Processing Systems 28 (NIPS 2015): 1135–1143.

[2]Hidenori田中Daniel Kunin Daniel l . k . yamin Ganguli苏利耶2020年。“修剪迭代神经网络不需要任何数据保护突触流。”第34会议神经信息处理系统(NeurlPS 2020)

另请参阅

功能

相关的话题