多维数组沿一维的向量点积

4
我希望使用Theano计算两个多维数组中一个维度上的乘积和。首先,我会用numpy描述我想做的事情。 numpy.tensordotnumpy.dot似乎总是执行矩阵乘积,而我实际上正在寻找批量等效的向量乘积。给定xy,我想这样计算z
x = np.random.normal(size=(200, 2, 2, 1000))
y = np.random.normal(size=(200, 2, 2))

# this is how I now approach it:
z = np.sum(y[:,:,:,np.newaxis] * x, axis=1)

# z is of shape (200, 2, 1000)

现在我知道numpy.einsum可能能帮助我,但是我想在Theano中进行这个特定的计算,它没有einsum等效函数。我将需要使用dottensordot或Theano的专用einsum子集函数batched_dotbatched_tensordot
我寻求改变我的方法的原因是性能;我怀疑使用内置(CUDA)点积将比依赖广播、逐元素乘积和求和更快。

我认为由于第一个轴的轴对齐要求,您可能希望扩展维度并进行求和,就像您在这里所做的那样。 - Divakar
2
仅为完整起见,einsum的解决方案如下:z2 = numpy.einsum('ijkl,ijk->ikl', x, y); numpy.allclose(z, z2); # True。请注意输出索引中没有 j(轴1),这是 einsum 隐式求和的结果。 - Nils Werner
1个回答

1
在Theano中,三维和四维张量的任何维度都不可广播。您需要明确地设置它们。然后Numpy原则就可以正常工作了。一种方法是使用T.patternbroadcast。要了解更多关于广播的信息,请参考this
其中一个张量有三个维度。因此,您首先需要在末尾添加一个单例维度,然后使该维度可广播。这两件事可以通过一个命令T.shape_padaxis来实现。整个代码如下:
import theano
from theano import tensor as T
import numpy as np

X = T.ftensor4('X')
Y = T.ftensor3('Y')
Y_broadcast = T.shape_padaxis(Y, axis=-1)  # appending extra dimension and making it 
                                           # broadcastable
Z = T.sum((X*Y_broadcast), axis=1)  # element-wise multiplication
f = theano.function([X, Y], Z, allow_input_downcast=True)

# Making sure that it works and gives correct results

x = np.random.normal(size=(3, 2, 2, 4))
y = np.random.normal(size=(3, 2, 2))

theano_result = f(x,y)
numpy_result = np.sum(y[:,:,:,np.newaxis] * x, axis=1)
print np.amax(theano_result - numpy_result)  # prints 2.7e-7 on my system, close enough!

我希望这能有所帮助。

实际上,我发布的示例在Theano中几乎完全像这样工作。自从相对较新的Theano版本以来,添加可广播轴可以像在Numpy中一样完成:x[:,:,np.newaxis]将创建一个具有可广播第三维的NxMx1张量。 - EelkeSpaak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接