2

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

我需要通过用 W 的第一列点 X 的前 ni 行来得到一个 (ni*43*91) 向量 y 以获得 y 的第一个 ni 元素和 X 的第二个 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 循环,这可能吗?

4

3 回答 3

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])
于 2014-08-10T15:19:49.560 回答
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)

如果您使用工作代码更新您的问题,即 and 的完整描述dim2dim3我们可以对其进行微调以返回完全相同的内容(如果还没有的话)。

于 2013-03-22T21:41:43.023 回答
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增长。

我现在有点着急,但是如果您需要进一步的解释,请发表评论。

于 2013-03-26T12:44:56.443 回答