본문 바로가기
C.W.K.
Stream
Lesson 05 of 11 · published

모양 바꾸기, 뷰, 축 순서와 연속성 함정

~14 min · reshape, view, permute, contiguous, stride

Level 0텐서 탐구자
0 XP0/62 lessons0/13 achievements
0/120 XP to next level120 XP to go0% complete

데이터가 보이는 모양을 바꾸는 연산

이 연산들은 가능하면 바이트를 옮기지 않고 스트라이드, 즉 PyTorch가 메모리를 따라가는 방법만 바꿔. 요청한 모양을 현재 메모리 배치로 표현할 수 없을 때만 복사가 일어나. 스트라이드를 이해하면 텐서가 왜 어떤 모양 변환에서는 복사되고 다른 변환에서는 복사되지 않는지 알 수 있어.

네 가지 연산

  • reshape(*shape): 가장 유연해. 메모리 배치가 허용하면 뷰를 반환하고 그렇지 않으면 복사하므로 언제나 동작해.
  • view(*shape): 복사 없이 뷰만 반환해. 텐서가 연속적이지 않으면 오류가 나.
  • transpose(d0, d1) / .T: 두 차원의 순서를 바꿔. 항상 뷰를 반환하며 결과는 보통 비연속적이야.
  • permute(*dims): 모든 차원의 순서를 바꿔. 역시 뷰를 반환하며 결과는 비연속적이야.

연속성 함정은 흔하면서도 미묘한 PyTorch 버그야. 전치하거나 축 순서를 바꾼 텐서는 메모리에 비연속적으로 놓이는 경우가 많아. 일부 연산, 특히 .view()와 여러 기존 사용자 정의 CUDA 커널은 연속 메모리를 요구해. 이때는 .contiguous()로 새 연속 블록에 복사하거나 .view() 대신 .reshape()를 사용해.

크기가 1인 차원 추가·제거

unsqueeze(dim)dim 위치에 크기가 1인 차원을 추가하고, squeeze(dim=None)은 그런 차원을 제거해. 둘 다 데이터를 복사하지 않고 메타데이터만 바꿔. 행 벡터와 열 벡터의 모양을 맞추는 것처럼 브로드캐스팅을 준비할 때 계속 사용하게 될 거야.

Code

reshape와 view는 언제 구분해서 쓸까?·python
import torch

t = torch.arange(12)

# reshape: most flexible. Always works.
a = t.reshape(3, 4)
b = t.reshape(2, -1)   # -1 means "infer this dim" → 2 x 6
c = t.reshape(-1, 3)   # → 4 x 3

# view: identical to reshape for contiguous tensors, errors otherwise.
v = t.view(3, 4)

# Rule of thumb: use reshape unless you specifically need the
# 'fail loudly when non-contiguous' guarantee that view gives you.
전치와 축 순서 변경 뒤 연속성 해결하기·python
import torch

x = torch.randn(2, 3, 4)   # (batch=2, seq=3, features=4)

# 2D transpose shorthand
m = torch.randn(3, 4)
mt = m.T            # equivalent to m.transpose(0, 1)
print(mt.is_contiguous())  # False!

# permute reorders ALL dims
y = x.permute(0, 2, 1)     # (2, 4, 3)
print(y.is_contiguous())   # False

# y.view(-1)  # RuntimeError: view size is not compatible
y_flat = y.contiguous().view(-1)  # works
y_flat = y.reshape(-1)             # also works (reshape handles it)

# Image format conversion: NHWC → NCHW
img = torch.randn(8, 224, 224, 3)
img_pytorch = img.permute(0, 3, 1, 2).contiguous()
print(img_pytorch.shape)   # torch.Size([8, 3, 224, 224])
차원 늘리기, 차원 줄이기, 브로드캐스팅 구성·python
import torch

v = torch.tensor([1, 2, 3])     # shape (3,)
v.unsqueeze(0).shape            # torch.Size([1, 3]) — row vector
v.unsqueeze(1).shape            # torch.Size([3, 1]) — column vector
v[None, :].shape                # same as unsqueeze(0)
v[:, None].shape                # same as unsqueeze(1)

# squeeze removes size-1 dims
x = torch.randn(1, 3, 1, 4)
x.squeeze().shape               # torch.Size([3, 4])
x.squeeze(0).shape              # torch.Size([3, 1, 4]) — only dim 0
x.squeeze(2).shape              # torch.Size([1, 3, 4]) — only dim 2

External links

Exercise

(8, 3, 32, 32) 모양의 4D 이미지 배치를 준비해. 축 순서를 바꿔 NHWC 배치로 만들고 비연속 텐서인지 확인한 뒤 다시 NCHW로 돌려놔. 그런 다음 (32, 3, 224, 224) 텐서에서 축 순서를 바꾼 뒤 .contiguous().view()를 쓰는 방식과 .reshape()를 쓰는 방식의 시간을 각각 재 봐.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.