Speeding up data transfer between CPU and GPU

craig.matadeen: <p>Hey guys, based on the topic, I’m not sure if this is possible for my use case but thought I’d ask just in case. I’ve had a read of the few different posts already existing on the forum associated to CPU &lt;==&gt; GPU memory transfer speeds but they don’t seem particularly applicable to my scenario, e.g.</p>
<ul>
<li><a href="https://discuss.pytorch.org/t/how-to-maximize-cpu-gpu-memory-transfer-speeds/173855/6" class="inline-onebox">How to maximize CPU &lt;==&gt; GPU memory transfer speeds? - #6 by aifartist</a></li>
<li><a href="https://discuss.pytorch.org/t/data-transfer-slow-from-gpu-to-cpu/208262" class="inline-onebox">Data Transfer slow from gpu to cpu</a></li>
<li><a href="https://pytorch.org/tutorials/intermediate/pinmem_nonblock.html" class="inline-onebox" rel="noopener nofollow ugc">A guide on good usage of non_blocking and pin_memory() in PyTorch — PyTorch Tutorials 2.4.0+cu121 documentation</a></li>
</ul>
<p>Pinned memory seems like it can increase the speed but I’m not really sure if it’s applicable to my scenario.</p>
<p>The following is a general python-based pseudocode of the process.</p>
<pre><code class="lang-auto">model = load_model().to("cuda")
tokeniser = load_tokeniser()

while True:
	data = fetch_from_postgres()

	if not data:
		break

	encoded_input = tokeniser(data).to("cuda")
	
	with torch.no_grad():
		# model output is m * n tensor;
		model_output = model(**encoded_input)

	# convert tensors to list to write to database;
	embeddings = [tensor.tolist() for tensor in model_output]

	write_to_postgres(embeddings)
</code></pre>
<p>Basically I’m reading text records from a postgres database, converting those records to embeddings and writing back the embeddings to the postgres database. I’ve benchmarked different sections of the code to try and understand where most of the batch times are and they seem to be mainly due to moving data from the GPU to the CPU with the tensor.tolist() function. I’ve done some benchmarks with moving the model_output.to(“cpu”) before the tensor.tolist() and noticed that the bulk of the time moves from the tensor.tolist() and to model_output.to(“cpu”).</p>
<p>In terms of machine specifications it’s as follows:</p>
<p>CPU: 20 vCores<br>
RAM: 128 GB<br>
GPU: 46 GB</p>
<p>In terms of times, the different blocks of codes observed are on average:</p>
<p>fetch_from_postgres: &lt; 1s<br>
encode_input: &lt; 1s<br>
model_output: &lt; 1s<br>
tensor.tolist() for m items: ~20s<br>
write_to_postgres: &lt;2s</p>
<p>Any ideas on if the embeddings process can be sped up or if it’s just something I’ll have to put up with in regards to data transfer speeds between the CPU and GPU?</p>

ptrblck: <aside class="quote no-group" data-username="craig.matadeen" data-post="1" data-topic="210120">
<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/craig.matadeen/48/73020_2.png" class="avatar"> craig.matadeen:</div>
<blockquote>
<p>I’ve benchmarked different sections of the code to try and understand where most of the batch times are and they seem to be mainly due to moving data from the GPU to the CPU with the tensor.tolist() function. I’ve done some benchmarks with moving the model_output.to(“cpu”) before the tensor.tolist() and noticed that the bulk of the time moves from the tensor.tolist() and to model_output.to(“cpu”).</p>
</blockquote>
</aside>
<p>The explicit <code>.cpu()</code> call or the implicit data transfer to the host via <code>.tolist()</code> will synchronize your code and will thus accumulate the GPU execution time of already scheduled kernels. To properly profile kernels you would need to synchronize the device before starting and stopping host timers.</p>

craig.matadeen: <p>Thanks for the response. From this I realised that the time is mainly in the embeddings generation  section and that I was timing the different sections incorrectly.</p>