카테고리 없음

[PyTorch] 1주차 - 데이터 작업, 모델 만들기, 모델 매개변수 최적화

콜라드리블 2024. 3. 7. 21:05
작성자 김명원
일 시 2024. 3. 7 (목) 18:00 ~ 21:00
장 소 복지관 b128-1호
참가자 명단 임혜진, 이재영, 성창민, 김명원, 장원준
사진

파이토치 스터디

https://tutorials.pytorch.kr/beginner/basics/quickstart_tutorial.html

 

빠른 시작(Quickstart)

파이토치(PyTorch) 기본 익히기|| 빠른 시작|| 텐서(Tensor)|| Dataset과 Dataloader|| 변형(Transform)|| 신경망 모델 구성하기|| Autograd|| 최적화(Optimization)|| 모델 저장하고 불러오기 이번 장에서는 기계 학습의

tutorials.pytorch.kr

코랩을 통해 코드를 실행시켰다.

%matplotlib inline
#notebook을 실행한 브라우저에서 바로 그림을 볼 수 있게 하는 역할

 

데이터셋(DataSet)은 샘플과 정답을 저장했다.

데이터로더(DataLeader)는 데이터셋을 순회 가능한 객체(데이터를 하나하나씩 처리할 수 있는 객체)로 감싸는 역할을 한다.

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor

 

공개 데이터셋에서 학습 데이터와 테스트 데이터를 내려받는다.

Q) 왜 트레이팅 데이터셋과 테스트 데이터가 같지?

A) 각각 train=True와 train=False로 학습 데이터와 테스트 데이터를 분리시킨다.

training_data = datasets.FashionMNIST( 
    root="data",
    train=True,
    download=True,
    transform=ToTensor(),
)
 
test_data = datasets.FashionMNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor(),
)

 

데어터셋을 데이터로더의 인자로 전달해 순회 가능한 객체로 감싸고, 자동화된 배치(batch), 샘플링(sampling), 섞기(shuffle) 및 다중 프로세스로 데이터 불러오기(multiprocess data loading)를 지원한다.

즉 데이터로더는 데이터셋에서 원본 데이터를 불러와 모델에서 필요로 하는 형식으로 처리하는 역할을 한다.

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

결과 : Shape of X [N, C, H, W]: torch.Size([64, 1, 28, 28]) Shape of y: torch.Size([64]) torch.int64

 

모델 만들기

사용할 CPU나 GPU, MPS 장치를 얻음

# 학습에 사용할 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")

결과 : Using cuda device

- CUDA를 지원하는 GPU를 사용중임

 

파이토치에서 신경망 모델은 nn.Module 을 상속받는 클래스를 생성하여 정의한다.

class NeuralNetwork(nn.Module):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten() #1차원으로 변환
        self.linear_relu_stack = nn.Sequential( #__init__에서 사용할 네트워크 모델들을 정의, forward() 함수에서 구현될 순전파를 Layer 형태로 가독성이 뛰어나게 코드를 작성할 수 있음
            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) #device = cuba로 했음
    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)

    )

)

- ReLU함수 사용, 입력값이 0보다 작으면 0으로 반환하고 0보다 크면 입력값을 그대로 반환한다.

 

모델 매개변수 최적화하기

모델을 학습하려면 손실함수와 옵티마이저가 필요하다.

손실함수 : 머신러닝 혹은 딥러닝 모델의 출력값과 사용자가 원하는 출력값의 오차

옵티마이저 : 딥러닝에서 손실함수를 최적화 해야한다. 이를 수행하는 알고리즘

loss_fn = nn.CrossEntropyLoss() #신경망의 출력과 정수 형태의 타겟(label)을 받아들여서, 해당 출력과 타겟 간의 교차 엔트로피 손실을 계산한다.
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3) #확률적 경사 하강법(SGD) 사용, model.parameters() : 모델의 학습 가능한 파라미터들을 반환하는 함수, lr=1e-3 : 학습률, 파라미터를 얼마나 많이 업데이트할 지를 제어

 

데이터와 타켓을 모델에 전달해서 예측값을 계산하고 손실함수를 사용하여 타겟 사이의 오차를 계산한다. 이 함수는 주로 반복적으로 호출되어 모델을 여러 에포크(epoch) 동안 학습시키는 데 사용한다.

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 = 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!")

결과 - Epoch 5

-------------------------------

loss: 1.338332 [ 64/60000]

loss: 1.325674 [ 6464/60000]

loss: 1.156638 [12864/60000]

loss: 1.264828 [19264/60000]

loss: 1.142240 [25664/60000]

loss: 1.159866 [32064/60000]

loss: 1.185633 [38464/60000]

loss: 1.123085 [44864/60000]

loss: 1.175986 [51264/60000]

loss: 1.088201 [57664/60000]

Test Error: Accuracy: 64.2%, Avg loss: 1.102630

 

Done!

 

이상 1주차 스터디를 마무리했다. 파이토치를 활용한 인공지능 개발을 위해 앞으로도 더욱 노력해야 할 것이다.
 데이터를 전처리하는 법도 배우고 앞으로도 다양한 기능들을 배워 멋진 모델을 만들어보고 싶다.