How to get gradients of multiple outputs w.r.t. inputs in LibTorch

lui.bonati: <p>Hi everyone,<br>
I have a model trained in Pytorch, which has been serialized and imported in C++ for inference.<br>
Let’s say the NN has <code>n_in</code> inputs and <code>n_out</code> outputs. For every sample, I would like to access the derivative of all the outputs with respect to the inputs. What I am doing is the following:</p>
<pre><code class="lang-auto">  //define input
  torch::Tensor x = torch::rand( {1,n_in} );
  x.set_requires_grad(true);

  //convert to Ivalue
  std::vector&lt;torch::jit::IValue&gt; inputs;
  inputs.push_back( x );

  //calculate output
  torch::Tensor output = model.forward( inputs ).toTensor();

  //calculate derivatives of every output j with respect to x
  for(unsigned j=0; j&lt;n_out; j++){
    output[0][j].backward();         // 0 because is a batch of size 1
    torch::Tensor der_j = x.grad()
    /*
    ...
    */
  }
</code></pre>
<p>The problem is that in this way the gradients are accumulated into <code>x.grad</code> at each call of <code>output[0][j].backward()</code>. Since I am not using an optimizer I cannot call <code>zero_grad()</code> on it. Should I access the gradient of x after each backward call and manually set to zero? Or are there better ways of doing this?</p>
<p>Thank you,<br>
Luigi</p>

AlbanOdot: <p>Hello.</p>
<p>I was wondering since the C++ API is pretty close to the python one.<br>
Could you try to use the autograd.grad function as described <a href="https://pytorch.org/docs/stable/autograd.html" rel="nofollow noopener">here</a>?</p>
<p>The gradient will be accumulated in the input_vector instead of in your case x.<br>
The input_vector is usually set to “ones” with the shape of the output_vector.</p>

glaringlee: <p><a class="mention" href="/u/lui.bonati">@lui.bonati</a>, I think <a class="mention" href="/u/albanodot">@AlbanOdot</a> is right, please try autograd.grad</p>

lui.bonati: <p>Thank <a class="mention" href="/u/albanodot">@AlbanOdot</a> and <a class="mention" href="/u/glaringlee">@glaringlee</a> for your answers. I will try using the <a href="https://pytorch.org/cppdocs/api/function_namespacetorch_1_1autograd_1a1e03c42b14b40c306f9eb947ef842d9c.html#_CPPv4N5torch8autograd4gradERK13variable_listRK13variable_listRK13variable_listN3c108optionalIbEEbb" rel="nofollow noopener">autograd.grad</a> C++ function.</p>
<p>Another option I figured out is by following the C++ documentation, where is described how <a href="https://pytorch.org/cppdocs/#autograd" rel="nofollow noopener">Autograd</a> works. However, the example reported there is not working since the variable c is not a scalar:</p>
<pre><code class="lang-auto">#include &lt;torch/csrc/autograd/variable.h&gt;
#include &lt;torch/csrc/autograd/function.h&gt;

torch::Tensor a = torch::ones({2, 2}, torch::requires_grad());
torch::Tensor b = torch::randn({2, 2});
auto c = a + b;
c.backward(); // a.grad() will now hold the gradient of c w.r.t. a.
</code></pre>
<p>In order to make this work, one has to call the backward function on each component,e.g.:</p>
<pre><code class="lang-auto">c[0][0].backward()
</code></pre>
<p>and then reset the gradients to obtain with a subsequent backward call the gradients w.r.t. a different output component:</p>
<pre><code class="lang-auto">a.grad().zero_();
</code></pre>
<p>I think the documentation should be updated to deal with the fact that backward on a non-scalar variable is not allowed anymore in LibTorch, since version 1.3 I think, as it was already in the Python version.</p>
<p>Best regards,<br>
Luigi</p>

AlbanOdot: <p>I’m glad you figured it out by yourself <a class="mention" href="/u/lui.bonati">@lui.bonati</a>.<br>
So backward default settings is for a single value tensor.</p>
<pre><code class="lang-auto">c.backward() == c.backward(torch.ones(1))
</code></pre>
<p>If you want to apply it to a vector you might want to pass a parameter in your backward function.<br>
Let’s say x is a tensor correctly setup and with the data you want to use.</p>
<pre><code class="lang-auto">ones = torch.ones_like(x)  # create a tensor full of one with the shape of x
x.backward(ones)
</code></pre>
<p>The <code>ones</code> vector is actually the variable w.r.t you differentiate. So it can be anything else than this.</p>