Add random layer output as part of final loss

blenderender: <p>Hi<br>
I have a loss function that looks something like this</p>
<p>loss = logits + lambda * get_value_of_random_fc_neuron(neuron_index)</p>
<p>I use forward hooks to get the random neuron value in get_value_of_random_fc_neuron()</p>
<p>The issue is the gradients are same if</p>
<ol>
<li>loss = logits or</li>
<li>loss = logits + lambda * get_value_of_random_fc_neuron(neuron_index)</li>
</ol>
<p>This is because the value of neuron is a tensor without grad_fn assigned. How do i make sure the gradient is calculated for full loss.</p>
<p>Thanks in advance</p>

ptrblck: <p>Could you post the code you are using to select the neuron?<br>
This dummy example seems to work:</p>
<pre><code class="lang-python">lin = nn.Linear(2, 2, bias=False)
x = torch.randn(1, 2)
out = lin(x)
loss = out.mean()
loss.backward()
print(lin.weight.grad)

lin.zero_grad()
out = lin(x)
loss = out.mean() + lin.weight[0, 0]
loss.backward()
print(lin.weight.grad)
</code></pre>
<p>I haven’t tested it on more complicated models, so let me know, what the difference between your code and the example is.</p>

blenderender: <p>Hi <a class="mention" href="/u/ptrblck">@ptrblck</a></p>
<p>Sorry for the confusion. I m looking at model activations and not the model weights.<br>
Heres a sample code of what i m trying to do.</p>
<p><strong>Case 1</strong></p>
<pre><code class="lang-auto">class model(nn.Module):
        def __init__():
              #init model
       def forward(self, x):
             x = self.conv1(x)
             x = self.fc1(x)
            return x


def pick_random_neuron(layer_list, index_list):
    # naive approach. Assume layer list and index list are just plain lists with layer names and corresponding list of number of neurons
    layer_name, index = random.choice((layer_list, index_list))

activation = {}
def get_activation(name):
    def hook(model, input, output):
        activation[name] = output.detach()


model.eval()
input.requires_grad = True # i want to modify input with gradients

for name, layer in model.named_modules():
    handle = layer.register_forward_hook(get_activation(name))

output = model(input)
layer_name, index= pick_random_neuron(layer_list, index_list)

#get activation value, assume conv and fc layers are reshaped to 1d vector

value = activation[layer_name][index]
some_loss = nn.Criterion(output, target)
loss = some_loss + value 
model.zero_grad()
loss.backward()

data_grad = input.grad.data
</code></pre>
<p>Since <code>value</code> is taken from forward hook, there is no grad_fn and <code>value</code> does not play a role in loss and grads calculation for finding gradients to change data. This basically ends up as adding some scalar value at the end to the loss function.</p>
<p>I can solve this problem by changing model forward to output all layers.</p>
<p><strong>Case 2</strong></p>
<pre><code class="lang-auto">
class model(nn.Module):
    def __init__(self):
        # model init
    def forward(self, x):
        x1 = self.conv1(x)
        x2 = self.fc1(x1)
        return x1, x2

x1, x2 = model(input)
layer_name, index= pick_random_neuron(layer_list, index_list)
if layer_name == 'Conv1':
    x1.view(-1)[index]
elif layer_name == 'fc1':
    x2.view(-1)[index]
</code></pre>
<p>Case 2 works. But is there a possiblity to solve this problem using forward hooks as they are more flexible for larger models?</p>

ptrblck: <p>Thanks for the update!<br>
Your forward hook detaches the output.<br>
Could you remove the <code>detach()</code> call and try it again?</p>

blenderender: <p>Hey <a class="mention" href="/u/ptrblck">@ptrblck</a>. Thanks a lot. That worked.</p>