Why don't we use torch.no_grad() when getting validation performance during training?

Addison: <p>I’ve seen posts (such as <a href="https://discuss.pytorch.org/t/model-eval-vs-with-torch-no-grad/19615">this</a> one) where people discuss using no_grad() purely for the purpose of saving memory during inference.</p>
<p>However I was wondering if it makes sense to use it during training? In most setups, including mine, a researcher will train their model for 100 epochs say, and every 10 epochs they’ll do a forward pass on validation data to report loss and/or accuracy. From my understanding, every time you do a forward pass with a torch model (and you are not in a torch.no_grad() block), then gradients will accumulate for the weight tensors of the model, so that when you go to do the backward pass, the gradients are already there and just need to be multiplied.</p>
<p>If this is the case, then doesn’t this mean it is a good idea to use torch.no_grad() whenever we test our validation loss/accuracy? Otherwise, won’t the model’s gradients be impacted by validation data, meaning validation data impacts training?</p>
<p>I’m guessing I’m misunderstanding something about how torch.no_grad() works / how gradients are really computed / stored.</p>
<p>Any clarification would be great! <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=10" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>

ptrblck: <aside class="quote no-group" data-username="Addison" data-post="1" data-topic="134393">
<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/a/49beb7/48.png" class="avatar"> Addison:</div>
<blockquote>
<p>From my understanding, every time you do a forward pass with a torch model (and you are not in a torch.no_grad() block), then gradients will accumulate for the weight tensors of the model, so that when you go to do the backward pass, the gradients are already there and just need to be multiplied.</p>
</blockquote>
</aside>
<p>That’s not quite right. The forward pass will store the intermediate activations, which would be needed to compute the gradients in the backward pass. The backward pass will then accumulate the gradients to each used parameter.<br>
Using <code>with torch.no_grad()</code> will not store the intermediate activations and will thus save memory.</p>
<p>And yes, you are right that <code>no_grad()</code> can and is also used during the validation run (not only when deploying the model) as seen e.g. in the <a href="https://github.com/pytorch/examples/blob/3970e068c7f18d2d54db2afee6ddd81ef3f93c24/imagenet/main.py#L312-L325">ImageNet example</a>. Here you can see that the model is set to <code>eval()</code> first and the validation loop is executed in the <code>no_grad</code> context.</p>

Addison: <aside class="quote no-group" data-username="ptrblck" data-post="2" data-topic="134393">
<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/ptrblck/48/1823_2.png" class="avatar"> ptrblck:</div>
<blockquote>
<p>pass will store the intermediate activations, which would be needed to compute the gradients in the backward pass. The backward pass will then accumulate the gradients to each used parameter.</p>
</blockquote>
</aside>
<p>I see, thank you!</p>
<p>So will the intermediate activations be accumulated or replaced?</p>
<p>In other words, if I did:</p>
<p>model.forward(validation_data)<br>
model.forward(train_data)</p>
<p>And then I proceeded to do a backwards pass and update weights, would the activations from the second forward pass only be used to compute gradients?</p>
<p>Thanks!</p>

ptrblck: <p>The activations are stored in the computation graph so they won’t be accumulated or replaced.<br>
I.e. if <code>train_data</code> is a new input tensor, which is not attached to any computation graph (e.g. from the previous forward pass) and if you compute the loss based on the output of the second pass only, the gradients will use only these intermediate activations.</p>
<p>However, if you reuse a computation graph, Autograd will backpropagate through the entire graph and will use <em>all</em> intermediate activations. This would be the case for e.g. a recursive model where the output is fed as the new input in a loop.</p>