如何分割成块(子矩阵),或处理一个巨大的矩阵,在 numpy 上产生内存错误?

Posted

技术标签:

【中文标题】如何分割成块(子矩阵),或处理一个巨大的矩阵,在 numpy 上产生内存错误?【英文标题】:How to split in chunks (submatrices), or handle a huge matrix giving memory error on numpy? 【发布时间】:2019-07-23 13:49:23 【问题描述】:

我有一个非常大的矩阵,不能简单地放入内存中。我必须使用的矩阵有 483798149136 元素,这意味着 4830 亿个浮点数。

我正在考虑的方法是以某种方式将这个巨大的矩阵拆分为适合内存的不同子矩阵,对这些子矩阵执行pooling 操作,然后将它们全部重新加入以重建希望适合内存的原始矩阵在所有池化操作之后。

如果我错了,请纠正我,这种方法只是我提出的一个想法,它是好是坏,我不知道。如果您有任何更好的替代想法,我愿意接受任何建议。

重现这个矩阵的代码是:

a = np.arange(695556).reshape(834,834)
np.meshgrid(a,a)

我一直在阅读this 帖子和this 帖子,以及同一个站点中的其他帖子,但它们都没有为这类问题提供真正的解决方案,它们只是给出了模糊的建议。

我现在的问题是:

    我的拆分和池化方法是否可行,或者还有其他更好的方法吗?

    我如何(以代码术语)将此矩阵拆分为多个部分(如窗口或多维内核)并稍后重新构建它

    是否有某种方法可以在 numpy 中以块的形式处理矩阵,以便对矩阵层执行操作,例如乘法、加法等...

    Python 中是否有特定的包可以帮助处理此类矩阵问题

编辑

由于一些用户询问我整个操作的目标,我将提供一些信息:

我正在做一个 3D 打印项目。在这个过程中,有一束激光可以熔化金属粉末以制造出复杂的金属件。在这件作品中有层,激光将金属一层一层地熔化。

我有 3 个 csv 文件,每个文件包含一个 834 x 834 的矩阵。第一个矩阵包含激光束穿过粉末床并熔化金属时 X 轴的坐标值,第二个矩阵对于Y 轴,第三个矩阵表示激光在同一像素点熔化的时间。这些值以秒为单位。

所以我有激光穿过 X 和 Y 轴的坐标,以及熔化每个点所需的时间。

此矩阵来自每个制造零件的部分图像。

问题在于,某个像素的温度和激光停留在该像素的时间会影响激光到达该像素时的第 n 个像素。所以我想创建一个距离矩阵,告诉我图像的每个像素在欧几里得距离方面有多么不同或相似。

这就是为什么如果我有例如 2 834 x 834 矩阵,我需要创建一个 695556 x 695556 的矩阵,其中包含矩阵中每个点之间的距离。这就是为什么它如此庞大且无法放入内存的原因。

我不知道我是否提供了太多信息,或者我的解释是否混乱。你可以问你需要什么,我会试着澄清它,但重点是我需要创建这个巨大的距离矩阵,以了解像素之间的数学距离,然后了解发生的事情之间的关系打印时工件的某个点以及在其他点需要做什么以避免制造缺陷。

非常感谢您

【问题讨论】:

您列出了一些不错的选择。对于 1,memmapped 数组允许选择性地加载部分数据。它们以最少的修改处理大多数代码。 3. "numexpr" 与此类似,尽管它旨在提供内存局部性。它不会修复内存不足错误,但使用 memmapped 数组可以很好地工作。 我会避免太多细节,因为我不知道您要解决的确切问题。他们都足够成熟,可以在线拥有良好的文档,(memmap 是 numpy 的一部分,它具有非常全面的文档)我建议从 *** 上的一些问题开始,以了解可能的情况(***.com/search?q=numpy+memmapped) . 虽然如果你的最终输出适合内存,memmapped 数组可能不是最佳选择。它们会引入相当多的磁盘读取开销。 或许了解更多有关您正在研究的算法的信息会有所帮助。有时,NumPy 向量化的方式在内存方面会变得更加昂贵,而 Numba 加速循环可以非常快,同时使用很少的内存。 大家好。该问题已更新,包含有关我的工作和矩阵的额外信息。 【参考方案1】:

毕竟,我找到了解决问题的方法。使用dask 可以轻松处理这个巨大的矩阵。 Dask 是一个 python 库,它允许分布式计算和数据划分成块以优化内存使用。它非常方便,因为它确实允许您以真正的低计算和内存成本处理大量数据,显然,它不如内存计算快,但我认为很多人会很高兴知道这一点。

这个包优化得很好,经常更新。最好的一点是它有 numpy/pandas sintax,它也可以像处理数组一样处理数据帧,如果你知道 pandas/numpy,你会感觉像在家里一样使用 dask。

您可以像这样创建一个 dask 分布式数组:

import numpy as np
import dask.array as da

Y = da.random.normal(size=(695556, 695556),
                         chunks=(1000, 1000))

然后,您可以对其执行一些操作,如下所示:

y = Y.mean(axis=0)[0:100].compute()

此外,如果您使用memory_profilerpackage,您还可以监控您的内存和 CPU 使用情况,并查看您的大量数据消耗了多少内存用于计算。

我发现一些实际示例非常具有说明性here。

另外,这个库中的解释性数组范围可以在here找到。

最后,关于 Python 3.X 中高性能计算的指南here。

希望这对遇到同样问题的人有所帮助。

【讨论】:

以上是关于如何分割成块(子矩阵),或处理一个巨大的矩阵,在 numpy 上产生内存错误?的主要内容,如果未能解决你的问题,请参考以下文章

使用python(numpy memmap,pytables或其他?)对巨大矩阵进行快速下采样

任何 DBMS 都可以发送/接收巨大的矩阵吗?

如何从一个巨大的(scipy.sparse)矩阵计算对角矩阵?

如何从矩阵中获取子矩阵?

关于灰度共生矩阵对纹理图像进行分割的问题

协方差矩阵在图像处理之特征脸处理中的应用