Python(Colab) 파이토치(Pytorch) + 딥러닝 + CNN + 손글씨 데이터

2023. 6. 21. 23:24파이썬/머신러닝 및 딥러닝

CNN을 적용해서 손글씨 데이터를 분류해보자

 

 

1. 기초설정

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.datasets as datasets
import torchvision.transforms as transforms
import matplotlib.pyplot as plt

from torch.utils.data import DataLoader

 

 

 

2. 코랩 환경에서 GPU로 돌리기

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

 

 

 

3. 데이터셋 받아오기

train_data = datasets.MNIST(
    root='data',
    train=True,
    transform = transforms.ToTensor(),
    download=True
)

test_data = datasets.MNIST(
    root='data',
    train=False,
    transform = transforms.ToTensor(),
    download=True
)
해석

데이터셋은 torchvision에서 제공하기 때문에 import 시킨 후 세부 설정
root: 데이터의 경로
train: 학습데이터여부
transform: 어떤 형태로 불러 올지 (일반이미지: H,W,C)형태 / Pytorch는 0 ~ 1사이 값을 가진 (C,H,W)형식
download: 데이터가 없으면 다운 받을지 여부

 

 

 

4. 데이터 셋 확인

print(train_data)
print(test_data)
해석
학습 데이터는 60,000개 / 학습용 데이터 / 형태는 텐서

 

 

 

5. 데이터로더 설정 후 학습데이터 시각화 확인

loader = DataLoader(
    dataset=train_data,
    batch_size=64,
    shuffle=True
)

imgs, labels = next(iter(loader))

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

for ax,img,label in zip(axes.flatten(),imgs,labels):
    ax.imshow(img.reshape((28,28)), cmap='gray')
    ax.set_title(label.item())
    ax.axis('off')
 
 
해석

첫번쨰 ) torch.utils.data의 DataLoader를 import 

두번째) DataLoder로 학습데이터를 설정
dataset는 학습 데이터
batch_size는 64(즉 64개 데이터가 1그룹)
shuffle: 순서를 섞는다.

세번째) 데이터 로더를 반복가능객체로 만든다. (return이 2개이기 때문에 2개 변수의 설정)

네번째) 반복문을 통해 시각화
plt.subplots(가로,세로, 전체 표사이즈) (return이 2개여서 2개 변수의 설정) 
fig는 표의 전체 프레임 , axes 그래프가 그려지는곳

zip 함수로 axes를 평탄화한 데이터  + img 데이터들 +  img 이름 데이터들을 반복

 

 

6. 모델 준비

 

model = nn.Sequential(
    nn.Conv2d(1,32,kernel_size=3,padding='same'),
    nn.ReLU(),
    nn.MaxPool2d(kernel_size=2),

    nn.Conv2d(32,64,kernel_size=3,padding='same'),
    nn.ReLU(),
    nn.MaxPool2d(kernel_size=2),

    nn.Flatten(),
    nn.Linear(7*7*64, 10)
).to(device)

print(model)
해석
CNN 모델처럼 만들었다.

컨볼루전 + 활성화 (Relu) + Maxpooling을 1개의 세트로 생각
2번 진행후
평탄화
선형회귀에 적용

 

7.학습 시키기

# 학습시키기

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

epochs= 10

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

    for x_batch,y_batch in loader:
        x_batch = x_batch.to(device)
        y_batch = y_batch.to(device)

        y_pred= model(x_batch)

        loss=nn.CrossEntropyLoss()(y_pred,y_batch)

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

        #배치 단위 loss 저장
        sum_losses = sum_losses + loss.item()
        #배치 단위 정확도 저장
        y_prob = nn.Softmax(1)(y_pred)
        y_pred_index = torch.argmax(y_prob, axis=1)
        acc= (y_batch == y_pred_index).float().sum() / len(y_batch) * 100

        sum_accs = sum_accs + acc.item()
    avg_loss = sum_losses / len(loader)
    avg_acc = sum_accs / len(loader)

    print(f'Epoch {epoch+1:4d}/{epochs} Loss: {avg_loss:.6f} Accuracy: {avg_acc:.2f}%')
배치 정확도 저장이 많이 헷갈린다

y_prob는 Softmax를 통해 0~1사이 값으로 변경 후 

예시) Tensor ([[0.7,0,8,0.7,0,8,0.7,0,8,0.7,0,8]])  / 1개의 데이터가 1~10중 어느것에 속할지 확률

y_prde_index라는 변수에 torch.argmax()를 통해 위에 데이터중 제일 값이 큰 값의 인덱스 번호를 가져온다.

그것이 y_batch와 맞는지의 여부를 float로 바꿔서 총합을 구함 (맞으면 1.00이 될 것고, 아니면0.0)

 

7.학습된 모델로 테스트해보기

 

 

test_loader = DataLoader(
    dataset=test_data,
    batch_size=64,
    shuffle=True
)

imgs, labels = next(iter(test_loader))

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

for ax,img,label in zip(axes.flatten(),imgs,labels):
    ax.imshow(img.reshape((28,28)), cmap='hot')
    ax.set_title(label.item())
    ax.axis('off')

 

# 모델의 모드를 test모델로 전환시키겠다.
model.eval()
 
sum_accs = 0
 
for x_batch,y_batch in test_loader:
    x_batch = x_batch.to(device)
    y_batch = y_batch.to(device)
    y_pred= model(x_batch)
 
    #배치 단위 정확도 저장
    y_prob = nn.Softmax(1)(y_pred)
    y_pred_index = torch.argmax(y_prob, axis=1)
    acc= (y_batch == y_pred_index).float().sum() / len(y_batch) * 100
    sum_accs = sum_accs + acc
 
avg_acc = sum_accs / len(test_loader)
print(f'테스트 정확도  / Accuracy: {avg_acc:.2f}% 입니다.')

 

 

 

728x90