无法分配具有形状和数据类型的数组


116

我在Ubuntu 18上在numpy中分配大型数组时遇到了一个问题,而在MacOS上却没有遇到同样的问题。

我想一个numpy的阵列形状分配内存(156816, 36, 53806) 使用

np.zeros((156816, 36, 53806), dtype='uint8')

当我在Ubuntu OS上遇到错误时

>>> import numpy as np
>>> np.zeros((156816, 36, 53806), dtype='uint8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
numpy.core._exceptions.MemoryError: Unable to allocate array with shape (156816, 36, 53806) and data type uint8

我没有在MacOS上得到它:

>>> import numpy as np 
>>> np.zeros((156816, 36, 53806), dtype='uint8')
array([[[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       ...,

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]],

       [[0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        ...,
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0],
        [0, 0, 0, ..., 0, 0, 0]]], dtype=uint8)

我读过某处np.zeros不应该真正分配数组所需的全部内存,而只分配了非零元素。即使Ubuntu计算机具有64gb的内存,而我的MacBook Pro却只有16gb。

版本:

Ubuntu
os -> ubuntu mate 18
python -> 3.6.8
numpy -> 1.17.0

mac
os -> 10.14.6
python -> 3.6.4
numpy -> 1.17.0

PS:在Google Colab上也失败


1
内存中是否还有其他进程在运行?
BlueRine小号

不,我想topfree -m,这些命令在那里推搡MEM的60GB免费多
马丁Brisiak

嗯。奇怪的。那不应该占用太多内存。它在Macos上占用了多少内存?
BlueRine S

1
不太可能,但您不是碰巧在Ubuntu中运行32位Python解释器,对吗?
jdehesa

1
np.zeros不创建sparse矩阵。填零可能会有延迟。但请参阅stackoverflow.com/q/27464039
hpaulj,

Answers:


115

这可能是由于系统的过量使用处理模式所致。

在默认模式下0

启发式过量使用处理。明显的地址空间过量使用被拒绝。用于典型的系统。它确保严重的野生分配失败,同时允许过量使用以减少交换使用。在此模式下,允许root分配更多的内存。这是默认值。

此处没有很好地解释所使用的确切启发式方法,但是在Linux上,在提交启发式方法本页上对此进行了更多讨论 。

您可以通过运行以下命令检查当前的过量使用模式

$ cat /proc/sys/vm/overcommit_memory
0

在这种情况下,您要分配

>>> 156816 * 36 * 53806 / 1024.0**3
282.8939827680588

约282 GB,并且内核说的很清楚,我无法将这么多物理页提交给它,并且它拒绝分配。

如果(以root用户身份)运行:

$ echo 1 > /proc/sys/vm/overcommit_memory

这将启用“始终过量使用”模式,并且您会发现,无论系统有多大(至少在64位内存寻址中),该系统的确允许您进行分配。

我自己在具有32 GB RAM的计算机上进行了测试。在过量提交模式下,0我还得到了一个MemoryError,但是将其更改回1它可以工作:

>>> import numpy as np
>>> a = np.zeros((156816, 36, 53806), dtype='uint8')
>>> a.nbytes
303755101056

然后,您可以继续写入阵列中的任何位置,并且只有在您明确写入物理页面时,系统才会分配物理页面。因此,您可以谨慎地将其用于稀疏数组。


2
这是Linux内核特有的功能,因此在MacOS上不一定有直接等效的功能,尽管可能类似。我认为在Mac上旋转内核设置并不容易。
Iguananaut

1
@Iguananaut“小心”警告的确切含义是什么?即。在带有GTX 1080 GPU的Ubuntu 18服务器上出现问题的最坏情况是什么?
mLstudent33年

1
@ mLstudent33首先,这与具有自己的内存的GPU无关。我的意思是,您仍然可以填满内存-每次写入内存中的某个页面时,该页面(通常为4k字节)都必须提交给物理内存。因此,最坏的情况是内存不足。
Iguananaut

1
此更改是否立即生效,还是我们需要重新启动Shell或机器本身?
dumbledad

2
它会立即生效,但是如果没有其他措施,它将无法重新启动。搜索其他有关如何最好地将/proc/sys设置持久保存在分发中的问题。
Iguananaut

53

我在Window上遇到了同样的问题,并遇到了这个解决方案。因此,如果有人在Windows中遇到此问题,那么对我来说,解决方案是增加页面文件的大小,因为这对我来说也是内存过量使用的问题。

Windows 8

  1. 在键盘上按WindowsKey + X,然后在弹出菜单中单击“系统”。
  2. 点击或单击高级系统设置。系统可能会要求您输入管理员密码或确认选择
  3. 在“高级”选项卡上的“性能”下,点击或单击“设置”。
  4. 点击或单击“高级”选项卡,然后在“虚拟内存”下,单击或单击“更改”
  5. 清除“自动管理所有驱动器的页面文件大小”复选框。
  6. 在驱动器[卷标签]下,点击或单击包含要更改的页面文件的驱动器
  7. 点击或单击“自定义大小”,在“初始大小(MB)”或“最大大小(MB)”框中输入新的大小(以兆字节为单位),单击或单击“设置”,然后单击或单击“确定”
  8. 重新启动系统

Windows 10

  1. 按Windows键
  2. 类型SystemPropertiesAdvanced
  3. 单击以管理员身份运行
  4. 在性能下,单击设置
  5. 选择高级选项卡
  6. 选择更改...
  7. 取消选中“自动管理所有驱动器的页面文件大小”
  8. 然后选择自定义尺寸并填写适当的尺寸
  9. 按设置,然后按确定,然后从“虚拟内存”,“性能选项”和“系统属性”对话框退出
  10. 重新启动系统

注意:在此示例中,我的系统上没有足够的内存供〜282GB使用,但对于我的特殊情况,此方法有效。

编辑

这里建议的页面文件大小建议:

有一个公式可以计算正确的页面文件大小。初始大小是系统总内存的一半(1.5)x。最大大小为三(3)x初始大小。因此,假设您有4 GB(1 GB = 1,024 MB x 4 = 4,096 MB)的内存。初始大小为1.5 x 4,096 = 6,144 MB,最大大小为3 x 6,144 = 18,432 MB。

这里要记住一些事情:

但是,这没有考虑到计算机可能特有的其他重要因素和系统设置。同样,让Windows选择要使用的内容,而不是依赖于在另一台计算机上工作的任意公式。

也:

页面文件大小的增加可能有助于防止Windows中的不稳定和崩溃。但是,硬盘驱动器的读/写时间比数据存储在计算机内存中的情况要慢得多。页面文件较大将增加硬盘驱动器的工作量,从而导致其他所有文件的运行速度变慢。仅当遇到内存不足错误时才应增加页面文件的大小,并且仅作为临时解决方案。更好的解决方案是向计算机添加更多的内存。


您现在有哪些自定义尺寸(初始尺寸+最大尺寸)设置?不确定为自己分配多少资源
Azizbro,

1
@Azizbro我现在回到了默认值,但只是调整了值,直到内存不足错误消失为止。
递归

我已经完成此操作,但仍然得到MemoryError: Unable to allocate 10.3 PiB for an array with shape (38137754, 38137754) and data type float64
george.adams1年

24

我也在Windows上遇到了这个问题。对我来说,解决方案是从32位版本的Python切换到64位版本的Python。的确,像32位CPU这样的32位软件最多可以分配4 GB的RAM(2 ^ 32)。因此,如果您拥有超过4 GB的RAM,则32位版本将无法利用它。

使用64位版本的Python(在下载页面中标记为x86-64的版本),问题就消失了。

您可以通过输入解释器来检查您拥有哪个版本。我具有64位版本,现在具有: Python 3.7.5rc1 (tags/v3.7.5rc1:4082f600a5, Oct 1 2019, 20:28:14) [MSC v.1916 64 bit (AMD64)],其中[MSC v.1916 64位(AMD64)]表示“ 64位Python”。

:为写这篇文章(2020年5)时,matplotlib是不可用的python39,所以我安装推荐python37,64位。

资料来源:


1
如何输入口译员?
莎燕

也解决了我的问题。使用Pycharm。卸载32位版本,重新安装64位版本,将项目解释器更改为新的64位python。
詹森目标

3

在我的情况下,添加dtype属性会将数组的dtype更改为较小的类型(从float64到uint8),减小数组的大小足以不会在Windows(64位)中引发MemoryError。

mask = np.zeros(edges.shape)

mask = np.zeros(edges.shape,dtype='uint8')


1

将数据类型更改为另一种使用较少内存的数据。对我来说,我将数据类型更改为numpy.uint8:

data['label'] = data['label'].astype(np.uint8)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.