Numpy 点积和
如何使用1000个不同的(8,16)权重矩阵将8个元素向量中的100个转换为10个16个元素向量?10个输出向量中的每一个都是100个点积的总和: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
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))
@MichaelSBnp.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