view()
다음 코드 스 니펫에서 방법 에 대해 혼란 스럽습니다 .
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2,2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16*5*5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16*5*5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
내 혼란은 다음 줄에 관한 것입니다.
x = x.view(-1, 16*5*5)
tensor.view()
기능은 무엇을 합니까? 여러 곳에서 사용법을 보았지만 매개 변수를 해석하는 방법을 이해할 수 없습니다.
view()
함수에 매개 변수로 음수 값을 지정하면 어떻게됩니까 ? 예를 들어, 전화하면 어떻게됩니까 tensor_variable.view(1, 1, -1)
?
누구든지 view()
몇 가지 예를 들어 주요 기능 원리를 설명 할 수 있습니까 ?
답변
뷰 기능은 텐서를 재 형성하기위한 것입니다.
텐서가 있다고 해
import torch
a = torch.range(1, 16)
a
1에서 16 (포함)까지 16 개의 요소를 가진 텐서입니다. 당신이 그것을 만들기 위해이 텐서 모양을 변경하려면 4 x 4
텐서 당신은 사용할 수 있습니다
a = a.view(4, 4)
이제 텐서 a
가 될 것 4 x 4
입니다. 모양을 변경 한 후에는 총 요소 수를 동일하게 유지해야합니다. 텐서 a
를 텐서 로 바꾸는 3 x 5
것은 적절하지 않습니다.
매개 변수 -1의 의미는 무엇입니까?
원하는 행 수를 모르지만 열 수를 확신하는 상황이있는 경우 -1로이를 지정할 수 있습니다. ( 이를 더 많은 치수의 텐서로 확장 할 수 있습니다. 축 값 중 하나만 -1이 될 수 있습니다 ). 이것은 라이브러리에 다음과 같은 방법으로 “열이 많은 텐서 (tensor)를 제공하고이를 수행하는 데 필요한 행 수를 계산합니다.”
이것은 위에서 지정한 신경망 코드에서 볼 수 있습니다. x = self.pool(F.relu(self.conv2(x)))
정방향 기능 의 선 뒤에 16 개의 깊이 피처 맵이 있습니다. 완전히 연결된 레이어에 제공하려면 이것을 평평하게해야합니다. 따라서 pytorch에게 얻은 텐서를 재구성하여 특정 수의 열을 가지도록하고 행 수를 결정하도록 지시하십시오.
numpy와 pytorch 사이의 유사성을 그리는 것은 view
numpy의 변형 기능 과 유사 합니다.
답변
더 간단한 것부터 더 어려운 것까지 몇 가지 예를 들어 봅시다.
-
이
view
메소드는 텐서와 동일한 데이터를 가진self
텐서를 리턴합니다 (반환 된 텐서가 동일한 수의 요소를 가짐을 의미 함). 예를 들면 다음과 같습니다.a = torch.arange(1, 17) # a's shape is (16,) a.view(4, 4) # output below 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [torch.FloatTensor of size 4x4] a.view(2, 2, 4) # output below (0 ,.,.) = 1 2 3 4 5 6 7 8 (1 ,.,.) = 9 10 11 12 13 14 15 16 [torch.FloatTensor of size 2x2x4]
-
-1
이것이 매개 변수 중 하나가 아니라고 가정하면 매개 변수를 곱하면 결과는 텐서의 요소 수와 같아야합니다. 그렇게하면 : 16 개의 요소가있는 입력에 모양 (3 x 3)이 유효하지 않기 때문에a.view(3, 3)
증가합니다RuntimeError
. 즉, 3 x 3은 16이 아니라 9입니다. -
당신은 사용할 수 있습니다
-1
번만 기능에 전달하지만, 그 매개 변수 중 하나. 그 모든 일이 그 방법이 그 차원을 채우는 방법에 대한 수학을 할 것입니다. 예를a.view(2, -1, 4)
들어와 같습니다a.view(2, 2, 4)
. [16 / (2 x 4) = 2] -
반환 된 텐서 는 동일한 데이터를 공유합니다 . “보기”를 변경하면 원래 텐서의 데이터가 변경됩니다.
b = a.view(4, 4) b[0, 2] = 2 a[2] == 3.0 False
-
이제 더 복잡한 사용 사례가 있습니다. 문서에 따르면 각각의 새 뷰 치수는 원래 치수의 하위 공간이거나 모두에 대해 다음과 같은 연속성 같은 조건을 만족하는 d, d + 1, …, d + k 범위 여야 합니다. i = 0에 . .., k-1, 보폭 [i] = 보폭 [i + 1] x 크기 [i + 1] . 그렇지 않으면
contiguous()
텐서를보기 전에 호출해야합니다. 예를 들면 다음과 같습니다.a = torch.rand(5, 4, 3, 2) # size (5, 4, 3, 2) a_t = a.permute(0, 2, 3, 1) # size (5, 3, 2, 4) # The commented line below will raise a RuntimeError, because one dimension # spans across two contiguous subspaces # a_t.view(-1, 4) # instead do: a_t.contiguous().view(-1, 4) # To see why the first one does not work and the second does, # compare a.stride() and a_t.stride() a.stride() # (24, 6, 2, 1) a_t.stride() # (24, 2, 1, 6)
의
a_t
경우 stride [0]! = stride [1] x size [1] 부터 24 이후 ! = 2 x 3
답변
torch.Tensor.view()
또는 에서 torch.Tensor.view()
영감을 얻은 간단하게 새로운보기를 만듭니다.numpy.ndarray.reshape()
numpy.reshape()
새로운 모양이 원래 텐서의 모양과 호환되는 한 텐서 을 .
구체적인 예를 사용하여 이것을 자세히 이해합시다.
In [43]: t = torch.arange(18)
In [44]: t
Out[44]:
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17])
이 t
모양 텐서 를 사용하면 다음 모양에 대해서만(18,)
새 보기를 만들 수 있습니다.
(1, 18)
또는 동등 (1, -1)
하거나 또는 동등 하거나 또는 동등 하거나 또는 동등 하거나 또는 동등 하거나 또는 동등 또는(-1, 18)
(2, 9)
(2, -1)
(-1, 9)
(3, 6)
(3, -1)
(-1, 6)
(6, 3)
(6, -1)
(-1, 3)
(9, 2)
(9, -1)
(-1, 2)
(18, 1)
(18, -1)
(-1, 1)
위의 모양 튜플에서 이미 알 수 있듯이 모양 튜플의 요소 (예 : 등) 의 곱셈은 항상 원래 텐서의 요소 수 (예 2*9
에서 3*6
)와 같아야합니다18
.
관찰해야 할 또 다른 사항 -1
은 각 모양 튜플의 장소 중 하나에서를 사용했다는 것 입니다. 를 사용함으로써 -1
, 우리는 계산 자체를 수행하는 데 게으르고 오히려 새로운 뷰를 만들 때 셰이프에 대한 해당 값의 계산을 수행하기 위해 작업을 PyTorch에 위임합니다 . 주목해야 할 한 가지는 셰이프 튜플에서 하나만 사용할 수 있다는 것 -1
입니다. 나머지 값은 당사에서 명시 적으로 제공해야합니다. 다른 PyTorch는 다음을 던져 불평합니다 RuntimeError
.
RuntimeError : 하나의 차원 만 유추 할 수 있습니다
따라서 위에서 언급 한 모든 모양으로 PyTorch는 항상 원래 텐서 의 새로운보기 를 반환합니다.t
. 이것은 기본적으로 요청 된 새로운 뷰 각각에 대해 텐서의 보폭 정보 만 변경한다는 것을 의미합니다.
아래는 텐서의 보폭이 각각의 새로운 뷰로 어떻게 바뀌는 지 보여주는 몇 가지 예입니다 .
# stride of our original tensor `t`
In [53]: t.stride()
Out[53]: (1,)
이제 우리는 새로운 견해에 대한 진전을 보게 될 것입니다 .
# shape (1, 18)
In [54]: t1 = t.view(1, -1)
# stride tensor `t1` with shape (1, 18)
In [55]: t1.stride()
Out[55]: (18, 1)
# shape (2, 9)
In [56]: t2 = t.view(2, -1)
# stride of tensor `t2` with shape (2, 9)
In [57]: t2.stride()
Out[57]: (9, 1)
# shape (3, 6)
In [59]: t3 = t.view(3, -1)
# stride of tensor `t3` with shape (3, 6)
In [60]: t3.stride()
Out[60]: (6, 1)
# shape (6, 3)
In [62]: t4 = t.view(6,-1)
# stride of tensor `t4` with shape (6, 3)
In [63]: t4.stride()
Out[63]: (3, 1)
# shape (9, 2)
In [65]: t5 = t.view(9, -1)
# stride of tensor `t5` with shape (9, 2)
In [66]: t5.stride()
Out[66]: (2, 1)
# shape (18, 1)
In [68]: t6 = t.view(18, -1)
# stride of tensor `t6` with shape (18, 1)
In [69]: t6.stride()
Out[69]: (1, 1)
이것이 바로 그 view()
기능 의 마술입니다 . 새로운 형태의 한, 새로운 시각 각각에 대한 (원래) 텐서의 보폭을 변경합니다. 뷰는 원래의 형상과 호환된다.
보폭 튜플에서 관찰 할 수있는 또 다른 흥미로운 점은 0 번째 위치의 요소 값 이 모양 튜플 의 1 번째 위치의 요소 값과 동일하다는 것 입니다.
In [74]: t3.shape
Out[74]: torch.Size([3, 6])
|
In [75]: t3.stride() |
Out[75]: (6, 1) |
|_____________|
이 때문입니다:
In [76]: t3
Out[76]:
tensor([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17]])
보폭은 (6, 1)
그 0에 따라 다음 요소로 하나 개의 요소에서 갈 말한다 일 우리가해야 할, 차원 이동 또는 6 조치를 취합니다. (즉에서 이동 0
로 6
. 하나는 6 단계를 수행하는,)하지만 1의 다음 요소로 하나 개의 요소에서 이동 번째 (예에서 이동하는 차원, 우리는 단지 하나의 단계를 필요 2
로 3
).
따라서 보폭 정보는 계산을 수행하기 위해 메모리에서 요소에 액세스하는 방법의 핵심입니다.
torch.reshape ()
이 함수는 뷰를 반환하며 torch.Tensor.view()
새 모양이 원래 텐서 모양과 호환되는 한 사용하는 것과 정확히 같습니다 . 그렇지 않으면 사본을 반환합니다.
그러나 다음과 같이 torch.reshape()
경고합니다.
호환 가능한 보폭을 가진 연속 입력 및 입력은 복사하지 않고 재구성 할 수 있지만 복사 대보기 동작에 의존해서는 안됩니다.
답변
내가 그 그것을 알아 냈 x.view(-1, 16 * 5 * 5)
에 해당 x.flatten(1)
매개 변수 (1) 당신이 볼 수 있듯이 1 차원합니다 ( ‘샘플’차원을 병합하지 않음)에서 패턴 화 된 프로세스 시작을 나타내는 경우, 후자의 사용은 I 있도록, 사용에 의미보다 명확하고 쉽게 선호합니다 flatten()
.
답변
매개 변수 -1의 의미는 무엇입니까?
-1
동적 매개 변수 수 또는 “anything”으로 읽을 수 있습니다 . 그 때문에 하나 개의 매개 변수가있을 수 있습니다 -1
에서 view()
.
요청 x.view(-1,1)
하면 [anything, 1]
의 요소 수에 따라 텐서 모양이 출력 됩니다 x
. 예를 들면 다음과 같습니다.
import torch
x = torch.tensor([1, 2, 3, 4])
print(x,x.shape)
print("...")
print(x.view(-1,1), x.view(-1,1).shape)
print(x.view(1,-1), x.view(1,-1).shape)
출력합니다 :
tensor([1, 2, 3, 4]) torch.Size([4])
...
tensor([[1],
[2],
[3],
[4]]) torch.Size([4, 1])
tensor([[1, 2, 3, 4]]) torch.Size([1, 4])
답변
weights.reshape(a, b)
데이터를 메모리의 다른 부분에 복사 할 때 크기 (a, b)가있는 가중치와 동일한 데이터를 가진 새 텐서를 반환합니다.
weights.resize_(a, b)
다른 모양의 동일한 텐서를 반환합니다. 그러나 새로운 모양으로 인해 원래 텐서보다 적은 수의 요소가 생성되면 일부 요소는 텐서에서 제거되지만 메모리에서는 제거되지 않습니다. 새 모양이 원래 텐서보다 많은 요소를 생성하면 메모리에서 새 요소가 초기화되지 않습니다.
weights.view(a, b)
크기 (a, b)의 가중치와 동일한 데이터를 가진 새로운 텐서를 반환합니다.
답변
@Jadiel de Armas 예제를 정말 좋아했습니다.
.view (…)에 대한 요소의 주문 방법에 대한 작은 통찰력을 추가하고 싶습니다.
- 모양이 (a, b, c) 인 텐서 의 경우 요소 의 순서 는 번호 매기기 시스템에 의해 결정됩니다. 첫 번째 숫자에는 숫자가 있고
두 번째 숫자에는 b 숫자가 있고 세 번째 숫자에는 c 숫자가 있습니다. - .view (…)에 의해 리턴 된 새로운 Tensor의 요소 맵핑은 원래 Tensor의 순서 를 유지합니다 .