2025.04.27
Part12. 파이토치
- Chapter.03 간단한 Model 학습 시키기
- 01_deeplearning Flow (1)
- 02_deeplearning Flow (2)
- 03_deeplearning Flow (3)
Deeplearning Flow
데이터 Load 및 전처리
관련 패키지를 import하고, torch에서 제공하는 MNIST 데이터를 Load 한다.
DataLoader는 제너레이터 양식으로 불러진다.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
## pytorch 관련 패키지
import torch
from torchvision import datasets, transforms
import torch.utils
batch_size = 32
## MNIST 데이터 Load
# "datasets/" : 데이터를 저장할 폴더 (없으면 만들어짐)
# download=True : 데이터가 없으면 자동으로 인터넷에서 다운로드. 있으면 다운로드 하지 않음.
# train=True : 훈련용 데이터를 쓰겠다는 의미 (False면 Test용 데이터)
train_loader = torch.utils.data.DataLoader(
datasets.MNIST("datasets/",download=True, train=True,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=(0.5,), std=(0.5,))
])),
batch_size = batch_size,
shuffle = True,
)
- transforms.ToTensor( ) : (정규화)
- 데이터 타입 변환
- (H, W, C) 형태의 PIL 이미지 또는 numpy 배열을
- (C, H, W) 형태의 PyTorch Tensor로 변환해.
- 값 스케일링
- 원래 이미지 픽셀값은 0~255 (8-bit unsigned int)이잖아?
- 이걸 0.0 ~ 1.0 사이로 나눈다.
- 즉, pixel_value / 255.0 을 자동으로 해줌. (0~1사이)
- 데이터 타입 변환
- transforms.Normalize( mean = (0.5,), std = (0.5,) ) : 왜하는가?? (표준화)
- ToTensor()로 0~1 범위로 스케일만 했을 때, 데이터는 이렇게 분포할 수 있어:
- 모든 값이 양수야 (0.0 ~ 1.0)
- 평균은 대략 0.5쯤
- 값들이 0을 중심으로 대칭적이지 않아
- 이렇게 되면 문제가 생겨:
- 뉴럴 네트워크에서 활성함수(ReLU, Sigmoid 등) 들이 작동할 때, 양수 방향으로 치우쳐.
- 가중치 업데이트(=경사 하강법) 방향도 한쪽으로 치우쳐서, 학습 속도가 느려지고 최적점을 제대로 못 찾을 수도 있어.
- Normalize(mean=0.5, std=0.5)를 하면:
- 데이터 범위가 대략 [-1, 1]로 바뀌고
- 평균은 0이 되고
- 표준편차는 1이 돼
- 장점:
- 데이터가 0 주변에 고르게 퍼져 있음 → 뉴런이 양방향(양수/음수) 으로 고르게 활성화돼.
- 경사하강법(optimizer)이 훨씬 빠르고 안정적으로 작동해.
- Vanishing Gradient 같은 문제도 어느 정도 완화할 수 있어.
- "mean=0.5, std=0.5를 주는 건 [0~1] 스케일을 [-1, 1]로 맞추기 위해서다."
- 현재 ToTensor( )를 통해서 픽셀값들이 0~1사이 값으로 맞추어져있음.
- 표준화를 하기 위해선, ${output} = \frac{input - mean}{std}$ 형태인데, input이 0인 경우 결과값은 -1, input이 1인 경우 결과값은 1이기 때문에, mean 과 std를 0.5로 설정한다.
- ToTensor()로 0~1 범위로 스케일만 했을 때, 데이터는 이렇게 분포할 수 있어:
표준화 (Normalize) 과정
문제: [3, 5, 7, 8] 이라는 데이터를 Normalize(평균 0, 표준편차 1) 하면 어떻게 되는지.
1. 평균(mean) 계산
평균은 값들의 합을 데이터 개수로 나눈 거야.
$${mean} = \frac{3+5+7+8}{4} = \frac{23}{4} = 5.75$$
2. 표준편차(std) 계산
표준편차는 각 값과 평균의 차이를 제곱하고, 그걸 평균낸 다음 루트 씌운 거야.
각 값과 평균의 차이를 제곱
- (3 - 5.75)² = (-2.75)² = 7.5625
- (5 - 5.75)² = (-0.75)² = 0.5625
- (7 - 5.75)² = (1.25)² = 1.5625
- (8 - 5.75)² = (2.25)² = 5.0625
평균낸다
$${var} = \frac{7.5625 + 0.5625 + 1.5625 + 5.0625}{4} = \frac{14.75}{4} = 3.6875$$
루트 씌운다 (표준편차)
$${std} = \sqrt{3.6875} \approx 1.920$$
3. 각 값을 Normalize 한다
Normalize 공식은:
$${normalized\_value} = \frac{\text{원래 값} - \text{mean}}{\text{std}}$$
계산하면:
- (3 - 5.75) / 1.920 ≈ -1.432
- (5 - 5.75) / 1.920 ≈ -0.391
- (7 - 5.75) / 1.920 ≈ 0.651
- (8 - 5.75) / 1.920 ≈ 1.172
최종 결과
원래값 | 정규화 값 |
3 | -1.432 |
5 | -0.391 |
7 | 0.651 |
8 | 1.172 |
[3, 5, 7, 8]
👉 평균 5.75, 표준편차 약 1.920
👉 Normalize 하면 [-1.432, -0.391, 0.651, 1.172]
이렇게 각각 값이 변환돼! 🎯
데이터 확인
Pytorch에서는 TensorFlow와 이미지를 표현하는데 있어서 차이점이 있음 (차원, 채널)
- TensorFlow : (batch, height, width, channel) → 마지막 차원이 흑백이면 1, 컬러면 3 이었던 차원요소
- Pytorch : (batch, channel, heightm width) → 컬러와 흑백을 표현하는 차원이 앞에 있다.
일단 batch-size만큼 32개의 데이터를 불러오게 되고, label 값이 같이 들어있는 자료형태로 반환된다.
images 와 labels에 할당하고 각각의 shape을 확인하면 아래와 같다.
iterater 실행 참고.
하지만 대부분 반복문을 이용해서 데이터를 꺼낸다.
학습할때는 굳이 꺼내지 않아도 자동으로 꺼내서 학습된다.
iter에서 불러온 첫번째 배치의 아무 데이터를 꺼내서 사진을 확인해보면....
images[18].shape
>> torch.Size([1, 28, 28])
## squeeze 를 통해서 첫번째 차원 축소
image = torch.squeeze(images[18])
image.shape
>> torch.Size([28, 28])
image = image.numpy()
## 커널충돌 설정
import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'
plt.imshow(image)
plt.title(labels[18].numpy())
plt.axis('off')
plt.tight_layout()
plt.show()
pytorch 모델정의
tensorflow 처럼 모델정의하기 위해 필요한 패키지를 import 한다.
from torch import nn
import torch.nn.functional as f
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(
in_channels=1, out_channels=32, kernel_size=5, stride=1, padding=2)
self.conv2 = nn.Conv2d(
in_channels=32, out_channels=64, kernel_size=5, stride=1, padding=2)
# Linear 사용 시 채널계산 필요
# 데이터 1X28X28
# conv1 = 32(out_channels) X 28X28 (출력크기 계산 참조)
# maxpool = 32 X 14 X 14 (커널 2X2, stride 2 → 절반으로 줄어듬)
# ( input - 커널 + 2 X padding ) / stride = ( 28 - 2 + 2 X 1 ) / 2 = 14
# conv2 = 64(out_channels) X 14X14
# axpool = 64 X 7 X 7 (커널 2X2, stride 2 → 절반으로 줄어듬)
# ( input - 커널 + 2 X padding ) / stride = ( 14 - 2 + 2 X 1 ) / 2 = 7
# 64 X 7 X 7
self.fc1 = nn.Linear(64*7*7, 256)
self.fc2 = nn.Linear(256, 10) # labels은 10개 (0 ~ 9)
def forward(self, x):
#F.max_pool2d(input, kernel_size, stride, padding=0, dilation=1, ceil_mode=False, return_indices=False)
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, 2, 2)
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, 2, 2)
x = x.reshape(x.size(0), -1) #Flatten
x = F.relu(self.fc1(x))
x = self.fc2(x)
return F.log_softmax(x, dim=1)
모델 선언
# device 설정
device = torch.device("cuda" if torch.cuda.is_available else "cpu")
model = Net().to(device)
print(model)
padding 값에 따른 출력크기 변화 (출력크기 계산)
학습로직 구현
Pytorch에서는 model을 Training 모드로 변경 후 Training 할 수 있다. 앞서 모델을 확인하면, 아래와 같이 확인할 수 있다.
import torch.optim as optim
optimizer = optim.SGD(model.parameters(), 0.0003)
for epoch in range(10):
model.train() #train mode 선언
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device) #cuda 설정
optimizer.zero_grad() # 초기화 (누적값 초기화화)
output = model(data) # 예측측
# cross_entropy X (one_hot encoding 안되어 있음)
# nll_loss = negative log likelihood loss
loss = F.nll_loss(output, target) # 순서 : 예측값, 정답값
loss.backward() # 오차 역전파파
optimizer.step() #loss에서 계산한 미분값(가중치) 업데이트
print(f'batch : {batch_idx}, loss : {loss.item()}')
이제 evaluation을 진행해보면, 우선 train 모드를 끄고 eval() 모드를 설정한 뒤 진행해야 한다.
model.eval()
test_loss = []
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device) #cuda 설정
output = model(data) # 예측
test_loss.append(F.nll_loss(output, target).item())
# batch 의 평균 Loss
mean_loss = sum(test_loss) / (len(test_loader.dataset) // 32)
단. test 데이터도 마찬가지로 "cuda"로 보내주어야 학습이 된다. 모델 선언 및 학습 시 "cuda"에서 학습했기 때문이다.
'Bootcamp_zerobase > Pytorch' 카테고리의 다른 글
Pytorch 데이터 다루기 (1) | 2025.05.28 |
---|---|
Pytorch의 모델링 및 학습 (0) | 2025.05.18 |
최적화 및 미분 (0) | 2025.04.27 |
Tensor 다루기 (1) | 2025.04.27 |
Pytorch #4 : 식물잎 사진으로 질병분류 (0) | 2025.04.26 |