Cupy OutOfMemoryError 尝试在内存映射模式下 cupy.load 较大尺寸的 .npy 文件,但 np.load 工作正常

Posted

技术标签:

【中文标题】Cupy OutOfMemoryError 尝试在内存映射模式下 cupy.load 较大尺寸的 .npy 文件,但 np.load 工作正常【英文标题】:Cupy OutOfMemoryError when trying to cupy.load larger dimension .npy files in memory map mode, but np.load works fine 【发布时间】:2020-01-05 02:07:25 【问题描述】:

我正在尝试使用内存映射模式在 cupy 中加载一些较大的 .npy 文件,但我一直遇到 OutOfMemoryError

我认为由于它是在内存映射模式下打开的,因此此操作不应该占用太多内存,因为内存映射实际上并未将整个数组加载到内存中。

我可以用 np.load 加载这些文件就好了,这似乎只发生在 cupy.load 上。我的环境是带有 Tesla K80 GPU 的 Google Colab。它有大约 12 gigs CPU ram、12 gigs GPU ram 和 350 gb 磁盘空间。

这是重现错误的最小示例:

import os
import numpy as np
import cupy

#Create .npy files. 
for i in range(4):
    numpyMemmap = np.memmap( 'reg.memmap'+str(i), dtype='float32', mode='w+', shape=( 10000000 , 128 ))
    np.save( 'reg.memmap'+str(i) , numpyMemmap )
    del numpyMemmap
    os.remove( 'reg.memmap'+str(i) )

# Check if they load correctly with np.load.
NPYmemmap = []
for i in range(4):
    NPYmemmap.append( np.load( 'reg.memmap'+str(i)+'.npy' , mmap_mode = 'r+' )  )
del NPYmemmap

# Eventually results in memory error. 
CPYmemmap = []
for i in range(4):
    print(i)
    CPYmemmap.append( cupy.load( 'reg.memmap'+str(i)+'.npy' , mmap_mode = 'r+' )  )

输出:

0
1
/usr/local/lib/python3.6/dist-packages/cupy/creation/from_data.py:41: UserWarning: Using synchronous transfer as pinned memory (5120000000 bytes) could not be allocated. This generally occurs because of insufficient host memory. The original error was: cudaErrorMemoryAllocation: out of memory
  return core.array(obj, dtype, copy, order, subok, ndmin)
2
3
---------------------------------------------------------------------------
OutOfMemoryError                          Traceback (most recent call last)
<ipython-input-4-b5c849e2adba> in <module>()
      2 for i in range(4):
      3     print(i)
----> 4     CPYmemmap.append( cupy.load( 'reg.memmap'+str(i)+'.npy' , mmap_mode = 'r+' )  )

1 frames
/usr/local/lib/python3.6/dist-packages/cupy/io/npz.py in load(file, mmap_mode)
     47     obj = numpy.load(file, mmap_mode)
     48     if isinstance(obj, numpy.ndarray):
---> 49         return cupy.array(obj)
     50     elif isinstance(obj, numpy.lib.npyio.NpzFile):
     51         return NpzFile(obj)

