2017-02-20 27 views
0

Я пытаюсь научиться эффективно реализовывать различную нейронную сеть в питоне и в настоящее время пытаюсь реализовать эту модельУпрощения петельных Numpy операции

.

Однако у меня возникли проблемы с использованием операций 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

Это лучше подходит для [код-обзор], если у вас есть конкретный вопрос/ошибка. – Julien

+0

@JulienBernu Извините, я новичок. Я редактировал. –

+0

Вам также нужно объяснить, что такое «требуемый результат». Люди вряд ли будут копать всю бумагу, чтобы понять, чего вы хотите. Пожалуйста, предоставьте [mcve]. – Julien

ответ

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.]]) 

Это подводит на j и k. В версии цикла сумма на 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]]])