【问题标题】:SVD MemoryError in PythonPython中的SVD内存错误
【发布时间】:2019-11-16 15:25:59
【问题描述】:

我想对一个大数组 M[159459,159459] 执行 SVD。

由于 SVD 计算依赖于形状 (159459,159459) 的输入矩阵,所以这个 here 不能满足我的目标。

我试过用:

  • scipy.linalg.svd
  • scipy.linalg.svd(check_finite=False)
  • 把驱动改成lapack_driver='gesvd
  • numpy.linalg.svd

但是,我总是收到 MemoryError。最后,我想计算完整的 SVD,因为我想执行 Procrustes 分析,即如果 M 是我现在拥有的矩阵,我需要 M = USV'

import numpy as np
from scipy import linalg

#M = np.load("M.npy")
M = np.random.rand(159459,159459)
U, s, Vh = linalg.svd(M, check_finite=False, lapack_driver='gesvd)

一切都失败了。

我的系统详情:

$ cat /proc/meminfo
MemTotal: 527842404 kB
MemFree: 523406068 kB
MemAvailable: 521659112 kB

【问题讨论】:

  • 使用 NumPy 的 mmaps 而不是将输入加载到内存中是否有帮助? (如果您还没有这样做,但我不确定在 SVD 中发生了多少非就地计算)。当然,当使用 mmap 时,预计计算时间会大大延长。
  • 这个我没试过。我去看看
  • 对于一个小的近似 Procrustes 矩阵,看一下 scikit-learn 中的TruncatedSVD;以n_components=1000 左右开头。

标签: python numpy linear-algebra svd arpack


【解决方案1】:

内存大小很重要,下一个延迟成本会伤害你:

给定mM.shape == [159459, 159459]
给定mM.dtype默认为float(64)
将需要大约:
203.42 [GB] 表示 mM[159459, 159459] 的原点,加上
203.42 [GB] 表示计算后的 mU[159459, 159459],加上
203.42 [GB] 用于计算的 Vh[159459, 159459]
0.0013 [GB] 用于计算的 vS[159459]

有史以来最便宜的一步,通过尝试从 float64float32 甚至 float16 的 2 倍(且不超过 4 倍)的线性缩减,这不是游戏规则的改变者,甚至会受到严重惩罚由numpy 效率低下(如果没有在内部再次执行高达float64 的反向转换 - 我自己的尝试在这方面太流血了,所以我在这里分享由此产生的不满,以避免在尝试开始时重复我自己的错误先挂最低的果实……)

如果您的分析可能仅适用于矢量 vS,则只有 .svd( ..., compute_uv = False, ... ) 标志将避免为大约 ~ 1/2 [TB] RAM-allocations 留出空间通过不返回(因此不为它们保留空间)mUVh 的实例。

即使是这样的情况并不意味着您的 SLOC 会像刚刚报告的 0.5 TB RAM 系统一样继续存在。 scipy.linalg.svd() 处理将分配内部工作资源,这些资源超出了您的编码范围(当然,除非您自己重新考虑和重新设计 scipy.linalg 模块,如果不确定,这很可能是公平的) 和配置控制。因此,请注意,即使您测试 compute_uv = False 处理模式,如果 .svd() 未能在内部分配不适合当前 RAM 的所需内部使用的数据结构,它仍可能引发错误。

这也意味着即使使用 numpy.memmap(),这也可能是卸载原始 mM(避免第一个需要 203.4 [GB] 的一些显着部分坐下来阻止主机 RAM 的使用),但使用此技巧您将需要支付费用。

我在.memmap-s 的较小规模上进行的实验,用于矩阵处理和 ML 优化,产生了大约 1E4 ~ 1E6 较慢的处理,因为尽管有智能缓存, numpy.memmap()-instances 依赖于磁盘 I/O。

最好的结果将来自使用先进的、TB 大小的 SSD-only-storage 设备,托管在一些快速和低延迟访问总线 M.2 或 PCIx16 上的计算设备上。

最后一段经验,可能还不想在这里听到:

使用更大的基于主机的 RAM(即使用多 TB 计算设备)是更安全的方法。如果降低性能和额外费用在您的项目预算范围内,则测试上述建议的步骤将有所帮助。如果没有,请使用母校或项目最近的研究中心的 HPC 中心,这种多 TB 计算设备在这些研究中心被普遍使用。

【讨论】:

  • 感谢您的回答。所以目前没有简单直接的方法。我需要计算 U 和 V 而不仅仅是 S 所以.svd( ..., compute_uv = False) 不适用于我的情况。
  • 永远欢迎 @serafeim 有用于执行此操作的多 TB 设备,请检查您项目的同事以获取适当的 HPC 资源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-02
  • 1970-01-01
  • 1970-01-01
  • 2019-06-14
  • 2019-01-31
  • 2013-12-04
相关资源
最近更新 更多