OpenAI 的强化学习 REINFORCE 和 actor-critic 示例具有以下代码:
加强:
policy_loss = torch.cat(policy_loss).sum()
loss = torch.stack(policy_losses).sum() + torch.stack(value_losses).sum()
torch.cat
,另一个使用 torch.stack
,用于类似的用例。
据我的理解,文档没有给出它们之间的任何明确区别。
我很高兴知道这些功能之间的差异。
t1 = torch.tensor([[1, 2],
[3, 4]])
t2 = torch.tensor([[5, 6],
[7, 8]])
这些功能类似于 和 numpy.concatenate
。
import torch
# stack vs cat
# cat "extends" a list in the given dimension e.g. adds more rows or columns
x = torch.randn(2, 3)
print(f'{x.size()}')
# add more rows (thus increasing the dimensionality of the column space to 2 -> 6)
xnew_from_cat = torch.cat((x, x, x), 0)
print(f'{xnew_from_cat.size()}')
# add more columns (thus increasing the dimensionality of the row space to 3 -> 9)
xnew_from_cat = torch.cat((x, x, x), 1)
print(f'{xnew_from_cat.size()}')
print()
# stack serves the same role as append in lists. i.e. it doesn't change the original
# vector space but instead adds a new index to the new tensor, so you retain the ability
# get the original tensor you added to the list by indexing in the new dimension
xnew_from_stack = torch.stack((x, x, x, x), 0)
print(f'{xnew_from_stack.size()}')
xnew_from_stack = torch.stack((x, x, x, x), 1)
print(f'{xnew_from_stack.size()}')
xnew_from_stack = torch.stack((x, x, x, x), 2)
print(f'{xnew_from_stack.size()}')
# default appends at the from
xnew_from_stack = torch.stack((x, x, x, x))
print(f'{xnew_from_stack.size()}')
print('I like to think of xnew_from_stack as a \"tensor list\" that you can pop from the front')
输出:
torch.Size([2, 3])
torch.Size([6, 3])
torch.Size([2, 9])
torch.Size([4, 2, 3])
torch.Size([2, 4, 3])
torch.Size([2, 3, 4])
torch.Size([4, 2, 3])
I like to think of xnew_from_stack as a "tensor list"
以下定义可供参考:
cat:连接给定维度中给定的 seq 张量序列。结果是特定尺寸改变尺寸,例如dim=0 那么您将向行添加元素,这会增加列空间的维度。
stack:沿新维度连接张量序列。我喜欢将其视为火炬“追加”操作,因为您可以通过从前面“弹出”来索引/获取原始张量。如果没有参数,它将张量附加到张量的前面。
tensor.torch
将张量的嵌套列表转换为具有多个维度且尊重嵌套列表深度的大张量。
def tensorify(lst):
"""
List must be nested list of tensors (with no varying lengths within a dimension).
Nested list of nested lengths [D1, D2, ... DN] -> tensor([D1, D2, ..., DN)
:return: nested list D
"""
# base case, if the current list is not nested anymore, make it into tensor
if type(lst[0]) != list:
if type(lst) == torch.Tensor:
return lst
elif type(lst[0]) == torch.Tensor:
return torch.stack(lst, dim=0)
else: # if the elements of lst are floats or something like that
return torch.tensor(lst)
current_dimension_i = len(lst)
for d_i in range(current_dimension_i):
tensor = tensorify(lst[d_i])
lst[d_i] = tensor
# end of loop lst[d_i] = tensor([D_i, ... D_0])
tensor_lst = torch.stack(lst, dim=0)
return tensor_lst
这里有一些单元测试(我没有编写更多测试,但它适用于我的真实代码,所以我相信它没问题。如果需要,请随时帮助我添加更多测试):
def test_tensorify():
t = [1, 2, 3]
print(tensorify(t).size())
tt = [t, t, t]
print(tensorify(tt))
ttt = [tt, tt, tt]
print(tensorify(ttt))
if __name__ == '__main__':
test_tensorify()
print('Done\a')
import torch
torch.__version__ # 1.10.2
x = [torch.randn(1) for _ in range(10000)]
torch.cat(x).shape, torch.stack(x).shape # torch.Size([10000]), torch.Size([10000, 1])
%timeit torch.cat(x) # 1.5 ms ± 476 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit torch.cat(x).reshape(-1,1) # 1.95 ms ± 534 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit torch.stack(x) # 5.36 ms ± 643 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
我的结论是,即使你想拥有torch.stack
的附加维度,使用
torch.cat
然后使用
reshape
会更好。
注意:这篇文章取自PyTorch论坛(我是原帖的作者)
stack() 可以连接一系列一个或多个 0D 或多个 D 张量,如下所示:
*备注:
stack()
可以与torch 一起使用,但不能与张量一起使用。
torch
的第一个参数是
tensors
(必需类型:
tuple
或
list
的
tensor
、
int
、
float
或
complex
)。 *张量的大小必须相同。
带有
bool
torch
(可选-默认:
dim
-类型:
0
)。
int
tensors+1D
cat()连接一系列
import torch
tensor1 = torch.tensor(2)
tensor2 = torch.tensor(7)
tensor3 = torch.tensor(4)
torch.stack(tensors=(tensor1,)) # tensor([2])
torch.stack(tensors=(tensor1, tensor2)) # tensor([2, 7])
torch.stack(tensors=(tensor1, tensor2, tensor3)) # tensor([2, 7, 4])
tensor1 = torch.tensor([[2, 7, 4], [8, 3, 2]])
tensor2 = torch.tensor([[5, 0, 8], [3, 6, 1]])
tensor3 = torch.tensor([[9, 4, 7], [1, 0, 5]])
torch.stack(tensors=(tensor1, tensor2, tensor3))
torch.stack(tensors=(tensor1, tensor2, tensor3), dim=0)
torch.stack(tensors=(tensor1, tensor2, tensor3), dim=-3)
# tensor([[[2, 7, 4], [8, 3, 2]],
# [[5, 0, 8], [3, 6, 1]],
# [[9, 4, 7], [1, 0, 5]]])
torch.stack(tensors=(tensor1, tensor2, tensor3), dim=1)
torch.stack(tensors=(tensor1, tensor2, tensor3), dim=-2)
# tensor([[[2, 7, 4], [5, 0, 8], [9, 4, 7]],
# [[8, 3, 2], [3, 6, 1], [1, 0, 5]]])
torch.stack(tensors=(tensor1, tensor2, tensor3), dim=2)
torch.stack(tensors=(tensor1, tensor2, tensor3), dim=-1)
# tensor([[[2, 5, 9], [7, 0, 4], [4, 8, 7]],
# [[8, 3, 1], [3, 6, 0], [2, 1, 5]]])
一个或多个 1D 或多个 D 张量,如下所示:
*备注:
seq