1. 데이터 작업하기: torch.utils.data.DataLoader, torch.utils.data.Dataset
2. 모델 만들기: __init__, forward
3. 모델 매개변수 최적화하기: loss function, optimizer
4. 모델 저장하기: torch.save
5. 모델 불러오기: torch.load
데이터 작업하기
PyTorch의 데이터 작업을 위한 기본 요소로는 두 가지가 있는데,
하나는 torch.utils.data.Dataset, 또 다른 하나는 torch.utils.data.DataLoader 이다.
- Dataset = 샘플과 정답(label)을 저장한다.
- DataLoader = Dataset을 순회 가능한 객체(iterable)로 감싼다.
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor
PyTorch에서 데이터셋과 함께 제공되는 도메인 특화 라이브러리로는 TorchText, TorchVision, TorchAudio 가 있다.
- torchvision.datasets 모듈을 사용하여 CIFAR, COCO 등 실제 비전(vision) 데이터에 대한 dataset을 사용할 수 있다.
- 아래의 코드는 FashionMNIST 데이터셋을 내려받는 코드 예시이다.
# 공개 데이터셋에서 학습 데이터를 내려받습니다.
training_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=ToTensor(),
)
# 공개 데이터셋에서 테스트 데이터를 내려받습니다.
test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=ToTensor(),
)
[참고] ToTensor
- PIL 이미지 또는 ndarray를 텐서로 변환하고 그에 따라 값의 크기를 조정한다.
- PIL 이미지가 속하는 경우 [0, 255] 범위의 이미지 또는 numpy.ndarray(H x W x C)를 [0.0, 1.0] 범위의 shape (C x H x W)의 torch.FloatTensor로 변환한다.
Dataset을 DataLoader의 인자로 전달한다.
- 아래 코드에서는 batch_size를 64로 정의하여 DataLoader 객체의 각 요소는 64개의 Feature와 Label을 묶음(batch)으로 반환한다.
batch_size = 64
# 데이터로더를 생성합니다.
train_dataloader = DataLoader(training_data, batch_size=batch_size)
test_dataloader = DataLoader(test_data, batch_size=batch_size)
for X, y in test_dataloader:
print(f"Shape of X [N, C, H, W]: {X.shape}")
print(f"Shape of y: {y.shape} {y.dtype}")
break
Out:
Shape of X [N, C, H, W]: torch.Size([64, 1, 28, 28])
Shape of y: torch.Size([64]) torch.int64
신경망 모델 만들기
PyTorch에서는 nn.Module을 상속받는 클래스를 생성하여 신경망 모델을 정의한다.
- __init__ 함수에서 신경망의 계층(layer)들을 정의하고, forward 함수에서 신경망에 데이터를 어떻게 전달할지 지정한다.
- 가능한 경우 GPU 또는 MPS로 신경망을 이동시켜 연산을 가속(accelerate)한다.
# 학습에 사용할 CPU나 GPU, MPS 장치를 얻습니다.
device = (
"cuda"
if torch.cuda.is_available()
else "mps"
if torch.backends.mps.is_available()
else "cpu"
)
print(f"Using {device} device")
# 모델을 정의합니다.
class NeuralNetwork(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(
nn.Linear(28*28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10)
)
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
model = NeuralNetwork().to(device)
print(model)
Out:
Using cpu device
NeuralNetwork(
(flatten): Flatten(start_dim=1, end_dim=-1)
(linear_relu_stack): Sequential(
(0): Linear(in_features=784, out_features=512, bias=True)
(1): ReLU()
(2): Linear(in_features=512, out_features=512, bias=True)
(3): ReLU()
(4): Linear(in_features=512, out_features=10, bias=True)
)
)
모델 매개변수 최적화하기
모델을 학습하려면 손실 함수(loss function)와 옵티마이저(optimizer)가 필요하다.
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)
각 학습 단계(training loop)에서 모델은 배치로 제공되는 학습 데이터셋에 대한 예측을 수행하고, 예측 오류를 역전파하여 모델의 매개변수를 조정한다.
def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
for batch, (X, y) in enumerate(dataloader):
X, y = X.to(device), y.to(device)
# 예측 오류 계산
pred = model(X)
loss = loss_fn(pred, y)
# 역전파
optimizer.zero_grad()
loss.backward()
optimizer.step()
if batch % 100 == 0:
loss, current = loss.item(), (batch + 1) * len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")
모델이 학습하고 있는지를 확인하기 위해 테스트 데이터셋으로 모델의 성능을 확인한다.
def test(dataloader, model, loss_fn):
size = len(dataloader.dataset)
num_batches = len(dataloader)
model.eval()
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in dataloader:
X, y = X.to(device), y.to(device)
pred = model(X)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= num_batches
correct /= size
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
학습 단계는 여러번의 반복 단계(epochs)를 거쳐 수행된다.
- 각 에폭에서 모델은 더 나은 예측을 위해 매개변수를 학습한다.
- 각 에폭마다 모델의 정확도(accuracy)와 손실(loss)를 출력한다.
- 에폭마다 정확도는 증가하고 손실은 감소해야 잘 학습되고 있다고 판단할 수 있다.
epochs = 5
for t in range(epochs):
print(f"Epoch {t+1}\n-------------------------------")
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)
print("Done!")
Out:
Epoch 1
-------------------------------
loss: 2.315824 [ 64/60000]
loss: 2.296531 [ 6464/60000]
loss: 2.282854 [12864/60000]
loss: 2.265180 [19264/60000]
loss: 2.246860 [25664/60000]
loss: 2.241881 [32064/60000]
loss: 2.229662 [38464/60000]
loss: 2.214478 [44864/60000]
loss: 2.204778 [51264/60000]
loss: 2.173828 [57664/60000]
Test Error:
Accuracy: 46.2%, Avg loss: 2.167986
Epoch 2
-------------------------------
loss: 2.182683 [ 64/60000]
loss: 2.170514 [ 6464/60000]
loss: 2.121113 [12864/60000]
loss: 2.127707 [19264/60000]
loss: 2.079593 [25664/60000]
loss: 2.037801 [32064/60000]
loss: 2.045603 [38464/60000]
loss: 1.985577 [44864/60000]
loss: 1.983998 [51264/60000]
loss: 1.906678 [57664/60000]
Test Error:
Accuracy: 59.6%, Avg loss: 1.911592
Epoch 3
-------------------------------
loss: 1.944817 [ 64/60000]
loss: 1.918335 [ 6464/60000]
loss: 1.810630 [12864/60000]
loss: 1.835921 [19264/60000]
loss: 1.735453 [25664/60000]
loss: 1.692328 [32064/60000]
loss: 1.693650 [38464/60000]
loss: 1.610339 [44864/60000]
loss: 1.629757 [51264/60000]
loss: 1.512189 [57664/60000]
Test Error:
Accuracy: 59.3%, Avg loss: 1.539860
Epoch 4
-------------------------------
loss: 1.608193 [ 64/60000]
loss: 1.575012 [ 6464/60000]
loss: 1.433054 [12864/60000]
loss: 1.487611 [19264/60000]
loss: 1.374316 [25664/60000]
loss: 1.375985 [32064/60000]
loss: 1.377512 [38464/60000]
loss: 1.309860 [44864/60000]
loss: 1.342401 [51264/60000]
loss: 1.238505 [57664/60000]
Test Error:
Accuracy: 62.3%, Avg loss: 1.265640
Epoch 5
-------------------------------
loss: 1.341270 [ 64/60000]
loss: 1.325380 [ 6464/60000]
loss: 1.166352 [12864/60000]
loss: 1.261305 [19264/60000]
loss: 1.137607 [25664/60000]
loss: 1.169888 [32064/60000]
loss: 1.185464 [38464/60000]
loss: 1.123889 [44864/60000]
loss: 1.162256 [51264/60000]
loss: 1.078794 [57664/60000]
Test Error:
Accuracy: 64.3%, Avg loss: 1.097026
Done!
모델 저장하기
모델의 매개변수들을 포함하여 내부 상태 사전(internal state dictionary)를 직렬화(serialize)한다.
torch.save(model.state_dict(), "model.pth")
print("Saved PyTorch Model State to model.pth")
Out:
Saved PyTorch Model State to model.pth
모델 불러오기
모델을 불러오는 과정에는 모델 구조를 다시 만들고, 상태 사전을 모델에 불러오는 과정이 포함된다.
model = NeuralNetwork().to(device)
model.load_state_dict(torch.load("model.pth"))
Out:
<All keys matched successfully>
이제, 이 모델을 사용해서 예측을 할 수 있다.
classes = [
"T-shirt/top",
"Trouser",
"Pullover",
"Dress",
"Coat",
"Sandal",
"Shirt",
"Sneaker",
"Bag",
"Ankle boot",
]
model.eval()
x, y = test_data[0][0], test_data[0][1]
with torch.no_grad():
x = x.to(device)
pred = model(x)
predicted, actual = classes[pred[0].argmax(0)], classes[y]
print(f'Predicted: "{predicted}", Actual: "{actual}"')
Out:
Predicted: "Ankle boot", Actual: "Ankle boot"
https://pytorch.org/vision/main/generated/torchvision.transforms.ToTensor.html
ToTensor — Torchvision main documentation
Shortcuts
pytorch.org
파이토치(PyTorch) 한국어 튜토리얼에 오신 것을 환영합니다!
파이토치(PyTorch) 한국어 튜토리얼에 오신 것을 환영합니다. 파이토치 한국 사용자 모임은 한국어를 사용하시는 많은 분들께 PyTorch를 소개하고 함께 배우며 성장하는 것을 목표로 하고 있습니다.
tutorials.pytorch.kr
'Deep Learning & Machine Learning > PyTorch' 카테고리의 다른 글
[PyTorch] tutorial, 5.Autograd (0) | 2024.05.19 |
---|---|
[PyTorch] tutorial, 4.신경망 모델 구성하기 (0) | 2024.05.19 |
[PyTorch] tutorial, 3.변형(Transform) (0) | 2024.05.19 |
[PyTorch] tutorial, 2.Dataset과 DataLoader (0) | 2024.05.19 |
[PyTorch] tutorial, 1.텐서(TENSOR) (0) | 2024.05.19 |