但是显然我做错了。
我整夜都在追踪错误,终于解决了。考虑:
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
中。
我发现的问题在于本质,我说df, hg -> dg
,但是如果我将h
换成f
,它会按预期工作:
a = np.einsum('df, fg -> dg', xs, W)
b = np.dot(xs, W)
现在,a == b
。
两种情况下的求和运算有何不同,我希望它们是相同的?
答案 0 :(得分:2)
以下是基于广播的等效表达方式,也许它们可以帮助您了解不同之处:
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情况进行对比,在dffg情况下,在xs的每一行和W的每一列之间形成点积。
答案 1 :(得分:1)
使用np.einsum
进行矩阵乘法的正确方法是重复“中间”索引(指示在“行时间”列上的求和),如下所示:
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)