혼공머신 - 13

Apic·2025년 8월 13일
0

이전의 코드를 파이토치 버전으로 작성했다.

from torchvision.datasets import FashionMNIST
from sklearn.model_selection import train_test_split
import torch.nn as nn
from torchinfo import summary
import torch
import torch.optim as optim
import matplotlib.pyplot as plt

# 데이터 불러오기
fm_train = FashionMNIST(root='.', train=True, download=True)
fm_test = FashionMNIST(root='.', train=False, download=True)

# 데이터 사이즈 확인
print(fm_train.data.shape, fm_test.data.shape)
# torch.Size([60000, 28, 28]) torch.Size([10000, 28, 28])

# input, taget 분리
train_input = fm_train.data
train_target = fm_train.targets

# 정규화
train_scaled = train_input / 255.0


# 데이터 분리
train_scaled, val_scaled, train_target, val_target = train_test_split(train_scaled, train_target, test_size=0.2, random_state=42)

# 데이터 크기 확인
print(train_scaled.shape, val_scaled.shape)
# torch.Size([48000, 28, 28]) torch.Size([12000, 28, 28])

model = nn.Sequential(
    nn.Flatten(), # 28*28 데이터를 1차원(784개)으로 평탄화
    nn.Linear(784, 100),  # 784개의 테이터를 100개로 
    nn.ReLU(),    # 활성화 함수로 ReLU 사용
    nn.Linear(100,10) # 100개의 데이터를 10개로
    # 파이토치에서는 softmax 생략(이후 손실 함수를 사용할 때 softmax가 포함되어있음)
)

# keras의 summary
print(summary(
    model, 
    input_size=(32, 28, 28) # 배치 사이즈 32, 28*28 데이터
))

==========================================================================================
Layer (type:depth-idx)                   Output Shape              Param #
==========================================================================================
Sequential                               [32, 10]                  --
├─Flatten: 1-1                           [32, 784]                 --
├─Linear: 1-2                            [32, 100]                 78,500
├─ReLU: 1-3                              [32, 100]                 --
├─Linear: 1-4                            [32, 10]                  1,010
==========================================================================================
Total params: 79,510
Trainable params: 79,510
Non-trainable params: 0
Total mult-adds (M): 2.54
==========================================================================================
Input size (MB): 0.10
Forward/backward pass size (MB): 0.03
Params size (MB): 0.32
Estimated Total Size (MB): 0.45
==========================================================================================

# GPU있는 경우 GPU 사용
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)

# 손실 함수 CrossEntropyLoss 사용
# 파이토치의 crossentropyLoss에는 softmax가 포함되어있다.
criterion = nn.CrossEntropyLoss()

"""
만약 다중 분류 손실 함수로 NLLLoss를 사용하는 경우에는 모델의 마지막에 LogSoftmax 층을 추가해야 한다.

model = nn.Sequential(
    nn.Flatten(), 
    nn.Linear(784, 100),  
    nn.ReLU(),     
    nn.Linear(100,10),
    nn.LogSoftmax(dim=1) 
    # dim = 1: 각 행(샘플) 안에서 클래스별로 확률 계산
    # dim = 0: 각 열(클래스) 방향으로 확률 계산

)

criterion = nn.NLLLoss()
""";

# 옵티마이저 Adam 사용
optimizer = optim.Adam(model.parameters())
# model.parameters: 훈련 가능한 모든 모델 파라미터를 전달함

EPOCHS = 20
BATCH_SIZE = len(train_scaled) // 32

acc_lst = []
loss_lst = []
for epoch in range(EPOCHS):
    model.train()   # 모델 훈련 모드로 변경
    train_loss = 0  # 훈련 손실 값
    train_acc = 0   # 훈련 정확도 값

    for i in range(BATCH_SIZE):
        # 배치 사이즈 만큼 데이터 추출
        inputs = train_scaled[i*32:(i+1)*32].to(device)
        targets = train_target[i*32:(i+1)*32].to(device)

        # 옵티마이저 기울기 초기화
        optimizer.zero_grad()
        # 출력 얻음
        outputs = model(inputs)

        # 출력값과 타깃을 비교하여 loss 계산
        loss = criterion(outputs, targets)
        
        # 파라미터에 대한 기울기를 계산
        loss.backward()
        # 계산된 기울기를 기반으로 모델 파라미터 업데이트
        optimizer.step()

        train_loss += loss.item()

        preds = outputs.argmax(dim=1)  # 각 샘플에서 최대값 인덱스
        train_acc += (preds == targets).sum().item()

    # acc, loss 계산하기
    avg_loss = round(train_loss/BATCH_SIZE, 4)
    avg_acc = round(train_acc/len(train_scaled), 4)

    loss_lst.append(avg_loss)
    acc_lst.append(avg_acc)
    
    print(f"epoch: {epoch+1}, acc: {avg_acc}, loss: {avg_loss}")

profile
코딩 공부하는 사람

0개의 댓글