Code and memory optimization

username: pierremrg
cooked: <p>Hi all,</p>
<p>I have developed a tracking system which operates on video. I also have strong constraints about embeddability (my code needs to run on small cards/CPUs) and the tracker must be real time. Thus, I spend a lot of time to optimize my code, using torch functions and doing as many operations as possible on GPU.</p>
<p>But there is a point not clear to me: I am not sure when data is exchanged between CPU and GPU, and how memory is exactly managed. For instance:</p>
<pre><code class="lang-python">a = torch.tensor([1, 2, 3]).float().cuda() # tensor a will be on GPU
b = a + 1 # tensor b will also be on GPU
c = len(a) # tensor c will still be on GPU
</code></pre>
<p>Few questions about these basic operations:</p>
<ul>
<li>On line 1, does the <code>.float()</code> function make a copy of <code>a</code> in memory?</li>
<li>On line 2, does the <code>+</code> operation copy the data of <code>a</code> to the CPU, then compute the result, then send the data back to the GPU? Or is torch intelligent enough to make the addition directly on the GPU? Is it always better to use the <code>.add()</code> torch function?</li>
<li>Do functions such as <code>len()</code> make a copy of the tensor on the CPU before counting?</li>
</ul>
<p>And finally, is there a difference between these two lines:</p>
<pre><code class="lang-python">a = torch.tensor(1.).cuda().add_(1.)
a = torch.tensor(1.).cuda().add_(torch.tensor(1.).cuda())
</code></pre>
<p>Thank you in advance, any help will be very appreciated! <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>

username: albanD
cooked: <aside class="quote no-group" data-username="pierremrg" data-post="1" data-topic="121530">
<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/p/b2d939/48.png" class="avatar"> pierremrg:</div>
<blockquote>
<p><code>c = len(a) # tensor c will still be on GPU</code></p>
</blockquote>
</aside>
<p><code>c</code> is not a Tensor here but a python number. And as such it will be on the CPU.</p>
<p>For you other questions:</p>
<ul>
<li><code>.float()</code> makes a full copy if the given Tensor is not of floating type, otherwise it returns the input as-is</li>
<li>All operations on GPU Tensors will happen on GPU. <code>+</code> or <code>add()</code> are the same thing so you can use either.</li>
<li><code>len()</code> returns a python number. So the result will always be on CPU (as python number cannot be on GPU). And it returns the size of the first dimension, which doesn’t need access to the content of the Tensor, only its metadata, which are read on the CPU side.</li>
<li>The two lines are very similar. The first one is preferable as a single plain number can be sent as an argument to the GPU kernel which will be faster than creating a full Tensor containing a 1. and send that to the GPU.</li>
</ul>
<p>Some other pointers for perf:</p>
<ul>
<li>PyTorch will <em>never</em> copy the content of a Tensor between device for you. Only when you call .cuda() or .cpu(), etc where a copy will happen.</li>
<li>It is better to create the Tensor you want on the right device directly to avoid extra copies: <code>torch.tensor([1, 2, 3]).float().cuda()</code> should be <code>torch.tensor([1, 2, 3], dtype=torch.float, device="cuda")</code></li>
</ul>

username: pierremrg
cooked: <p>That is perfectly clear. Thank you very much for your quick answer!</p>