function [map, featureLayer, reductionLayer] = gradCAM(varargin)
% gradCAM  Explain network predictions using Grad-CAM
% 
%   map = gradCAM(net, X, label) computes a map of the change in
%   classification score for the specified class label using the
%   gradient-weighted class activation mapping (Grad-CAM) technique. net is
%   a SeriesNetwork, DAGNetwork, or dlnetwork trained for 2-D image, 3-D
%   image, or vector sequence classification.
%
%   The function uses the Grad-CAM deep learning interpretability
%   technique, which utilizes the gradients of the classification score
%   with respect to the final convolutional feature map, to identify the
%   parts of the input data that most impact the classification score.
% 
%   map = gradCAM(net, X, reductionFcn) computes the Grad-CAM importance
%   map using a reduction function. reductionFcn is a function handle which
%   reduces the output activations of the reduction layer to a single value
%   and must reduce a dlarray to a scalar. This scalar fulfils the role of
%   the class score for classification problems and generalizes the
%   Grad-CAM technique to non-classification tasks such as regression. For
%   example, reductionFcn = @(x)x(1) computes the Grad-CAM importance for
%   the first element of the activations of the reduction layer.
%
%   The size of the output map depends on the type of data.
%
%   - For 2-D image data, map(i,j) corresponds to the Grad-CAM importance at 
%     the specified class label at the spatial location (i,j). If you 
%     provide class labels as a vector of categoricals, char vectors, or
%     strings, then map(:,:,n) corresponds to the map for label(n).
%  
%   - For 3-D image data, map(i,j,k) corresponds to the Grad-CAM importance 
%     at the specified class label at the spatial location (i,j,k). If you 
%     provide class labels as a vector of categoricals, char vectors, or
%     strings, then map(:,:,:,n) corresponds to the map for label(n).
%  
%   - For vector sequence data, map(:,i) corresponds to the Grad-CAM 
%     importance at the specified class label at time step i. If you provide
%     class labels as a vector of categoricals, char vectors, or strings,
%     then map(:,:,n) corresponds to the map for label(n).
%
%   [map, featureLayer, reductionLayer] = gradCAM(...) also returns the
%   names of the feature and reduction layers used to compute the Grad-CAM
%   map.
% 
%   [...] = gradCAM(__, Name, Value) specifies additional options for the 
%   computation using one or more name-value pair arguments: 
% 
%   'FeatureLayer'  - Name of layer to extract feature map from. The 
%                     feature layer must have the same data format as the 
%                     input layer. For most tasks, use the last ReLU layer 
%                     with nonsingleton spatial or time dimensions, or the
%                     last layer that gathers the outputs of ReLU layers 
%                     (such as depth concatenation or addition layers). If
%                     your network does not contain any ReLU layers, 
%                     specify the name of the final convolutional layer
%                     that has nonsingleton spatial or time dimensions in 
%                     the output. Use the function analyzeNetwork to 
%                     examine your network and select the correct layer.
%                     The default value is the final layer with the same 
%                     data format as the input layer and nonsingleton 
%                     spatial or time dimensions.
%  'ReductionLayer' - Name of layer to extract output activations from. For
%                     classification tasks, this layer is the final softmax 
%                     layer. For other tasks, this layer is usually the 
%                     penultimate layer for DAGNetworks and SeriesNetworks 
%                     and the final layer for dlnetworks. Use the function 
%                     analyzeNetwork to examine your network and select the 
%                     correct layer. The default value is the penultimate 
%                     layer in DAG networks and series networks, and the 
%                     final layer in dlnetworks.
%   'Format'        - Character vector assigning a format label to each 
%                     dimension of the input data. Each character in the 
%                     format must be one of the following format labels:
%                       - 'S' - spatial 
%                       - 'C' - channel 
%                       - 'B' - batch
%                       - 'T' - time
%                     For more information, see DLARRAY.  
%  'OutputUpsampling' 
%                   - Method for upsampling the output map, specified as
%                     one of the following:
%                       - 'bicubic'. The map is upsampled to the input
%                         data's spatial or time resolution.
%                         For 2-D image and vector sequence input data,
%                         this method uses IMRESIZE using the 'bicubic'
%                         method. For 3-D input data, this method uses
%                         IMRESIZE3 using the 'cubic' method. This produces 
%                         a smooth map the same size as the input data.
%                         This is the default.
%                       - 'nearest'. The map is upsampled to the input 
%                         data's spatial or time resolution with IMRESIZE 
%                         for 2-D image and vector sequence data and
%                         IMRESIZE3 for 3-D data, both using the
%                         'nearest' method. The resulting map reflects the
%                         resolution of the Grad-CAM computation.
%                       - 'none'. The map is not upsampled and can be 
%                         smaller or larger than the size of the input
%                         data.
%                     Upsampling 3-D input data using the 'bicubic' or
%                     'nearest' methods requires Image Processing Toolbox.
%  'ExecutionEnvironment' 
%                   - Execution environment for the network. Hardware 
%                     resources to use to run the computation, specified as 
%                     one of the following: 
%                       - 'auto'. Use a GPU if available, otherwise use the 
%                          CPU. This is the default. 
%                       - 'gpu'. Use the GPU. To use a GPU, you must have 
%                         Parallel Computing Toolbox (TM) and a supported
%                         GPU device. If a suitable GPU is not available, 
%                         the function returns an error.
%                       - 'cpu'. Use the CPU. 
% 
%   Example: 
%      % Load pretrained network 
%       net = googlenet; 
% 
%       % Load image 
%       X = imresize(imread("sherlock.jpg"),[224 224]); 
%       label = "golden retriever"; 
% 
%       % Compute Grad-CAM map
%       map = gradCAM(net,X,label);
%       imshow(X); 
%       hold on;
%       colormap jet;
%       imagesc(map,'AlphaData',0.5); 
% 
%   See also occlusionSensitivity, imageLIME, deepDreamImage

% References: 
%   Selvaraju, Ramprasaath R., et al. “Grad-CAM: Visual Explanations from
%   Deep Networks via Gradient-Based Localization.” International Journal
%   of Computer Vision, vol. 128, no. 2, Feb. 2020, pp. 336–59. arXiv.org,
%   doi:10.1007/s11263-019-01228-7.

% Copyright 2020-2023 The MathWorks, Inc.

narginchk(3,Inf);

factory = deep.internal.viz.gradcam.GradCAMFactory();
try
    [map, featureLayer, reductionLayer] = deep.internal.viz.gradcam.computeGradCAM(factory, varargin{:});
catch err
   throw(err);
end

end