/usr/local/lib/python3.6/dist-packages/cupy/creation/from_data.py in array(obj, dtype, copy, order, subok, ndmin)
     39 
     40     """
---> 41     return core.array(obj, dtype, copy, order, subok, ndmin)
     42 
     43 

cupy/core/core.pyx in cupy.core.core.array()

cupy/core/core.pyx in cupy.core.core.array()

cupy/core/core.pyx in cupy.core.core.ndarray.__init__()

cupy/cuda/memory.pyx in cupy.cuda.memory.alloc()

cupy/cuda/memory.pyx in cupy.cuda.memory.MemoryPool.malloc()

cupy/cuda/memory.pyx in cupy.cuda.memory.MemoryPool.malloc()

cupy/cuda/memory.pyx in cupy.cuda.memory.SingleDeviceMemoryPool.malloc()

cupy/cuda/memory.pyx in cupy.cuda.memory.SingleDeviceMemoryPool._malloc()

cupy/cuda/memory.pyx in cupy.cuda.memory._try_malloc()

OutOfMemoryError: out of memory to allocate 5120000000 bytes (total 20480000000 bytes)

我还想知道这是否可能与 Google Colab 及其环境/GPU 有关。

为方便起见,这里是这个最小代码的 Google Colab 笔记本

https://colab.research.google.com/drive/12uPL-ZnKhGTJifZGVdTN7e8qBRRus4tA

【问题讨论】:

因此听起来,将任何文件固定在磁盘上都会占用与磁盘上相同数量的 GPU RAM 空间。那么,这是否意味着将 GPU 内存映射数据直接加载到 GPU Ram 中没有优势?如果数据大于 GPU RAM,GPU 保存到磁盘/从磁盘保存的最快方法是什么? 这完全回答了我的问题,如果您将此作为答案提交,我会接受。我正在尝试更多地研究您描述的过程。我用谷歌搜索了“cuda pin memory cpu gpu ram”,但没有人提到(据我所知)固定需要 CPU 而不是 GPU 内存。如果您有针对我的情况特别推荐的来源,请告诉我。 【参考方案1】:

内存映射时磁盘文件的numpy.load 机制可能不需要将整个文件从磁盘加载到主机内存中。

但是,cupy.load 似乎要求整个文件首先适合主机内存,然后是设备内存。

您的特定测试用例似乎正在创建 4 个磁盘文件,每个文件大小约为 5GB。如果您每个都有 12GB,这些将不适合主机或设备内存。因此,如果不是更早的话,我预计第三次文件加载会失败。

您可以将numpy.load 机制与映射内存一起使用,然后通过cupy 操作选择性地将部分数据移动到GPU。在这种情况下,GPU 上的数据大小仍将受限于 GPU RAM,对于像 cupy 数组这样的常见事物。

即使您可以使用 CUDA 固定的“零拷贝”内存,它仍然会被限制为主机内存大小(此处为 12GB)或更小。

【讨论】:

“如果您只是想从磁盘加载数据,则没有必要在 cupy 或 CUDA 中使用此方法。”在我的情况下,我需要同时读取和写入磁盘。通常正常的方法包括阅读。我的案例将在每个训练步骤(其中可能有数十万个)都进行写入和读取,因此该过程需要非常快。我相信我不久前测试了 np.memmap pytorch,发现这个过程太慢了。 好吧,如果您想使用您概述的方法,并且想在该 google colab 实例上执行此操作,请查看是否可以使用 ~5GB 内存而不是 20GB。你基本上没有足够的空间来做 20GB。如果您将 Tesla 卡安装在具有 128GB 主机内存的 GPU 服务器中,这将不成问题。如果您从 google 搜索中阅读过任何讨论,您会发现与普通 GPU 内存分配相比,CUDA 中的固定内存“慢”。 我的情况是我正在训练大型推荐系统,比如 1000 万个项目,每个项目由 128 维嵌入表示。 colab GPU 似乎无法处理这么多参数,因为我在训练期间收到“RuntimeError:CUDA 错误:设备端断言已触发”。因此,虽然我所追求的方法速度较慢,但​​它足够体面,我可以在合理的时间内对我的数据进行训练。 Google Colab 现在还提供 25 GB 的实例,看来您必须先让系统崩溃。多亏了您的洞察力,我才知道要选择这个选项。 我从一位 Cupy 开发人员那里收到了这条消息。 “[Ryosuke Okuta,chainer]CuPy 无法处理 mmap 内存。因此,CuPy 默认直接使用 GPU 内存。docs-cupy.chainer.org/en/stable/reference/generated/… 如果您想使用统一内存,可以更改默认内存分配器。” .你怎么看这个? 我刚刚尝试在顶部使用cupy.cuda.set_allocator(MemoryPool(malloc_managed).malloc) 运行我的代码,但没有发现任何明显的差异

以上是关于Cupy OutOfMemoryError 尝试在内存映射模式下 cupy.load 较大尺寸的 .npy 文件,但 np.load 工作正常的主要内容,如果未能解决你的问题,请参考以下文章

为啥cupy安装过程检测不到Microsoft Visual C++?

在没有 GPU 支持的 MacOS 上安装 cupy

可以在google colab上安装cupy吗?

如何在 Cupy 中使用多个 GPU?

如何正确使用 CuPy 流

Cupy 找不到 CUDA 存储库