我对numpy的memmap
在使用写时复制(mmap_mode=c
)时如何处理数据更改感到困惑。由于没有任何内容写入磁盘上的原始阵列,因此我希望它必须将所有更改存储在内存中,因此,如果您修改每个元素,则可能会耗尽内存。令我惊讶的是,没有。
我正在尝试减少在共享群集上运行的机器学习脚本的内存使用情况(每个实例占用的内存越少,我可以同时运行的实例越多)。我的数据是非常大的numpy数组(每个> 8 Gb)。我的希望是使用np.memmap
来处理这些具有较小内存(<4Gb可用)的阵列。
但是,每个实例可能会不同地修改数据(例如,每次可能选择不同地规范化输入数据)。这对存储空间有影响。如果我使用r+
模式,则在脚本中规范化数组将永久更改存储的数组。
由于我不需要数据的冗余副本,而只想将原始数据存储在磁盘上,因此我认为我应该使用'c'
模式(写时复制)打开阵列。但是,您的更改又去了哪里?更改是否仅保存在内存中?如果是这样的话,如果我更改了整个阵列,我是否会在小型内存系统上用完内存?
这是我预计失败的测试示例:
在大型内存系统上,创建数组:
import numpy as np
GB = 1000**3
GiB = 1024**3
a = np.zeros((50000, 20000), dtype='float32')
bytes = a.size * a.itemsize
print('{} GB'.format(bytes / GB))
print('{} GiB'.format(bytes / GiB))
np.save('a.npy', a)
# Output:
# 4.0 GB
# 3.725290298461914 GiB
现在,在只有2 Gb内存的计算机上,这将按预期失败:
a = np.load('a.npy')
但这两个将按预期成功:
a = np.load('a.npy', mmap_mode='r+')
a = np.load('a.npy', mmap_mode='c')
问题1:我运行此代码的内存不足,试图修改内存映射的数组(无论r + / c模式如何都失败):
for i in range(a.shape[0]):
print('row {}'.format(i))
a[i,:] = i*np.arange(a.shape[1])
为什么这会失败(尤其是为什么即使在r+
模式下它也可以写入磁盘的情况下也失败)?我以为memmap
只会将数组的一部分加载到内存中?
问题2:当我强制numpy偶尔刷新一次更改时,两种r + / c模式均成功完成了循环。 但是在c
模式下怎么做??我不认为flush()
在c
模式下会做什么?这些更改不会写入磁盘,因此会保留在内存中,但是以某种方式,所有必须超过3Gb的更改不会导致内存不足错误吗?
for i in range(a.shape[0]):
if i % 100 == 0:
print('row {}'.format(i))
a.flush()
a[i,:] = i*np.arange(a.shape[1])
答案 0 :(得分:2)
Numpy在这里没有做任何聪明的事情,只是顺应了内置的memmap
模块,该模块有一个access
参数:
接受以下四个值之一:
ACCESS_READ
,ACCESS_WRITE
或ACCESS_COPY
,以指定只读,直写式或写时复制内存分别。
在linux上,通过使用{p>
mmap
创建一个私有的写时复制映射。更新到 映射对其他映射相同的进程不可见 文件,并且不会传递到基础文件。
关于您的问题
这些更改未写入磁盘,因此保留在内存中,但是某种程度上所有必须超过3Gb的更改不会引起内存不足错误吗?
这些更改可能 写入了磁盘,但没有写入您打开的文件。它们很可能被分页到某个地方的虚拟内存中。