Numpy 点积和

Numpy 点积和,numpy,tensorflow,matrix-multiplication,dot-product,numpy-einsum,Numpy,Tensorflow,Matrix Multiplication,Dot Product,Numpy Einsum,如何使用1000个不同的(8,16)权重矩阵将8个元素向量中的100个转换为10个16个元素向量?10个输出向量中的每一个都是100个点积的总和: A = np.random.randn(100,8) W = np.random.randn(1000,8,16) B = [] for i in range(10): sum = np.zeros((1,16)) for j in range(100): sum += np.dot(A[j], W[i*100+j]) B

如何使用1000个不同的(8,16)权重矩阵将8个元素向量中的100个转换为10个16个元素向量?10个输出向量中的每一个都是100个点积的总和:

A = np.random.randn(100,8)
W = np.random.randn(1000,8,16)
B = []

for i in range(10):
  sum = np.zeros((1,16))
  for j in range(100):
    sum += np.dot(A[j], W[i*100+j])   
  B.append(sum)
B = np.asarray(B)     #B.shape=(10,16)
Numpy或TensorFlow中是否有用于此的函数?我看了努比的多特、坦索多、艾因森和马特穆尔,我仍然不确定哪一个是正确的选择

编辑:我刚刚意识到我实际上想在求和点积之前产生一个中间结果:(100,8)x(10100,8,16)->(10100,16)

我猜这可以通过重塑(100,8)到(1100,1,8)和(1000,8,16)到(10100,8,16)以及执行
np.einsum('ijkl,ijlm->ijm',A,B)
来实现,但我不确定它是否能正确地广播1到10

根据@Divakar注释,
np.einsum('jk,ijkl->ijl',V,W.reformate(10100,8,16))
起到了作用。

在一行中,它是

B1 = np.einsum('ij,ikjl', A, np.reshape(W, (100, 10, 8, 16), order='F'))
在需要的地方使用
np.allclose(B.squence(),B1)
对其进行测试
.squence
,因为您的B有一个大小为1的额外维度

说明:你的W的形状很难看,它的第一个尺寸1000应该被分成10个尺寸100的块(就像你在循环中的索引操作一样)。这就是重塑的目的。需要Fortran风格的顺序,因为我们希望通过最快地更改第一个索引来删除W的元素


然后是简单的爱因斯坦求和:在j上有矩阵乘法,在i上加100个结果。

你可以使用基于张量的乘法-

运行时测试-

In [62]: A = np.random.randn(100,8)
    ...: W = np.random.randn(1000,8,16)

In [63]: %%timeit 
    ...: B = []
    ...: for i in range(10):
    ...:   sum = np.zeros((1,16))
    ...:   for j in range(100):
    ...:     sum += np.dot(A[j], W[i*100+j])   
    ...:   B.append(sum)
    ...: B = np.asarray(B)     #B.shape=(10,16)
1000 loops, best of 3: 1.81 ms per loop

# Other post's einsum soln
In [64]: %timeit np.einsum('ij,ikjl',A,np.reshape(W,(100,10,8,16), order='F'))
10000 loops, best of 3: 83.4 µs per loop

# Other post's einsum soln without fortran re-ordering
In [65]: %timeit np.einsum('jk,ijkl', A, np.reshape(W, (10, 100, 8, 16)))
10000 loops, best of 3: 83.3 µs per loop

In [66]: %timeit tensordot_app(A, W)
10000 loops, best of 3: 193 µs per loop

没想到会这样,但这比
tensordot
快。此外,您还可以使用以下命令避免fortran语言:
np.einsum('jk,ijkl',A,np.restrape(W,(10100,8,16))
。在我的帖子中添加了计时。@Divakar,为什么这个不起作用:
np.einsum('ij,ikjl',A,np.reformate(W,(100,10,8,16))
?它生成正确的输出形状,但值错误…@MichaelSB,因为我们需要拆分
W
的第一个轴,以便后一个轴的长度为100,与A的第一个轴的长度之和减小。@MichaelSB默认情况下,C-style,最后一个索引变化最快。因此,将1000个元素重塑为(100,10)可以得到100个大小为10的块,而不是10个大小为100的块。我通过使用Fortran风格来解决这个问题,通过改变轴的顺序来使用Divakar。对于一个具体的例子,比较一下
np.reformate(np.arange(6)、(2,3))
np.reformate(np.arange(6)、(2,3),order='F')
,和
np.reformate(np.arange(6)、(3,2))
@MichaelSB
np.einsum('jk,ijkl->ijl',a,np.reformate(W,(10,100,8,16))
In [62]: A = np.random.randn(100,8)
    ...: W = np.random.randn(1000,8,16)

In [63]: %%timeit 
    ...: B = []
    ...: for i in range(10):
    ...:   sum = np.zeros((1,16))
    ...:   for j in range(100):
    ...:     sum += np.dot(A[j], W[i*100+j])   
    ...:   B.append(sum)
    ...: B = np.asarray(B)     #B.shape=(10,16)
1000 loops, best of 3: 1.81 ms per loop

# Other post's einsum soln
In [64]: %timeit np.einsum('ij,ikjl',A,np.reshape(W,(100,10,8,16), order='F'))
10000 loops, best of 3: 83.4 µs per loop

# Other post's einsum soln without fortran re-ordering
In [65]: %timeit np.einsum('jk,ijkl', A, np.reshape(W, (10, 100, 8, 16)))
10000 loops, best of 3: 83.3 µs per loop

In [66]: %timeit tensordot_app(A, W)
10000 loops, best of 3: 193 µs per loop