主要内容

生成INT8深度学习网络代码

深度学习使用的神经网络架构包含许多处理层,包括卷积层。深度学习模型通常适用于大型标记数据集。训练这些模型和执行推理需要大量的计算,消耗大量的内存。当输入在网络中传播时,神经网络使用内存存储输入数据、参数(权重)和来自每一层的激活。大多数预先训练的神经网络和使用深度学习工具箱™训练的神经网络使用单精度浮点数据类型。即使是规模很小的网络也需要大量的内存和硬件来执行这些浮点算术操作。这些限制可能会阻碍深度学习模型部署到计算能力较低、内存资源较少的设备上。通过使用较低的精度来存储权重和激活,可以减少网络的内存需求。

您可以将深度学习工具箱与深度学习工具箱模型量化库支持包结合使用,通过将卷积层的权重、偏差和激活量化为8位缩放整数数据类型,来减少深度神经网络的内存占用。万博1manbetx然后,您可以使用GPU Coder™生成CUDA®优化后的网络代码。生成的代码利用了NVIDIA®CUDA深度神经网络库(cuDNN)或TensorRT™高性能推理库。生成的代码可以作为源代码、静态或动态库,或可部署到各种NVIDIA GPU平台的可执行程序集成到您的项目中。

使用INT8推理优化的网络对图像进行分类

这个例子之前被命名为“使用量化网络在GPU上分类图像”,但在R2022a中重新命名,以避免与由数字转换(深度学习工具箱)函数。代码生成不支持量化的深度神经网络产生万博1manbetx数字转换函数。

在本例中,您使用GPU Coder为深度卷积神经网络生成优化的CUDA代码并对图像进行分类。生成的代码使用8位整数数据类型为卷积层执行推理计算。本例使用了预训练的squeezenet(深度学习工具箱)卷积神经网络。

SqueezeNet已经接受了超过100万张图像的训练,可以将图像分为1000个对象类别(如键盘、咖啡杯、铅笔和许多动物)。该网络已经学习了广泛的图像的丰富特征表示。该网络将图像作为输入,并输出图像中对象的标签以及每个对象类别的概率。

本示例包含以下步骤:

  • 修改SqueezeNet利用神经网络对包含五个对象类别的图像进行转移学习分类。

  • 使用校准(深度学习工具箱)函数使用样本输入进行网络测试,并收集范围信息以生成校准结果文件。

  • 方法为网络生成优化的代码codegen命令和校准结果文件。

第三方的先决条件

要求

  • CUDA支持NVIDIA®GPU和兼容的驱动程序。

可选

对于非mex构建,如静态、动态库或可执行程序,此示例具有以下附加要求。

使用SqueezeNet的转移学习

要对一组新的图像进行分类,您可以通过迁移学习对预先训练的SqueezeNet卷积神经网络进行微调。在迁移学习中,您可以使用预先训练的网络,并将其作为学习新任务的起点。用迁移学习对网络进行优化通常比用随机初始化的权重从头开始训练网络要快得多,也容易得多。您可以使用较少的训练图像快速地将学到的特征转移到新任务中。

负荷训练数据

解压缩并加载新映像作为映像数据存储。的imageDatastore函数根据文件夹名称自动标记图像,并将数据存储为ImageDatastore对象。图像数据存储使您能够存储大型图像数据,包括不适合内存的数据,并在卷积神经网络训练期间有效地读取批量图像。将数据划分为训练和验证数据集。使用70%的图像进行训练,30%用于验证。splitEachLabel分裂的洛桑国际管理发展学院数据存储到两个新的数据存储。

解压缩(“MerchData.zip”);imds = imageDatastore(“MerchData”...“IncludeSubfolders”,真的,...“LabelSource”“foldernames”);[imdsTrain,imdsValidation] = splitEachLabel(imds,0.7,“随机”);numTrainImages = numel(imdsTrain.Labels);idx = randperm(numTrainImages,4);Img = imtile(imds,“帧”, idx);图imshow(img) title(“来自训练数据集的随机图像”);

图中包含一个axes对象。标题为Random Images from Training Dataset的axes对象包含一个类型为image的对象。

负载预训练网络

加载预先训练的SqueezeNet网络。如果您没有安装所需的支持包,该软件提供下载链接。万博1manbetx

网=挤压网;

的对象包含了DAGNetwork对象。第一层是图像输入层,要求输入图像的大小为227 × 227 × 3,其中3是颜色通道的数量。您可以使用analyzeNetwork(深度学习工具箱)功能,以显示网络架构的交互式可视化,检测网络中的错误和问题,并显示有关网络层的详细信息。层信息包括层激活和可学习参数的大小,可学习参数的总数,循环层的状态参数的大小。

inputSize = net.Layers(1).InputSize;

更换最后的图层

网络提取图像的卷积层特征是最后的可学习层和最后的分类层用来对输入图像进行分类。这两层,“conv10”而且“ClassificationLayer_predictions”在SqueezeNet中,包含了如何将网络提取的特征组合成类概率、损失值和预测标签的信息。

