解决 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
。如果您的数字很小,您甚至可以考虑 int16
或 int8
之类的东西。不要使用 float16
,因为它在 CPU 上没有计算支持(非常慢)。
如果不是这种情况,您可以考虑 numba
,它允许您将 python 循环编译为高效的 CPU 代码并使其成为 运行 在所有核心上,这应该是 CPU 上的最佳解决方案(不需要生成临时数组)。
Scipy还有scipy.spatial.distance.pdict
。不确定它在内存方面的表现如何,但您可以尝试一下。
我正在尝试计算一个 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
。如果您的数字很小,您甚至可以考虑int16
或int8
之类的东西。不要使用float16
,因为它在 CPU 上没有计算支持(非常慢)。如果不是这种情况,您可以考虑
numba
,它允许您将 python 循环编译为高效的 CPU 代码并使其成为 运行 在所有核心上,这应该是 CPU 上的最佳解决方案(不需要生成临时数组)。Scipy还有
scipy.spatial.distance.pdict
。不确定它在内存方面的表现如何,但您可以尝试一下。