如何计算外和(类似于外积

问题描述 投票:0回答:3

给定张量

x
y
,每个形状为
(num_batches, d)
,如何使用 PyTorch 计算批次中
x
y
的每个组合的总和?

这与外积类似,只不过我们不想相乘,而是sum。 (这意味着我可以通过求幂、外积和取对数来解决这个问题,但这当然有数值和性能上的缺点)。

可以通过笛卡尔积来完成,然后对每个组合求和。

本质上,我想要

osum[b, i, j] == x[b, i] + y[b, j]
。 PyTorch 可以在张量中做到这一点,而不需要循环吗?

pytorch numpy-einsum
3个回答
1
投票

这可以通过将单例维度引入

x
y
以及沿这些单例维度进行 广播 来轻松完成:

osum = x[..., None] + y[:, None, :]

例如:

x = torch.arange(6).view(2,3)
y = x * 10
osum = x[..., None] + y[:, None, :]

结果:

tensor([[[ 0, 10, 20],
         [ 1, 11, 21],
         [ 2, 12, 22]],

        [[33, 43, 53],
         [34, 44, 54],
         [35, 45, 55]]])

更新(7 月 14 日): 它是如何工作的?

您有两个张量,

x
y
,形状为
b
x
n
,并且您想要计算:

osum[b,i,j] = x[b, i] + y[b, j]

从概念上讲,我们可以通过沿第三个维度重复

xx
yy
的每个元素来创建新变量
x
y
,这样:

xx[b, i, j] == x[b, i]  # for all j
yy[b, i, j] == y[b, j]  # for all i

通过这些新变量,很容易看出:

osum = xx + yy

从那时起,根据定义

osum[b, i, j] == xx[b, i, j] + yy[b, i, j] == x[b, i] + y[b, j]

现在,您可以使用

torch.expand
torch.repeat
等命令来显式地创建
xx
yy
- 但为什么还要麻烦呢?由于它们的元素只是沿特定维度的元素的简单重复,因此广播隐式地为您完成此操作。


1
投票

您可以使用广播来执行此类操作:

>>> x = torch.randint(0,10,(2,4))
tensor([[0, 6, 5, 8],
        [3, 0, 7, 5]])
>>> y = torch.randint(0,10,(2,5))
tensor([[6, 9, 9, 8, 7],
        [0, 4, 6, 2, 5]])

>>> x[:,:,None].shape
(2, 4, 1)

>>> y[:,None].shape
(2, 1, 5])

向不同的维度添加单例可确保“外部”操作 已执行。

>>> osum = x[:,:,None] + y[:,None]
tensor([[[ 6,  9,  9,  8,  7],
         [12, 15, 15, 14, 13],
         [11, 14, 14, 13, 12],
         [14, 17, 17, 16, 15]],

        [[ 3,  7,  9,  5,  8],
         [ 0,  4,  6,  2,  5],
         [ 7, 11, 13,  9, 12],
         [ 5,  9, 11,  7, 10]]])

0
投票

也许有点晚了,但是如果你将结构化张量放在列表中,你可以做这样的事情。

def outer_sum(x: List[torch.Tensor]) -> torch.Tensor:
    """
    Returns the outer sum of a list of one-dimensional arrays
    Example: 
    x = [a, b, c]
    out = a[..., None, None] + b[..., None] + c
    """
    def _sum(a, b):
        return a[..., None] + b
    return reduce(_sum, x)

使用

reduce
中的
functools
可以得到更优雅的解决方案。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.