albermax / albermax/innvestigate

Implementing Contrastive Layer-wise Relevance Propagation

Open
#137 25 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
1.3k
Forks
230
PR merge metrics
No merged PRs in 30d

Description

I'm trying to implement CLRP[1] for a binary classifier based on VGG using innvestigate, but I'm not getting the expected results.

In case you are unfamiliar with CLRP, it's an adaptation of Layer-wise Relevance Propagation with the goal of make the output saliency map (more) class-discriminative. In order to do this the relevance of the desired class is calculated as follows:

The paper proposes two similar but different ways of defining **R***CLRP*:

1. **R***CLRP* = LRP(X, W_overline, S_y_j) where W_overline is {W_1, W_2, ..., W_(L-1), -1 * W_L_j} or in words, all the weights are the same as for the normal concept except for the output layer where the weight of the node representing the target class is negated.

2. **R***CLRP* = max(0, **R** - **R***dual*)
**R***dual* = LRP(X W_overline, S_y_j). Here W_overline is define as {W_1, W_2, ..., W_(L-1), W_L{-j}} where W_L{-j} means the weights connected to the output layer excluding the j-th neuron.

Since I'm working with binary classification, both methods should be rather easy to implement.

Method 1:

analyzer = innvestigate.create_analyzer(rule, model_wo_sm, neuron_selection_mode="index")
model_wo_sm_clrp0 = keras.models.clone_model(model_wo_sm)
model_wo_sm_clrp1 = keras.models.clone_model(model_wo_sm)
weights = model_wo_sm.get_weights()
for i, m in enumerate([model_wo_sm_clrp0, model_wo_sm_clrp1]):
w = weights.copy()
neg = np.ones(len(w[-1]))
neg[i] *= -1
w[-1] *= neg
m.set_weights(w)

clrp_analyzer = innvestigate.create_analyzer(rule, model_wo_sm_clrp1, neuron_selection_mode="index")
R = analyzer.analyze(X, 0)
R_dual = clrp_analyzer.analyze(X, 1)
R_clrp = np.clip(R - R_dual, a_min = 0, a_max = None)

And method 2:

analyzer = innvestigate.create_analyzer(rule, model_wo_sm, neuron_selection_mode="index")
R = analyzer.analyze(X, 0)
R_dual = analyzer.analyze(X, 1)
R_clrp = np.clip(R - R_dual, a_min = 0, a_max = None)

But for both methods `R_clrp` is very close to zero. When I normalize the values of `R_clrp` between 0 and 1 and plot the result is similar to that of the paper. However if I flip the selected neurons/class I get an all zero output.

Upon further research I noticed that for the second method `R` and `R_dual` are both negative and very small.

min max
R -0.0012369031 -4.169839e-09
R_dual -0.002584224 -8.481891e-09

So my **questions are**: is the returned value of the `analyze` method the relevance or am I mistaken in that assumption? And if that is correct, then why would the relevance be so small and negative?

Cheers!

[1]

@article{gu2018understanding,
title={Understanding Individual Decisions of CNNs via Contrastive Backpropagation},
author={Gu, Jindong and Yang, Yinchong and Tresp, Volker},
journal={arXiv preprint arXiv:1812.02100},
year={2018}
}

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.