在PyTorch中添加多个张量

在PyTorch中添加多个张量,pytorch,tensor,Pytorch,Tensor,我可以像这样加上两个张量x和y x = x.add(y) 如果所有的张量都有相同的尺寸,有没有一种方法可以对三个或更多的张量进行相同的处理?result=torch.sum(torch.stack([x,y,…]),dim=0) 无堆栈: 从functools导入reduce 结果=减少(torch.add,[x,y,…]) 编辑 正如@LudvigH所指出的,第二种方法的内存效率不如就地加法。所以最好是这样: 从functools导入reduce 结果=减少( torch.Tensor.

我可以像这样加上两个张量
x
y

x = x.add(y)
如果所有的张量都有相同的尺寸,有没有一种方法可以对三个或更多的张量进行相同的处理?

result=torch.sum(torch.stack([x,y,…]),dim=0)
无堆栈:

从functools导入reduce
结果=减少(torch.add,[x,y,…])
编辑

正如@LudvigH所指出的,第二种方法的内存效率不如就地加法。所以最好是这样:

从functools导入reduce
结果=减少(
torch.Tensor.add\,
[x,y,…],
torch.zero_like(x)#可选择设置初始元素以避免更改'x'`
)
result=torch.sum(torch.stack([x,y,…]),dim=0)
无堆栈:

从functools导入reduce
结果=减少(torch.add,[x,y,…])
编辑

正如@LudvigH所指出的,第二种方法的内存效率不如就地加法。所以最好是这样:

从functools导入reduce
结果=减少(
torch.Tensor.add\,
[x,y,…],
torch.zero_like(x)#可选择设置初始元素以避免更改'x'`
)

操作到位有多重要

我相信进行加法的唯一方法是使用
add\uu
函数

例如:

a = torch.randn(5)
b = torch.randn(5)
c = torch.randn(5)
d = torch.randn(5)

a.add_(b).add_(c).add_(d) # in place addition of a+b+c+d

操作到位有多重要

我相信进行加法的唯一方法是使用
add\uu
函数

例如:

a = torch.randn(5)
b = torch.randn(5)
c = torch.randn(5)
d = torch.randn(5)

a.add_(b).add_(c).add_(d) # in place addition of a+b+c+d

一般来说,PyTorch中的就地操作比较棘手。他们不鼓励使用它。我认为这源于这样一个事实,即它很容易搞糟,破坏计算图表,并给你带来意想不到的结果。此外,还有许多GPU优化无论如何都会完成,强制就地操作最终会降低性能。但是假设你真的知道你在做什么,并且你想用兼容的形状求和很多张量,我会使用以下模式:

导入工具
进口经营者
_张量列表=[a,b,c]#一些先前定义的张量
functools.reduce(operator.iadd,张量列表)
###现在张量a是所有张量的总和
它建立在
reduce
模式的基础上,这意味着“对列表/iterable中的所有元素执行此操作”,以及
operator.iadd
模式的基础上,这意味着
+=
+=
有很多注意事项,因为它可能会搞乱范围,并对字符串等不可变变量表现出意外的行为。但在PyTorch的背景下,它做了我们想要的。它调用
添加


下面,您可以看到一个简单的基准

从functools导入reduce
从操作员导入iadd
进口火炬
def make_张量():
返回[torch.randn(5,5)在(1000)范围内]
def配置文件_操作(标签、操作):
打印(标签)
张量列表=生成张量()
使用torch.autograd.profiler.profile(
profile\u memory=True,record\u shapes=True
)作为教授:
动作(张量列表)
打印(prof.key\u averages().表(sort\u by=“self\u cpu\u memory\u usage”))
剖面图_动作(“案例A:”,lambda张量:torch.sum(torch.stack(张量),dim=0))
剖面_作用(“情况B:,λ张量:和(张量))
剖面_作用(“案例C:,lambda张量:reduce(torch.add,张量))
剖面_作用(“案例C:,lambda张量:reduce(iadd,张量))
当然,每次运行的结果各不相同,但这种拷贝粘贴在我的机器上有一定的代表性。试试你的!pytorch版本可能也会有一些变化

--------------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  
                Name    Self CPU %      Self CPU   CPU total %     CPU total  CPU time avg       CPU Mem  Self CPU Mem    # of Calls
--------------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------
       aten::resize_         0.14%      14.200us         0.14%      14.200us      14.200us      97.66 Kb      97.66 Kb             1
         aten::empty         0.06%       5.800us         0.06%       5.800us       2.900us         100 b         100 b             2
         aten::stack        17.38%       1.751ms        98.71%       9.945ms       9.945ms      97.66 Kb           0 b             1
     aten::unsqueeze        30.55%       3.078ms        78.55%       7.914ms       7.914us           0 b           0 b          1000
    aten::as_strided        48.02%       4.837ms        48.02%       4.837ms       4.833us           0 b           0 b          1001
           aten::cat         0.73%      73.800us         2.78%     280.000us     280.000us      97.66 Kb           0 b             1
          aten::_cat         1.87%     188.900us         2.05%     206.200us     206.200us      97.66 Kb           0 b             1
           aten::sum         1.09%     109.400us         1.29%     130.100us     130.100us         100 b           0 b             1
         aten::fill_         0.17%      16.700us         0.17%      16.700us      16.700us           0 b           0 b             1
            [memory]         0.00%       0.000us         0.00%       0.000us       0.000us     -97.75 Kb     -97.75 Kb             2
--------------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------
Self CPU time total: 10.075ms

-----------------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  
                   Name    Self CPU %      Self CPU   CPU total %     CPU total  CPU time avg       CPU Mem  Self CPU Mem    # of Calls
-----------------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------
              aten::add        99.32%      14.711ms       100.00%      14.812ms      14.812us      97.66 Kb      97.65 Kb          1000
    aten::empty_strided         0.07%      10.400us         0.07%      10.400us      10.400us           4 b           4 b             1
               aten::to         0.37%      54.900us         0.68%     100.400us     100.400us           4 b           0 b             1
            aten::copy_         0.24%      35.100us         0.24%      35.100us      35.100us           0 b           0 b             1
               [memory]         0.00%       0.000us         0.00%       0.000us       0.000us     -97.66 Kb     -97.66 Kb          1002
-----------------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------
Self CPU time total: 14.812ms

-------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  
         Name    Self CPU %      Self CPU   CPU total %     CPU total  CPU time avg       CPU Mem  Self CPU Mem    # of Calls
-------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------
    aten::add       100.00%      10.968ms       100.00%      10.968ms      10.979us      97.56 Kb      97.56 Kb           999
     [memory]         0.00%       0.000us         0.00%       0.000us       0.000us     -97.56 Kb     -97.56 Kb           999
-------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------
Self CPU time total: 10.968ms

--------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  
          Name    Self CPU %      Self CPU   CPU total %     CPU total  CPU time avg       CPU Mem  Self CPU Mem    # of Calls
--------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------
    aten::add_       100.00%       5.184ms       100.00%       5.184ms       5.190us           0 b           0 b           999
--------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------  ------------
Self CPU time total: 5.184ms
我分配1000个包含25倍32位浮点的张量(每个张量总共100b,100kb=97.66Kb)。运行时和内存占用的差异非常惊人

案例A,
torch.sum(torch.stack(张量列表),dim=0)
为堆栈分配100kb,为结果分配100b,耗时10ms

案例B
sum
需要14毫秒。我想主要是因为python的开销。它为每个加法的所有中间结果分配10kb

案例C使用了
reduce add
,它消除了一些开销,获得了运行时性能(11ms),但仍然分配了中间结果。这一次,它不是以0-初始化开始的,而
sum
是以0-初始化开始的,因此我们只进行999次加法,而不是1000次,并分配一个中间结果。与案例B的区别很小,在大多数运行中,它们都有相同的运行时


案例D是我推荐的就地添加可数/张量列表的方法。它大约需要一半的时间,并且不分配额外的内存。有效率的但是你浪费了列表中的第一个张量,因为你在原地执行操作。

一般来说,PyTorch中的原地操作很棘手。他们不鼓励使用它。我认为这源于这样一个事实,即它很容易搞糟,破坏计算图表,并给你带来意想不到的结果。此外,还有许多GPU优化无论如何都会完成,强制就地操作最终会降低性能。但是假设你真的知道你在做什么,并且你想用兼容的形状求和很多张量,我会使用以下模式:

导入工具
进口经营者
_张量列表=[a,b,c]#一些先前定义的张量
functools.reduce(operator.iadd,张量列表)
###现在张量a是所有张量的总和
它建立在
reduce
模式的基础上,这意味着“对列表/iterable中的所有元素执行此操作”,以及
operator.iadd
模式的基础上,这意味着
+=
+=
有很多注意事项,因为它可能会搞乱范围,并对字符串等不可变变量表现出意外的行为。但在PyTorch的背景下,它做了我们想要的。它调用
添加


下面,您可以看到一个简单的基准

fro