为什么这个例子中的这个tensor.unfold方法会增加一个维度呢?
Why does this tensor.unfold method in this example add a dimension?
我正在熟悉 https://pytorch.org/docs/stable/tensors.html#torch.Tensor.unfold
中的 Pytorch 展开方法
我看了他们的例子
>>> 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
因此,结果是一个 ar运行不同chunk的gement,分别是[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)
的输出。为什么最后多了一个维度呢?有人可以直观地详细说明吗?
文档指出:
An additional dimension of size size
is appended in the returned tensor.
其中 size
是您指定的块的大小(第二个参数)。根据定义,它总是添加一个额外的维度,无论您选择什么尺寸,它都会保持一致。仅仅因为维度的大小为 1,并不意味着它应该被自动省略。
关于这背后的直觉,让我们考虑一下,我们创建一个包含所有块的列表,而不是 return 使用最后一个维度表示块的张量。为简单起见,我们将其限制为步长为 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
随着这一变化,任何使用此功能的人现在都需要考虑两种情况。如果您不区分列表和单个块(张量),您将得到意想不到的结果,例如遍历块将改为遍历张量的第一维。
编程直观的方法总是return一个块列表,torch.unfold
做同样的事情,但它不是一个块列表,而是一个张量,其中最后一个维度可以被视为块列表。
我正在熟悉 https://pytorch.org/docs/stable/tensors.html#torch.Tensor.unfold
中的 Pytorch 展开方法我看了他们的例子
>>> 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
因此,结果是一个 ar运行不同chunk的gement,分别是[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)
的输出。为什么最后多了一个维度呢?有人可以直观地详细说明吗?
文档指出:
An additional dimension of size
size
is appended in the returned tensor.
其中 size
是您指定的块的大小(第二个参数)。根据定义,它总是添加一个额外的维度,无论您选择什么尺寸,它都会保持一致。仅仅因为维度的大小为 1,并不意味着它应该被自动省略。
关于这背后的直觉,让我们考虑一下,我们创建一个包含所有块的列表,而不是 return 使用最后一个维度表示块的张量。为简单起见,我们将其限制为步长为 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
随着这一变化,任何使用此功能的人现在都需要考虑两种情况。如果您不区分列表和单个块(张量),您将得到意想不到的结果,例如遍历块将改为遍历张量的第一维。
编程直观的方法总是return一个块列表,torch.unfold
做同样的事情,但它不是一个块列表,而是一个张量,其中最后一个维度可以被视为块列表。