CUDA initialization error when DataLoader with CUDA Tensor

SangWoong_Yoon: <p>My dataset is small, and I want to load all my dataset into GPU memory when a dataset is created. Meanwhile, I still want to use <code>torch.utils.data.DataLoader</code> because of compatibility with other situations where I load my data on the fly.</p>
<p>My short working example is as follows.</p>
<pre><code class="lang-auto">import numpy as np
from torch.utils.data import TensorDataset, DataLoader
import torch

data = np.array([[1,2,3], [4,5,6]])
# I move dataset to GPU first
ds = TensorDataset(torch.Tensor(data).cuda())                                 
dl = DataLoader(ds, batch_size=1, num_workers=1, shuffle=True) 
for x in dl:
    print(x)
</code></pre>
<p>However, it crashes.</p>
<pre><code class="lang-auto">---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
&lt;ipython-input-10-11b3bb8f6574&gt; in &lt;module&gt;
      6 ds = TensorDataset(torch.Tensor(data).cuda())
      7 dl = DataLoader(ds, batch_size=1, num_workers=1, shuffle=True)
----&gt; 8 for x in dl:
      9     print(x)

~/.conda/envs/ml/lib/python3.6/site-packages/torch/utils/data/dataloader.py in __next__(self)
    635                 self.reorder_dict[idx] = batch
    636                 continue
--&gt; 637             return self._process_next_batch(batch)
    638 
    639     next = __next__  # Python 2 compatibility

~/.conda/envs/ml/lib/python3.6/site-packages/torch/utils/data/dataloader.py in _process_next_batch(self, batch)
    656         self._put_indices()
    657         if isinstance(batch, ExceptionWrapper):
--&gt; 658             raise batch.exc_type(batch.exc_msg)
    659         return batch
    660 

RuntimeError: Traceback (most recent call last):
  File "/home/swyoon/.conda/envs/ml/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 138, in _worker_loop
    samples = collate_fn([dataset[i] for i in batch_indices])
  File "/home/swyoon/.conda/envs/ml/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 138, in &lt;listcomp&gt;
    samples = collate_fn([dataset[i] for i in batch_indices])
  File "/home/swyoon/.conda/envs/ml/lib/python3.6/site-packages/torch/utils/data/dataset.py", line 40, in __getitem__
    return tuple(tensor[index] for tensor in self.tensors)
  File "/home/swyoon/.conda/envs/ml/lib/python3.6/site-packages/torch/utils/data/dataset.py", line 40, in &lt;genexpr&gt;
    return tuple(tensor[index] for tensor in self.tensors)
RuntimeError: CUDA error: initialization error
</code></pre>
<p>Is using a DataLoader when all my data is loaded on GPU?<br>
Is the error an intended feature of Pytorch?</p>

SangWoong_Yoon: <p>When I write a custom data loader which simply batches through the <code>TensorDatasest</code>, everything is fine.<br>
Then I guess the problem is the multiprocessing, so I tried <code>num_workers=0</code> which disables multiprocessing in the original <code>DataLoader</code>.<br>
Now it works.</p>

ptrblck: <p>If you would like to use multiple workers in your <code>DataLoader</code>, pass the <code>data</code> tensor as a CPU tensor to <code>TensorDataset</code> and push each batch to the GPU using:</p>
<pre><code class="lang-python">ds = TensorDataset(torch.from_numpy(data))
dl = DataLoader(ds, batch_size=1, num_workers=1, shuffle=True)
for x in dl:
    x = x.to('cuda', non_blocking=True)
</code></pre>
<p>Otherwise multiple CUDA contexts will be initialized yielding your error.</p>

SangWoong_Yoon: <p><a class="mention" href="/u/ptrblck">@ptrblck</a> Thanks for the reply.</p>
<ol>
<li>
<p>Which way would you recommend in terms of performance? The reason why I’m putting all my data to GPU first is to increase the speed.</p>
</li>
<li>
<p>When using <code>non_blocking=True</code>, is it okay not to use <code>pin_memory=True</code> in <code>DataLoader</code>? The <a href="https://pytorch.org/docs/stable/tensors.html#torch.Tensor.cuda" rel="nofollow noopener">torch.Tensor.cuda() doc</a> says <code>non_blocking</code> is effective when the data is in pin memory.</p>
</li>
</ol>

ptrblck: <ol>
<li>
<p>If your data is already on the GPU, you won’t really need multiple workers, since most likely you are just slicing the data and passing the the model (or passing all the data at once). However, this approach uses some of your limited GPU memory, which might be used for e.g. a bigger model etc.</p>
</li>
<li>
<p>The op will be non_blocking, if <code>pin_memory</code> was set to <code>True</code>, so you should do it. I’ve missed that part in my code snippet so thanks for pointing it out. <img src="https://discuss.pytorch.org/images/emoji/apple/wink.png?v=9" title=":wink:" class="emoji" alt=":wink:"></p>
</li>
</ol>

SangWoong_Yoon: <p><a class="mention" href="/u/ptrblck">@ptrblck</a> Now I think everything is clear. Thank you very much!</p>

Even_Oldridge: <p>The above is exactly the same issue I’m running into now.  I’ve got a working version that loads the data into gpu memory without cuda calls (or at least without causing this issue)  via pyarrow.read_parquet and it’s 2.3x faster with 4 workers than it is with 0, despite all of the data being in pinned gpu memory.</p>
<p>Following the <a href="https://pytorch.org/docs/master/notes/multiprocessing.html#sharing-cuda-tensors" rel="nofollow noopener">instructions for multiprocessing best practices</a> I’ve tried to set torch’s multiprocessing start method to spawn (I’ve also tried forkserver) but when I do this I run into invalid device pointer: 0x7f8a8c000000 at /pytorch/aten/src/THC/THCCachingAllocator.cpp:301 exceptions.</p>
<p>If the data is already on GPU I’d expect 0 workers would be fast, but there’s a big performance hit, so much so that it’s not really worth doing from what I can see.  I’m relatively new to multiprocessing so there’s a good chance I’m doing something wrong, and it may just make sense to stick to CPU dataloading to keep the GPU memory available for the model, but I’d love to figure out a more robust solution, particularly in light of in GPU preprocessing options like RAPIDS.</p>

Andreas_Bloch: <aside class="quote no-group" data-username="Even_Oldridge" data-post="7" data-topic="43390">
<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/even_oldridge/48/11504_2.png" class="avatar"> Even_Oldridge:</div>
<blockquote>
<p>s not really worth doing from what I can see. I’m relatively new to multiprocessing so there’s a good chance I’m doing something wrong, and it may just make sense to stick to CPU dataloading to keep the GPU memory available for the model, but I’d love to figure out a more robust solution, particularly in light of in GPU prepro</p>
</blockquote>
</aside>
<p>It doesn’t seem to me that the data will be pre-loaded to the GPU. Also if the next operation depends on the data this doesn’t really gain any performance. Also if we’re moving data back to the CPU the data-loading isn’t overlapped. Is there any way to pre-load the data in the main CUDA context?</p>

pietern: <p>The easiest way to preload all data on GPU is by simply copying it there (<code>Tensor.cuda()</code>) and maintaining a Python list with all samples that you want to process. Then, instead of iterating over a dataset, you iterate over a Python list with pre-existing CUDA tensors. The reasons these multiprocessing data loaders exist are 1) datasets are typically much larger than a single GPU can hold resident in memory, 2) a single CPU cannot preprocess enough examples per second to saturate GPU throughput.</p>