%% Code Generation for Deep Learning Networks
% This example shows how to perform code generation for an image classification application that uses deep learning. It uses the codegen command to generate a MEX function that runs prediction by using image classification networks such as MobileNet-v2, ResNet, and GoogLeNet.
%% Third-Party Prerequisites
% Required
% This example generates CUDA MEX and has the following third-party requirements.
% CUDA® enabled NVIDIA® GPU and compatible driver.
% Optional
% For non-MEX builds such as static, dynamic libraries or executables, this example has the following additional requirements.
% NVIDIA toolkit.
% NVIDIA cuDNN library.
% Environment variables for the compilers and libraries. For more information, see Third-party Products and Environment Variables.
%% Verify GPU Environment
% Use the coder.checkGpuInstall function to verify that the compilers and libraries necessary for running this example are set up correctly.

envCfg = coder.gpuEnvConfig('host');
envCfg.DeepLibTarget = 'cudnn';
envCfg.DeepCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

%
%% mobilenetv2_predict Entry-Point Function
% MobileNet-v2 is a convolutional neural network that is trained on more than a million images from the ImageNet database. The network is 155 layers deep and can classify images into 1000 object categories, such as keyboard, mouse, pencil, and many animals. The network has an image input size of 224-by-224. Use the analyzeNetwork function to display an interactive visualization of the deep learning network architecture.

net = mobilenetv2();
analyzeNetwork(net);

%
% The mobilenetv2_predict.m entry-point function takes an image input and runs prediction on the image using the pretrained MobileNet-v2 convolutional neural network. The function uses a persistent object  mynet to load the series network object and reuses the persistent object for prediction on subsequent calls.

type('mobilenetv2_predict.m')

%
%% Run MEX Code Generation
% To generate CUDA code for the mobilenetv2_predict entry-point function, create a GPU code configuration object for a MEX target and set the target language to C++. Use the coder.DeepLearningConfig function to create a CuDNN deep learning configuration object and assign it to the DeepLearningConfig property of the GPU code configuration object. Run the codegen command and specify an input size of [224,224,3]. This value corresponds to the input layer size of the MobileNet-v2 network.

cfg = coder.gpuConfig('mex');
cfg.TargetLang = 'C++';
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
codegen -config cfg mobilenetv2_predict -args {ones(224,224,3)} -report

%
%% Generated Code Description
% The series network is generated as a C++ class containing an array of 155 layer classes and functions to set up, call predict, and clean up the network.
% class b_mobilenetv2_0
% {
%    ....
%    public:
%      b_mobilenetv2_0();
%      void setup();
%      void predict();
%      void cleanup();
%      ~b_mobilenetv2_0();
% };
% The setup() method of the class sets up handles and allocates memory for each layer of the network object. The predict() method performs prediction for each of the 155 layers in the network.
% The entry-point function mobilenetv2_predict() in the generated code file mobilenetv2_predict.cu constructs a static object of b_mobilenetv2 class type and invokes setup and predict on this network object.
% static b_mobilenetv2_0 mynet;
% static boolean_T mynet_not_empty;
% /* Function Definitions */
% void mobilenetv2_predict(const real_T in[150528], real32_T out[1000])
% {
%   if (!mynet_not_empty) {
%     DeepLearningNetwork_setup(&mynet);
%     mynet_not_empty = true;
%   }
%    /*  pass in input    */
%    DeepLearningNetwork_predict(&mynet, in, out);
%  }
% Binary files are exported for layers with parameters such as fully connected and convolution layers in the network. For instance, files cnn_mobilenetv2_conv*_w and cnn_mobilenetv2_conv*_b correspond to weights and bias parameters for the convolution layers in the network. To see a list of the generated files, use:
% dir(fullfile(pwd, 'codegen', 'mex', 'mobilenetv2_predict'))
%% Run Generated MEX
% Load an input image.

im = imread('peppers.png');
imshow(im);

%
% Call mobilenetv2_predict_mex on the input image.

