Update only parameters of choosen neurones in the Backpropagation phase of a Neural Network

ykemiche: <p>I want to update only paramters of choosen neurones(and freeze other neurones parameters) when performing the backpropagation step</p>
<p>How could that be possible since Pytorch rely on automatic differentiation which differentiate over entire layers, not on single parameters/neurons ?</p>
<p>for example I want to freeze the parameters of the green neurones(image below) and update the rest only in the backpropagation phase:</p>
<p><img src="https://discuss.pytorch.org/uploads/default/original/3X/4/8/48182fc8f68d06b67fafbef9491f8a003a9cadf4.png" alt="nn" data-base62-sha1="ahMcfomXzvIG62X5mVuMV8AVqII" width="316" height="326"></p>
<p>Thanks in advance</p>

srishti-git1110: <p>You could try to manually set their <code>requires_grad</code> attribute to False like <a href="https://discuss.pytorch.org/t/how-the-pytorch-freeze-network-in-some-layers-only-the-rest-of-the-training/7088">here</a>.</p>

ykemiche: <p>But I want to freeze some neurones of a layer, not the layer itself</p>

srishti-git1110: <p>Hi,<br>
Please see if this helps:</p>
<pre><code class="lang-auto">import torch
import torch.nn as nn
class Model(nn.Module):
  def __init__(self):
    super().__init__()
    self.fc1 = nn.Linear(2, 4)

  def forward(self, x):
    return self.fc1(x)

net = Model()
old_param = None
for layer in net.children():
  for param in layer.parameters():
    print(param)
</code></pre>
<p>out -</p>
<pre><code class="lang-auto">Parameter containing:
tensor([[ 0.1986,  0.5461],
        [-0.3179,  0.6386],
        [-0.5540,  0.6484],
        [ 0.4686,  0.1718]], requires_grad=True)
Parameter containing:
tensor([ 0.6834,  0.4345,  0.1403, -0.3439], requires_grad=True)
</code></pre>
<p>Update all the parameters once and recover specific nodes, like so:</p>
<pre><code class="lang-auto">for layer in net.children():
  for param in layer.parameters():
    old_param = param.detach().clone() # weight
    break # bias not needed


loss_fn = nn.MSELoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.5)


for epoch in range(1):
  input = torch.tensor([1.0, 20])
  out = net(input)
  target = torch.tensor([15.0, 20, 25, 30])
  loss = loss_fn(out, target)
  loss.backward()
  optimizer.step() # updates all parameters

  # restoring the ones that do not need an update using old_param
  for layer in net.children():
    for param in layer.parameters():
      param.requires_grad = False # required otherwise an in-place error would occur in the next step
      param[2] = old_param[2]
      break

for layer in net.children():
    for param in layer.parameters():
      print(param)

# setting the requires_grad back to True
for layer in net.children():
    for param in layer.parameters():
      param.requires_grad = True
</code></pre>
<p>gives:</p>
<pre><code class="lang-auto">Parameter containing:
tensor([[ 0.6986,  1.0461],
        [ 0.1821,  1.1386],
        [-0.5540,  0.6484],
        [ 0.9686,  0.6718]])
Parameter containing:
tensor([1.1834, 0.9345, 0.6403, 0.1561], requires_grad=True)
</code></pre>
<p>This could easily get messy for a larger model, but this is the only way that I was able to figure out as of now.<br>
Best,<br>
S</p>

ykemiche: <p><a class="mention" href="/u/srishti-git1110">@srishti-git1110</a>  thanks for your reply, but my goal is to save computation by skipping some gradient calculations,and the method you suggested is not the right one for me</p>

ykemiche: <p>Hi <a class="mention" href="/u/ptrblck">@ptrblck</a>, do you think it’s possible to update parameters only of desired neurons(by assuming that some neurones parameters don’t need to be updated…to save computation)?</p>

ptrblck: <aside class="quote no-group" data-username="ykemiche" data-post="5" data-topic="164249">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/letter_avatar_proxy/v4/letter/y/5f8ce5/48.png" class="avatar"> ykemiche:</div>
<blockquote>
<p>but my goal is to save computation by skipping some gradient calculations</p>
</blockquote>
</aside>
<p>I don’t think you will be able to save gradient computation as PyTorch will calculate the gradients for the entire parameter which then needs some additional processing.</p>
<p><a class="mention" href="/u/srishti-git1110">@srishti-git1110</a>’s approach of restoring parameters is valid and also makes sure that optimizers using running stats will work. If you are using simple optimizers which use the gradients only (i.e. no running stats), you might also be able to use gradient hooks and zero out the gradient of the parameter values which should be static.</p>

ykemiche: <p><a class="mention" href="/u/ptrblck">@ptrblck</a> Thanks for your answer,</p>
<p>Is it possible to make a copy of the whole model and run the forward propagation and backpropagation separately as follows:</p>
<p>model A: the original model<br>
model B: the copy of the whole model without the neurons that are at equilibrium which do not need to be updated (obtained using my function).</p>
<p>Following the following steps:</p>
<p>1-run the forward propagation on the model A<br>
2-pass the equivalent parameters to model B<br>
3-run the backpropagation on the model B(using the loss obtained with the model A)<br>
4-pass the equivalent parameters to the model A and repeat the loop</p>
<p>do you think this is possible and will reduce the training time?<br>
do you have a better idea?</p>
<p>Thanks in advance</p>

srishti-git1110: <p>Hi,<br>
Some code would probably help to better understand the steps you laid out.</p>
<p>[For step-3…]<br>
In any case, note that the tensor you call backward on determines which tensors the gradients get calculated for.<br>
That to say, if you call <code>loss.backward()</code>, the grad attribute of only the leaf tensors in the graph of <code>loss</code> shall get populated.</p>
<p>(It’s possible for non-leaf tensors but that isn’t relevant here.)</p>
<p>I’m not sure what you mean by passing the parameters from one model to the other.</p>