본문 바로가기
Python/ML&DL

[파이썬, Python] 데이터로더(DataLoader) - 배치 단위로 학습시키기!

by coding-choonsik 2023. 6. 29.
728x90
반응형
SMALL

📄사용할 예제 - sklearn의 손글시 데이터셋

[데이터셋 정보] https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_digits.html

 

sklearn.datasets.load_digits

Examples using sklearn.datasets.load_digits: Recognizing hand-written digits Recognizing hand-written digits A demo of K-Means clustering on the handwritten digits data A demo of K-Means clustering...

scikit-learn.org


1. 손글씨 인식 모델 만들기

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.datasets as datasets
import torchvision.transforms as transfoms
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits  # 손글씨 데이터

 

✅ GPU 환경으로 변경

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(device)

# device.to(): 연산할 matrix를 gpu로 보내야 사용할 수 있음!!

📍 코랩에서 런타임 ➡️ 런타임 유형 변경 ➡️  GPU 로 변경 ➡️  런타임 재실행!!

 

digits = load_digits()

x_data = digits['data']
y_data = digits['target']

print(x_data.shape)  # (1797, 64): 1797글씨를 8x8 바이트(64) 픽셀로 되어있음
print(y_data.shape)

>>> 
(1797, 64)
(1797,)

 

 

✅ x_data 시각화해서 보기

fig, axes = plt.subplots(nrows=2, ncols=5, figsize=(14, 8))

for i, ax in enumerate(axes.flatten()):   #flatten():배열을 한줄로 만듦
  ax.imshow(x_data[i].reshape((8,8)), cmap='gray')
  ax.set_title(y_data[i])
  ax.grid('off')

 

✅ 데이터를 텐서형으로 변경

# tensor로 변경
x_data = torch.FloatTensor(x_data)
y_data = torch.LongTensor(y_data)

print(x_data.shape)
print(y_data.shape)

>>>
torch.Size([1797, 64])
torch.Size([1797])

 

✅ 데이터 원 핫 인코딩 

# one-hot-encoding
y_one_hot = nn.functional.one_hot(y_data, num_classes=10).float()  # 0~ 9
y_one_hot[:10]

▲ 0 ~ 9까지의 데이터를 원핫인코딩

 

✅ 학습데이터와 테스트데이터 분리

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(x_data, y_one_hot, test_size=0.2, random_state=10)

print(x_train.shape)
print(x_test.shape)
print(y_train.shape)
print(y_test.shape)

>>> torch.Size([1437, 64])
torch.Size([360, 64])
torch.Size([1437, 10])
torch.Size([360, 10])

2. 데이터 로더(DataLoader)

  • 데이터의 양이 많을 때 배치 단위로 학습하는 방법

 

✅ 데이터 로더 생성 - 배치사이즈가 64

loader = torch.utils.data.DataLoader(
    dataset = list(zip(x_train, y_train)),
    batch_size=64,
    shuffle=True
)
# next(): iterator 값을 하나씩 꺼냄(더이상 없을 때 까지 )
# iter(): next()로 꺼낸 데이터를 iterable한 객체로 만듦
imgs, labels = next(iter(loader))

fig, axes = plt.subplots(nrows=8, ncols=8, figsize=(16,16))

for ax, img, label in zip(axes.flatten(), imgs, labels):   #flatten():배열을 한줄로 만듦
  ax.imshow(img.reshape((8,8)), cmap='gray')
  ax.set_title(str(torch.argmax(label)))  # 텐서값중 확률이 가장 큰 값의 label
  ax.grid('off')

▲ 정답값과 픽셀화된 손글씨

 

✅ 배치단위로 학습시키기

 

# 모델 정의
model = nn.Sequential(
    nn.Linear(64, 10)  # batch size: 64(input), 계산이 2개이상 들어가는 모델-> 딥러닝 모델
)

optimizer = optim.Adam(model.parameters(), lr=0.01)

epochs = 50

for epoch in range(epochs + 1):
  sum_losses = 0
  sum_accs = 0

  # 배치 사이즈:64
  for x_batch, y_batch in loader:
    y_pred = model(x_batch)
    loss = nn.CrossEntropyLoss()(y_pred, y_batch)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    sum_losses = sum_losses + loss  # 누적

  # 배치 단위로  정확도 저장
    y_prob = nn.Softmax(1)(y_pred)
    y_pred_index = torch.argmax(y_prob, axis=1)    # 예측된 레이블에서 값이 가장 큰 레이블의 인덱스
    y_batch_index = torch.argmax(y_batch, axis=1)  # 실제 레이블에서 값이 가장 큰 레이블의 인덱스
    acc = (y_batch_index == y_pred_index ).float().sum() / len(y_batch) * 100  # 일치하는 bool값을 float형으로 바꾸고 더한 뒤 전체 데이터 수로 나눔 (백분율)

    sum_accs = sum_accs + acc

  avg_loss = sum_losses / len(loader)  # 배치단위(64개)를 50번 반복하기 때문에 평균으로 찍어줌
  avg_acc = sum_accs / len(loader)


  print(f'Epoch {epoch:4d} / {epochs}  Loss: {avg_loss:.6f} Accuracy: {avg_acc:.2f}%')

 📍배치단위로 학습했기 때문에 평균 loss와 평균 정확도를 계산함!

 

✅ 0번 테스트 데이터 확인

plt.imshow(x_test[0].reshape((8,8)), cmap='gray')

 

 ✅테스트 데이터로 예측값 도출

y_pred = model(x_test)
y_pred[0]

>>> tensor([ 2.1293, -4.6106, -6.3739,  0.0610, -2.6799, 16.4323, -4.4906, -2.6905,
        -1.4101, -3.9731], grad_fn=<SelectBackward0>)

 

✅ 예측값에 대한 확률 도출

y_prob = nn.Softmax(1)(y_pred)
y_prob[0]

>>> tensor([6.1420e-07, 7.2645e-10, 1.2457e-10, 7.7629e-08, 5.0084e-09, 1.0000e+00,
        8.1908e-10, 4.9553e-09, 1.7830e-08, 1.3742e-09],
       grad_fn=<SelectBackward0>)

 

✅ 0 ~ 9까지의 확률값을 뽑아내 어떤 숫자로 예측하였는지 보기

for i in range(10):
  print(f'숫자 {i}일 확률: {y_prob[0][i]:.2f}')
  
>>>
숫자 0일 확률: 0.00
숫자 1일 확률: 0.00
숫자 2일 확률: 0.00
숫자 3일 확률: 0.00
숫자 4일 확률: 0.00
숫자 5일 확률: 1.00
숫자 6일 확률: 0.00
숫자 7일 확률: 0.00
숫자 8일 확률: 0.00
숫자 9일 확률: 0.00

 

✅ 테스트 정확도

y_pred_index = torch.argmax(y_prob, axis=1)
y_test_index = torch.argmax(y_test, axis=1)
accuracy = (y_test_index == y_pred_index ).float().sum() / len(y_test) * 100
print(f'테스트 정확도는 {accuracy:.2f}% 입니다!')

>>> 테스트 정확도는 95.83% 입니다!

 

728x90
반응형
LIST