在 Python 的 Numpy 中,点积不等同于 einsum,我不确定为什么不

In Python's Numpy, a dot product isn't equivalent to an einsum, and I'm not sure why not

但显然我做错了什么。

找了一晚上的bug,终于解决了。考虑:

xs = np.arange(100 * 3).reshape(100, 3)
W = np.arange(3 * 17).reshape(3, 17)

a = np.einsum('df, hg -> dg', xs, W)
b = np.dot(xs, W)

在上面a != b.

我发现的问题是在 einsum 中,我说 df, hg -> dg,但是如果我将 h 换成 f,它会按预期工作:

a = np.einsum('df, fg -> dg', xs, W)
b = np.dot(xs, W)

现在,a == b.

两种情况下的求和有何不同,我希望它们相同?

以下是等效的基于广播的表达式,也许它们可以帮助您理解其中的区别:

dffg = (xs[:,:,None]*W[None,:,:]).sum(1)
dfhg = (xs[:,:,None,None]*W[None,None,:,:]).sum((1,2))

(a==dfhg).all()
# True
(b==dffg).all()
# True

在 dfhg 的情况下,数据轴实际上并不重叠;因此可以分别对每一项进行求和:

dfhg_ = (xs.sum(1)[:,None]*W.sum(0)[None,:])
(a==dfhg_).all()
# True

将此与 dffg 情况进行对比,其中在 xs 的每一行和 W 的每一列之间形成点积。

使用 np.einsum 进行矩阵乘法的正确方法是重复 "middle" 索引(表示对行时间列求和),如您所见:

a = np.array([[1,2],[3,4]])
b = np.array([[1,-2],[-0.4,3]])
np.einsum('df,fg->dg', a, b)
array([[ 0.2,  4. ],
       [ 1.4,  6. ]])

a.dot(b) 
array([[ 0.2,  4. ],
       [ 1.4,  6. ]])

如果不这样做,您会得到 a 的每个值 乘以 b:

np.einsum('df, hg -> dfhg', a, b)

array([[[[  1. ,  -2. ],
         [ -0.4,   3. ]],

        [[  2. ,  -4. ],
         [ -0.8,   6. ]]],


       [[[  3. ,  -6. ],
         [ -1.2,   9. ]],

        [[  4. ,  -8. ],
         [ -1.6,  12. ]]]])

相同
a[:,:, None, None] * b

当您在使用显式运算符 -> 时省略中间索引时,您对这些轴求和:

np.einsum('df, hg -> dg', a, b)

array([[ 1.8,  3. ],
       [ 4.2,  7. ]])

等同于:

np.einsum('df, hg -> dfhg', a, b).sum(axis=1).sum(axis=1)

Here is a good guide to einsum(不是我的)。