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.
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.
squeezenet_raspi_predict
FunctionThis 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
Create a code generation configuration object for generation of an executable program. Specify generation of C++ code.
cfg = coder.config('exe'); cfg.TargetLang = 'C++';
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';
cfg.DeepLearningConfig = dlcfg;
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');
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;
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';
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
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;
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 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)
outputfile = [targetDirPath, '/output.txt'];
r.getFile(outputfile);
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);