Captum: How should I use captum to calculate and visualize Integrated Gradients and Grad Cam on Image Captioning

Created on 1 Apr 2020  路  8Comments  路  Source: pytorch/captum

question

Most helpful comment

Hi @shaunak27, thank you for creating the issue. Note that GradCam is meaningful to apply on models from CNN family (on a convolutional layer).
W.r.t. IG, you can definitely apply on that model. As an output, you can take a token such as 'Giraffes' and attribute it to the pixels of the image. Have you tried something like that ?

All 8 comments

The model consists of a Encoder CNN used to extract features and a decoder Rnn which generated the caption
This is the exact model:
https://github.com/yunjey/pytorch-tutorial/tree/master/tutorials/03-advanced/image_captioning

If you can let me know the process for calculating and visualising Integrated Grads and Grad Cam , it would be very helpful, As I wish to interpret this image captioning model using Captum.
Thanks

Hi @shaunak27, thank you for creating the issue. Note that GradCam is meaningful to apply on models from CNN family (on a convolutional layer).
W.r.t. IG, you can definitely apply on that model. As an output, you can take a token such as 'Giraffes' and attribute it to the pixels of the image. Have you tried something like that ?

@NarineK Thank you very much for your help. Sorry for replying late, I followed the tutorial related to VQA for calculating and visualizing Integrated Gradient with Captum for my Image Captioning Problem.

The model which I have used takes in an image as input and returns a list of indices like [2,14,1,6,8]
which are the indices of words(tokens) from my vocab. So when I used the ig.attribute function as:
```
attributions = ig.attribute(inputs=image_features,baselines=image_features * 0.0,
target = 3, n_steps=30)

When I run this function I get an error : 
> element 0 of tensors does not require grad and does not have a grad_fn

The following is the model that I have used:

class Encodersub(nn.Module):
def __init__(self, embed_size):
"""Load the pretrained ResNet-152 and replace top fc layer."""
super(Encodersub, self).__init__()
resnet = models.resnet152(pretrained=True)
modules = list(resnet.children())[:-1] # delete the last fc layer.
self.resnet = nn.Sequential(*modules)
self.linear = nn.Linear(resnet.fc.in_features, embed_size)
self.bn = nn.BatchNorm1d(embed_size, momentum=0.01)

def forward(self, images):
    """Extract feature vectors from input images."""        
    features = self.resnet(images)
    features = features.reshape(features.size(0), -1)
    features = self.bn(self.linear(features))
    return features

class Decodermain(nn.Module):
def __init__(self, embed_size, hidden_size, vocab_size, num_layers, max_seq_length=20):
"""Set the hyper-parameters and build the layers."""
super(Decodermain, self).__init__()
self.encoder = Encodersub(embed_size)
self.embed = nn.Embedding(vocab_size, embed_size)
self.lstm = nn.LSTM(embed_size, hidden_size, num_layers, batch_first=True)
self.linear = nn.Linear(hidden_size, vocab_size)
self.max_seg_length = max_seq_length

def forward(self, features, captions, lengths):
    """Decode image feature vectors and generates captions."""
    features = self.encoder(features)
    embeddings = self.embed(captions)
    embeddings = torch.cat((features.unsqueeze(1), embeddings), 1)
    packed = pack_padded_sequence(embeddings, lengths, batch_first=True) 
    hiddens, _ = self.lstm(packed)
    outputs = self.linear(hiddens[0])
    return outputs

def sample(self, features, states=None):
    """Generate captions for given image features using greedy search."""
    sampled_ids = []
    features = self.encoder(features)
    inputs = features.unsqueeze(1)
    for i in range(self.max_seg_length):
        hiddens, states = self.lstm(inputs, states)          # hiddens: (batch_size, 1, hidden_size)
        outputs = self.linear(hiddens.squeeze(1))            # outputs:  (batch_size, vocab_size)
        _, predicted = outputs.max(1)                        # predicted: (batch_size)
        sampled_ids.append(predicted)
        inputs = self.embed(predicted)                       # inputs: (batch_size, embed_size)
        inputs = inputs.unsqueeze(1)                         # inputs: (batch_size, 1, embed_size)
    sampled_ids = torch.stack(sampled_ids, 1)                # sampled_ids: (batch_size,max_seq_length)

    return sampled_ids

`` Also I have used sample as my forward_func in Integrated Grad. as: ig = IntegratedGradients(model.sample)`
where model = Decodermain()
I would be really grateful If you could help me here.
Thank you

@NarineK Any Issue in my Code that might result into this error?

@NarineK It would be great If you could help me with this one, as I am not sure which part of my code is responsible for this error. Thanks !

Hi @shaunak27 , I took a quick look at your code, the issue is that you cannot take gradients with respect to argmax indices. You would instead need to attribute with respect to the output probability of the token, rather than the token index. To do this, you should modify your model to also store the score of the top token, e.g.
score, predicted = outputs.max(1)
and return the stacked scores. You will then be able to attribute with respect to the corresponding score.

Hi @vivekmig , Thank you so much for advice, It worked perfectly after incorporating the change that use suggested. Really grateful for your help.

Great, I'm glad it worked!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AvantiShri picture AvantiShri  路  5Comments

kmario23 picture kmario23  路  4Comments

elboyran picture elboyran  路  5Comments

yangfantrinity picture yangfantrinity  路  5Comments

asalimih picture asalimih  路  5Comments