기존에 구현된 Pytorch 기반의 코드로 분석을 진행하던 중, view 함수 부분에서 다음과 같은 에러가 발생하였습니다.
"RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead."
에러에 나타난대로 view 함수를 reshape로 대체하니 에러 없이 잘 진행되었지만, 왜 에러가 발생했는지 정확하게 알기 위해 view와 reshape 함수 간의 차이를 알아보고자 합니다.
1. view, reshape 함수의 기능
우선 두 함수는 numpy 모듈의 reshape 함수를 기반으로 합니다. numpy의 reshape 함수는 특정 배열을 원하는 차원의 배열로 변경해주는 역할을 합니다. numpy의 reshape 함수의 예제 코드는 다음과 같습니다. 1차원이던 배열 x를 reshape를 통해 2차원 배열로 변경하는 것이 가능합니다. Pytorch의 view와 reshape 함수도 동일한 역할을 수행할 수 있습니다.
reshape 함수에 -1을 넣을 경우, 들어가야 할 남은 차원이 자동으로 할당됩니다. z 객체 부분을 보면, 값을 (2, -1)을 입력하였습니다. 첫 번째 차원을 2로 설정하였기 때문에 들어가야 할 남은 차원도 2로, z의 결과는 y와 동일하게 출력됩니다. -1은 남은 차원을 자동으로 할당하는 것이므로, reshape 함수 내에서 여러 번 활용될 수는 없습니다.
>>> import numpy as np
>>>
>>> x = np.arange(4)
>>> print(x)
[0 1 2 3]
>>> y = x.reshape(2, 2)
>>> print(y)
[[0 1]
[2 3]]
>>> z = x.reshape(2, -1)
>>> print(z)
[[0 1]
[2 3]]
2. view, reshape 함수의 차이
Pytorch의 view와 reshape 함수 간의 차이는 우선 코드를 통해 살펴보도록 하겠습니다. 우선 같은 shape의 x와 y 두 tensor를 생성합니다. 여기서 y는 transpose를 통해 생성한 것이고, x는 처음부터 (3, 2)의 shape를 갖고 있습니다.
>>> import torch
>>>
>>> x = torch.randn(3, 2)
>>> print(x)
tensor([[ 1.5817, -2.1456],
[ 0.4544, 0.6752],
[ 1.6731, -0.0576]])
>>> y = torch.randn(2, 3)
>>> y.transpose_(0, 1)
>>> print(y)
tensor([[-0.1702, -0.2626],
[-1.6158, 0.1117],
[ 1.4518, -0.0277]])
두 tensor x와 y가 가진 값들의 메모리 주소를 살펴보도록 하겠습니다. x는 메모리 주소가 4를 간격으로 증가하지만, y는 순서대로 증가하지 않는 것을 확인할 수 있습니다.
>>> for i in range(3):
>>> for j in range(2):
>>> print(x[i][j].data_ptr())
57534720
57534724
57534728
57534732
57534736
57534740
>>> for i in range(3):
>>> for j in range(2):
>>> print(y[i][j].data_ptr())
57533504
57533516
57533508
57533520
57533512
57533524
이는 contiguous 여부와 관련이 있습니다. is_contiguous() 함수를 통해 x와 y의 contiguous 여부를 살펴보면, x는 메모리 주소가 순서대로이므로 True를 반환하지만, y는 순서가 섞였기 때문에 False를 반환하는 것을 볼 수 있습니다. y의 처음이었던 (2, 3) shape에서는 is_contiguous()의 결과가 True였겠지만, transpose가 진행되면서 순서가 바뀌게 된 것입니다.
>>> x.is_contiguous()
True
>>> y.is_contiguous()
False
view 함수는 contiguous가 아닌 tensor에 일부 사용이 제한될 수 있다는 특징이 있고, reshape 함수는 contiguous 여부에 상관없이 사용할 수 있다는 특징이 있습니다. 이에 따라 view 함수에서는 에러가 발생하고 reshape 함수에서는 에러가 발생하지 않았던 것입니다. 이를 코드로 한번 더 확인해보면 다음과 같습니다. contiguous를 만족하지 않았던 y에 view를 적용하면 에러가 발생하고, reshape를 적용하면 에러가 발생하지 않는 것을 확인할 수 있습니다.
>>> y.view(2, 3)
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-30-ffdb6dd4c16a> in <module>
----> 1 y.view(2, 3)
RuntimeError: view size is not compatible with input tensor`s size and stride (at least
one dimension spans across two contiguous subspaces). Use .reshape(...) instead.
>>> y.reshape(2, 3)
tensor([[-0.1702, -0.2626, -1.6158],
[ 0.1117, 1.4518, -0.0277]])
해당 글은 업무를 진행하면서 헷갈렸던 부분을 정리하기 위한 것으로, 아래 블로그의 내용과 예제를 참고하여 작성되었음을 알려드립니다.
<참고>
https://jimmy-ai.tistory.com/151
[Pytorch] torch.view, torch.reshape의 사용법과 차이 비교
파이토치 view 함수와 reshape 함수 비교 안녕하세요. 이번 글에서는 파이토치에서 텐서의 차원 변환을 할 때 사용하는 torch.view와 torch.reshape 함수의 기본적인 사용법과 두 함수의 차이에 대하여 다
jimmy-ai.tistory.com
https://jimmy-ai.tistory.com/122
[Pytorch] contiguous 원리와 의미
torch의 contiguous에 대해서 안녕하세요. 이번 시간에는 파이토치에서 메모리 내에서의 자료형 저장 상태로 등장하는 contiguous의 원리와 의미에 대해서 간단히 살펴보도록 하겠습니다. contiguous 여부
jimmy-ai.tistory.com
댓글