gpt4 book ai didi

python - 在 PyTorch 中固定内存实际上更慢?

转载 作者:行者123 更新时间:2023-12-03 15:14:15 27 4
gpt4 key购买 nike

我想知道为什么在 PyTorch 中固定内存会使事情变得更慢。通过阅读torch.utils.data.dataloader的代码,我找到了pin_memory=True DataLoader 的选项只需调用.pin_memory()在每批退货之前。返回的张量仍在 CPU 上,我必须调用 .cuda(non_blocking=True)在此之后手动。因此,整个过程将是

for x in some_iter:
yield x.pin_memory().cuda(non_blocking=True)

我将其性能与

for x in some_iter:
yield x.cuda()

这是实际的代码

a = torch.rand(1024, 655360)

%%time
for i in a:
i.pin_memory().cuda(non_blocking=True)
# CPU times: user 1.35 s, sys: 55.8 ms, total: 1.41 s
# Wall time: 396 ms

%%time
for i in a:
i.pin_memory().cuda()
# CPU times: user 1.6 s, sys: 12.2 ms, total: 1.62 s
# Wall time: 404 ms

%%time
for i in a:
i.cuda(non_blocking=True)
# CPU times: user 855 ms, sys: 3.87 ms, total: 859 ms
# Wall time: 274 ms

%%time
for i in a:
i.cuda()
# CPU times: user 314 ms, sys: 12 µs, total: 314 ms
# Wall time: 313 ms

结果, 不固定内存使用更少的 CPU 时间,并且在实际时间方面更快 .固定内存不应该使数据传输异步并因此更快吗?如果不是这样,我们为什么要做引脚内存?

PS。我想过钉住整个 TensorDataset的可能性提前(而不是每次都固定批处理)。但这不能固定大于 GPU 内存的张量:

a = np.memmap('../dat/R/train.3,31,31B', '3,31,31B', 'r')
a.nbytes // 2**30
## 68

torch.from_numpy(a).pin_memory()
## ---------------------------------------------------------------------------
## RuntimeError Traceback (most recent call last)
## <ipython-input-36-d6f2d74da8e7> in <module>
## ----> 1 torch.from_numpy(a).pin_memory()
##
## RuntimeError: cuda runtime error (2) : out of memory at /tmp/pip-req-build-58y_cjjl/aten/src/THC/THCCachingHostAllocator.cpp:296

如果我确实想固定一个小张量,为什么不直接将整个张量提前移动到 GPU 内存中呢?

最佳答案

TL:博士
您的代码较慢,因为您每次调用生成器时都会分配一个新的固定内存块。每次分配新内存都需要每次同步,这使得它比非固定内存慢得多。很可能,您正在测量此开销。
您在编辑中的代码示例在 THCCaching 中失败。 主持人 Allocator.cpp .这不是 GPU 内存不足,而是您的主机拒绝您分配 68GB 的​​固定物理内存。

Pinning memory is actually slower in PyTorch?


创建或释放固定内存( cudaHostAlloc()/ cudaFreeHost() 通过 CUDA Runtime )比 malloc 慢得多/ free因为它涉及设备(GPU和主机)之间的同步。很可能,您正在测量的是 - 在很大程度上 - 这种开销,因为您正在逐步分配固定内存。

Shouldn't pinning memory make data transfer asynchronous and therefore be faster? If that's not the case, why would we do pin memory?


它可以,但如果您在每次传输之前暂停/加入同步以分配内存,则不能。
固定内存最终的作用是防止内存块被操作系统换出;它保证保留在 RAM 中。这种保证使 GPU 的 DMA 能够在该 block 上运行而无需通过 CPU(其中必须检查数据是否需要换回)。因此,CPU 在此期间可以自由地做其他事情。
这不是一个完美的类比,但您可以将固定内存视为 GPU 和主机之间的共享内存。双方可以在不通知对方的情况下对其进行操作;有点像一个进程中的多个线程。如果您实现非阻塞代码,这可能会快得多。但是,如果聚会结束 join,它也可能会慢得多。一直在 ing。
将此与非固定方法进行对比,其中 CPU 从 RAM 加载数据(必要时交换),然后将其发送到 GPU。它不仅速度较慢(需要通过北桥两次),而且还使线程(因此一个 CPU 内核)保持忙碌。 Python 也有臭名昭著的 GIL,因此可能是您的整个应用程序都在等待同步 I/O。
如果您想使用固定内存将成批数据洗牌到 GPU 中,那么一种方法是将固定内存用作(循环)缓冲区。 CPU 可以从磁盘加载数据,应用预处理,并将批处理放入缓冲区。然后,GPU 可以在自己的时间内从缓冲区中获取批处理并进行推理。如果实现做得好,那么 GPU 就不会闲置过多,主机和 GPU 之间也不再需要同步。

And if I do want to pin a small tensor, why don't I directly move the whole tensor into GPU memory in advance?


如果您不需要从 CPU 访问张量并且它适合 GPU,那么确实不需要将其放入固定内存中。
在您的示例中,您正在打开一个内存映射的 numpy 数组 memmap ,然后要求将其传输到固定内存。内存映射文件的工作方式与分页内存非常相似,因为不再适合 RAM 的数据被刷新到磁盘,并在再次访问时重新加载。
这种“交换”不会发生在固定内存中,因为我们需要保证整个 block 都驻留在 RAM 中。因此,我们需要首先将整个数组加载到主机内存中 - 一个 68 GB 的连续 block - 可能会在此过程中创建数组的副本以不破坏 memmap对象,然后我们需要固定那个内存块,告诉主机将 68GB 的​​托管物理内存交给我们的应用程序。操作系统可以拒绝这两个步骤中的任何一个并引发 OutOfMemory错误。
这几乎就是您所看到的,因为您在 THCCaching 中失败了 主持人 Allocator.cpp .

关于python - 在 PyTorch 中固定内存实际上更慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58741872/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com