解决 python 列表中的内存错误问题或 Numpy 中更聪明的方法

Getting around memory error problem in python lists or a more clever way in Numpy

我正在尝试计算一个 DTW 距离矩阵,该矩阵将查看 150,000 个时间序列,每个时间序列具有 13 到 24 个观察值 - 即生成的距离矩阵将是一个大小约为 (150,000 x 150,000)/ 的列表2= 11,250,000,000。

我正在 运行在 200GB 大小的大数据集群上进行此操作,但出现内存错误。

我正在使用 dtaidisatance 库并使用 distance_matrix_fast 函数,我可以在列表中一次传递整个时间序列,但我得到了类似的记忆错误,但从包装中出来。不过,我 运行 错误立即被抛出。我还使用了包中的 block 函数,但似乎无法立即开始使用所有时间序列。

所以我决定通过一个循环计算每两对时间序列之间的距离,然后将其附加到一个列表中。但是我确实得到了相同的 运行宁了半天又出现如下内存错误:

文件“/root/anaconda2/test/final_clustering_2.py”,第 93 行,位于 distance_matrix_scaled.append(dtw.distance_fast(Series_scaled[i], Series_scaled[j])) 内存错误

下面是我的代码:

distance_matrix_scaled = []

m=len(Series_scaled)
#m=100000
for i in range(0, m - 1):
    for j in range(i + 1, m):

distance_matrix_scaled.append(dtw.distance_fast(Series_scaled[i], Series_scaled[j]))

# save it to the disk
np.save('distance_entire',  distance_matrix_scaled)

你能帮我回答一下为什么会出现这个内存错误吗?是 python 列表限制还是我的集群大小导致的?我可以使用 numpy 中的巧妙方法或格式来解决这个问题吗?

你的双 for 循环有 4999950000 次迭代。您将多次附加到列表中。还是很奇怪?

如果距离是一个标量,那么您确实可以通过预先分配一个如此大的数组来节省内存(并希望最好,内存方面):

import numpy as np

m = 100000
distances = np.empty(m*(m-1)/2) # size: 4999950000
k = 0
for i in range(0, m - 1):
    for j in range(i + 1, m):
         distances[k] = dtw.distance_fast(Series_scaled[i], Series_scaled[j])
         k += 1

由于 numpy 数组占用连续的内存块,因此它们在大规模时比原生列表更有效。数组本身的开销几乎可以忽略不计,因此您主要获得实际数据的大小。

如果这个巨大的数组不适合你的记忆,你就有麻烦了。您必须切割数据并以更小的块工作。或者可能使用某种内存映射。

然而,一个小注意事项:我们正在填充的数组(假设 64 位双精度数)占用大约 37 GB 的 RAM。好多啊。如果您 可以 将其放入您的记忆中,您将不得不等待 5 十亿 次 python(双)循环的迭代.这需要……很多时间。不要屏住呼吸。

如果您正在计算类似欧氏距离的东西,请查看计算任务的内存成本,您将生成一个大小为 150000*149999/2*(13~24) 的中间临时数组,其中

  • 150000*149999/2表示150000个时间序列中无序对的个数(不包括self-self对)

  • 13~24表示两个时间序列向量之间的差异,稍后将norm编辑并减少为每对一个数字。

每个数字通常是 4 或 8 字节的浮点数或双精度数。所以算法会占用1T~4T内存,这显然会让200G爆表。

除了手动划分为较小的任务外,还有一些技巧可用于降低内存成本:

  • 如果你坚持用numpy,一定要选择较小的dtype,比如float32。如果您的数字很小,您甚至可以考虑 int16int8 之类的东西。不要使用 float16,因为它在 CPU 上没有计算支持(非常慢)。

  • 如果不是这种情况,您可以考虑 numba,它允许您将 python 循环编译为高效的 CPU 代码并使其成为 运行 在所有核心上,这应该是 CPU 上的最佳解决方案(不需要生成临时数组)。

  • Scipy还有scipy.spatial.distance.pdict。不确定它在内存方面的表现如何,但您可以尝试一下。