%% Quantize a Neural Network for GPU Target
% This example shows how to quantize learnable parameters in the convolution layers of a neural network for GPU and explore the behavior of the quantized network. In this example, you quantize the squeezenet neural network after retraining the network to classify new images according to the Train Deep Learning Network to Classify New Images example. In this example, the memory required for the network is reduced approximately 75% through quantization while the accuracy of the network is not affected.
% Load the pretrained network. net is the output network of the Train Deep Learning Network to Classify New Images example.

load squeezenetmerch
net

% Define calibration and validation data to use for quantization.
% The calibration data is used to collect the dynamic ranges of the weights and biases in the convolution and fully connected layers of the network and the dynamic ranges of the activations in all layers of the network. For the best quantization results, the calibration data must be representative of inputs to the network.
% The validation data is used to test the network after quantization to understand the effects of the limited range and precision of the quantized convolution layers in the network.
% In this example, use the images in the MerchData data set. Define an augmentedImageDatastore object to resize the data for the network. Then, split the data into calibration and validation data sets.

unzip('MerchData.zip');
imds = imageDatastore('MerchData', ...
    'IncludeSubfolders',true, ...
    'LabelSource','foldernames');
[calData, valData] = splitEachLabel(imds, 0.7, 'randomized');
aug_calData = augmentedImageDatastore([227 227], calData);
aug_valData = augmentedImageDatastore([227 227], valData);

% Create a dlquantizer object and specify the network to quantize.

quantObj = dlquantizer(net);

% Define a metric function to use to compare the behavior of the network before and after quantization. This example uses the hComputeModelAccuracy metric function.
% function accuracy = hComputeModelAccuracy(predictionScores, net, dataStore)
% %% Computes model-level accuracy statistics
%
%     % Load ground truth
%     tmp = readall(dataStore);
%     groundTruth = tmp.response;
%
%     % Compare with predicted label with actual ground truth
%     predictionError = {};
%     for idx=1:numel(groundTruth)
%         [~, idy] = max(predictionScores(idx,:));
%         yActual = net.Layers(end).Classes(idy);
%         predictionError{end+1} = (yActual == groundTruth(idx)); %#ok
%     end
%
%     % Sum all prediction errors.
%     predictionError = [predictionError{:}];
%     accuracy = sum(predictionError)/numel(predictionError);
% end
% Specify the metric function in a dlquantizationOptions object.

quantOpts = dlquantizationOptions('MetricFcn',{@(x)hComputeModelAccuracy(x, net, aug_valData)});

% Use the calibrate function to exercise the network with sample inputs and collect range information. The calibrate function exercises the network and collects the dynamic ranges of the weights and biases in the convolution and fully connected layers of the network and the dynamic ranges of the activations in all layers of the network. The function returns a table. Each row of the table contains range information for a learnable parameter of the optimized network.

calResults = calibrate(quantObj, aug_calData)

% Use the validate function to quantize the learnable parameters in the convolution layers of the network and exercise the network. The function uses the metric function defined in the dlquantizationOptions object to compare the results of the network before and after quantization.

valResults = validate(quantObj, aug_valData, quantOpts)

% Examine the validation output to see the performance of the quantized network.

valResults.MetricResults.Result
valResults.Statistics

% In this example, the memory required for the network was reduced approximately 75% through quantization. The accuracy of the network is not affected.
% The weights, biases, and activations of the convolution layers of the network specified in the dlquantizer object now use scaled 8-bit integer data types.
% Copyright 2020 The MathWorks, Inc.