在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
案例Bsum
需要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