为了重新训练预训练的网络来分类新图像,用适应新数据集的新层替换这两层。您可以手动或使用助手函数完成此操作findLayersToReplace自动找到这些层。

lgraph = layerGraph(net);[learnableLayer,classLayer] = findLayersToReplace(lgraph);numClasses = numel(categories(imdsTrain.Labels));newConvLayer = convolution2dLayer([1,1],numClasses,“WeightLearnRateFactor”...10日,“BiasLearnRateFactor”10“名称”“new_conv”);lgraph = replaceLayer(lgraph,“conv10”, newConvLayer);newclassificationlayer = classificationLayer(“名字”“new_classoutput”);lgraph = replaceLayer(lgraph,“ClassificationLayer_predictions”, newClassificatonLayer);

列车网络的

网络需要大小为227 × 227 × 3的输入图像,但是图像数据存储中的图像有不同的大小。使用增强图像数据存储自动调整训练图像的大小。指定要在训练图像上执行的附加增强操作:沿垂直轴随机翻转训练图像,并在水平和垂直方向随机转换它们至30像素。数据增强有助于防止网络过度拟合和记忆训练图像的精确细节。

pixelRange = [-30 30];imageAugmenter = imageDataAugmenter(...“RandXReflection”,真的,...“RandXTranslation”pixelRange,...“RandYTranslation”, pixelRange);augimdsTrain = augmentedImageDatastore(inputSize(1:2),imdsTrain,...“DataAugmentation”, imageAugmenter);

若要自动调整验证图像的大小而不执行进一步的数据增强,请使用增强图像数据存储而不指定任何额外的预处理操作。

augimdsValidation = augmentedImageDatastore(inputSize(1:2),imdsValidation);

指定培训选项。对于转移学习,保留预训练网络早期层的特征(转移层权值)。为了降低迁移层的学习速度,可以将初始学习率设置为较小的值。在前面的步骤中,您增加了卷积层的学习率因子,以加快新的最终层的学习。这种学习率设置的组合导致只在新层中实现快速学习,而在其他层中实现较慢学习。在执行迁移学习时,您不需要训练那么多课时。一个epoch是整个训练数据集上的一个完整的训练周期。指定小批处理大小为11,以便在每个epoch中考虑所有数据。该软件每天验证网络ValidationFrequency培训期间的迭代。

options = trainingOptions(“个”...“MiniBatchSize”11...“MaxEpochs”7...“InitialLearnRate”2的军医,...“洗牌”“every-epoch”...“ValidationData”augimdsValidation,...“ValidationFrequency”3,...“详细”假的,...“阴谋”“训练进步”);

训练由传输层和新层组成的网络。

netTransfer = trainNetwork(augimdsTrain,lgraph,options);

