Freeing extra memory from intermediate tensors after training

Matt_Gorbett: <p>I’m running a memory report prior to training and after training a single epoch and noticed extra Tensors are being allocated to memory.  Is there any way to get rid of these?   Saving the optimizer and deleting the version in mem helps some, but I cant get rid of these extra tensors that get created as a result of training.  eval() mode doesn’t do it.</p>
<p>I am running the memory report from this link: <a href="https://gist.github.com/Stonesjtu/368ddf5d9eb56669269ecdf9b0d21cbe#file-mem_report-py" class="inline-onebox" rel="noopener nofollow ugc">A simple Pytorch memory usages profiler · GitHub</a></p>
<pre><code class="lang-auto">mem_report()
for epoch in range(1, self.args.epochs + 1):
    epoch_loss = self.train()
    self.train_loss = epoch_loss
    test_loss, test_acc = self.test()
    ...
    mem_report()
</code></pre>
<p>Before training:</p>
<pre><code class="lang-auto">Element type	Size			Used MEM(MBytes)
Storage on GPU
-----------------------------------------------------------------
Parameter		(1024, 784)		3.06
Parameter		(10, 1024)		0.04
-----------------------------------------------------------------
Total Tensors: 813056 	Used Memory Space: 3.10 MBytes

</code></pre>
<p>After training one epoch:</p>
<pre><code class="lang-auto">Element type	Size			Used MEM(MBytes)
Storage on GPU
-----------------------------------------------------------------
Tensor		(1024, 784)		3.06
Tensor		(1024, 784)		3.06
Tensor		(1024, 784)		3.06
Tensor		(10, 1024)		0.04
Tensor		(10, 1024)		0.04
Tensor		(10, 1024)		0.04
Parameter		(10, 1024)		0.04
Parameter		(1024, 784)		3.06
-----------------------------------------------------------------
Total Tensors: 3252224 	Used Memory Space: 12.41 MBytes

</code></pre>

ptrblck: <p>I guess the additional tensors are allocated to store the intermediate forward activations which are needed for the gradient computation. If you don’t want to train your model you can disable it by wrapping the forward pass into a <code>torch.no_grad()</code> or <code>torch.inference_mode()</code> guard.</p>

Matt_Gorbett: <p>Is there any way to free these after training?  In the second call to mem_report above the model is in eval mode, so I don’t need these extra tensors then.<br>
I’m iteratively training many models in a loop and I’m running into memory issues when I try to train a subsequent model because the first model is holding onto these extra tensors. Additionally I’ll need to train each model several times.</p>

ptrblck: <aside class="quote no-group" data-username="Matt_Gorbett" data-post="3" data-topic="172999">
<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/matt_gorbett/48/56453_2.png" class="avatar"> Matt_Gorbett:</div>
<blockquote>
<p>In the second call to mem_report above the model is in eval mode, so I don’t need these extra tensors then.</p>
</blockquote>
</aside>
<p>That’s not the case, since the <code>model.train()</code> and <code>.eval()</code> modes do not influence the gradient calculation, but change the behavior of certain layers (e.g. dropout will be disabled during <code>model.eval()</code>). To disable gradient calculation use the aforementioned guards.</p>

Matt_Gorbett: <p>Thanks a bunch for your help.  These tensors are still showing up in the report. The test method does forward passes on the model.  Same behavior with inference_mode().</p>
<pre><code class="lang-auto">with torch.no_grad():
    test_loss, test_acc = self.test()
    mem_report()
    print(torch.sum(self.model.fc1.weight.grad.abs())) #This is &gt;0
</code></pre>
<p>The grad is one of the tensors in my list that I’m looking to free. This above snippet is after the train code where new tensors get allocated.  Is there any way to automatically free these after training without manually setting each to None?</p>

ptrblck: <p>The intermediate activations which were created during the training will be freed in the <code>backward</code> operation. Gradients (i.e. the <code>.grad</code> attributes of parameters) can be freed by calling <code>.zero_grad(set_to_none=True)</code> on the model or optimizer.</p>

Matt_Gorbett: <p>Deleting the optimizer gets rid of a few of the intermediate tensors in memory, however the weight.grads still exists unless you run <code>.zero_grad(set_to_none=True)</code> after a training loop.  In my case I need to explicitly do both.  Thanks for the help <a class="mention" href="/u/ptrblck">@ptrblck</a></p>