【问题标题】:Memory usage issue for large numpy arrays within the for loop & arithmetic operationsfor 循环和算术运算中大型 numpy 数组的内存使用问题
【发布时间】:2020-12-21 23:22:00
【问题描述】:

我对python很陌生。我有一个隐式的循环时间积分,即下一步取决于上一步。基本上,我试图通过利用 numpy 数组的广播功能而不使用更多的 for 循环来解决所有不同情况的时间积分。因此,我有很大的数组。

循环运行时间很短(2.5 秒),但在 for 循环中执行操作时,我的 RAM(8 GB)几乎达到了它的容量。因此,我正在尝试解决内存使用问题。

ndata = 9624
u.shape = (3, 9624, 11, 3, 1000)
p.shape = (9624, 11, 1, 1000)
a1.shape = (11, 3, 1000)
a2.shape = (11, 3, 1000)
a3.shape = (11, 3, 1000)
p_star.shape = (11, 3, 1000)
delta_t.shape =(11, 1, 1)
k_star.shape =(11, 3, 1000)

for i in range(0,ndata-1):
    p_star = p[i+1] + a1 * u[0,i] + a2 * u[1,i] + a3 * u[2,i]
    u[0,i+1] = p_star / k_star
    u[1,i+1] = gama * (u[0,i+1]-u[0,i]) / (beta * delta_t) + u[1,i] * (1 - gama/beta) + delta_t * u[2,i] * (1 - gama/(2*beta))
    u[2,i+1] = (u[0,i+1]-u[0,i]) / (beta * (delta_t ** 2)) - u[1,i] / (beta * delta_t) - u[2,i] * ((1 / (2*beta)) - 1)

You can see memory usage in the loop here

在算术运算期间,会创建并分配数组的临时副本。我认为这里的主要问题是创建数组的副本。为了克服这个问题,应该就地进行算术运算。

据我所知,要进行这些操作,应该定义 numpy ufuncs 的可选参数 out= 或者应该使用 += -= *= /= 。例如,numpy.sum(a1,a2, out=a1)

但为了以就地方式执行上述操作,我必须定义许多辅助(或缓冲区)变量。 我的问题是减少这种内存使用的最佳方法是什么。我相信,在 python 中,必须有一种优雅的方式来就地执行这些类型的算术运算。

我也愿意接受其他建议。

buff1 = np.zeros_like(u[0,0])
buff2 = np.zeros_like(u[0,0])
buff3 = np.zeros_like(u[0,0])
buff4 = np.zeros_like(u[0,0])
for i in range(0,ndata-1):
    # first line
    np.multiply(a1, u[0,i], out = buff1);
    np.multiply(a2, u[1,i], out = buff2);
    np.multiply(a3, u[2,i], out = buff3);
    buff1 += p[i+1];
    buff1 += buff2;
    buff1 += buff3;
    #second line
    np.divide(buff1, k_star, out = u[0,i+1])
    #third line
    np.subtract(u[0,i+1], u[0,i], out = buff1);
    buff1 *= gama
    buff1 /= beta
    buff1 /= delta_t
    np.divide(gama,beta, out = buff2)
    np.subtract(1, buff2, out=buff2)
    np.multiply(u[1,i], buff2, out=buff2)
    np.multiply(2, beta, out = buff3)
    np.divide(gama, buff3, out = buff3)
    np.subtract(1, buff3, out = buff3)
    np.multiply(u[2,i], buff3, out = buff3)
    np.multiply(delta_t, buff3, out = buff3)
    np.add(buff1, buff2, out = u[1,i+1])
    np.add(buff3, u[1,i+1], out = u[1,i+1])
    #last line goes like that
    

【问题讨论】:

  • 您的u 数组本身就有近十亿个元素。根据 dtype,仅该数组就可以填满您的 RAM。您正在严重挑战硬件的极限。
  • 看起来您并不需要一次将所有u 存储在内存中。每个时间步仅依赖于前一个时间步。您不需要同时存储 9624 个时间步长的数据。
  • 是的,它非常大,但是在 for 循环 RAM 使用率降低到正常水平(~1-1.5 GB)之后,包括 u 在内的变量会保留。所以这就是为什么我指向循环内的内存使用操作。
  • 我将使用 u 中的数据进行进一步计算。不幸的是,需要所有 9624 个时间步
  • 有些重要的事情你没有告诉我们。与u 本身相比,循环中创建的任何临时对象都很小。它们远没有大到足以引起你所说的你看到的记忆效应。只有up 本身大到足以引起问题。

标签: python arrays numpy numpy-ndarray


【解决方案1】:

问题实际上是数组 p 和 u 的大小。结合起来,它们由大约十亿个浮点数组成,每个浮点数用 64 位表示。或者,总共 8 GB。如果您需要保留所有 9264 个时间步,恐怕您无能为力——当然,如果您只能保留最后两个时间步,情况就会改变。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-06
    • 2020-09-08
    • 1970-01-01
    • 1970-01-01
    • 2022-11-22
    • 1970-01-01
    相关资源
    最近更新 更多