我想通过载体(长度M)的n昏暗堆乘以m * m的矩阵的n昏暗堆叠,使得所得到的m * n个数组包含在第n个的矩阵和向量的点积的结果条目:
vec1=np.array([0,0.5,1,0.5]); vec2=np.array([2,0.5,1,0.5])
vec=np.transpose(n.stack((vec1,vec2)))
mat = np.moveaxis(n.array([[[0,1,2,3],[0,1,2,3],[0,1,2,3],[0,1,2,3]],[[-1,2.,0,1.],[0,0,-1,2.],[0,1,-1,2.],[1,0.1,1,1]]]),0,2)
outvec=np.zeros((4,2))
for i in range(2):
outvec[:,i]=np.dot(mat[:,:,i],vec[:,i])
通过这篇文章的启发向量和矩阵的元素明智的点积 ,我曾尝试在einsum指数组合的所有不同的扰动,并发现
np.einsum('ijk,jk->ik',mat,vec)
给出正确的结果。
不幸的是我真的不明白这一点 - 我认为我重复的条目k上的事实“IJK,JK”部分是指我乘和加通过k个。 我试着阅读文档https://docs.scipy.org/doc/numpy-1.15.1/reference/generated/numpy.einsum.html ,但我还是不明白。
(包括我以前的尝试,
np.einsum('ijk,il->ik', mat, vec)
我甚至不知道这意味着什么。 恰巧当时我放弃它的指标L是什么?)
提前致谢!
In [321]: vec1=np.array([0,0.5,1,0.5]); vec2=np.array([2,0.5,1,0.5])
...: vec=np.transpose(np.stack((vec1,vec2)))
In [322]: vec1.shape
Out[322]: (4,)
In [323]: vec.shape
Out[323]: (4, 2)
对一件很好的事stack
功能,我们可以指定一个轴,跳过转:
In [324]: np.stack((vec1,vec2), axis=1).shape
Out[324]: (4, 2)
为什么的搭配np.
和n.
? NameError: name 'n' is not defined
。 这种事情几乎把我带走。
In [326]: mat = np.moveaxis(np.array([[[0,1,2,3],[0,1,2,3],[0,1,2,3],[0,1,2,3]],[[-1,2.,0
...: ,1.],[0,0,-1,2.],[0,1,-1,2.],[1,0.1,1,1]]]),0,2)
In [327]: mat.shape
Out[327]: (4, 4, 2)
In [328]: outvec=np.zeros((4,2))
...: for i in range(2):
...: outvec[:,i]=np.dot(mat[:,:,i],vec[:,i])
...:
In [329]: outvec
Out[329]:
array([[ 4. , -0.5 ],
[ 4. , 0. ],
[ 4. , 0.5 ],
[ 4. , 3.55]])
In [330]: # (4,4,2) (4,2) 'kji,ji->ki'
从你的循环,在位置i
轴线(2号)是明确的-最后在所有3个阵列。 这就为一个轴vec
,让我们称之为j
。 这对与上次(旁边i
的mat
)。 k
从携带在mat
到outvec
。
In [331]: np.einsum('kji,ji->ki', mat, vec)
Out[331]:
array([[ 4. , -0.5 ],
[ 4. , 0. ],
[ 4. , 0.5 ],
[ 4. , 3.55]])
通常情况下, einsum
字符串本身写道。 例如,如果mat
被描述为(M,N,k)和vec
为(n,k)的,其结果为(M,K)
在这种情况下,只有j
维度总结-它出现在左边,而右边。 最后一个层面, i
在我的符号,不总结,因为如果出现在两侧,就像它在你的迭代。 我认为,作为“走出去,一起换了骑”。 这不是积极的部分dot
产品。
你是,实际上,堆叠在最后一个维度,2号之一。 通常我们堆栈上的第一次,但你既转放,去年。
你的“失败”的尝试运行,并且可以复制为:
In [332]: np.einsum('ijk,il->ik', mat, vec)
Out[332]:
array([[12. , 4. ],
[ 6. , 1. ],
[12. , 4. ],
[ 6. , 3.1]])
In [333]: mat.sum(axis=1)*vec.sum(axis=1)[:,None]
Out[333]:
array([[12. , 4. ],
[ 6. , 1. ],
[12. , 4. ],
[ 6. , 3.1]])
该j
和l
尺寸没有出现在右侧,所以他们相加。 他们可以因为他们似乎只在一个学期每个乘以之前来概括。 我加入了None
以使广播(乘法ik
与i
)。
np.einsum('ik,i->ik', mat.sum(axis=1), vec.sum(axis=1))
如果您想堆叠在第一,并增加了一个维度vec
(2,4,1),它会matmul
用(2,4,4)垫。 mat @ vec[...,None]
。
In [337]: m1 = mat.transpose(2,0,1)
In [338]: m1@v1[...,None]
Out[338]:
array([[[ 4. ],
[ 4. ],
[ 4. ],
[ 4. ]],
[[-0.5 ],
[ 0. ],
[ 0.5 ],
[ 3.55]]])
In [339]: _.shape
Out[339]: (2, 4, 1)
阅读上爱因斯坦的求和符号 。
基本上,规则是:
如果没有->
- 在输入重复任意字母代表的轴线被multipled和求和
- 在输入端不重复任意字母被包括在输出
用->
- 在输入重复任意字母表示待multipled通过一个轴
- 不任何字母在输出表示待求和的轴线
因此,例如,具有矩阵A
和B
王氏相同的形状:
np.einsum('ij, ij', A, B) # is A ddot B, returns 0d scalar
np.einsum('ij, jk', A, B) # is A dot B, returns 2d tensor
np.einsum('ij, kl', A, B) # is outer(A, B), returns 4d tensor
np.einsum('ji, jk, kl', A, B) # is A.T @ B @ A, returns 2d tensor
np.einsum('ij, ij -> ij', A, B) # is A * B, returns 2d tensor
np.einsum('ij, ij -> i' , A, A) # is norm(A, axis = 1), returns 1d tensor
np.einsum('ii' , A) # is tr(A), returns 0d scalar
einsum
容易(你有没有和指标的排列玩了一会,这是...)。
让我们来简单的东西,2×2点矩阵三堆和2×三堆,阵列工作
import numpy as np
a = np.arange(3*2*2).reshape((3,2,2))
b = np.arange(3*2).reshape((3,2))
我们需要知道我们要计算使用einsum
In [101]: for i in range(3):
...: print(a[i]@b[i])
[1 3]
[23 33]
[77 95]
我们所做的? 我们有一个索引i
当我们堆叠矩阵中的一个和所述堆叠的矢量(均由索引中的一个之间进行的点积被固定i
)与各个输出线意味着在堆叠矩阵的最后索引和求和堆叠的矢量的孤索引。
这是很容易在编码einsum
指令
- 我们要同
i
的索引来指定矩阵,向量,也是输出, - 我们要沿着过去的矩阵指数和剩余矢量指数降低,说
k
- 我们希望在输出作为每个堆叠矩阵的行的列数,说
j
于是
In [102]: np.einsum('ijk,ik->ij', a, b)
Out[102]:
array([[ 1, 3],
[23, 33],
[77, 95]])
我希望我的我是如何得到该指令的讨论权是清楚的,正确的和有益的。
文章来源: numpy - einsum notation: dot product of a stack of matrices with stack of vectors