如何使用我的 numpy 数组 (3000,3) 和 (3,2,3000) 进行广播

How to use broadcasting with my numpy arrays (3000,3) and (3,2,3000)

我目前有 2 个数组,形状为 v1=(3000,3) 和 v2=(3,2,3000)。 3000 是时间维度,因此 v1 有 3000 (1,3) 个样本,v2 有 3000 (3,2) 个样本。我希望沿 3000 维进行矩阵乘法和广播,以便在 return.

中得到 3000 (1,2) 个向量

我试过重塑形状,使 v1 = (1,3,3000) 和 v2 = (3,2,300),这给出了一个错误,指出形状未对齐。

代码:

v1 = np.ones((1,3,3000)) +1
v2 = np.ones((3,2,3000)) - 0.5
np.dot(v1,v2)

v1 的形状 (3000,3)v2 作为 (3,2,3000),我们可以使用 np.einsum -

np.einsum('ij,jki->ik',v1,v2)

这为我们提供了形状为 (3000,2) 的输出。

我们可以在 np.einsum 中使用 optimize arg。对于 optimize = True,它在内部利用 BLAS,对于 optimize = False 则诉诸于简单的 C 循环。 BLAS 方式也需要一些设置工作。因此,对于经过总和减少的适当长度的轴,我们可能希望将该标志设置为 TrueFalse 否则。在这种情况下,这些轴似乎真的很短,所以我们最好使用默认值:optimize = False 输入。

我建议您不要使用 optimize=True 标志,因为出于某些奇怪的原因,它效率低下。此外,我建议您显式 将 2D 数组提升 为 3D,执行 批量矩阵乘法 然后压缩结果的单维数组,如果你最后需要一个二维数组作为最终结果。请在下面找到代码:

# sample arrays
In [25]: v1 = np.random.random_sample((3000, 3))
In [26]: v2 = np.random.random_sample((3, 2, 3000))

# Divakar's approach
In [27]: %timeit np.einsum('ij,jki->ik',v1,v2, optimize=True)
80.7 µs ± 792 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

# needed for future use
In [28]: res_optimized = np.einsum('ij,jki->ik',v1,v2, optimize=True)

# promoting to 3D array and swapping axes
In [29]: v1 = v1[:, np.newaxis, :]
In [30]: v2 = np.moveaxis(v2, 2, 0)

# perform batch matrix multiplication
In [31]: %timeit np.einsum("bij, bjk -> bik", v1, v2)
47.9 µs ± 496 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

# for sanity checking
In [32]: res = np.einsum("bij, bjk -> bik", v1, v2)

In [33]: res.shape, res_optimized.shape
Out[33]: ((3000, 1, 2), (3000, 2))

# squeeze the singleton dimension and perform sanity check with Divakar's approach
In [34]: np.allclose(res.squeeze(), res_optimized)
Out[34]: True

所以,正如我们从上面的时间安排中看到的那样,我们获得了大约。通过不使用 optimize=True 标志实现 2 倍加速。此外,明确地将数组整形为 3D 可以让我们更好地了解我们使用 numpy.einsum().

时发生的事情。

注意:计时是使用最新的 NumPy 版本执行的'1.16.1'


P.S。阅读更多关于 Understanding NumPy einsum()