Pytorch를 사용하면 항상 비슷한 에러를 다루게 된다. 본 글은 pytorch를 사용하며 헷갈렸던 내용을 모아 봤다.
데이터 & 레이블 타입
보통 학습할 때 데이터(이미지, 텍스트 등)와 이에 대응하는 레이블(클래스)을 사용한다.
- 데이터 → FloatTensor
- 레이블 → LongTensor
dataset = dataset.float()
label = label.long()
레이어는 주로 FloatTensor 타입 가중치를 가진다. 따라서 연산을 위해 같은 타입으로 통일해야 한다. 예를 들어, 데이터가 정수형일 경우 오류가 발생한다.
레이블은 loss를 계산할 때 사용한다. 이때 loss 함수가 LongTensor를 사용하기 때문에 long으로 바꾸지 않으면 오류가 발생한다.
CUDA & CPU
torch에서는 같은 FloatTensor라고 해도 GPU 위에 올라가면 cuda.FloatTensor라는 다른 타입이 된다. 따라서 연산할 데이터를 모두 CPU 또는 GPU 위에 올려야 한다.
CUDA 사용. cuda는 주로 학습할 때 사용한다. 모델, Loss 함수, 데이터, 레이블을 모두 GPU에 올린다. 참고로 optimizer는 특정 device에 의존하지 않는다.
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
model.to(device) # 학습할 모델
criterion.to(device) # Loss 함수
for epoch in epochs:
for data, label in loader:
data = data.to(device) # 입력 데이터
label = label.to(device) # 정답 레이블
output = model(data)
loss = criterion(output, label)
CPU 사용. 평가 지표를 계산할 때는 CPU를 사용한다. 따라서 모델 출력을 GPU에서 CPU로 옮겨야 한다.
output = model(data)
prediction = output.detach().cpu().numpy()
prediction # CPU에서 활용
detach().cpu()를 이용해 텐서를 CPU 위로 올린 뒤, numpy()를 이용해 텐서를 numpy 배열로 변경한다. detach().cpu().numpy()는 세트처럼 사용한다.
레이어 입력
처음 시작하면 가장 어려운 부분이 레이어 입력을 맞추는 일이다. 자주 사용하는 레이어에 대해 정리해 보았다.
Linear | (batch, *) |
Conv2d | (batch, channel, 세로, 가로) |
RNN (batch_first) | (batch, 길이, 임베딩 차원) |
MultiHeadAttention (batch_first) | |
Transformer (batch_first) |
어떤 레이어는 batch를 처음에 받고, 어떤 모델은 그렇지 않다. 그래서 batch_first 옵션을 사용해 항상 batch가 처음에 오도록 하면 쉽게 처리할 수 있다. 특히, 이미지를 다룰 때 더욱 그렇다.
# batch_first 예시
nn.RNN(64, 128, batch_first=True)
데이터 크기 변경
데이터 크기(size)를 바꾸는 방법은 크게 4가지가 있다.
x = torch.randn(2, 3, 4, 5) # Shape: (batch=2, channels=3, width=4, height=5)
x_permuted = x.permute(0, 2, 3, 1) # Shape: (batch, width, height, channels)
x_transposed = x.transpose(0, 1) # Shape: (channels, batch, height, channels)
x_viewed = x.view(2, -1) # Shape: (batch=2, features=3*4*5=60)
x_reshaped = x.reshape(2, -1) # Shape: (batch=2, features=60)
permute vs transpose. 둘 다 차원 순서를 바꿀 때 사용하며, 메모리를 새로 할당하지 않는다.
- permute: 모든 차원에 대해 변경 가능
- transpoe: 두 차원을 맞교환
permute는 Size([1, 2, 3])를 Size([2, 3, 1])로 바꾸는 식으로 차원 순서를 마음대로 바꿀 수 있다. 반면, transpose는 딱 2개의 차원만 맞교환한다.
view vs reshape. 둘 다 -1을 통해 남은 차원을 flatten 시킬 수 있다.
- view: contiguous한 텐서만 동작
- reshape: 모든 경우에 동작
기본적으로 둘 다 메모리를 새로 할당하지 않는다. 대신 contiguous하지 않은 텐서를 reshape할 경우, 메모리를 새로 할당할 수 있다.
정말 모르겠다면 permute와 reshape만 기억하자.
torchsummary 오류
Pytorch 모델을 학습시키던 중 오류가 발생했다.
AttributeError: 'NoneType' object has no attribute 'size'
아무리 찾아봐도 모델과 데이터 모두 문제가 없었다. 문제는 torchsummary였다.
torchsummary is deprecated as it wasn’t updated in a couple of years as seen in
their repository. Use torchinfo instead...
https://discuss.pytorch.org/t/attributeerror-nonetype-object-has-no-attribute-size/176882
확인해 보니 torchsummary는 더 이상 지원하지 않았다. 대신 torchinfo로 옮겨왔다.
!pip install torchinfo
from torchinfo import summary
summary(model, input_size=(1, 28, 28))
모델 변경 없이 torchinfo를 사용하니 오류가 해결됐다. 이거 몰라서 한참 헤맸다.