Code Generation for Deep Learning on Raspberry Pi

This example shows how to generate and deploy code for prediction on a Raspberry Pi™ by using codegen with the MATLAB Support Package for Raspberry Pi Hardware.

When you generate code for prediction using the ARM® Compute Library and a hardware support package, codegen generates code on the host computer, copies the generated files to the target hardware, and builds the executable on the target hardware.

Prerequisites

  • ARM processor that supports the NEON extension

  • ARM Compute Library (on the target ARM hardware)

  • Open Source Computer Vision Library

  • Environment variables for the compilers and libraries

  • MATLAB® Coder™

  • The support package MATLAB Coder Interface for Deep Learning

  • Deep Learning Toolbox™

  • MATLAB Support Package for Raspberry Pi Hardware

For supported versions of libraries and for information about setting up environment variables, see Prerequisites for Deep Learning with MATLAB Coder (MATLAB Coder). This example is not supported for MATLAB Online.

The squeezenet_raspi_predict Function

This example uses the DAG network SqueezeNet to show image classification with the ARM Compute Library. A pretrained SqueezeNet for MATLAB is available in the Deep Learning Toolbox. The squeezenet_arm_predict function loads the SqueezeNet network into a persistent network object. On subsequent calls to the function, the persistent object is reused.

So that the generated executable program links against the OpenCV libraries, the squeezenet_arm_predict function specifies linker options by using coder.updateBuildInfo.

type squeezenet_raspi_predict
% Copyright 2018 The MathWorks, Inc.

function out = squeezenet_raspi_predict(in)
%#codegen

% A persistent object mynet is used to load the DAGNetwork object.
% At the first call to this function, the persistent object is constructed and
% set up. When the function is called subsequent times, the same object is reused 
% to call predict on inputs, avoiding reconstructing and reloading the
% network object.


persistent net;
opencv_linkflags = '`pkg-config --cflags --libs opencv`';
coder.updateBuildInfo('addLinkFlags',opencv_linkflags);
if isempty(net)
    net = coder.loadDeepLearningNetwork('squeezenet', 'squeezenet');
end

out = net.predict(in);

end


Set Up a Code Generation Configuration Object

Create a code generation configuration object for generation of an executable program. Specify generation of C++ code.

cfg = coder.config('exe');
cfg.TargetLang = 'C++';

Set Up a Configuration Object for Deep Learning Code Generation with ARM Compute Library

Create a coder.ARMNEONConfig object. Specify the version of the ARM Compute library that is on the Raspberry Pi. Specify the architecture of the Raspberry Pi.

dlcfg = coder.DeepLearningConfig('arm-compute');
dlcfg.ArmArchitecture = 'armv7';
dlcfg.ArmComputeVersion = '19.05';

Attach the Deep Learning Configuration Object to the Code Generation Configuration Object

cfg.DeepLearningConfig = dlcfg;

Create a Connection to the Raspberry Pi

Use the MATLAB Support Package for Raspberry Pi Support Package function, raspi, to create a connection to the Raspberry Pi. In the following code, replace:

  • raspiname with the name of your Raspberry Pi

  • username with your user name

  • password with your password

r = raspi('raspiname','username','password');

Configure Code Generation Hardware Parameters for Raspberry Pi

Create a coder.Hardware object for Raspberry Pi and attach it to the code generation configuration object.

hw = coder.hardware('Raspberry Pi');
cfg.Hardware = hw;

Specify the build folder on the Raspberry Pi

buildDir = '~/remoteBuildDir';
cfg.Hardware.BuildDir = buildDir;

Provide a C++ Main File

The C++ main file reads the input image, runs prediction on the image, and displays the classification labels on the image.

Specify the main file in the code generation configuration object.

cfg.CustomSource = 'main_squeezenet_raspi.cpp';

Generate the Executable Program on the Raspberry Pi

Use codegen to generate the C++ code. When you use codegen with the MATLAB Support Package for Raspberry PI Hardware, the executable is built on the Raspberry Pi.

Make sure that you set the environment variables ARM_COMPUTELIB and LD_LIBRARY_PATH on the Raspberry Pi. See Prerequisites for Deep Learning with MATLAB Coder (MATLAB Coder).

codegen -config cfg squeezenet_raspi_predict -args {ones(227, 227, 3,'single')} -report

Fetch the Generated Executable Directory

To test the generated code on the Raspberry Pi, copy the input image to the generated code directory. You can find this directory manually or by using the raspi.utils.getRemoteBuildDirectory API. This function lists the directories of the binary files that are generated by using codegen. Assuming that the binary is found in only one directory, enter:

applicationDirPaths = raspi.utils.getRemoteBuildDirectory('applicationName','squeezenet_raspi_predict');
targetDirPath = applicationDirPaths{1}.directory;

Copy Example Files to the Raspberry Pi

To copy files required to run the executable program, use putFile, which is available with the MATLAB Support Package for Raspberry Pi Hardware.

r.putFile('synsetWords_squeezenet_raspi.txt', targetDirPath);
r.putFile('coffeemug.png',targetDirPath);

Run the Executable Program on the Raspberry Pi

Run the executable program on the Raspberry Pi from MATLAB and direct the output back to MATLAB.

exeName = 'squeezenet_raspi_predict.elf';
argsforexe = ' coffeemug.png '; % Provide the input image;
command = ['cd ' targetDirPath ';./' exeName argsforexe];
output = system(r,command)

Get the Prediction Scores

outputfile = [targetDirPath, '/output.txt'];
r.getFile(outputfile);

Map the Prediction Scores to Labels

Map the top five prediction scores to corresponding labels in the trained network.

net = squeezenet;
ClassNames = net.Layers(end).ClassNames;

Read the classification.

fid = fopen('output.txt') ;
S = textscan(fid,'%s');
fclose(fid) ;
S = S{1} ;
predict_scores = cellfun(@(x)str2double(x), S);

Remove NaN values that were strings.

predict_scores(isnan(predict_scores))=[];
[val,indx] = sort(predict_scores, 'descend');
scores = val(1:5)*100;
top5labels = ClassNames(indx(1:5));

Display classification labels on the image.

im = imread('coffeemug.png');
im = imresize(im, [227 227]);
outputImage = zeros(227,400,3, 'uint8');
for k = 1:3
    outputImage(:,174:end,k) = im(:,:,k);
end
scol = 1;
srow = 1;
outputImage = insertText(outputImage, [scol, srow], 'Classification with Squeezenet', 'TextColor', 'w','FontSize',20, 'BoxColor', 'black');
srow = srow + 30;
for k = 1:5
    outputImage = insertText(outputImage, [scol, srow], [top5labels{k},' ',num2str(scores(k), '%2.2f'),'%'], 'TextColor', 'w','FontSize',15, 'BoxColor', 'black');
    srow = srow + 25;
end
imshow(outputImage);