如何对这个乘法进行矢量化?

时间:2013-03-22 20:52:49

标签: python numpy vectorization

我有一个形状为(ni * 43 * 91)x67的X矩阵和一个形状为67x43x91的W张量。 ni各不相同

我需要通过在第一列的W点上X的第一行来获得(ni * 43 * 91)矢量y,得到y的第一个ni元素和第二列的第二个W得到y的第二个ni元素,依此类推。当我用完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

没有for循环可以吗?

3 个答案:

答案 0 :(得分:0)

我不完全了解您的dim2dim3数组是什么,以及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)

如果您使用工作代码更新问题,即dim2dim3的完整说明,我们可以对此进行微调以返回完全相同的内容(如果尚未完成)。

答案 1 :(得分: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 - 行,您将很快看到此算法的作用。

如果这就是你想要的,那么你可以用这个单线快速完成:

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

尽管有一些索引重排,但这里的关键技巧是使用repeat,因为在循环中,b,c步骤的ni“冻结”,而k增长。{{1}}增长。

此刻我有点匆忙,但如果您需要进一步解释,请发表评论。

答案 2 :(得分: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])