Part XXI — Explainable AI & Model Interpretability · Chapter 3

Grad-CAM

Hook

A saliency map scores every pixel independently — 36 separate numbers for a 6×6 image. Grad-CAM — short for Gradient-weighted Class Activation Mapping — asks a coarser, more targeted question instead: which regions did the convolution layer's own feature map actually rely on, for this specific class?

Intuition
0.00.03.03.00.00.03.03.00.00.03.03.00.00.03.03.0
the conv layer's own 4×4 feature map (after ReLU)

This is the same minimal CNN (short for Convolutional Neural Network)'s 4×4 feature map after ReLU (short for Rectified Linear Unit) — the exact tensor that gets pooled and fed to the dense layer. Grad-CAM reweights this map by how much each of its cells actually mattered to the predicted class, then clips anything left negative to zero.

Formalize

Grad-CAM has two steps. First, weight each feature-map channel by how much it mattered to class cc's logit — averaging that channel's gradient over every spatial location:

αkc=1HWi,jycAijk\alpha_k^c = \frac{1}{HW}\sum_{i,j} \frac{\partial y^c}{\partial A^k_{ij}}
  • αkc\alpha_k^c — the weight for channel kk: how much that channel matters to class cc's logit.
  • H,WH, W — the feature map's height and width, i.e. its number of spatial locations.
  • ycy^c — class cc's logit, the model's raw output score for that class.
  • AijkA^k_{ij} — the feature map's activation for channel kk at spatial location (i,j)(i,j).
  • kk — the index over feature-map channels.
  • cc — the class being explained.

Then combine the channels using those weights, and clip to only the positive evidence:

Grad-CAMc=ReLU ⁣(kαkcAk)\text{Grad-CAM}^c = \text{ReLU}\!\left(\sum_k \alpha_k^c A^k\right)
  • Grad-CAMc\text{Grad-CAM}^c — the final heatmap for class cc: a weighted, positive-only combination of the feature-map channels.
  1. With one filter, one channel weight

    With only one convolution filter, there's just one channel kk, so αc\alpha^c collapses to a single number.

  2. But that number still depends on the class

    That single number still depends on which class cc you ask about, which is exactly what makes Grad-CAM class-discriminative instead of a fixed, class-blind map.

Play
0.00.01.51.50.00.01.51.50.00.01.51.50.00.01.51.5
weight = 0.50 — Grad-CAM for "Edge detected"

Switch classes. The weight flips from +0.5+0.5 to 0.5-0.5 — same feature map, opposite sign — because "Edge detected" and "No edge" read the identical evidence with opposite-signed dense weights. Watch what that does to the CAM itself once ReLU is applied.

Worked example

The feature map is (0033)\begin{pmatrix}0&0&3&3\end{pmatrix} in every one of its 4 rows — the same tied activations from the saliency chapter, one level before pooling:

  1. The channel weight, for each class

    Every 2×2 pooling window here is a 4-way tie (all 00s or all 33s), so nudging any one cell up by ϵ\epsilon makes it that window's new unique max — the pooled output rises by ϵ\epsilon — while nudging it down by ϵ\epsilon leaves the other three tied cells still winning, so the pooled output doesn't move at all. That one-sided response is what the numerical gradient plusminus2ϵ\frac{\text{plus}-\text{minus}}{2\epsilon} picks up:

    • For "Edge detected" (dense weight +1+1 on every flattened position), one cell's plus-side logit rises by 1×ϵ1\times\epsilon while its minus-side logit is unchanged, giving gradient ϵ02ϵ=0.5\frac{\epsilon-0}{2\epsilon}=0.5 for every cell (the same tie-breaking happens in every window). Averaging 16 identical 0.50.5s over all 16 cells just gives back 0.50.5, so αedge=0.5\alpha^{\text{edge}} = 0.5.
    • For "No edge"'s 1-1 dense weight, the same argument gives 0.5-0.5 everywhere instead, so αno edge=0.5\alpha^{\text{no edge}} = -0.5.
  2. Grad-CAM for 'Edge detected'

    ReLU(0.5×(0033))=(001.51.5)\text{ReLU}(0.5 \times \begin{pmatrix}0&0&3&3\end{pmatrix}) = \begin{pmatrix}0&0&1.5&1.5\end{pmatrix} — the two right-hand columns, exactly where the edge evidence lives.

  3. Grad-CAM for 'No edge'

    ReLU(0.5×(0033))=ReLU(001.51.5)=(0000)\text{ReLU}(-0.5 \times \begin{pmatrix}0&0&3&3\end{pmatrix}) = \text{ReLU}\begin{pmatrix}0&0&-1.5&-1.5\end{pmatrix} = \begin{pmatrix}0&0&0&0\end{pmatrix} — completely zero. There's no region of this image that positively supports "no edge," so ReLU throws all of it away.

Checkpoint

Pick the class whose Grad-CAM has no positive evidence anywhere — every cell exactly zero.

0.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.0
pick a class
Pick a class to try it
Summary
αkc=1HWi,jycAijk,Grad-CAMc=ReLU ⁣(kαkcAk)\alpha_k^c = \frac{1}{HW}\sum_{i,j} \frac{\partial y^c}{\partial A^k_{ij}}, \qquad \text{Grad-CAM}^c = \text{ReLU}\!\left(\sum_k \alpha_k^c A^k\right)

Grad-CAM trades saliency's pixel-level precision for something a real, many-channel CNN needs: a way to ask "where, and for which class." In a network with hundreds of filters, most channels are irrelevant to any one class — the weighting step is what picks out the handful that actually matter, before painting a coarse heatmap back onto the image. The next two chapters leave images behind entirely and explain a prediction the same way regardless of what kind of model produced it.