%% Compute Grad-CAM Map for Image Regression Network
% Use Grad-CAM to visualize which parts of an image are most important to the predictions of an image regression network.
% Load the sample data, which consists of synthetic images of handwritten digits. The third output contains the corresponding angles of rotation of the digits, in degrees.

rng default
[XTrain,~,YTrain] = digitTrain4DArrayData;
[XTest,~,YTest] = digitTest4DArrayData;

numTrainImages = numel(YTrain);
idx = randperm(numTrainImages,20);

% Construct an image regression network that can predict the rotation of an image.

layers = [ ...
    imageInputLayer([28 28 1],'Name','input')
    convolution2dLayer(12,25,'Name','conv')
    reluLayer('Name','relu')
    fullyConnectedLayer(1,'Name','fc')
    regressionLayer('Name','output')];

% Specify the training options.

options = trainingOptions('sgdm', ...
    'InitialLearnRate',0.001, ...
    'Verbose',false, ...
    'Plots','training-progress');

% Train the network.

net = trainNetwork(XTrain,YTrain,layers,options);

%
% Evaluate the performance of the network on a test image.

testDigit = XTest(:,:,:,idx(4));

% Use predict to predict the angle of rotation and compare the predicted rotation to the true rotation.

predRotation = predict(net,testDigit)
trueRotation = YTest(idx(4))

% Visualize the regions of the image most important to the network prediction using gradCAM. Select the ReLU layer as the feature layer and the fully connected layer as the reduction layer.

featureLayer = 'relu';
reductionLayer = 'fc';

% Define the reduction function. The reduction function must reduce the output of the reduction layer to a scalar value. The Grad-CAM map displays the importance of different parts of the image to that scalar. In this regression problem, the network predicts the angle of rotation of the image. Therefore, the output of the fully connected layer is already a scalar value and so the reduction function is just the identity function.

reductionFcn = @(x)x;

% Compute the Grad-CAM map.

scoreMap = gradCAM(net,testDigit,reductionFcn, ...
    'ReductionLayer',reductionLayer, ...
    'FeatureLayer',featureLayer);

% Display the Grad-CAM map over the test image.

ax(1) = subplot(1,2,1);
imshow(testDigit)
title("True Rotation = " + trueRotation + '\newline Pred Rotation = ' + round(predRotation,0))
colormap(ax(1),'gray')

ax(2) = subplot(1,2,2);
imshow(testDigit)
hold on
imagesc(scoreMap)
colormap(ax(2),'jet')
title("GradCAM")
hold off

% The Grad-CAM map shows that the network is focusing on the area in the bottom left, which is where the tail of the digit would be if the image had zero rotation. The map suggests that to predict the negative rotation, the network is using the empty space.
% Copyright 2020 The MathWorks, Inc.