{

classNames = netTransfer.Layers(end).Classes;保存(“mySqueezenet.mat”“netTransfer”);

生成网络校准结果文件

创建一个dlquantizer对象,并指定网络。

quantObj = dlquantizer(netTransfer);

定义一个度量函数,用来比较量化前后网络的行为。

类型(“hComputeModelAccuracy.m”);
function accuracy = hComputeModelAccuracy(predictionScores, net, dataStore) %%计算模型级精度统计% Load ground truth tmp = readall(dataStore);groundTruth = tmp.response;%比较预测标签与实际的地面真值predictionError = {};for idx=1:numel(groundTruth) [~, idy] = max(predictionScores(idx,:));yActual = net.Layers(end).Classes(idy);predictionError{end+1} = (yActual == groundTruth(idx));%#ok结束%汇总所有预测错误。predictionError = [predictionError{:}];accuracy = sum(predictionError)/numel(predictionError);结束

在a中指定度量函数dlquantizationOptions对象。

quantOpts = dlquantizationOptions(“MetricFcn”...{@ (x) hComputeModelAccuracy (x, netTransfer augimdsValidation)});

使用校准函数用样本输入练习网络并收集范围信息。的校准函数练习网络,收集网络卷积层和全连接层的权值和偏差的动态范围以及网络各层激活的动态范围。函数返回一个表。表的每一行都包含优化网络的可学习参数的范围信息。

calResults = calibrate(quantObj,augimdsTrain);保存(“squeezenetCalResults.mat”“calResults”);保存(“squeezenetQuantObj.mat”“quantObj”);

您可以使用验证函数量化网络卷积层中的可学习参数,并对网络进行训练。函数中定义的度量函数dlquantizationOptions对象,比较量化前后的网络结果。

valResults = validate(quantObj,augimdsValidation,quantOpts);

创建入口点函数

在MATLAB中编写一个入口点函数:

类型(“predict_int8.m”);
函数out = predict_int8(netFile, in)持久化mynet;if isempty(mynet) mynet = code . loaddeeplearningnetwork (netFile);End out =预测(mynet,in);结束

持久化对象mynet加载DAGNetwork对象。在第一次调用入口点函数时,将构造和设置持久对象。在对该函数的后续调用中,将重用相同的对象来调用预测在输入端,避免重构和重新加载网络对象。

请注意

确保在校准和验证步骤中执行的所有预处理操作都包含在设计文件中。

使用生成代码codegen

要配置生成设置,如输出文件名、位置和类型,您需要创建编码器配置对象。要创建对象,请使用coder.gpuConfig函数。例如,当生成CUDA MEX使用codegen命令,使用cfg = code .gpu config ('mex');

要为cuDNN指定代码生成参数,请设置DeepLearningConfiga的财产编码器。CuDNNConfig对象创建的编码器。DeepLearningConfig

cfg = code .gpu config (墨西哥人的);cfg。TargetLang =“c++”;cfg.GpuConfig.ComputeCapability =“6.1”;cfg。DeepLearningConfig =编码器。DeepLearningConfig (“cudnn”);cfg.DeepLearningConfig.AutoTuning = true;cfg.DeepLearningConfig.CalibrationResultFile =“squeezenetQuantObj.mat”;cfg.DeepLearningConfig.DataType =“int8”

指定包含校准数据的mat文件的位置。

方法指定受支持层中推理计算的精度万博1manbetx数据类型财产。对于8位整数,使用“int8”.使用ComputeCapability属性来设置适当的计算能力值。

运行codegen命令。的codegen命令生成CUDA代码predict_int8.mMATLAB入口点函数。

输入={编码器。常数(“mySqueezenet.mat”), (inputSize,“uint8”)};codegen配置cfgarg游戏输入predict_int8
代码生成成功。

当代码生成成功时,您可以通过单击查看生成的代码生成报告查看报告在MATLAB命令窗口中。报表显示在“报表查看器”窗口中。如果代码生成器在代码生成过程中检测到错误或警告,报告将描述问题并提供问题MATLAB代码的链接。

运行生成的MEX

要分类的图像必须与网络的输入大小相同。读取要分类的图像,并将其调整为网络的输入大小。这种调整会略微改变图像的纵横比。

testImage = imread(“MerchDataTest.jpg”);testImage = imresize(testImage,inputSize(1:2));

在输入图像上调用SqueezeNet预测。

predictScores(:,1) = predict(netTransfer,testImage)';predictScores(:,2) = predict_int8_mex(“mySqueezenet.mat”, testImage);

以直方图的形式显示预测的标签及其相关概率。

H =图;h.Position(3) = 2*h.Position(3);Ax1 = subplot(1,2,1);Ax2 = subplot(1,2,2);图像(ax₁,testImage);barh (ax2 predictScores)包含(ax2,“概率”) yticklabels(ax2,classNames)XLim = [0 1.1];ax2。YAxisLocation =“左”;传奇(“Matlab单”'cuDNN 8位整数');sgtitle (“使用Squeezenet进行预测”

图中包含两个坐标轴对象和另一个subplottext类型的对象。坐标轴对象1包含一个image类型的对象。Axes对象2包含两个bar类型的对象。这些对象表示Matlab Single, cuDNN 8位整数。

辅助函数

函数[learnableLayer,classLayer] = findLayersToReplace(lgraph)% findLayersToReplace(lgraph)查找单个分类层和层的前可学习层(全连通层或卷积层)% graph lgraph。如果~ isa (lgraph“nnet.cnn.LayerGraph”)错误(参数必须是LayerGraph对象结束获取源、目标和层名称。src = string(lgraph.Connections.Source);dst = string(lgraph.Connections.Destination);layerNames = string({lgraph.Layers.Name}');找到分类层。图层图必须有一个%分类层。isClassificationLayer = arrayfun(@(l)...(isa (l,“nnet.cnn.layer.ClassificationOutputLayer”...| isa (l,“nnet.layer.ClassificationLayer”)),...lgraph.Layers);如果sum(isClassificationLayer) ~= 1 error(“图层图必须有一个分类层。”结束classLayer = lgraph.Layers(isClassificationLayer);从分类开始反向遍历层图。%层。如果网络分支,抛出错误。currentLayerIdx = find(isClassificationLayer);真正的如果numel(currentLayerIdx) ~= 1 msg = [“图层图必须有一个可学习的图层”...'在分类层之前。'];错误(味精)结束currentLayerType = class(lgraph.Layers(currentLayerIdx));= ismember(currentLayerType);...“nnet.cnn.layer.FullyConnectedLayer”“nnet.cnn.layer.Convolution2DLayer”]);如果learnableLayer = lgraph.Layers(currentLayerIdx);返回结束currentDstIdx = find(layerNames(currentLayerIdx) == dst);currentLayerIdx = find(src(currentDstIdx) == layerNames);结束结束

限制

  • 中执行推理时INT8在使用cuDNN 8.1.0版本时,NVIDIA库中的问题可能会导致性能的显著下降。

  • 当针对NVIDIA CUDA深度神经网络库(cuDNN)库万博1manbetx时,8位整数量化不支持以下层。

    • leakyReluLayer

    • clippedReluLayer

    • globalAveragePooling2dLayer

另请参阅

应用程序

功能

对象

相关的话题