0

我对张量点操作有一个相当快速的问题。我试图弄清楚是否有一种方法可以在两个张量之间执行张量积以获得我想要的正确形状输出。其中一个张量是 BXLXD 维度,另一个是 BX 1 XD 维度,我试图弄清楚是否有可能最终得到 BXD 矩阵。

目前,我正在遍历 B 维并在 1 个 XD 和 DXL(转置 LXD)矩阵之间执行矩阵乘法并将它们堆叠到最后得到 BXL 矩阵。这显然不是最快的方法,因为循环可能很昂贵。是否可以通过执行快速张量点获得所需的 BXD 形状输出?我似乎无法找到摆脱其中一个 B 的方法。

任何见解或方向将不胜感激。

4

2 回答 2

1

一种选择

是使用torch.bmm()which 正是这样做的(docs)。

它采用形状为 (b, n, m) 和 (b, m, p) 的张量,并返回形状为 (b, n, p) 的批量矩阵乘法。

(我假设您输入了 BXL 的结果,因为 1 XD 和 DXL 的矩阵乘法的形状为 1 XL 而不是 1 XD)。

在你的情况下:

import torch
B, L, D = 32, 10, 512

a = torch.randn(B, 1, D)    #shape (B X 1 X D)
b = torch.randn(B, L, D)    #shape (B X L X D)

b = b.transpose(1,2)        #shape (B X D X L)

result = torch.bmm(a, b)

result = result.squeeze()
print(result.shape)
>>> torch.Size([32, 10])

或者

您可以使用torch.einsum(),在我看来,它更紧凑但可读性较差:

import torch
B, L, D = 32, 10, 512

a = torch.randn(B, 1, D)
b = torch.randn(B, L, D)

result = torch.einsum('abc, adc->ad', a, b)

print(result.shape)
>>> torch.Size([32, 10])

最后的挤压是为了使您的结果为形状 (32, 10) 而不是形状 (32, 1, 10)。

于 2021-11-05T22:04:56.893 回答
0

我相信torch.einsum这是执行张量求和最直观的方法:

>>> torch.einsum('bld,bed->bd', x, y)

其形状为(B, D)

明确表述,这里执行的操作等价于:

res = torch.zeros(B, D)
for b in range(B):
    for l in range(L):
        for d in range(D):
            res += x[b,l,d]*y[b,0,d]

实际上,第二个轴y也循环了,但范围只是[0],因为y的第二维是单例。

于 2021-11-05T22:10:35.690 回答