Assign variable to model parameter

username: antspy
cooked: <p>Hello,</p>
<p>I have a trained model with some parameters.</p>
<p>What I would like to do is to assign to some of those parameters variables that I create, so that I can backpropagate through the variables.</p>
<p>Up until now I have done something like</p>
<pre><code>for p in model.parameters():
    p.data = #whatever
</code></pre>
<p>But now this won’t work because the backpropagation will not function this way. I need to do something like</p>
<pre><code>myParameter = functionToBackward(parameterToSubstitute)
module.parameterToSubstitute = myParameter
l = loss(module.forward(input))
l.backward()
#use gradient on myParameter
</code></pre>
<p>How can I achieve this? Also note that I want to substitute every parameter in the model, so I would like something that works with a for loop or something</p>
<p>thank you!</p>

username: antspy
cooked: <p>Update: I have found something that almost works, namely:</p>
<pre><code>for name, parameter in self.named_parameters():
    newParam = myFunction(parameter)
    setattr(self, name, newParam)
</code></pre>
<p>The issue now is that setattr does not work, as it complains that newParam is a Variable as opposed to a Parameter. I guess that even if we pass a Parameter to a function, the result is always a variable. How can I then set the parameter equal to the variable?</p>
<p>Doing something like nn.Parameter(newParam.data) clearly won’t work, because we won’t be able to backpropagate the gradients through myFunction. What do you suggest?</p>

username: fmassa
cooked: <p>Have a look at the answer in <a href="https://discuss.pytorch.org/t/why-cant-model-parameters-be-variables/6153/2?u=fmassa">Why can't model parameters be variables?</a><br>
Let me know if something is not clear</p>

username: antspy
cooked: <p>Hi,</p>
<p>thanks for your answer. But I am not sure how to use the functional interface in my case.<br>
I have a certain trained model; now I want to modify its weights in a certain way (using a function with learnable parameters) and be able to backpropagate to optimize the parameters of the function that modify the weights.</p>
<p>Is there a “clean” way to achieve this? The “dirty” option, if I am not mistaken, would be to call backward() manually; so doing something like</p>
<pre><code>for p in self.parameters():
    p.data = myFunction.forward(p.data)

loss.backward()

for p in self.parameters():
    p.grad.data = myFunction.backward(p.grad.data)
</code></pre>
<p>I am not sure this would work though. What do you think?</p>

username: fmassa
cooked: <p>Suppose you have your trained model <code>m</code> with a convolution layer <code>m.conv</code>, which contains a <code>weight</code> and a <code>bias</code>.<br>
You want to perform some function on the <code>weight</code> and <code>bias</code>, and be able to backprop through it.<br>
Consider the following snippet in the <code>forward</code> of your model:</p>
<pre><code class="lang-python">class Model(nn.Module):
    # define init etc
    def forward(self, input):
        new_weight = self.net_weight(self.conv.weight, input)
        new_bias = self.net_bias(self.conv.bias, input)
        result = F.conv2d(input, self.conv.weight, self.conv.bias, stride)
        return result
</code></pre>
<p>Note that instead of using <code>result = self.conv(input)</code>, I used the functional interface of it in its weight and bias.</p>

username: antspy
cooked: <p>Thank you for your answer! I was looking for something a little more general though. In your example if I want to modify the weights of a certain model (and use backward() on them) I need to rewrite the whole model using the functional interface.</p>
<p>If all I take in input is the model itself and treat it like a black box, I can’t do that; and since I can’t assign variables to the model parameters, I will have to do it using forward() and backward() manually</p>

username: fmassa
cooked: <p>Not necessarily. You can write a <code>nn.Module</code> class for your operation and reuse it, e.g., <a href="https://github.com/szagoruyko/diracnets/blob/master/diracconv.py#L15-L41">https://github.com/szagoruyko/diracnets/blob/master/diracconv.py#L15-L41</a></p>

username: antspy
cooked: <p>But how will that help? I still can’t assign variables to networks weights, so I can’t backprop through it unless I modify the network to support a functional interface.</p>
<p>I can create a custom module class for my operation, but then what?</p>

username: fmassa
cooked: <p>You don’t want to assign Variables to the network weights. You want the network weights to be <code>Parameters</code>, and you can perform any operation you want on them, using those generated Variables as weights if you want.<br>
Without further information, it’s difficult to understand why the proposed approach is not sufficient.</p>

username: antspy
cooked: <p>" using those generated Variables as weights if you want"</p>
<p>exactly, I want to use them as weights in the same network. Without rewriting the network using the functional interface.<br>
The proposed approach works if I can use the transformed parameters to do my computations, but I can’t do that, because the computations I want to do on them is the ones that the network would do, and there is no way to do that without rewriting the network in functional form.</p>

username: Yunhun_Jang
cooked: <p>Hi, <a class="mention" href="/u/antspy">@antspy</a>. Have you found the solution for this problem? I’m facing exact same issue now. It would be really helpful if you share the solution.<br>
Thanks.</p>

username: antspy
cooked: <p>Hi,</p>
<p>Unfortunately no, I haven’t found a solution.</p>

username: shaform
cooked: <p>I know that convnets could use  F.conv2d, but how about LSTMs, RNNs?<br>
Is there a functional interface for LSTMs?</p>
<p>EDIT: It looks like 2nd order gradients are not supported for LSTMs anyway. So it is of no use to assign weights to LSTMs for now.</p>

username: zhihe_lu
cooked: <p>Hi, thank you for your question. I got the same issue as you. Have you fixed this problem now?</p>

username: Zeeky
cooked: <p>I’m facing the same problem.</p>
<p><code>setattr(self, name, newParam)</code> require a nn.Parameter, but once you convert Variable to nn.Parameter, you lost the gradients creating that Variable.</p>
<p>There must be a way that we can bypass this!</p>
<p>Oh yeah! Re-write all nn.Module layers (using register_buffer) would definitely solve to problem.</p>
<p>But Is it worth?</p>

username: bknyaz
cooked: <p>This is old, but I was able to work around this issue by accessing module attributes using  <code>__dict__</code> instead of <code>setattr</code>:</p>
<pre><code class="lang-auto">some_nn_module.__dict__['weight'] = myFunction(x)
</code></pre>
<p>This requires using <code>self.named_modules()</code> instead of <code>self.named_parameters()</code>, but doesn’t require writing any custom modules or changing existing ones.</p>

username: talesa
cooked: <p>When I first encountered this thread (over a year ago) I was doing some meta-learning, and this (quite recent) library <a href="https://github.com/facebookresearch/higher" rel="nofollow noopener">https://github.com/facebookresearch/higher</a> does exactly what I was trying to achieve, maybe it will help you as well!</p>