简化循环numpy操作

时间:2017-02-20 00:35:07

标签: python numpy scipy matrix-multiplication

我正在努力学习如何在python中有效地实现各种神经网络,并且我正在尝试实现这个模型

但是,我在使用numpy操作来实现求和时遇到了麻烦。

我一直关注this existing implementation并试图简化它,但我并不完全清楚正在执行的所有阵列操作是什么。我的解释是C乘以R的每一列并求和。但是,我的einsum实现np.einsum('ijk,km->ij', C, R)似乎没有产生所需的结果。

我希望有一些简化此实现的指示。我目前的尝试是使用np.einsum,但到目前为止还没有让我到任何地方。

简化代码(在图像/第一个链接中解释):

batchsize = X.shape[0]
R = self.R
C = self.C
bw = self.bw

# Obtain word features
tmp = R.as_numpy_array()[:,X.flatten()].flatten(order='F')
tmp = tmp.reshape((batchsize, self.K * self.context))
words = np.zeros((batchsize, self.K, self.context))
for i in range(batchsize):
    words[i,:,:] = tmp[i,:].reshape((self.K, self.context), order='F')
words = gpu.garray(words)

# Compute the hidden layer (predicted next word representation)
acts = gpu.zeros((batchsize, self.K))
for i in range(self.context):
    acts = acts + gpu.dot(words[:,:,i], C[i,:,:])

1 个答案:

答案 0 :(得分:2)

创建小words

In [565]: words = np.zeros((2,3,4))
In [566]: tmp = np.arange(2*3*4).reshape((2,3*4))
In [567]: for i in range(2):
     ...:     words[i,:,:] = tmp[i,:].reshape((3,4),order='F')
     ...:     
In [568]: tmp
Out[568]: 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]])
In [569]: words
Out[569]: 
array([[[  0.,   3.,   6.,   9.],
        [  1.,   4.,   7.,  10.],
        [  2.,   5.,   8.,  11.]],

       [[ 12.,  15.,  18.,  21.],
        [ 13.,  16.,  19.,  22.],
        [ 14.,  17.,  20.,  23.]]])

我很确定这可以在没有循环的情况下完成

In [577]: C = np.ones((4,3,3))
In [578]: acts = np.zeros((2,3))
In [579]: for i in range(4):
     ...:     acts += np.dot(words[:,:,i], C[i,:,:])
     ...:     
In [580]: acts
Out[580]: 
array([[  66.,   66.,   66.],
       [ 210.,  210.,  210.]])

dot循环可以einsum表示为:

In [581]: np.einsum('ijk,kjm->im', words, C)
Out[581]: 
array([[  66.,   66.,   66.],
       [ 210.,  210.,  210.]])

这是jk的总结。在循环版本中,j上的总和在dot中完成,k上的总和在循环中完成。但是对于非常大的数组,并且gpu加速,循环版本可能更快。如果问题空间太大,einsum可能会很慢,甚至会出现内存错误(尽管最新版本有一些优化选项)。

words可以从tmp创建,无需循环:

In [585]: tmp.reshape(2,3,4, order='F')
Out[585]: 
array([[[ 0,  3,  6,  9],
        [ 1,  4,  7, 10],
        [ 2,  5,  8, 11]],

       [[12, 15, 18, 21],
        [13, 16, 19, 22],
        [14, 17, 20, 23]]])