如何矢量化 Python 中的点积?
How can I vectorize the dot product in Python?
我想计算 N 组的点积,假设每个组都是一个 (4,3) 矩阵,称为 x_i。于是我将这些N矩阵向量化为一个(N,4,3)矩阵,如:
[[[1,2,3],
[4,5,6],
[7,8,9],
[0,1,2]],
...
[7,2,2],
[4,2,4],
[7,1,9],
[3,1,2]]]. # #N matrices
如果我分别计算 x_i 和 x_i.T 的每个点积:
np.dot(x_i, x_i.T)
它会得到一个(4,4)矩阵。
但是矢量化后如何计算这些?
最终结果应该是(N,4,4)。
您可以生成 3D 列表。我会把它变成这样:
N=[]
for n in range (len(N)):
N.append(n,np.dot(x_i, x_i.T))
In [31]: x = np.arange(5*12).reshape(5,4,3)
In [32]: x@x.transpose(0,2,1)
Out[32]:
array([[[ 5, 14, 23, 32],
[ 14, 50, 86, 122],
[ 23, 86, 149, 212],
[ 32, 122, 212, 302]],
[[ 509, 626, 743, 860],
[ 626, 770, 914, 1058],
[ 743, 914, 1085, 1256],
[ 860, 1058, 1256, 1454]],
[[ 1877, 2102, 2327, 2552],
[ 2102, 2354, 2606, 2858],
[ 2327, 2606, 2885, 3164],
[ 2552, 2858, 3164, 3470]],
[[ 4109, 4442, 4775, 5108],
[ 4442, 4802, 5162, 5522],
[ 4775, 5162, 5549, 5936],
[ 5108, 5522, 5936, 6350]],
[[ 7205, 7646, 8087, 8528],
[ 7646, 8114, 8582, 9050],
[ 8087, 8582, 9077, 9572],
[ 8528, 9050, 9572, 10094]]])
In [33]: _.shape
Out[33]: (5, 4, 4)
正在检查
In [34]: x[0,...].dot(x[0,...].T)
Out[34]:
array([[ 5, 14, 23, 32],
[ 14, 50, 86, 122],
[ 23, 86, 149, 212],
[ 32, 122, 212, 302]])
@
或 matmul
在最后两个维度上进行点积,同时像您一样将第一个维度视为 'i' 维度。
x.tanspose(0,2,1)
切换最后两个维度,保持第一个不变。对于二维数组 x.transpose()
是 x.transpose(1,0)
。就是你表达的 x_i.T
.
与 dot
一样,a@b
的关键是 a
的最后一个维度与 b
的第 2 到最后一个维度一起工作。
np.matmul 会成功:
N=2; m=4; n=3
x = np.ones((N,m,n))
np.matmul(x,x.transpose(0,2,1))
array([[[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.]],
[[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.]]])
形状检查:
np.matmul(x,x.reshape((N,n,m))).shape
(2, 4, 4)
P.S.,正如hpaulj在评论中提到的这个解决方案基本上等同于他的!
似乎 np.einsum
可以做到这一点
x = np.arange(5*12).reshape(5,4,3)
np.einsum("nik, njk->nij", x, x)
我想计算 N 组的点积,假设每个组都是一个 (4,3) 矩阵,称为 x_i。于是我将这些N矩阵向量化为一个(N,4,3)矩阵,如:
[[[1,2,3],
[4,5,6],
[7,8,9],
[0,1,2]],
...
[7,2,2],
[4,2,4],
[7,1,9],
[3,1,2]]]. # #N matrices
如果我分别计算 x_i 和 x_i.T 的每个点积:
np.dot(x_i, x_i.T)
它会得到一个(4,4)矩阵。
但是矢量化后如何计算这些?
最终结果应该是(N,4,4)。
您可以生成 3D 列表。我会把它变成这样:
N=[]
for n in range (len(N)):
N.append(n,np.dot(x_i, x_i.T))
In [31]: x = np.arange(5*12).reshape(5,4,3)
In [32]: x@x.transpose(0,2,1)
Out[32]:
array([[[ 5, 14, 23, 32],
[ 14, 50, 86, 122],
[ 23, 86, 149, 212],
[ 32, 122, 212, 302]],
[[ 509, 626, 743, 860],
[ 626, 770, 914, 1058],
[ 743, 914, 1085, 1256],
[ 860, 1058, 1256, 1454]],
[[ 1877, 2102, 2327, 2552],
[ 2102, 2354, 2606, 2858],
[ 2327, 2606, 2885, 3164],
[ 2552, 2858, 3164, 3470]],
[[ 4109, 4442, 4775, 5108],
[ 4442, 4802, 5162, 5522],
[ 4775, 5162, 5549, 5936],
[ 5108, 5522, 5936, 6350]],
[[ 7205, 7646, 8087, 8528],
[ 7646, 8114, 8582, 9050],
[ 8087, 8582, 9077, 9572],
[ 8528, 9050, 9572, 10094]]])
In [33]: _.shape
Out[33]: (5, 4, 4)
正在检查
In [34]: x[0,...].dot(x[0,...].T)
Out[34]:
array([[ 5, 14, 23, 32],
[ 14, 50, 86, 122],
[ 23, 86, 149, 212],
[ 32, 122, 212, 302]])
@
或 matmul
在最后两个维度上进行点积,同时像您一样将第一个维度视为 'i' 维度。
x.tanspose(0,2,1)
切换最后两个维度,保持第一个不变。对于二维数组 x.transpose()
是 x.transpose(1,0)
。就是你表达的 x_i.T
.
与 dot
一样,a@b
的关键是 a
的最后一个维度与 b
的第 2 到最后一个维度一起工作。
np.matmul 会成功:
N=2; m=4; n=3
x = np.ones((N,m,n))
np.matmul(x,x.transpose(0,2,1))
array([[[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.]],
[[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.],
[3., 3., 3., 3.]]])
形状检查:
np.matmul(x,x.reshape((N,n,m))).shape
(2, 4, 4)
P.S.,正如hpaulj在评论中提到的这个解决方案基本上等同于他的!
似乎 np.einsum
可以做到这一点
x = np.arange(5*12).reshape(5,4,3)
np.einsum("nik, njk->nij", x, x)