본문 바로가기
Artificial Intelligence/21. PyTorch

[PYTORCH] 텐서 변형의 핵심인 view, reshape, transpose 3가지 차이점과 메모리 불연속성 해결 방법

by Papa Martino V 2026. 4. 5.
728x90

view, reshape, transpose
view, reshape, transpose 3가지 차이점

 

PyTorch를 활용한 딥러닝 모델 설계 과정에서 가장 빈번하게 발생하는 런타임 에러 중 하나는 텐서의 Shape(형태) 불일치입니다. 특히 view(), reshape(), 그리고 transpose()는 겉보기에는 비슷해 보이지만, 내부적인 메모리 레이아웃(Memory Layout) 처리 방식에서 결정적인 차이를 보입니다. 본 포스팅에서는 이들의 메커니즘을 심층 분석하고 실무에서 발생하는 RuntimeError: input is not contiguous 문제를 해결하는 전략을 제시합니다.


1. 텐서 변형 함수의 내부 메커니즘 분석

PyTorch 텐서는 메모리 상에서 연속적인 블록(Contiguous Block)으로 저장됩니다. 하지만 연산 효율성을 위해 실제 데이터를 복사하지 않고 Stride(보폭) 값만 변경하여 데이터의 형태를 다르게 보여주는 방식을 취합니다. 여기서 세 함수의 운명이 갈립니다.

  • view(): 기존 텐서와 메모리를 공유하며, 오직 Contiguous(연속적) 상태인 텐서에서만 작동합니다. 메모리 복사가 일어나지 않아 매우 빠르지만 제한적입니다.
  • reshape(): view()와 유사하지만 더 유연합니다. 만약 텐서가 불연속적이라면 내부적으로 clone()을 호출하여 새로운 메모리 공간을 할당하고 연속적인 상태로 변환한 뒤 형태를 바꿉니다.
  • transpose(): 차원의 순서를 바꿉니다. 중요한 점은 차원 순서가 바뀌는 순간 메모리 상의 실제 데이터 배치와 인덱싱 순서가 일치하지 않게 되어 Non-contiguous(불연속적) 상태가 된다는 점입니다.

2. 비교 분석: view vs reshape vs transpose

개발자가 상황에 따라 가장 적절한 함수를 선택할 수 있도록 핵심 지표를 비교하였습니다.

비교 항목 view() reshape() transpose() / permute()
메모리 복사 여부 절대 복사 안 함 (Shared) 상황에 따라 복사 (Conditional) 데이터 공유 (Meta-data 변경)
연속성 제약 (Contiguous) 필수 (불만족 시 에러 발생) 제약 없음 (자동 해결) 실행 후 불연속 상태가 됨
차원 변형 범위 전체 형태 재구성 전체 형태 재구성 축(Axis) 간 위치 교환
성능 (Speed) 최고 (O(1)) 보통 (복사 시 O(N)) 높음 (메타데이터만 수정)

3. 실무 적용을 위한 7가지 Sample Example (Best Practices)

단순한 문법을 넘어 실무 파이프라인에서 직면하는 데이터 변형 문제를 해결하는 7가지 시나리오입니다.

Example 1: CNN Feature Map을 Fully Connected 레이어에 입력하는 방법

이미지 배치를 1차원으로 펼칠 때 가장 효율적인 방법입니다.


import torch

# Batch Size=32, Channels=64, Height=7, Width=7
x = torch.randn(32, 64, 7, 7)
# view를 사용하여 메모리 복사 없이 Flatten
flattened = x.view(x.size(0), -1) 
print(flattened.shape) # [32, 3136]
        

Example 2: transpose() 후 발생하는 view() 에러 해결 방법

차원을 바꾼 뒤 view를 쓰면 에러가 납니다. 이때 contiguous()의 역할을 이해해야 합니다.


y = torch.randn(10, 20)
y_t = y.transpose(0, 1) # Non-contiguous 상태

try:
    y_t.view(-1)
except RuntimeError as e:
    print(f"Error caught: {e}")
    # 해결: contiguous()로 메모리를 재배치한 후 view 호출
    y_resolved = y_t.contiguous().view(-1)
        

Example 3: 안전한 장치 간 이식성을 위한 reshape() 활용

복사 여부를 신경 쓰지 않고 안전하게 코드를 짜고 싶을 때 사용합니다.


z = torch.randn(4, 4)
# 데이터가 불연속적일 가능성이 있는 외부 라이브러리 연동 시 안전함
z_reshaped = z.reshape(2, 8) 
        

Example 4: RNN/LSTM 시퀀스 데이터 축 변경 (permute)

여러 차원의 순서를 한꺼번에 바꿀 때는 transpose보다 permute가 유리합니다.


# (Batch, Seq, Feature) -> (Seq, Batch, Feature)
seq_data = torch.randn(32, 10, 512)
permuted = seq_data.permute(1, 0, 2)
        

Example 5: 특정 차원 확장과 축소를 이용한 연산 해결

unsqueeze와 view를 혼합하여 브로드캐스팅 연산을 준비합니다.


v = torch.randn(10) # [10]
# [1, 10, 1] 형태로 변형하여 3D 연산에 투입
v_expanded = v.view(1, -1, 1)
        

Example 6: 원본 데이터 유지 유무 확인 (Sharing Test)

메모리 공유 특성을 이용하여 원본 텐서가 변하는지 확인하는 디버깅 기법입니다.


original = torch.ones(2, 2)
viewed = original.view(-1)
viewed[0] = 0
print(original[0, 0]) # 0.0 출력 (메모리 공유 증명)
        

Example 7: Multi-head Attention 구조에서의 차원 분할

Transformer 모델 구현 시 필수적인 Q, K, V 분할 기법입니다.


# (Batch, Seq, Embed_dim=512) -> (Batch, Seq, Heads=8, Head_dim=64)
batch_size, seq_len = 16, 50
embed_dim = 512
q = torch.randn(batch_size, seq_len, embed_dim)

q_split = q.view(batch_size, seq_len, 8, 64).transpose(1, 2)
# 최종 형태: (Batch, Heads, Seq, Head_dim)
        

4. 결론: 성능과 안정성 사이의 선택

2026년 현재의 고도화된 AI 인프라에서도 메모리 효율은 모델의 처리량(Throughput)에 큰 영향을 미칩니다. view()는 성능 최적화의 정점에 있으며, reshape()는 개발의 편의성과 안정성을 보장합니다. transpose()는 수학적 연산을 위해 필수적이지만, 이후 연산에서 발생할 수 있는 '불연속성'에 대해 항상 인지하고 있어야 합니다. 추천하는 황금률은 다음과 같습니다: "성능이 중요하다면 view()를 먼저 시도하고, 에러가 발생하면 원인을 파악하여 contiguous().view()나 reshape()를 사용하라."

5. 참고 문헌 및 출처

  • PyTorch Documentation: Tensor View (https://pytorch.org/docs/stable/tensor_view.html)
  • NVIDIA Developer Blog: Optimizing PyTorch Memory Layout
  • Deep Learning with PyTorch by Eli Stevens, Luca Antiga, and Thomas Viehmann
  • StackOverflow: Difference between view, reshape and clone in PyTorch
728x90