如何使用我的 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
方式也需要一些设置工作。因此,对于经过总和减少的适当长度的轴,我们可能希望将该标志设置为 True
和 False
否则。在这种情况下,这些轴似乎真的很短,所以我们最好使用默认值: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()
我目前有 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
方式也需要一些设置工作。因此,对于经过总和减少的适当长度的轴,我们可能希望将该标志设置为 True
和 False
否则。在这种情况下,这些轴似乎真的很短,所以我们最好使用默认值: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()