numpy 中的 3d 矩阵乘法
3d Matrix multiplication in numpy
我正在使用 numpy 执行矩阵乘法,但我不知道如何利用 numpy 进行 3d 矩阵乘法。
假设我有一个 3x3 矩阵 a,我将它乘以一个 3x1 向量 b。这将给出一个 3x1 向量,c.
这是在 numpy 中完成的:
# (3, 3) * (3, 1) -> (3, 1)
c = np.matmul(a, b)
好的,所以现在我想对本质上是 2500 个 3x3 矩阵的 3d 矩阵执行类似的操作。现在我正在做一些事情:
# (2500, 3, 3) * (2500, 3, 1) -> list of (3, 1) vectors with length 2500
C = [np.matmul(a, b) for a, b in zip(A, B)]
其中 returns (3, 1) 个向量的列表。
我宁愿不循环,而是充分利用 numpy 的矢量化和 matrix/tensor 产品。有什么手术可以做吗...
# (2500, 3, 3) * (2500, 3, 1) -> (2500, 3, 1)
np.<function>(A, B, <args>)
我看过有关使用 np.tensordot 的资料,但我不知道如何设置坐标轴。
np.tensordot(A, B, axes=???)
对于您拥有的 3 维数组(或 3 阶张量),您可以使用 np.einsum
doc 进行更复杂的矩阵乘法。在您的特定情况下,您可以使用以下
>>> import numpy as np
>>> x = np.random.randint(0, 3, (3, 3, 3)) # shape (3, 3, 3)
>>> y = np.random.randint(0, 3, (3, 3, 3)) # shape (3, 3, 3)
>>> np.einsum('ijk,ikl->ijl', x, y) # still shape (3, 3, 3)
特别是,einsum
表达式 'ijk,ikl->ijl'
表示对于每个 i
矩阵,进行常规矩阵乘法 jk,kl->jl
并将结果放入 i
结果张量 (ndarray) 中的第一个条目。此过程的更一般形式可以是
np.einsum('...jk,...kl->...jl', x, y)
你可以在你拥有的每个张量 (ndarray) 前面有任意数量的维度。
有关完整示例,请参阅以下内容:
>>> import numpy as np
>>> x = np.random.randint(0, 3, (3, 3, 3)) # shape (3, 3, 3)
>>> x
array([[[0, 0, 1],
[2, 2, 1],
[2, 1, 1]],
[[2, 0, 2],
[2, 2, 1],
[2, 2, 2]],
[[2, 2, 2],
[1, 1, 2],
[0, 2, 2]]])
>>> y = np.random.randint(0, 3, (3, 3, 3)) # shape (3, 3, 3)
>>> y
array([[[0, 0, 1],
[2, 1, 0],
[0, 0, 2]],
[[1, 2, 0],
[2, 0, 1],
[2, 2, 1]],
[[0, 2, 1],
[0, 1, 0],
[0, 2, 1]]])
>>> np.einsum('ijk,ikl->ijl', x, y)
array([[[ 0, 0, 2],
[ 4, 2, 4],
[ 2, 1, 4]],
[[ 6, 8, 2],
[ 8, 6, 3],
[10, 8, 4]],
[[ 0, 10, 4],
[ 0, 7, 3],
[ 0, 6, 2]]])
>>> np.einsum('...ij,...jk->...ik', x, y)
array([[[ 0, 0, 2],
[ 4, 2, 4],
[ 2, 1, 4]],
[[ 6, 8, 2],
[ 8, 6, 3],
[10, 8, 4]],
[[ 0, 10, 4],
[ 0, 7, 3],
[ 0, 6, 2]]])
np.matmul(A,B)
工作得很好。您遇到了什么错误?
In [263]: A,B = np.arange(24).reshape(2,3,4), np.arange(8).reshape(2,4,1)
einsum
解决方案:
In [264]: np.einsum('ijk,ikl->ijl',A,B)
Out[264]:
array([[[ 14],
[ 38],
[ 62]],
[[302],
[390],
[478]]])
In [265]: _.shape
Out[265]: (2, 3, 1)
matmul
解决方案:
In [266]: A@B
Out[266]:
array([[[ 14],
[ 38],
[ 62]],
[[302],
[390],
[478]]])
你的循环:
In [267]: [np.matmul(a, b) for a, b in zip(A, B)]
Out[267]:
[array([[14],
[38],
[62]]),
array([[302],
[390],
[478]])]
matmul
文档:
If either argument is N-D, N > 2, it is treated as a stack of
matrices residing in the last two indexes and broadcast accordingly.
我正在使用 numpy 执行矩阵乘法,但我不知道如何利用 numpy 进行 3d 矩阵乘法。
假设我有一个 3x3 矩阵 a,我将它乘以一个 3x1 向量 b。这将给出一个 3x1 向量,c.
这是在 numpy 中完成的:
# (3, 3) * (3, 1) -> (3, 1)
c = np.matmul(a, b)
好的,所以现在我想对本质上是 2500 个 3x3 矩阵的 3d 矩阵执行类似的操作。现在我正在做一些事情:
# (2500, 3, 3) * (2500, 3, 1) -> list of (3, 1) vectors with length 2500
C = [np.matmul(a, b) for a, b in zip(A, B)]
其中 returns (3, 1) 个向量的列表。
我宁愿不循环,而是充分利用 numpy 的矢量化和 matrix/tensor 产品。有什么手术可以做吗...
# (2500, 3, 3) * (2500, 3, 1) -> (2500, 3, 1)
np.<function>(A, B, <args>)
我看过有关使用 np.tensordot 的资料,但我不知道如何设置坐标轴。
np.tensordot(A, B, axes=???)
对于您拥有的 3 维数组(或 3 阶张量),您可以使用 np.einsum
doc 进行更复杂的矩阵乘法。在您的特定情况下,您可以使用以下
>>> import numpy as np
>>> x = np.random.randint(0, 3, (3, 3, 3)) # shape (3, 3, 3)
>>> y = np.random.randint(0, 3, (3, 3, 3)) # shape (3, 3, 3)
>>> np.einsum('ijk,ikl->ijl', x, y) # still shape (3, 3, 3)
特别是,einsum
表达式 'ijk,ikl->ijl'
表示对于每个 i
矩阵,进行常规矩阵乘法 jk,kl->jl
并将结果放入 i
结果张量 (ndarray) 中的第一个条目。此过程的更一般形式可以是
np.einsum('...jk,...kl->...jl', x, y)
你可以在你拥有的每个张量 (ndarray) 前面有任意数量的维度。
有关完整示例,请参阅以下内容:
>>> import numpy as np
>>> x = np.random.randint(0, 3, (3, 3, 3)) # shape (3, 3, 3)
>>> x
array([[[0, 0, 1],
[2, 2, 1],
[2, 1, 1]],
[[2, 0, 2],
[2, 2, 1],
[2, 2, 2]],
[[2, 2, 2],
[1, 1, 2],
[0, 2, 2]]])
>>> y = np.random.randint(0, 3, (3, 3, 3)) # shape (3, 3, 3)
>>> y
array([[[0, 0, 1],
[2, 1, 0],
[0, 0, 2]],
[[1, 2, 0],
[2, 0, 1],
[2, 2, 1]],
[[0, 2, 1],
[0, 1, 0],
[0, 2, 1]]])
>>> np.einsum('ijk,ikl->ijl', x, y)
array([[[ 0, 0, 2],
[ 4, 2, 4],
[ 2, 1, 4]],
[[ 6, 8, 2],
[ 8, 6, 3],
[10, 8, 4]],
[[ 0, 10, 4],
[ 0, 7, 3],
[ 0, 6, 2]]])
>>> np.einsum('...ij,...jk->...ik', x, y)
array([[[ 0, 0, 2],
[ 4, 2, 4],
[ 2, 1, 4]],
[[ 6, 8, 2],
[ 8, 6, 3],
[10, 8, 4]],
[[ 0, 10, 4],
[ 0, 7, 3],
[ 0, 6, 2]]])
np.matmul(A,B)
工作得很好。您遇到了什么错误?
In [263]: A,B = np.arange(24).reshape(2,3,4), np.arange(8).reshape(2,4,1)
einsum
解决方案:
In [264]: np.einsum('ijk,ikl->ijl',A,B)
Out[264]:
array([[[ 14],
[ 38],
[ 62]],
[[302],
[390],
[478]]])
In [265]: _.shape
Out[265]: (2, 3, 1)
matmul
解决方案:
In [266]: A@B
Out[266]:
array([[[ 14],
[ 38],
[ 62]],
[[302],
[390],
[478]]])
你的循环:
In [267]: [np.matmul(a, b) for a, b in zip(A, B)]
Out[267]:
[array([[14],
[38],
[62]]),
array([[302],
[390],
[478]])]
matmul
文档:
If either argument is N-D, N > 2, it is treated as a stack of
matrices residing in the last two indexes and broadcast accordingly.