PyTorch 정리 (기초2)

강다빈·2025년 12월 10일

PyTorch 공부

목록 보기
2/3

1. Transform(변형)

  • 데이터 전처리(Preprocessing)와 데이터 증강(Augmentation)을 수행

1-1. 관련 코드

# pytorch pre-loaded 데이터 로딩 코드

import torch
from torchvision import datasets
from torchvision.transforms import ToTensor, Lambda

ds = datasets.FashionMNIST(
    root="data",
    train=True,
    download=True,
    transform=ToTensor(),
    target_transform=Lambda(lambda y: torch.zeros(10, dtype=torch.float).scatter_(0, torch.tensor(y), value=1))
)
  • ToTensor() 함수 : 데이터를 Pytorch 텐서(Tensor)로 변환하고, 픽셀 값을 0.0~1.0 범위로 스케일링
transform=ToTensor()

- PIL Image/Numpy를 PyTorch의 기본 단위인 FloatTensor로 바꾸면서 특성스케일링인 정규화(값의 범위를 0.0 ~ 1.0으로) 진행
- 차원 변경 : (높이, 너비, 채널) -> (채널, 높이, 너비)
  • Lambda() 함수 : 사용자 정의 함수(lambda)를 적용하여 정답 데이터를 변형
target_transform=Lambda(lambda y: torch.zeros(10, dtype=torch.float).scatter_(0, torch.tensor(y), value=1))

- 해당 코드에서는 원-핫 인코딩 수행
- y : 정답 라벨
- torch.zeros(10, dtype=torch.float) : (1차원)길이가 10인 float 0으로 채워진 벡터 생성
- .scatter_(0, torch.tensor(y), value=1) : 0번째 차원(1차원) 기준으로, 앞서 torch.zeros에서 만든 벡터의 y번째 인덱스에 value 1를 할당

2. nn.Module(신경망 모델 구성)

예시 코드

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

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)

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}")

2-1. 코드 설명

- __init__

  • 사용할 레이어들을 선언 (신경망 계층 초기화)

- forward()

  • 순전파, __init__에서 선언한 레이어 사용
  • 주의: model.forward()는 직접 호출하면 안됨, 무조건 model를 사용해야함

- nn.Flatten()

  • 평탄화 계층
  • n차원을 1차원 배열로 변환 -> 다음 레이어인 nn.Linear는 1차원 데이터만 받을 수 있기 때문

- nn.Sequential()

  • 내부에 정의된 레이어를 순서대로 실행해주는 컨테이너

- nn.Linear()

  • 선형 변환 적용 계층 -> 1차원 데이터만 받을 수 있음
  • 가중치와 편향을 사용하여 입력에 선형 변환 적용

- nn.ReLU()

  • 활성화 함수 -> 보통 은닉층에서 사용됨 -> 특징 잘 학습하기 위해
  • 비선형성 적용 계층
  • 입력과 출력 사이에 복잡한 관계(mapping) 만듬

- nn.Softmax()

  • 활성화 함수 -> 보통 출력층에서 사용됨 -> 최종 결과를 확률로 해석하기 위해
  • softmax(다중분류), sigmoid(이진분류)에 사용됨

- 전체 코드 설명

# 1. 신경망 모델 정의 (nn.Module을 상속받아야 함)
class NeuralNetwork(nn.Module):
    def __init__(self):
        super().__init__() # 부모 클래스(nn.Module) 초기화 (필수!)
        
        # 평탄화 계층: 28x28(2차원) 이미지를 784(1차원) 벡터로 쫙 펴주는 역할
        self.flatten = nn.Flatten()
        
        # 순차 컨테이너: 내부에 정의된 층들을 순서대로 통과시킴
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(28*28, 512), # 입력층 -> 은닉층1 (입력 784개, 출력 512개)
            nn.ReLU(),             # 활성화 함수 (비선형성 추가)
            nn.Linear(512, 512),   # 은닉층1 -> 은닉층2 (입력 512개, 출력 512개)
            nn.ReLU(),             # 활성화 함수
            nn.Linear(512, 10),    # 은닉층2 -> 출력층 (출력 10개 = 클래스 개수)
        )

    # 순전파(Forward): 데이터가 모델을 통과하는 경로 정의
    def forward(self, x):
        x = self.flatten(x)                # 1. 이미지를 1차원으로 폄
        logits = self.linear_relu_stack(x) # 2. 신경망 층을 통과 (결과값은 Logits)
        return logits                      # 3. Logits 반환 (아직 확률 아님)

# 2. 모델 인스턴스 생성 및 장치(CPU/GPU)로 이동
# device 변수는 앞서 정의되어 있어야 함 (예: "cuda" or "cpu")
model = NeuralNetwork().to(device)
print(model) # 모델 구조 출력 확인

# 3. 모델 테스트 (추론)
# 더미(가짜) 입력 데이터 생성 (배치크기 1, 28x28 이미지)
X = torch.rand(1, 28, 28, device=device)

# 모델에 입력 데이터 넣고 예측 실행
# 주의: model.forward(X)가 아니라 model(X)로 호출해야 함!
logits = model(X) 

# 예측 결과(Logits)를 확률(Probability)로 변환
# dim=1은 클래스 차원을 기준으로 합이 1이 되게 하라는 뜻
pred_probab = nn.Softmax(dim=1)(logits)

# 가장 높은 확률을 가진 클래스의 인덱스(번호) 추출
y_pred = pred_probab.argmax(1)

print(f"Predicted class: {y_pred}")

3. Optimization(최적화)

  • 준비된 데이터와 모델을 활용하여 매개변수 최적화하여 모델 학습, 검증, 테스트 진행

    • epoch -> 반복
    • loss -> 추측과 정답 사이 오류
    • optimize -> 오류의 도함수를 수집한 뒤 경사하강법을 사용하여 파라미터 최적화
    • train_loop -> model, loss, backward, optimizer.step 실행
      • model은 문제풀기(답을 찍는 행동)
      • loss는 정답지와 비교하여 틀린 점수 확인
      • backward는 loss를 미분하여 틀린 부분 찾는 과정 -> 미분으로 기울기 계산
      • optimizer는 가중치 수정하여 잘 맞히도록 수정 -> 계산된 기울기만큼 가중치 수정
  • 더 자세한 설명 : https://tutorials.pytorch.kr/beginner/basics/optimization_tutorial.html

예시 코드

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)

device = "cuda" if torch.cuda.is_available() else "cpu"

# 모델 구성
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)

# 실제 학습 실행 (데이터, 모델, 손실함수, 옵티마이저를 매개변수로)
def train_loop(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)
    model.train()
    for batch, (X, y) in enumerate(dataloader):
        X, y = X.to(device), y.to(device)

        pred = model(X)
        loss = loss_fn(pred, y)

        loss.backward()
        optimizer.step()
        optimizer.zero_grad()

        if batch % 100 == 0:
            loss, current = loss.item(), batch * len(X)
            print(f"loss: {loss:>7f}  [{current:>5d}/{size:>5d}]")

# 테스트 실행 (데이터, 모델, 손실함수)
def test_loop(dataloader, model, loss_fn):
    model.eval()
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    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")

learning_rate = 1e-3
batch_size = 64
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!")

참고

profile
하루살이

0개의 댓글