2013-03-22 2 views
2

У меня есть X-матрица с формой (ni * 43 * 91) x67 и тензор W с формой 67x43x91. ni меняетсяКак векторизовать это умножение?

Мне нужно получить вектор (ni * 43 * 91) y, усеяв первые ni строки X первым столбцом W, чтобы получить первые ni элементов y и вторых ni строк X с второй столбец W для получения вторых ni элементов y и т. д. и т. д. Когда у меня заканчиваются столбцы в W, я перехожу к следующему измерению и продолжаю.

У меня есть две маски dim2 и dim3, обе формы (ni * 43 * 91), в порядке. Сейчас это то, что я делаю (упрощенно), и это очень медленно

for d3 in range(91): 
    for d2 in range(43): 
    mask = ((dim3 == d3) & (dim2 == d2)) 
    curr_X = X[mask, :] 
    curr_W = W[:,d2,d3] 
    curr_y = numpy.dot(curr_X,curr_W) 
    y[mask] = curr_y 

Возможно ли это без петель для?

+3

Не уверен, что это сработает, но вы просмотрели http://docs.scipy.org/doc/numpy/reference/generated/numpy.einsum.html или http://docs.scipy.org/doc/numpy /reference/generated/numpy.tensordot.html#numpy.tensordot – JoshAdel

ответ

0

Я не совсем понимаю, что ваши dim2 и dim3 массивов, и как строятся mask, но из вашего описания, вы хотите что-то близкое к этому:

ni = 10 
a, b, c = 43, 91, 67 
X = np.random.rand(ni*a*b, c) 
W = np.random.rand(c, a, b) 

X = X.reshape(ni, a*b, c) 
W = W.reshape(c, a*b) 

y = np.einsum('ijk, kj -> ij', X, W) 
y = y.reshape(-1) 

Если вы обновляете ваш вопрос с рабочим код, то есть полное описание dim2 и dim3, мы можем точно настроить его, чтобы вернуть то же самое, если он этого еще не сделал.

+0

ni не является постоянным, но меняется. dim2 и dim3 являются масками, так что я могу взять строки ni, соответствующие размерности d2 и d3 W. Они подобны dim2 = [0,0,0,1,1,2,3,3,0,0, 1,2,2,3] dim3 = [0,0,0,0,0,0,0,0,1,1,1,1,1,1] n1 = 3 n2 = 2 n3 = 1 n4 = 2 ... – siamii

+2

@ bizso09 Вы пробовали, если код в ответе дает вам те же результаты, что и ваши циклы? – Jaime

+0

у вас ni фиксированный как 10, поэтому я не могу его сравнить. – siamii

0

Во-первых, неясно, что вы хотите делать, так как ваш код не работает. Я могу только догадываться вы хотите сделать это:

from numpy import * 
from numpy.random import rand 

ni=12 
A=67 
B=43 
C=91 


X = rand(ni*B*C,A) 
W = rand(A,B,C) 

y = zeros((ni*B*C)) 

for k in xrange(len(y)): 
    b = (k/ni)/C 
    c = (k/ni) % C 

    #print 'y[%i] = dot(X[%i,:],W[:,%i,%i])'%(k,k,b,c) 

    y[k] = dot(X[k,:],W[:,b,c]) 

Если вы просто установите A,B,C,ni в некоторых более низких значений и раскомментируйте print -LINE, вы будете быстро увидеть, что делает этот алгоритм.

Если это то, что вы хотите, то вы можете сделать это быстрее с этим однострочника:

y2 = sum(X * (W.reshape((A,B*C)).swapaxes(0,1).repeat(ni,axis=0)),axis=1) 

Несмотря на некоторый индекс-перестроек решающий трюк здесь заключается в использовании repeat, потому что в цикле индексы b,c «заморозить» для ni шагов, в то время как k растет.

Я немного спешу в данный момент, но если вам нужны дополнительные объяснения, просто оставьте комментарий.

+0

ni меняется, а не постоянна. Вы не можете объявить его сверху – siamii

+1

Я не понимаю этого, как может варьироваться количество элементов в 'X'? Что означает формулировка * X-матрица с формой (ni * 43 * 91) x67 *, когда «ni» меняется »? – flonk

+0

Число элементов в X не меняется, только ni. если X имеет m строк, то разделите эти m строк на 43 * 91 блоков. Размер первого блока равен n1 ... размер (43 * 91) -го блока равен n (43 * 91). Вы получили каждый блок через маску в моем примере. – siamii

0

Это довольно трудно понять из вопроса, что желаемый результат, но результат я думаю вы после этого можно получить довольно легко, как так:

y = (X.T * W[:,dim2,dim3]).sum(axis=0) 

Сравнение правильности и скорости:

еще
import numpy as np 

# some test data, the sorting isn't really necessary 
N1, N2, N3 = 67, 43, 91 
ni_avg = 1.75 
N = int(ni_avg * N2 * N3) 

dim2 = np.random.randint(N2, size=N) 
dim3 = np.sort(np.random.randint(N3, size=N)) 
for d3 in range(N3): 
    dim2[dim3==d3].sort() 

X = np.random.rand(N, N1) 
W = np.random.rand(N1, N2, N3) 

# original code 
def original(): 
    y = np.empty(X.shape[0]) 
    for d2 in range(W.shape[1]): 
     for d3 in range(W.shape[2]): 
      mask = ((dim3 == d3) & (dim2 == d2)) 
      curr_X = X[mask, :] 
      curr_W = W[:,d2,d3] 
      curr_y = numpy.dot(curr_X,curr_W) 
      y[mask] = curr_y 
    return y 

# comparison 
%timeit original() 
# 1 loops, best of 3: 672 ms per loop 
%timeit (X.T * W[:,dim2,dim3]).sum(axis=0) 
# 10 loops, best of 3: 31.8 ms per loop 
np.allclose(original(), np.sum(X.T * W[:,dim2,dim3], axis=0)) 
# True 

чуть быстрее будет использовать

y = np.einsum('ij,ji->i', X, W[:,dim2,dim3]) 
Смежные вопросы