%% Quantize Network for FPGA Deployment
% This example shows how to quantize learnable parameters in the convolution layers of a neural network, and validate the quantized network. Rapidly prototype the quantized network by using MATLAB simulation or an FPGA to validate the quantized network. In this example, you quantize the LogoNet neural network.
% For this example, you need:
% Deep Learning Toolbox ™
% Deep Learning HDL Toolbox ™
% Deep Learning Toolbox Model Quantization Library
% Deep Learning HDL Toolbox Support Package for Xlinx FPGA and SoC Devices
% MATLAB Coder Interface for Deep Learning Libraries.
%
%% Load Pretrained Network
% To load the pretrained LogoNet network and analyze the network architecture, enter:

snet = getLogoNetwork;
analyzeNetwork(snet);

%
%
%% Define Calibration and Validation Data Sets
% This example uses the logos_dataset data set. The data set consists of 320 images. Each image is 227-by-227 in size and has three color channels (RGB). Create an augmentedImageDatastore object to use for calibration and validation. Expedite calibration and validation by reducing the calibration data set to 20 images. The MATLAB simulation workflow has a maximum limit of five images when validating the quantized network. Reduce the validation data set sizes to five images. The FPGA validation workflow has a maximum limit of one image when validating the quantized network. Reduce the FPGA validation data set to a single image.

curDir = pwd;
newDir = fullfile(matlabroot,'examples','deeplearning_shared','data','logos_dataset.zip');
copyfile(newDir,curDir,'f');
unzip('logos_dataset.zip');
imageData = imageDatastore(fullfile(curDir,'logos_dataset'),...
'IncludeSubfolders',true,'FileExtensions','.JPG','LabelSource','foldernames');
[calibrationData, validationData] = splitEachLabel(imageData, 0.5,'randomized');
calibrationData_reduced = calibrationData.subset(1:20);
validationData_simulation = validationData.subset(1:5);
validationData_FPGA = validationData.subset(1:1);

%
% Create Quantized Network Object
% Create a dlquantizer object and specify the network to quantize. Specify the execution environment as FPGA for one object. Run the MATLAB simulation on for the second dlquantizer object.

dlQuantObj_simulation = dlquantizer(snet,'ExecutionEnvironment',"FPGA",'Simulation','on');
dlQuantObj_FPGA = dlquantizer(snet,'ExecutionEnvironment',"FPGA");

%
% Calibrate Quantized Network
% Use the calibrate function to exercise the network with sample inputs and collect the range information. The calibrate function exercises the network and collects the dynamic ranges of the weights and biases. The calibrate function returns a table. Each row of the table contains range information for a learnable parameter of the quantized network.

dlQuantObj_simulation.calibrate(calibrationData_reduced)
dlQuantObj_FPGA.calibrate(calibrationData_reduced)

%
%% Create Target Object
% Create a target object with a custom name for your target device and an interface to connect your target device to the host computer. Interface options are JTAG and Ethernet. To use JTAG, install Xilinx™ Vivado™ Design Suite 2020.1. To set the Xilinx Vivado toolpath, enter:
% % hdlsetuptoolpath('ToolName', 'Xilinx Vivado', 'ToolPath', 'C:\Xilinx\Vivado\2020.1\bin\vivado.bat');
% To create the target object, enter:

hTarget = dlhdl.Target('Xilinx','Interface','Ethernet');

% Alternatively, you can also use the JTAG interface.

% hTarget = dlhdl.Target('Xilinx', 'Interface', 'JTAG');

%
% Create dlQuantizationOptions Object
% Create a dlquantizationOptions object. Specify the target bitstream and target board interface. The default metric function is a Top-1 accuracy metric function.

options_FPGA = dlquantizationOptions('Bitstream','zcu102_int8','Target',hTarget);
options_simulation = dlquantizationOptions;

% To use a custom metric function, specify the metric function in the dlquantizationOptions object.

% options_FPGA = dlquantizationOptions('MetricFcn',{@(x)hComputeAccuracy(x, snet, validationData_FPGA)},'Bitstream','zcu102_int8','Target',hTarget);
% options_simulation = dlquantizationOptions('MetricFcn',{@(x)hComputeAccuracy(x, snet,validationData_simulation)})

%
% Validate Quantized Network
% Use the validate function to quantize the learnable parameters in the convolution layers of the network. The validate function simulates the quantized network in MATLAB. The validate function uses the metric function defined in the dlquantizationOptions object to compare the results of the single data type network object to the results of the quantized network object.

prediction_simulation = dlQuantObj_simulation.validate(validationData_simulation,options_simulation)

%  For an FPGA based validation, The validate function uses the output of the compile function to program the FPGA board by using the programming file. It also downloads the network weights and biases. The validate function uses the metric function defined in the dlquantizationOptions object to compare the results of the network before and after quantization.

prediction_FPGA = dlQuantObj_FPGA.validate(validationData_FPGA,options_FPGA)

%
% View Performance of Quantized Neural Network
% Examine the MetricResults.Result field of the validation output to see the performance of the quantized network.

prediction_simulation.MetricResults.Result
prediction_FPGA.MetricResults.Result

% Examine the QuantizedNetworkFPS field of the validation output to see the frames per second performance of the quantized network.

prediction_FPGA.QuantizedNetworkFPS

%
%% See Also
% dlquantizer
% calibrate
% validate
% dlquantizationOptions
% Quantization of Deep Neural Networks
% Copyright 2020 The MathWorks, Inc.