【问题标题】:Calculate every 4-element-product in a vector with python用python计算向量中的每个4元素乘积
【发布时间】:2021-10-27 15:25:44
【问题描述】:

我有一个 (500000,30) numpy 数组,我们可以将其视为长度为 500000 的大小为 30 的向量列表。我想在向量中选择任意 4 个元素,计算其乘积,并存储所有 4 元素乘积。最后我需要计算 500000 个结果的平均值。

我已经用np.einsum 尝试过,但运行速度非常慢。如何提高效率?

# array.shape = (500000,30)
expect = np.sum(np.einsum('ni,nj,nk,nr->ijkr',array,array,array,array),axis=0)/500000

【问题讨论】:

  • 请在 5x4 数组上展示基于循环的实现,选择 3 个元素。我看不到您在哪里选择 4 个元素。当散文和代码不匹配时,很难测试实现。
  • 一个非常有价值的调试和实现工具是制作一个您可以完全可视化的示例,即minimal reproducible example。你不能指望我测试一个 500k 长度的数组,但你肯定可以期望我匹配一个 5 长度的数组。

标签: python numpy numpy-einsum


【解决方案1】:

向量v 中4 个条目的所有可能乘积之和等于v 的条目和的4 次方。 请注意,这假设相同的向量条目可以在一个产品中出现多次,并且总和将包括仅在其条目顺序上有所不同的产品(例如,v[1] * v[2] * v[3] * v[4]v[4] * v[3] * v[2] * v[1] 将被视为不同的产品)。由于您的代码执行相同的计算,我假设这就是您想要的。无论如何,价值

np.sum(np.einsum('ni,nj,nk,nr->ijkr', array, array, array, array))

相同
(array.sum(axis=1)**4).sum()

但后者的计算速度会更快。

在您的代码中,您沿 np.einsum 生成的 30x30x30x30 数组的 0 轴求和,但我不知道为什么。

【讨论】:

  • 小心,OP 已编辑问题 使用np.sum(...,axis=0) 而不是np.sum(...)。前者在输出中给出一个矩阵,而后者给出一个标量并且更容易计算。两者产生不同的输出。
  • @JérômeRichard 这在我的回答的最后一句话中有说明。 OP 写道,他们想要计算 500,000 个结果的平均值。因为无论哪种情况都没有 500,000 个结果,我不确定这里的真正目标是什么。
【解决方案2】:

您可以通过在最后一维中分解点积来更有效地计算解决方案。此外,您可以告诉 Numpy 优化 einsum(以更高的延迟为代价,这在此处不是问题)。这是生成的代码:

expect = np.einsum('n,nj,nk,nr->jkr',np.sum(array, axis=1),array,array,array,optimize=True)/500000

这在我的机器上 快了 63 倍。如果您想进一步优化这一点,您可以使用多个线程并行执行计算。实际上,默认的 Numpy 实现是顺序的。您可以使用 Numba 来做到这一点。我希望我的 6 核机器上的计算速度大约快 360 倍(因为计算是compute-bound)。

【讨论】:

    猜你喜欢
    • 2011-11-01
    • 2017-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-09
    • 2019-03-28
    相关资源
    最近更新 更多