im = imresize(im, [224,224]);
predict_scores = mobilenetv2_predict_mex(double(im));

%
% Get the top five prediction scores and their labels.

[scores,indx] = sort(predict_scores, 'descend');
classNames = net.Layers(end).ClassNames;
classNamesTop = classNames(indx(1:5));

h = figure;
h.Position(3) = 2*h.Position(3);
ax1 = subplot(1,2,1);
ax2 = subplot(1,2,2);

image(ax1,im);
barh(ax2,scores(5:-1:1))
xlabel(ax2,'Probability')
yticklabels(ax2,classNamesTop(5:-1:1))
ax2.YAxisLocation = 'right';
sgtitle('Top Five Predictions That Use MobileNet-v2')

% Clear the static network object that was loaded in memory.

clear mex;

%
%% Classification of Images by Using ResNet-50 network
% You can also use the DAG network ResNet-50 for image classification. A pretrained ResNet-50 model for MATLAB is available in the ResNet-50 support package of Deep Learning Toolbox. To download and install the support package, use the Add-On Explorer. To learn more about finding and installing add-ons, see docid:matlab_env#buytlwx.

net = resnet50;
disp(net)

%
%% Run MEX Code Generation
% To generate CUDA code for the resnet_predict.m entry-point function,create a GPU code configuration object for a MEX target and set the target language to C++. This entry-point function calls the resnet50 function to load the network and perform prediction on the input image.

cfg = coder.gpuConfig('mex');
cfg.TargetLang = 'C++';
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
codegen -config cfg resnet_predict -args {ones(224,224,3)} -report

%
% Call resnet_predict_mex on the input image.

predict_scores = resnet_predict_mex(double(im));

%
% Get the top five prediction scores and their labels.

[scores,indx] = sort(predict_scores, 'descend');
classNames = net.Layers(end).ClassNames;
classNamesTop = classNames(indx(1:5));

h = figure;
h.Position(3) = 2*h.Position(3);
ax1 = subplot(1,2,1);
ax2 = subplot(1,2,2);

image(ax1,im);
barh(ax2,scores(5:-1:1))
xlabel(ax2,'Probability')
yticklabels(ax2,classNamesTop(5:-1:1))
ax2.YAxisLocation = 'right';
sgtitle('Top Five Predictions That Use ResNet-50')

%
% Clear the static network object that was loaded in memory.

clear mex;

%
%% Classification of Images by Using GoogLeNet (Inception) network
% A pretrained GoogLeNet model for MATLAB is available in the GoogLeNet support package of Deep Learning Toolbox. To download and install the support package, use the Add-On Explorer. To learn more about finding and installing add-ons, see docid:matlab_env#buytlwx.

net = googlenet;
disp(net)

%
%% Run MEX Code Generation
% Generate CUDA code for the googlenet_predict.m entry-point function. This entry-point function calls the googlenet function to load the network and perform prediction on the input image. To generate code for this entry-point function, create a GPU configuration object for MEX target.

cfg = coder.gpuConfig('mex');
cfg.TargetLang = 'C++';
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
codegen -config cfg googlenet_predict -args {ones(224,224,3)} -report

%
% Call googlenet_predict_mex on the input image.

im = imresize(im, [224,224]);
predict_scores = googlenet_predict_mex(double(im));

%
% Get the top five prediction scores and their labels.

[scores,indx] = sort(predict_scores, 'descend');
classNames = net.Layers(end).ClassNames;
classNamesTop = classNames(indx(1:5));

h = figure;
h.Position(3) = 2*h.Position(3);
ax1 = subplot(1,2,1);
ax2 = subplot(1,2,2);

image(ax1,im);
barh(ax2,scores(5:-1:1))
xlabel(ax2,'Probability')
yticklabels(ax2,classNamesTop(5:-1:1))
ax2.YAxisLocation = 'right';
sgtitle('Top Five Predictions That Use GoogLeNet')

%
% Clear the static network object that was loaded in memory.

clear mex;

%
% Copyright 2017-2020 The MathWorks, Inc.