Theano - 使用tensordot计算两个张量的点积

4

我想使用tensordot计算两个张量特定维度的点积。例如:

A是一个形状为(3,4,5)的张量, B是一个形状为(3,5)的张量。

我想在A的第三个维度和B的第二个维度上进行点积运算,并获得一个输出,其维度为(3,4)。

如下所示:

for i in range(3):
    C[i] = dot(A[i], B[i])

如何使用tensordot完成此操作?


1
你似乎想要将B的第三个轴与A的第二个轴相乘,但似乎你并不想保留所有的组合(那将是形状为(3, 4, 3)和tensordot结果)。因此,你应该明确表示你想要结果的对角线。 - eickenberg
2个回答

4

好的,您需要使用numpy还是Theano进行翻译呢?根据您所述的情况,如果您想将A的轴3缩减与B的轴2相乘,则两者都很简单:

import numpy as np

a = np.arange(3 * 4 * 5).reshape(3, 4, 5).astype('float32')
b = np.arange(3 * 5).reshape(3, 5).astype('float32')

result = a.dot(b.T)

Theano中的写法如下:

import theano.tensor as T

A = T.ftensor3()
B = T.fmatrix()

out = A.dot(B.T)

out.eval({A: a, B: b})

然而,输出结果的形状为 (3, 4, 3)。由于您似乎想要一个形状为 (3, 4) 的输出结果,因此numpy提供了另一种替代方案,使用einsum函数,如下所示:

einsum_out = np.einsum('ijk, ik -> ij', a, b)

然而,Theano 中不存在 einsum。因此,可以通过以下方式模拟这个特殊情况

out = (a * b[:, np.newaxis]).sum(2)

这也可以用Theano编写

out = (A * B.dimshuffle(0, 'x', 1)).sum(2)
out.eval({A: a, B: b})

2
在这种情况下,einsum 可能比 tensordot 更容易理解。例如:
c = np.einsum('ijk,ik->ij', a, b)

我将简化解释以使事情更易于理解。我们有两个输入数组(由逗号分隔),这产生了我们的输出数组(在 -> 右侧)。

  • a 的形状为 3, 4, 5,我们将其称为 ijk
  • b 的形状为 3, 5ik
  • 我们希望输出 c 的形状为 3, 4ij

看起来有点神奇,不是吗?让我们稍微分解一下。

  • 我们穿过 -> 时“失去”的字母是将被求和的轴。这也是 dot 所做的。
  • 我们希望输出的形状为 3, 4,因此我们要消除 k
  • 因此,输出 c 应该是 ij
  • 这意味着我们将把 b 称为 ik

完整示例:

import numpy as np

a = np.random.random((3, 4, 5))
b = np.random.random((3, 5))

# Looping through things
c1 = []
for i in range(3):
    c1.append(a[i].dot(b[i]))
c1 = np.array(c1)

# Using einsum instead
c2 = np.einsum('ijk,ik->ij', a, b)

assert np.allclose(c1, c2)

你也可以使用 tensordot 来完成这个操作。我会尽快添加一个例子。(当然,如果有人想在此期间添加另一个 tensordot 的例子作为答案,欢迎!)

谢谢!期待张量点积版本! - Joe

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