我正在熟悉来自https://pytorch.org/docs/stable/tensors.html#torch.Tensor.unfold的method展开方法。
我看了他们的例子
>>> x = torch.arange(1., 8)
>>> x
tensor([ 1., 2., 3., 4., 5., 6., 7.])
>>> x.unfold(0, 2, 1)
tensor([[ 1., 2.],
[ 2., 3.],
[ 3., 4.],
[ 4., 5.],
[ 5., 6.],
[ 6., 7.]])我在上面了解到,当我们在维数0中展开时,我们一次取2大小的块,步幅为1,因此,结果是排列不同的块,即[1., 2.]、[2., 3.]等等。因为我们在最后有6块,这些块将被放在一起,最后的形状是(6,2)。
但是,我还有另一个示例,如下所示。
In [115]: s = torch.arange(20).view(1,10,2)
In [116]: s
Out[116]:
tensor([[[ 0, 1],
[ 2, 3],
[ 4, 5],
[ 6, 7],
[ 8, 9],
[10, 11],
[12, 13],
[14, 15],
[16, 17],
[18, 19]]])
In [117]: s.unfold(0,1,1)
Out[117]:
tensor([[[[ 0],
[ 1]],
[[ 2],
[ 3]],
[[ 4],
[ 5]],
[[ 6],
[ 7]],
[[ 8],
[ 9]],
[[10],
[11]],
[[12],
[13]],
[[14],
[15]],
[[16],
[17]],
[[18],
[19]]]])
In [119]: s.unfold(0,1,1).shape
Out[119]: torch.Size([1, 10, 2, 1])所以你看,我原来的张量是形状的(1,10,2),我要求用参数s.unfold(0, 1, 1)展开运算。
根据上一个例子中的原始理解,我假设这意味着在维度0中,我们一次取1块,步幅为1。因此,当我们进入维度0时,我们看到只有一个块大小的(10,2)。因此,输出应该只接受这个块,可能它应该添加一个维度来包装这个块,并给我一个大小为(1, 10, 2)的输出。
但是,它给了我一个大小为(1, 10, 2, 1)的输出。为什么它在最后有一个额外的维度?有人能直截了当地解释一下吗?
发布于 2020-06-12 03:16:16
这些文件指出:
在返回的张量中附加了尺寸为
size的附加维数。
其中size是您指定的块的大小(第二个参数)。根据定义,它总是添加一个额外的维度,这使得无论您选择什么大小,它都是一致的。仅仅因为一个维度的大小为1,并不意味着它应该被自动省略。
关于这背后的直觉,让我们考虑一下,与其返回一个张量,在最后一个维度中表示块,我们创建了一个所有块的列表。为了简单起见,我们将它限制在第一个维度上,步骤为1。
import torch
from typing import List
def list_chunks(tensor: torch.Tensor, size: int) -> List[torch.Tensor]:
chunks = []
for i in range(tensor.size(0) - size + 1):
chunks.append(tensor[i : i + size])
return chunks
x = torch.arange(1.0, 8)
s = torch.arange(20).view(1, 10, 2)
# As expected, a list with 6 elements, as there are 6 chunks.
list_chunks(x, 2)
# => [tensor([1., 2.]),
# tensor([2., 3.]),
# tensor([3., 4.]),
# tensor([4., 5.]),
# tensor([5., 6.]),
# tensor([6., 7.])]
# The list has only a single element, as there is only a single chunk.
# But it's still a list.
list_chunks(s, 1)
# => [tensor([[[ 0, 1],
# [ 2, 3],
# [ 4, 5],
# [ 6, 7],
# [ 8, 9],
# [10, 11],
# [12, 13],
# [14, 15],
# [16, 17],
# [18, 19]]])]我特意添加了类型注释,以便更清楚地了解我们对函数的期望。如果只有一个块,它将是一个包含一个元素的列表,因为它总是一个块列表。
您期待的是一种不同的行为,即当存在单个块时,您需要的是单个块,而不是列表。这将对实现进行如下更改。
from typing import List, Union
def list_chunks(tensor: torch.Tensor, size: int) -> Union[List[torch.Tensor], torch.Tensor]:
chunks = []
for i in range(tensor.size(0) - size + 1):
chunks.append(tensor[i : i + size])
# If it's a single chunk, return just the chunk itself
if len(chunks) == 1:
return chunks[0]
else:
return chunks有了这个改变,任何使用这个函数的人现在都需要考虑两种情况。如果您不区分列表和单个块(张量),您将得到意想不到的结果,例如,在块上循环将循环在张量的第一个维度上。
编程上直观的方法是总是返回块列表,torch.unfold也会这样做,但是它不是块列表,而是一个张量,其中最后一个维度可以被看作是块的列表。
https://stackoverflow.com/questions/62334729
复制相似问题