无法分配具有形状和数据类型的数组
- 2024-12-18 08:38:00
- admin 原创
- 163
问题描述:
我在 Ubuntu 18 上的 numpy 中分配巨大数组时遇到问题,而在 MacOS 上没有遇到同样的问题。
我正在尝试为形状(156816, 36, 53806)
为
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 上也失败了
解决方案 1:
这可能是由于您的系统的过度提交处理模式造成的。
在默认模式下0
,
启发式过量使用处理。拒绝明显的地址空间过量使用。用于典型系统。它确保严重的分配失败,同时允许过量使用以减少交换使用。在此模式下,根可以分配稍多的内存。这是默认设置。
这里没有很好地解释所使用的确切启发式方法,但在 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:
我在 Windows 上也遇到了同样的问题,并找到了这个解决方案。所以如果有人在 Windows 中遇到这个问题,对我来说,解决方案就是增加页面文件大小,因为对我来说这也是一个内存过量使用的问题。
Windows 8
在键盘上按 WindowsKey + X,然后在弹出菜单中单击系统
点击或单击“高级系统设置”。系统可能会要求你输入管理员密码或确认你的选择
在“高级”选项卡上的“性能”下,点击或单击“设置”。
点击或单击“高级”选项卡,然后在“虚拟内存”下点击或单击“更改”
清除“自动管理所有驱动器的分页文件大小”复选框。
在“驱动器 [卷标]”下,点击或单击包含要更改的页面文件的驱动器
点击或单击“自定义大小”,在“初始大小 (MB)”或“最大大小 (MB)”框中输入新大小(以兆字节为单位),点击或单击“设置”,然后点击或单击“确定”
重新启动系统
Windows 10
按下 Windows 键
类型 SystemPropertiesAdvanced
单击以管理员身份运行
在“性能”下,单击“设置”
选择“高级”选项卡
选择更改...
取消选中自动管理所有驱动器的分页文件大小
然后选择自定义尺寸并填写合适的尺寸
按“设置”,然后按“确定”,然后退出虚拟内存、性能选项和系统属性对话框
重新启动系统
注意:在这个例子中,我的系统上没有足够的内存来容纳~282GB,但对于我的特定情况,这是可行的。
编辑
以下是针对页面文件大小的建议:
有一个公式可以计算正确的页面文件大小。初始大小是系统总内存量的 1.5 倍。最大大小是初始大小的 3 倍。假设您有 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 不稳定和崩溃。但是,硬盘的读写时间比数据在计算机内存中时要慢得多。较大的页面文件会增加硬盘的额外工作量,导致其他所有东西运行得更慢。只有在遇到内存不足错误时才应增加页面文件大小,并且只能作为临时解决方案。更好的解决方案是向计算机添加更多内存。
解决方案 3:
我在 Windows 上也遇到了这个问题。对我来说,解决方案是从 32 位切换到 64 位版本的 Python。事实上,32 位软件(如 32 位 CPU)最多可以处理 4 GB的 RAM(2^32)。因此,如果您的 RAM 超过 4 GB,则 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”。
资料来源:
Quora-大型numpy数组产生的内存错误
Stackoverflow:32 位或 64 位版本的 Python
解决方案 4:
就我而言,添加 dtype 属性将数组的 dtype 更改为较小的类型(从 float64 到 uint8),从而将数组大小减小到足以不会在 Windows(64 位)中抛出 MemoryError。
从
mask = np.zeros(edges.shape)
到
mask = np.zeros(edges.shape,dtype='uint8')
解决方案 5:
将数据类型更改为另一种占用较少内存的类型即可。对我来说,我将数据类型更改为 numpy.uint8:
data['label'] = data['label'].astype(np.uint8)
解决方案 6:
我在 EC2 上的 docker contain 中运行 pandas 时遇到了同样的问题。我尝试了上述允许过度使用内存分配的解决方案sysctl -w vm.overcommit_memory=1
(有关更多信息,请参见此处),但这仍然无法解决问题。
我没有深入研究 Ubuntu / EC2 的内存分配内部结构,而是开始研究并行化 DataFrame 的选项,并发现在我的案例中使用dask是可行的:
import dask.dataframe as dd
df = dd.read_csv('path_to_large_file.csv')
...
您的里程可能会有所不同,并请注意 dask API 非常相似,但并不完全像 pandas/numpy(例如,您可能需要根据您对数据的处理在某些地方进行一些代码更改)。
解决方案 7:
我在尝试使用 numpy 时遇到了这个问题,尝试将图像大小设为 600x600(360K),我决定将其缩小到 224x224(~50k),将内存使用量减少了 7 倍。
X_set = np.array(X_set).reshape(-1 , 600 * 600 * 3)
现在是
X_set = np.array(X_set).reshape(-1 , 224 * 224 * 3)
希望这有帮助
解决方案 8:
from pandas_profiling import ProfileReport
prof = ProfileReport(df, minimal=True)
prof.to_file(output_file='output.html')
为我工作
扫码咨询,免费领取项目管理大礼包!