안녕하세요 대머리 낙지입니다.
Pytorch를 활용한 이미지 분류(Classification) 문제를 다루는 전반적인 flow를 기록해보려 합니다.
Google colab환경에서 CIFAR10 이미지 데이터를 활용해 간단한 CNN을 돌려보겠습니다.
CIFAR10?
- CIFAR10은 10가지 사물에 대한 32X32X3 크기의 이미지 데이터셋입니다. 크기도 작고 가벼워 테스트에 많이들 활용하십니다.
해당 dataset은 torchvision을 통해 쉽게 다운로드 받을 수 있습니다.
먼저 필요한 모듈들을 import 합니다.
# import modules
import torch
import torch. nn as nn
import torchvision.transforms as transforms
import torch.optim as optim
import torchvision
import matplotlib.pyplot as plt
import numpy as np
# torch 연산을 수행할 환경 설정
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print('using device:', device)
여기서 중요한 포인트는 "device"라는 변수에 torch 연산을 수행할 환경을 넣는 것 입니다.
gpu가 사용 가능한 경우 "cuda"가, 불가능한 경우 "cpu"가 입력됩니다.
CIFAR10 이미지 데이터를 불러오기 전에 Augmentation을 설정해줍니다.
# Image augmentation - train
transform_train = transforms.Compose([
transforms.RandomCrop(32, padding=4), # 테두리에 4만큼 여분을 준뒤 그 안에서 32X32의 Random 영역 자르기
transforms.RandomHorizontalFlip(0.5), # 50% 확률로 좌우 반전
# transforms.RandomVerticalFlip(0.5), # 50% 확률로 상하 반전
transforms.ToTensor(), # pixel 값들을 0~1 사이로 scaling하고 tensor 객체로 변환
])
# Image augmentation - test
transform_test = transforms.Compose([
transforms.ToTensor(), # pixel 값들을 0~1 사이로 scaling하고 tensor 객체로 변환
])
train 시에는 이미지를 조금 흔들어주기 위해서 random crop, 상하좌우 반전 등을 넣었고,
test 시에는 이미지를 그대로 사용하기 위해 rescaling만 진행하였습니다.
설정이 필요한 일부 Hyper parameter들과 CIFAR10 데이터셋을 활용하여 Dataloader를 만들어줍니다.
Dataloader는 for문을 돌며 설정된 옵션들을 따라 이미지와 라벨을 뱉어줍니다.
#==== Hyper parameters ====
LEARNING_RATE = 1e-3
BATCH_SIZE = 128
# LOAD CIFAR10 & Make dataset
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform_train)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=BATCH_SIZE, shuffle=True, num_workers=1)
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)
testloader = torch.utils.data.DataLoader(testset, batch_size=100, shuffle=False, num_workers=1)
Train/Test Dataloader를 확인해보겠습니다.
전부다 확인이 필요하시면 batch 내에서 for문을 돌리시고, break을 해제 해주시면 됩니다.
for batch, label in trainloader:
img = batch[0].numpy()# batch 내 index=0 데이터 확인
img = img.transpose(1,2,0) # c, h w --> h, w, c 변환
plt.figure()
plt.imshow(img)
plt.show()
break
for batch, label in testloader:
img = batch[3].numpy() # batch 내 index=3 데이터 확인
img = img.transpose(1,2,0) # c, h w --> h, w, c 변환
plt.figure()
plt.imshow(img)
plt.show()
break
Trainloader의 경우 Augmentation이 적용된 것을 확인할 수 있습니다.
그럼 Classification을 수행할 모델을 생성해보겠습니다.
모델은 아래와 같이 구성하였습니다.
# 모델 생성
class MyCNN(nn.Module):
# model 초기화 및 사용할 layer들 정의
def __init__(self):
super(MyCNN, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=3, padding=1)
# 3ch input을 64ch로 확장, size는 동일하게 유지하는 conv layer
self.maxpool = nn.MaxPool2d(2) # size / 2
self.conv2 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
# 64ch input을 128ch로 확장, size는 동일하게 유지하는 conv layer
self.avgpool = nn.AdaptiveAvgPool2d(1) # avg pooling layer
self.flatten = nn.Flatten() # feature들을 1차원화
self.dropout = nn.Dropout(0.5) # 50% 확률로 dropout 적용
self.fc1 = nn.Linear(128, 32)
self.fc_out = nn.Linear(32, 10) # CIFAR10의 lable 수만큼 출력
# model의 연산이 진행되는 부분
def forward(self, x):
x = self.conv1(x)
x = self.maxpool(x)
x = self.conv2(x)
x = self.avgpool(x)
x = self.flatten(x)
x = self.fc1(x)
x = self.dropout(x)
x = self.fc_out(x)
return x
다음으로 생성된 모델을 학습하고 평가하기 위한 코드를 작성하였습니다.
매 epoch마다 학습되는 과정을 모니터링할 수 있도록 설정하였습니다.
# test model
def test_model(model, testloader):
model.eval() # test mode 전환
correct = 0
for x, y in testloader:
x = x.to(device)
y = y.to(device)
y_hat = model(x)
pred = y_hat.max(1)[1] # model output을 max index로 예측
correct += sum(y == pred).item()
print("test acc: {:.4f}".format(correct/len(testloader.dataset)) )
# train define
model = MyCNN() # model에 생성한 model class를 할당해줍니다.
criterion = nn.CrossEntropyLoss() # Loss function 정의 : multiclass의 단일 예측 문제 cross entropy
opt = optim.Adam(model.parameters(), lr=LEARNING_RATE)
#==== Hyper parameters ====
epochs = 30
model.to(device) # 초기에 설정한 device로 모델을 보내줍니다 (cuda or cpu)
for ep in range(epochs):
epoch_loss = 0
epoch_acc = 0
for x, y in trainloader:
# to device
x = x.to(device)
y = y.to(device)
# set train mode
model.train()
# init.
opt.zero_grad() # batch 별 grad 계산을 위한 초기화
# run model
y_hat = model(x)
pred = y_hat.max(1)[1]
loss = criterion(y_hat, y)
# update weights
loss.backward() # backpropagation을 이용한 weight update
opt.step() # lr 만큼 학습 진행
epoch_loss += loss.item()
# monitoring
epoch_acc += (pred==y).sum().item()
epoch_acc = epoch_acc/len(trainloader.dataset)
# 매 epoch 마다 학습결과 모니터링
if ep%1 == 0:
print('epoch: {}, loss: {:.4f}, acc: {:.4f}'.format(ep, epoch_loss, epoch_acc))
test_model(model, testloader)
생성한 모델의 학습이 진행되며 loss는 줄고, accuracy는 상승하는 것을 볼 수 있습니다.
좀 더 빠르고 정확하게 모델을 학습하기 위해서는 모델의 변경과 Hyper parameter의 적절한 튜닝을 진행하면 됩니다.
감사합니다.
[취미생활/Python] - [딥러닝 / Pytorch / 이미지 분석] Classification 예제 정리2 - VGGNet
[취미생활/Python] - [딥러닝 / Pytorch / 이미지 분석] Classification 예제 정리3 - ResNet
'취미 낙지 > Python' 카테고리의 다른 글
[딥러닝 / Pytorch / 이미지 분석] GAN 기초 (0) | 2023.06.27 |
---|---|
[딥러닝 / Pytorch / 이미지 분석] Classification 예제 정리3 - ResNet (0) | 2023.06.26 |
[딥러닝 / Pytorch / 이미지 분석] Classification 예제 정리2 - VGGNet (0) | 2023.06.26 |