numpy的 - einsum符号:与载体的叠层的堆叠矩阵的点积(numpy - einsum n

2019-11-05 06:17发布

我想通过载体(长度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是什么?)

提前致谢!

Answer 1:

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 。 这对与上次(旁边imat )。 k从携带在matoutvec

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]])

jl尺寸没有出现在右侧,所以他们相加。 他们可以因为他们似乎只在一个学期每个乘以之前来概括。 我加入了None以使广播(乘法iki )。

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)


Answer 2:

阅读上爱因斯坦的求和符号 。

基本上,规则是:

如果没有->

  • 在输入重复任意字母代表的轴线被multipled和求和
  • 在输入端不重复任意字母被包括在输出

->

  • 在输入重复任意字母表示待multipled通过一个轴
  • 不任何字母在输出表示待求和的轴线

因此,例如,具有矩阵AB王氏相同的形状:

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


Answer 3:

einsum容易(你有没有和指标的排列玩了一会,这是...)。

让我们来简单的东西,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