-이전 Dataset과 DataLoader, 신경망 모델 구성하기의 코드입니다.
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor
training_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=ToTensor()
)
test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=ToTensor()
)
train_dataloader = DataLoader(training_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)
class NeuralNetwork(nn.Module):
def __init__(self):
super(NeuralNetwork, self).__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()
traing_data
, test_data
train_dataloader
, test_dataloader
를 로드NeuralNetwork
클래스 정의learning_rate = 1e-3
batch_size = 64
epochs = 5
-학습 단계에서 일어나는 몇가지 개념을 간략히 살펴보겠습니다.
nn.LogSoftmax
와 nn.NLLLoss
를 합친 nn.CrossEntropyLoss
등이 있음#손실 함수를 초기화합니다.
loss_fn = nn.CrossEntropyLoss()
- nn.MSELoss : 평균 제곱 오차(Mean Squared Error), 예측값과 실제 타겟값의 차이의 제곱을 평균한 것
torch.nn.MSELoss(reduction='mean')
-인수와 기본값
-reduction: 손실 값을 어떻게 줄일지를 지정하는 인수로, 기본값은 mean
- nn.NLLLoss : (Negative Log Likelihood) 주로 다중 클래스 분류(Multi-class classification) 문제에 사용되며, 모델의 출력 확률 분포와 실제 타깃 레이블 사이의 차이를 측정하여 모델을 학습하는데 사용됨
- 모델이 출력하는 로그 확률 중 실제 타깃 레이블에 해당하는 값이 로그 확률을 사용하여 NLL 손실을 계산합니다.
- NLL손실은 실제 타깃 레이블에 해당하는 로그 확률의 음수 값으로 정의되며, 모델의 예측이 실제 타깃 레이블과 일치할수록 손실 값이 낮아짐,
-NLLLoss는 모델의 예측이 정확하게 타깃 레이블을 예측하는 데 중요한 역할을 함- NLLLoss는 다양한 옵션을 제공하여 손실 값의 계산방식을 조절할 수 있음, 가중치, 무시할 레이블 , 손실 값의 평균 또는 합, 그리고 손실 값의 줄임 방식 등을 설정하여 모델 학습에 적합한 손실 함수를 사용할 수 있음
torch.nn.NLLLoss(weight=None, ignore_index=-100, reduction='mean')
-인수와 기본값
- weight : 각 클래스에 대한 가중치를 지정하는 인수로, 클래스 불균형을 처리할 때 사용될 수 있습니다. 기본값은 None, 모든 클래스에 대한 동일한 가중치를 사용합니다.
- ignore_index : 손실 계산시 무시할 레이블의 인덱스를 지정하는 인수로, 기본값은 -100입니다.
ex)padding이 있는 시퀀스 데이터를 처리할 때, 패딩 토큰에 해당하는 레이블을 무시할 수 있습니다.- reduction : 손실 값을 어떻게 줄일지를 지정하는 인수로, 기본값은 mean입니다. sum,none 옵션도 가지고 있습니다.
- nn.CrossEntropyLoss : 다중 클래스 분류 문제에서 주로 사용되며, 모델의 예측값과 실제 레이블 간의 차이를 계산하여 모델을 학습시키는데 사용됨
- torch.nn.CrossEntropyLoss 클래스를 제공하여 계산할 수 있음, 그리고 이 클래스는 소프트맥스 함수를 내장하고 있어, 모델의 출력값에 소프트맥스를 적용할 필요 없이 모델의 출려값과 레이블을 입력으로 받아 손실을 계산합니다.
torch.nn.CrossEntropyLoss(weight=None, ignore_index=-100, reduction='mean')
-CrossEntropyLoss 인수
- weight: 클래스별 가중치를 적용할 경우 사용하는 가중치 텐서, 기본값은 None
- ignore_index: 무시할 클래스의 인덱스, 기본값은 -100
- reduction: 손실을 감소할 방법을 지정,(mean,sun,none 중 하나를 선택) 기본값은 mean
최적화: 각 학습단계에서 모델의 오류를 줄이기 위한 모델 매개변수를 조정하는 과정,
-최적화 알고리즘은 이 과정이 수행되는 방식,여기서SGD(Stochatic Gradient Descent)를 정의
모든 최적화 절차는 optimizer
객체에 캡슐화 됨
-이번 코드에서는 SGD 옵티마이저를 사용하고 있고, Pytorch에는 ADAM이나 RMSProp과 같은 다른 종류의 모델과 데이터에서 더 잘 작동되는 다양한 옵티마이저가 있음
학습하려는 모델의 매개변수와 학습률 하이퍼파라미터를 등록하여 옵티마이저를 초기화함
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
Pytorch의 다른 옵티마이저
- ADAM
- RMSProp
train_loop
와 테스트 데이터로 모델의 성능을 측정하는 test_loop
를 정의해보자def train_loop(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
for batch, (X, y) in enumerate(dataloader):
# 예측(prediction)과 손실(loss) 계산
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_loop(dataloader, model, loss_fn):
size = len(dataloader.dataset)
num_batches = len(dataloader)
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in dataloader:
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")
.backward()
를 호출하여 역전파를 수행합니다. 역전파를 수행하며 gradient를 계산하고 optimizer를 사용하여 모델의 매개변수를 업데이트 합니다.loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
epochs = 10
for t in range(epochs):
print(f"Epoch {t+1}\n-------------------------------")
train_loop(train_dataloader, model, loss_fn, optimizer)
test_loop(test_dataloader, model, loss_fn)
print("Done!")