我在Ubuntu 18上遇到了一个在numpy中分配巨大数组的问题,而在MacOS上没有遇到同样的问题。
我正在尝试为形状为(156816, 36, 53806)
的numpy数组分配内存
np.zeros((156816, 36, 53806), dtype='uint8')
当我在Ubuntu操作系统上遇到错误时
>>> 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上也失败了
8条答案
按热度按时间uajslkp61#
这可能是由于系统的overcommit handling模式所致。
在默认模式下,
0
、启发式过量提交处理。拒绝地址空间的明显过量提交。用于典型系统。它确保严重的胡乱分配失败,同时允许过量提交以减少交换使用。在此模式下,允许根分配稍多的内存。这是默认设置。
这里没有很好地解释所使用的确切启发式算法,但是在Linux over commit heuristic和on this page上对此进行了更多的讨论。
可以通过运行以下命令检查当前的过量使用模式:
在本例中,您将分配
~282 GB,内核说,很明显,我不可能将这么多物理页面提交给它,它拒绝了分配。
如果(以root用户身份)运行:
这将启用“总是过量使用”模式,并且您会发现,无论分配的内存有多大(至少在64位内存寻址范围内),系统都允许您进行分配。
我在一台内存为32 GB的机器上测试了这个方法。在过量使用模式
0
下,我也得到了一个MemoryError
,但在将它改回1
后,它就工作了:然后你可以继续写数组中的任何位置,系统只会在你显式地写那个页面时才分配物理页面,所以你可以小心地把它用于稀疏数组。
fcg9iug32#
我在Windows上遇到了同样的问题,并遇到了这个解决方案。所以如果有人在Windows中遇到这个问题,我的解决方案是增加pagefile的大小,因为这对我来说也是一个内存过度使用的问题。
Windows 8操作系统
1.在键盘上按Windows键+ X,然后在弹出菜单中单击系统
1.点击或单击高级系统设置。系统可能会要求您输入管理员密码或确认您的选择
1.在“高级”选项卡的“性能”下,单击或单击“设置”。
1.点击或单击高级选项卡,然后在虚拟内存下点击或单击更改
1.清除“自动管理所有驱动器的分页文件大小”复选框。
1.在驱动器[卷标]下,点击或单击包含要更改的页面文件的驱动器
1.点击或单击自定义大小,在初始大小(MB)或最大大小(MB)框中输入新大小(以兆字节为单位),点击或单击设置,然后点击或单击确定
1.重新启动系统
Windows 10操作系统
1.按下Windows键
1.类型系统属性高级
1.单击以管理员身份运行
1.在性能下,单击设置
1.选择高级选项卡
1.选择更改...
1.取消选中自动管理所有驱动器的分页文件大小
1.然后选择“自定义大小”并填入适当的大小
1.按“设置”,然后按“确定”,然后退出“虚拟内存”、“性能选项”和“系统属性”对话框
1.重新启动系统
注意:在这个示例中,我的系统上没有足够的内存来容纳~ 282 GB,但对于我的特定情况,这是可行的。
编辑
从here页面文件大小的建议:
有一个计算正确页面文件大小的公式。初始大小为1.5(1.5)x系统内存总量。最大大小为3(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。
here中需要注意的一些事项:
但是,这并没有考虑其他重要因素和您的计算机所特有的系统设置。同样,让Windows选择要使用的内容,而不是依赖在其他计算机上工作的某些任意公式。
还有:
增加页面文件大小可能有助于防止Windows不稳定和崩溃。但是,硬盘的读/写速度比数据存储在计算机内存中时要慢得多。页面文件越大,硬盘的工作量就越大,导致其他操作运行速度越慢。只有在遇到内存不足错误时,才应增加页面文件大小。而且只是作为暂时的修复。一个更好的解决方案是给计算机增加更多的内存。
ldfqzlk83#
我在Windows上也遇到过这个问题。对我来说,解决办法是从32位版本的Python转换到64位版本的Python。事实上,32位软件就像32位CPU一样,可以访问maximum of 4 GB的RAM(2^32)。因此,如果你有超过4GB的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位(AMD 64)]表示“64位Python”。来源:
lvmkulzt4#
有时,这个错误弹出是因为内核已经达到了它的限制。尝试重新启动内核重做必要的步骤。
yzuktlbb5#
在我的例子中,添加一个dtype属性将数组的dtype更改为一个更小的类型(从float64更改为uint8),将数组大小减小到足以在Windows(64位)中不抛出MemoryError。
自
至
cmssoen26#
将数据类型更改为另一种占用较少内存的数据类型是可行的。
23c0lvtd7#
我在EC2上的docker容器中运行panda时遇到了同样的问题。我尝试了上述通过
sysctl -w vm.overcommit_memory=1
(有关here的更多信息)允许过度使用内存分配的解决方案,但这仍然没有解决问题。我没有深入研究Ubuntu/EC2的内存分配内部机制,而是开始研究并行化DataFrame的选项,并发现使用dask在我的案例中是有效的:
您的里程可能会有所不同,请注意,dask API非常相似,但并不完全像panda/numpy那样(例如,您可能需要根据您对数据所做的操作在某些地方进行一些代码更改)。
kmpatx3s8#
我在尝试600 x600(360 K)的图像大小时遇到了这个问题,我决定减少到224 x224(~ 50 K),内存使用减少了7倍。
X_set = np.array(X_set).reshape(-1 , 600 * 600 * 3)
现在是
X_set = np.array(X_set).reshape(-1 , 224 * 224 * 3)
我希望这能有所帮助