How to reverse gradient sign during backprop?

hadaev8: <p>For example, I have models net0 and net1 working like this</p>
<pre><code class="lang-auto">out0 = net0(inp0)
out1 = net0(net1(net0(inp1)))
loss = criterion(out0, out1, target)
</code></pre>
<p>I want to reverse the gradient sign from the output of model net1 but calculate net0(inp0) as usual.</p>
<p>In simple case, I would do</p>
<pre><code class="lang-auto">out0 = net0(inp0)
out1 = net0(net1(inp1))
loss = criterion(out0, out1, target)
loss.backward()
[p.grad.data.neg_() for p in net1.parameters()]
opt.step()
</code></pre>
<p>Can I do some hook to reverse gradients from output of net1?</p>

JuanFMontesinos: <pre><code class="lang-auto">loss = -criterion(out0, out1, target)
</code></pre>

hadaev8: <p>Its not my case, i want to reverse partially and from one branch.</p>

JuanFMontesinos: <p>Oh sorry I tend to read partially <img src="https://discuss.pytorch.org/images/emoji/apple/smiley.png?v=10" title=":smiley:" class="emoji" alt=":smiley:"><br>
The approach you are following is the simplest one IMO. In fact when you call backward you can see an iterative process like that so I don’t think it would have the performance.</p>
<p>Still you can use <a href="https://pytorch.org/docs/stable/generated/torch.nn.Module.html?highlight=register_backward_hook#torch.nn.Module.register_full_backward_hook" class="inline-onebox" rel="noopener nofollow ugc">Module — PyTorch 1.10.0 documentation</a></p>
<p><code>register_full_backward_hook</code></p>

hadaev8: <p>My solution will work in simple case without using net0 two times.<br>
I will check docs, thanks.</p>

KFrank: <p>Hi Had!</p>
<aside class="quote no-group" data-username="hadaev8" data-post="1" data-topic="134810" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/hadaev8/48/16280_2.png" class="avatar"> hadaev8:</div>
<blockquote>
<p>I want to reverse the gradient sign from the output of model net1 but calculate net0(inp0) as usual.</p>
</blockquote>
</aside>
<p>As an alternative to using a hook, you could write a custom <a href="https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function" rel="noopener nofollow ugc">Function</a><br>
whose <code>forward()</code> simply passes through the tensor(s) unchanged, but<br>
whose <code>backward()</code> flips the sign of the gradient(s).</p>
<p>You would then insert it at the desired place in your network, e.g.:</p>
<pre data-code-wrap="python"><code class="lang-python">out1 = net0 (GradientReversalFunction.apply (net1 (inp1)))
</code></pre>
<p>I don’t really have an opinion about which method is cleaner.</p>
<p>Best.</p>
<p>K. Frank</p>

hadaev8: <p>Much cleaner with function, because I can’t find tutorials or examples of hook use.<br>
So I need to apply the function on the output tensor and all previous calculations will be with reversed gradients, right?</p>
<p>Also, while googling function, I found this example</p>
<pre><code class="lang-auto">-x + (x*2).detach()
</code></pre>

JuanFMontesinos: <p>Hi,<br>
here you ahve a tutorial <a href="https://blog.paperspace.com/pytorch-hooks-gradient-clipping-debugging/" class="inline-onebox" rel="noopener nofollow ugc">Debugging and Visualisation in PyTorch using Hooks</a> which looks nice.<br>
Here you have a tutorial about how to modify the backward function:<br>
<a href="https://pytorch.org/docs/master/notes/extending.html" class="inline-onebox" rel="noopener nofollow ugc">Extending PyTorch — PyTorch master documentation</a></p>

hadaev8: <p>Thanks a lot you both</p>