파이토치 한국어 튜토리얼에서 '신경망 모델 구성하기', 'Autograd', '최적화' 부분에 대해서 공부하고 정리함
1. 신경망 모델 구성하기
import os
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
학습을 얻기 위한 장치
device = (
"cuda"
if torch.cuda.is_available()
else "mps"
if torch.backends.mps.is_available()
else "cpu"
)
print(f"Using {device} device")
--------------------------------------------------
Using cpu device
클래스 정의하기
- 신경망 모델을 nn.Module의 하위클래스로 정의하고, __init__에서 신경망 계층들을 초기화 함
- nn.Module을 상속받은 모든 클래스는 forward 메소드에 입력 데이터에 대한 연산들을 구현함
class NeuralNetwork(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten() # 28*28dml 2D 이미지를 784 픽셀 값을 갖는 연속된 배열로 변환(미니배치 차원은 유지)
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
- NeuralNetwork의 인스턴스를 생성하고 이를 device로 이동한 뒤, 구조 출력
model=NeuralNetwork().to(device)
print(model)
--------------------------------------------------
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)
)
)
- 모델을 사용하기 위해 입력 데이터 전달하여 2차원 텐서 반환(dim=0은 각 분류에 대한 원시 예측값, dim=1은 각 출력의 개별 값)
X = torch.rand(1, 28, 28, device=device)
logits = model(X)
pred_probab = nn.Softmax(dim=1)(logits)
y_pred = pred_probab.argmax(1)
print(f"Predicted class: {y_pred}")
--------------------------------------------------
Predicted class: tensor([3])
모델 매개변수
- 신경망 내부의 많은 계층들은 매개변수화 됨
- nn.Module을 상속하면 모델 객체 내부의 모든 필드들이 자동으로 추적되며, 모델의 parameters() 및 named_parameters() 메소드로 모든 매개변수에 접근할 수 있게 됨
print(f"Model structure: {model}\n\n")
for name, param in model.named_parameters():
print(f"Layer: {name} | Size: {param.size()} | Values : {param[:2]} \n")
--------------------------------------------------
Model structure: 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)
)
)
Layer: linear_relu_stack.0.weight | Size: torch.Size([512, 784]) | Values : tensor([[ 0.0278, 0.0166, -0.0172, ..., -0.0335, -0.0249, 0.0034],
[ 0.0146, 0.0302, -0.0315, ..., -0.0069, 0.0262, 0.0155]],
grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.0.bias | Size: torch.Size([512]) | Values : tensor([-0.0038, 0.0291], grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.2.weight | Size: torch.Size([512, 512]) | Values : tensor([[-0.0012, -0.0015, 0.0282, ..., -0.0367, 0.0321, -0.0216],
[ 0.0293, -0.0112, 0.0343, ..., 0.0147, 0.0309, 0.0351]],
grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.2.bias | Size: torch.Size([512]) | Values : tensor([0.0218, 0.0240], grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.4.weight | Size: torch.Size([10, 512]) | Values : tensor([[ 0.0131, 0.0106, 0.0004, ..., 0.0173, 0.0369, -0.0060],
[-0.0135, -0.0165, 0.0021, ..., 0.0297, -0.0381, 0.0410]],
grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.4.bias | Size: torch.Size([10]) | Values : tensor([ 0.0130, -0.0029], grad_fn=<SliceBackward0>)
2. Autograd
import torch
x = torch.ones(5) # input tensor
y = torch.zeros(3) # expected output
w = torch.randn(5, 3, requires_grad=True)
b = torch.randn(3, requires_grad=True)
z = torch.matmul(x, w)+b
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, y)
변화도(gradient) 계산
- 신경망에서 매개변수의 가중치를 최적화하려면 매개변수에 대한 손실함수의 도함수를 계산
loss.backward()
print(w.grad)
print(b.grad)
--------------------------------------------------
tensor([[0.1513, 0.1044, 0.0981],
[0.1513, 0.1044, 0.0981],
[0.1513, 0.1044, 0.0981],
[0.1513, 0.1044, 0.0981],
[0.1513, 0.1044, 0.0981]])
tensor([0.1513, 0.1044, 0.0981])
변화도 추적 멈추기
- requires_grad=True인 모든 텐서들은 연산 기록을 추적하고 변화도 계산을 지원
- 모델을 학습한 뒤 입력 데이터를 단순히 적용하기만 하는 경우와 같이 순전파 연산만 필요한 경우에는 이러한 추적이 필요없음(이와 같은 경우에는 torch.no.grad() 블록으로 둘러싸서 연산 추적을 멈출 수 있음)
z = torch.matmul(x, w)+b
print(z.requires_grad)
with torch.no_grad():
z = torch.matmul(x, w)+b
print(z.requires_grad)
--------------------------------------------------
True
False
- backward를 두 차례 호출하면 변화도 값이 달라짐(역전파를 수행할 때, 파이토치가 변화도를 누적해주기 때문)
- 제대로 된 변화도를 계산하기 위해서는 grad 속성을 먼저 0으로 만들어야 함(실제 학습 과정에서는 옵티마이저가 이 과정을 도와줌)
3. 최적화
하이퍼파라미터
- 에폭수: 데이터셋을 반복하는 횟수
- 배치크기: 매개변수가 갱신되기 전 신경망을 통해 전파된 데이터 샘플의 수
- 학습률: 각 배치/에폭에서 모델의 매개변수를 조절하는 비율
손실함수
- 획득한 결과와 실제 값 사이의 틀린 정도를 측정하며, 학습 중에 이 값을 최소화하려고 함
- nn.CrossEntropyLoss는 nn.LogSoftmax와 nn.NLLLoss를 합친 것
loss_fn = nn.CrossEntropyLoss()
옵티마이저
- 각 학습 단계에서 모델의 오류를 줄이기 위해 모델 매개변수를 조정하는 과정
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
학습 단계에서 최적화는 세단계로 이루어짐
optimizer.zero_grad(): 모델 매개변수의 변화도를 재설정
loss.backwards(): 예측 손실을 역전파(각 매개변수에 대한 손실의 변화도 저장)
optimizer.step(): 역전파 단계에서 수집된 변화도로 매개변수 조정
출처 : 신경망 모델 구성하기 — 파이토치 한국어 튜토리얼 (PyTorch tutorials in Korean)
'파이토치' 카테고리의 다른 글
[딥러닝 파이토치 교과서] 성능 최적화 (0) | 2023.06.17 |
---|---|
[딥러닝 파이토치 교과서] 합성곱 신경망2 (0) | 2023.05.28 |
[딥러닝 파이토치 교과서] 합성곱 신경망 이해하기 (1) | 2023.05.13 |
[딥러닝 파이토치 교과서] RNN, LSTM, GRU (0) | 2023.04.22 |
[딥러닝 파이토치 교과서] 활성화함수와 손실 함수 (0) | 2023.04.16 |