徽标识别网络
此示例说明如何为使用深度学习的徽标分类应用程序生成代码。它使用名为 LogoNet 的预训练网络,并将一个输入图像分类为 32 个徽标类别。此示例还说明如何使用经过预处理的训练数据集来训练网络。最后,此示例使用 codegen
命令生成 MEX 函数并执行预测。
此示例说明了以下概念:
通过提取徽标并将大小调整为 227×227×3 来预处理训练图像。随后,使用图像增强来增大训练数据大小。
使用具有动量的随机梯度下降 (SGDM) 优化器来训练网络。
生成 CUDA® MEX 并运行该 MEX。
第三方前提条件
必需
此示例生成 CUDA MEX,需要支持 CUDA 的 NVIDIA® GPU 和兼容的驱动程序。
可选
对于非 MEX 编译,如静态、动态库或可执行文件,此示例有以下附加要求。
NVIDIA 工具包。
NVIDIA cuDNN 库。
编译器和库的环境变量。有关详细信息,请参阅Third-Party Hardware (GPU Coder)和Setting Up the Prerequisite Products (GPU Coder)。
验证 GPU 环境
使用 coder.checkGpuInstall
(GPU Coder) 函数验证运行此示例的编译器和库是否已正确设置。
envCfg = coder.gpuEnvConfig('host'); envCfg.DeepLibTarget = 'cudnn'; envCfg.DeepCodegen = 1; envCfg.Quiet = 1; coder.checkGpuInstall(envCfg);
徽标识别网络
徽标帮助用户进行品牌辨识和识别。许多公司在广告、文档材料和促销活动中使用其徽标。徽标识别网络是在 MATLAB® 中开发的,包含 22 个层。该网络包含四组卷积最大池化层、三个全连接层和降低计算成本的丢弃层。该网络接受大小为 227×227×3 的输入图像,并将其分类为 32 个徽标类别。由于该网络专注于识别,因此可以在不需要定位的应用中使用。通过使用 Flickr32Logos[1] 和 Flickr32 Plus[2] 训练数据集在 MATLAB 中训练该网络。这两个数据集包含每个徽标的大约 200 个图像。通过使用带动量的随机梯度下降 (SGDM) 优化器、0.0001 的学习率、40 轮训练和小批量大小为 45 来训练网络。默认情况下,该示例使用经过预训练的徽标识别网络。借助预训练网络,您无需等待训练完成即可运行整个示例。
要训练网络,请将以下代码中的 doTraining
变量设置为 true
。您还必须从徽标识别深度学习下载 Logos-32plus 数据集,并将下载的 Logos-32plus_v1.0.1.zip 文件的位置提供给 logozipPath
。Logos-32plus 数据集的大小为 1.95 GB。根据您的 Internet 连接,下载过程可能需要一些时间。该数据集有 32 个图像子文件夹,包含来自不同品牌的总共 7830 个徽标图像。真实值 MAT 文件提供每个图像中徽标的边界框信息。
preprocessLogoData
函数对数据进行预处理以用于网络训练。Logos-32plus 数据集中的图像大小不一。您必须将图像的大小调整为网络的输入层大小 (227×227×3)。图像还包含您必须删除的背景信息。preprocessLogoData.m
通过使用边界框信息提取徽标来执行这些步骤,并创建可用于网络训练的 imageDatastore
对象。trainLogonet
函数创建徽标识别层,并通过使用指定的训练选项来训练网络。使用至少包含每个徽标的 110 个图像的数据来训练该网络。
您还可以使用数据增强来增加训练样本的数量。数据增强有助于防止网络过拟合和记忆训练图像的具体细节。为了增加训练数据,系统提供了四种类型的数据增强:随机翻转、高斯模糊、剪切和对比度归一化。要使用数据增强,请将以下代码中的 doAugmentation
变量设置为 true
。
doTraining = false; if ~doTraining getLogonet; else logozipPath = '';% provide path of the downloaded zip file zipData = fullfile(logozipPath,'Logos-32plus_v1.0.1.zip'); unpackedData = fullfile(logozipPath,'Logos32plus'); if ~exist(unpackedData,'dir') unzip(zipData,unpackedData); end doAugmentation = false; logoData = preprocessLogoData(unpackedData,doAugmentation); trainLogonet(logoData); end load('LogoNet.mat'); convnet
convnet = SeriesNetwork with properties: Layers: [22×1 nnet.cnn.layer.Layer] InputNames: {'imageinput'} OutputNames: {'classoutput'}
将 SeriesNetwork
网络对象转换为 dlnetwork
对象,并将网络保存到 MAT 文件中。
dlconvnet = dag2dlnetwork(convnet); save dlLogoNet.mat dlconvnet
要查看网络架构,请使用 analyzeNetwork
函数。
analyzeNetwork(dlconvnet)
logonet_predict
入口函数
logonet_predict.m
入口函数以图像作为输入,并使用保存在 dlLogoNet.mat
文件中的深度学习网络对图像执行预测。该函数将 dlLogoNet.mat
中的网络对象加载到持久变量 dlLogonet
中,并在后续的预测调用中重用该持久变量。dlarray 对象是在函数中创建的,函数的输入和输出属于原始数据类型。有关详细信息,请参阅 Code Generation for dlarray (GPU Coder)。
type('logonet_predict.m')
function out = logonet_predict(in) %#codegen % Copyright 2017-2023 The MathWorks, Inc. % A persistent object dlLogonet is used to load the network object. At the % first call to this function, the persistent object is constructed and % setup. When the function is called subsequent times, the same object is % reused to call predict on inputs, thus avoiding reconstructing and % reloading the network object. dlIn = dlarray(in, 'SSC'); persistent dlLogonet; if isempty(dlLogonet) dlLogonet = coder.loadDeepLearningNetwork('dlLogoNet.mat','dlLogonet'); end dlOut = predict(dlLogonet, dlIn); out = extractdata(dlOut); end
为 logonet_predict
函数生成 CUDA MEX
为 MEX 目标创建一个 GPU 配置对象,并将目标语言设置为 C++。使用 coder.DeepLearningConfig
(GPU Coder) 函数创建 CuDNN
深度学习配置对象。将其分配给 GPU 代码配置对象的 DeepLearningConfig
属性。要生成 CUDA MEX,请使用 codegen
命令并指定输入大小为 [227,227,3]。该值对应于 logonet 网络的输入层大小。
cfg = coder.gpuConfig('mex'); cfg.TargetLang = 'C++'; cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn'); codegen -config cfg logonet_predict -args {ones(227,227,3,'single')} -report
Code generation successful: View report
运行生成的 MEX
加载输入图像。对输入图像调用 logonet_predict_mex
。
im = imread('test.png');
imshow(im);
im = imresize(im, [227,227]); predict_scores = logonet_predict_mex(single(im));
将排名前五的预测分数映射到 Wordnet 字典 synset 中的单词(徽标)。
synsetOut = convnet.Layers(end).Classes;
[val,indx] = sort(predict_scores, 'descend');
scores = val(1:5)*100;
top5labels = synsetOut(indx(1:5));
显示排名前五的分类标签。
outputImage = zeros(227,400,3, 'uint8'); for k = 1:3 outputImage(:,174:end,k) = im(:,:,k); end scol = 1; srow = 20; for k = 1:5 outputImage = insertText(outputImage, [scol, srow],... [char(top5labels(k)),' ',num2str(scores(k),'%2.2f'),'%'],... 'TextColor', 'w','FontSize',15, 'BoxColor', 'black'); srow = srow + 20; end imshow(outputImage);
清除内存中已加载的静态网络对象。
clear logonet_predict_mex;
参考资料
[1] Romberg, Stefan, Lluis Garcia Pueyo, Rainer Lienhart, and Roelof van Zwol."Scalable Logo Recognition in Real-World Images." ACM International Conference on Multimedia Retrieval 2011 (ICMR11):1-8. https://doi.org/10.1145/1991996.1992021
[2] Bianco, Simone, Marco Buzzelli, Davide Mazzini, and Raimondo Schettini."Deep Learning for Logo Recognition."Neurocomputing 245 (2017):23-30. https://doi.org/10.1016/j.neucom.2017.03.051.