pytorch 沿着维的点积

yquaqz18  于 6个月前  发布在  其他
关注(0)|答案(2)|浏览(64)

I有两个形状为[B,3,240,320]的Tensor,其中B表示批量,3表示通道,240表示高度(H),320表示宽度(W)。
我需要找到沿着通道维度(3个通道)的点积,这样得到的Tensor将是[B,1,240,320]的形状。我的Tensor在GPU中有float32个元素(cuda到backprop)。
你们能建议我怎么做吗?
谢谢你,谢谢
更多说明:
假设我们有B=10,H=100,W=200。因此,从上面可以看出,第一Tensor和第二Tensor是共同的。如果我们保持B,H,W不变,我们得到一个一维矢量作为合成Tensor(有3个元素)。我需要取这两个矢量的点积。因此合成Tensor的维数为[B,1,240,320]

bwntbbo3

bwntbbo31#

点积是两个向量中的值相乘的总和:


的数据
所以我猜你想乘所有值沿沿着通道尺寸和需要找到的总和的结果,请纠正我,如果我的理解是错误的。

import torch

t1 = torch.rand(10, 3, 240, 320)
t2 = torch.rand(10, 3, 240, 320)

# Multiply two tensors and sum along the channel dimension
multp  = t1 * t2 
summed = multp.sum(dim = 1, keepdim = True)

print(summed.shape)  # torch.Size([10, 1, 240, 320])

字符串

moiiocjp

moiiocjp2#

@yutasrobot的答案很好,但有时你不想显式地计算中间乘法。如果广播的形状太大,可能会导致太多的内存消耗。它也会损害性能,可能是因为它破坏了该高速缓存的增益。看看this答案了解更多关于缓存的信息。
另一种解决方案是使用矩阵乘法或einsum,它不会将乘积复制到RAM中,然后再次获取它。

>>> A = torch.randn(1000, 500, 200)
>>> B = torch.randn(1000, 500, 1)
>>> torch.allclose((A * B).sum(dim=-1), torch.einsum('abc,abc->ab', A, B), atol = 1e-4)
True

>>> %timeit (A * B).sum(dim=-1)
181 ms ± 856 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

>>> %timeit torch.einsum('abc,abc->ab', A, B)
49.4 ms ± 494 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

字符串
额外奖励:
我注意到以下输出为False:

>>> torch.allclose((A * B).sum(dim=-1), torch.einsum('abc,abc->ab', A, B))
False


在检查我是否做错了什么之后,我意识到这不是一个einsum的问题,而是后者的问题。不计算中间产品也有助于数值精度。将乘法存储在另一个Tensor中会产生许多浮点错误,而将产品动态求和可以获得更好的精度。这可以通过以下示例来证明:

>>> C = torch.randn(1000000)
>>> D = torch.randn(1000000)

>>> (C * D).sum()
tensor(191.5947)

>>> torch.dot(C, D)
tensor(191.5979)

>>> torch.einsum('i,i->', C, D)
tensor(191.5979)

相关问题