콘텐츠로 이동

transpose와 permute

transpose(dim0, dim1) 은 지정한 두 차원의 순서를 교환합니다. 결과는 원본과 메모리를 공유 합니다.

import torch
t = torch.randn(3, 4) # shape: (3, 4)
# 2D: dim 0과 dim 1 교환 (행렬 전치)
t_T = torch.transpose(t, 0, 1)
print(t_T.shape) # torch.Size([4, 3])
# .T 속성은 2D에서 transpose(0, 1)과 동일
print(t.T.shape) # torch.Size([4, 3])

3D 텐서에서 두 특정 차원을 교환합니다.

t3 = torch.randn(2, 3, 4) # shape: (2, 3, 4)
# dim 1과 dim 2 교환
print(torch.transpose(t3, 1, 2).shape) # torch.Size([2, 4, 3])
# dim 0과 dim 2 교환
print(torch.transpose(t3, 0, 2).shape) # torch.Size([4, 3, 2])

permute()모든 차원의 순서를 한 번에 지정 합니다. transpose가 두 차원의 교환에 한정된 반면, permute는 임의의 순열을 지원합니다.

t = torch.randn(2, 3, 4) # shape: (2, 3, 4)
# (0, 1, 2) → (2, 0, 1): 원래 dim 2가 첫 번째로
print(t.permute(2, 0, 1).shape) # torch.Size([4, 2, 3])
# (0, 1, 2) → (1, 2, 0)
print(t.permute(1, 2, 0).shape) # torch.Size([3, 4, 2])
# 역순
print(t.permute(2, 1, 0).shape) # torch.Size([4, 3, 2])
t.permute(2, 0, 1)
↑ ↑ ↑
결과의 0 1 2 번째 차원이
원본의 2 0 1 번째 차원에서 옴
t = torch.randn(A, B, C) # shape: (A, B, C)
# t.permute(2, 0, 1).shape == (C, A, B)

딥러닝에서 이미지 텐서는 두 가지 형식이 혼용됩니다.

형식설명사용처
(H, W, C)Height, Width, ChannelNumPy, PIL, OpenCV, matplotlib
(C, H, W)Channel, Height, WidthPyTorch, torchvision
import torch
# NumPy/PIL 방식: (H, W, C)
image_hwc = torch.randn(256, 256, 3)
print(image_hwc.shape) # torch.Size([256, 256, 3])
# PyTorch 방식으로 변환: (H, W, C) → (C, H, W)
image_chw = image_hwc.permute(2, 0, 1)
print(image_chw.shape) # torch.Size([3, 256, 256])
# 배치 포함: (B, H, W, C) → (B, C, H, W)
batch_hwc = torch.randn(32, 256, 256, 3)
batch_chw = batch_hwc.permute(0, 3, 1, 2)
print(batch_chw.shape) # torch.Size([32, 3, 256, 256])
# 역변환: (C, H, W) → (H, W, C) — matplotlib 출력용
restored = image_chw.permute(1, 2, 0)
print(restored.shape) # torch.Size([256, 256, 3])

transpose: (2, 3) → (3, 2) — 원소 재배치 확인

변환 전
1
2
3
4
5
6
형태: [2, 3]
변환 후
1
2
3
4
5
6
형태: [3, 2]
메모리 순서 (1D 평탄화)
1
2
3
4
5
6

transpose()permute() 는 메모리 레이아웃을 바꾸지 않고 스트라이드(stride) 만 변경합니다. 따라서 결과 텐서는 non-contiguous 상태가 됩니다.

t = torch.randn(3, 4)
t_T = t.T
print(t.is_contiguous()) # True
print(t_T.is_contiguous()) # False
# non-contiguous 텐서에 view() 적용 시 오류
# t_T.view(12) # RuntimeError!
t = torch.randn(3, 4)
t_T = t.T
# 방법 1: contiguous() 후 view()
r1 = t_T.contiguous().view(12)
print(r1.shape) # torch.Size([12])
# 방법 2: reshape() — 내부적으로 자동 처리
r2 = t_T.reshape(12)
print(r2.shape) # torch.Size([12])
t = torch.randn(3, 4)
print(t.stride()) # (4, 1) — 행 이동 시 4칸, 열 이동 시 1칸
t_T = t.T
print(t_T.stride()) # (1, 4) — 전치 후 스트라이드 역전
t_c = t_T.contiguous()
print(t_c.stride()) # (3, 1) — 복사 후 새로운 연속 메모리
상황권장 함수
2D 행렬 전치.T 또는 transpose(0, 1)
두 특정 차원 교환transpose(dim0, dim1)
세 개 이상의 차원 재배열permute(순열)
이미지 형식 변환 (HWC ↔ CHW)permute()
# transpose 두 번으로 permute 대체 가능 (비권장)
t = torch.randn(2, 3, 4)
r1 = t.permute(2, 0, 1) # 권장
r2 = t.transpose(0, 2).transpose(0, 1) # 비권장 (가독성 낮음)
print(torch.allclose(r1, r2)) # True