본문 바로가기
머신러닝, 딥러닝/파이토치

[파이토치 스터디] AlexNet - CIFAR 10 이미지 분석

by 장찐 2022. 1. 31.

AlexNet 사용해서 이미지 분류하기 

 

 AlexNet은 2012 이미지넷 경진대회에서 우승한 사전학습 CNN 모델이다. 파이토치를 이용해서 AlexNet을 이용한 이미지 분류를 실시한다. 데이터는 CIFAR 10 데이터를 사용한다. 

 

import torch 
import torchvision 
import torchvision.transforms as transforms
from torch.utils.data import DataLoader

import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import matplotlib.pyplot as plt

필요한 라이브러리를 불러온다. 

 

✔ 기본 전처리 

transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=True)

testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=True)

라인1에서 transforms.Normalize를 이용해서 평균과 표준편차를 따르는 정규분포로 이미지를 표준화한다. 

CIFAR 10 이미지는 컬러 이미지이므로 RGB 각 채널마다 표준화를 실시한다. 원래는 학습 데이터의 이미지의 표준과 편차를 사용하지만, 여기서는 모두 평균과 표준편차 모두 0.5로 설정했다. 

 

 

✔ 모델 구축 

class AlexNet(nn.Module):
    def __init__(self):
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3,64,3), nn.ReLU(), #Conv2d(입력채널수, 출력채널수, 필터 크기)
            nn.MaxPool2d(2,2),
            nn.Conv2d(64, 192, 3, padding=1), nn.ReLU(),
            nn.MaxPool2d(2,2),
            nn.Conv2d(192, 384, 3, padding=1), nn.ReLU(),
            nn.Conv2d(384, 256, 3, padding=1), nn.ReLU(),
            nn.Conv2d(256, 256, 1), nn.ReLU(),
            nn.MaxPool2d(2,2))
        
        #Dense layer 구축 
        self.classifier = nn.Sequential(
            nn.Dropout(0.5),
            nn.Linear(256*3*3, 1024), nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(1024,512), nn.ReLU(),
            nn.Linear(512,10))
    
    def forward(self, x):
        x = self.features(x)
        x = x.view(-1, 256*3*3)
        x = self.classifier(x)
        return x

 

 

✔ 손실함수 및 최적화방법 정의 

criterion = nn.CrossEntropyLoss()
alexnet = AlexNet()
optimizer = optim.Adam(alexnet.parameters(), lr=1e-3)

다중분류에서는 cross entropy 손실함수를 사용하는 경우가 많다. 파이토치에서 제공하는 크로스 엔트로피는 softmax 계산까지 포함되어 있으므로 모델 마지막에 별도로 softmax를 적용하지 않아도 된다. 

GPU 연산을 위해서는 모델을 불러올 때 device를 통해서 GPU 연산을 활성화하고, 라인2 뒤에 .to(device)를 반드시 붙여야 한다. 

 

 

✔ 모델 학습 

loss_ =[]

n = len(trainloader) #배치 개수 

for epoch in range(50):
    running_loss = 0.0
    for data in trainloader:
        inputs, labels = data[0], data[1] #배치 데이터 
        optimizer.zero_grad()
        outputs = alexnet(inputs) #예측값 산출 
        loss = criterion(outputs, labels) #손실 함수 계산 
        loss.backward() #손실 함수 기준으로 역전파 선언 
        optimizer.step() #가중치 최적화 
        running_loss += loss.item()
        
    loss_.append(running_loss / n)
    print('[%d] loss: %.3f' %(epoch +1, running_loss / len(trainloader)))

모델을 학습하고 trainset에서 결과를 확인한다. 

 

 

✔ 학습한 모델을 저장하거나 다시 불러오기 

#모델 성능이 괜찮다면 추후에 다시 사용하기 위해서 모델을 저장할 수 있음 
PATH = 'C:/Users/Yeong/Desktop/파이토치스터디/Alexnet모델.pth'
torch.save(alexnet.state_dict(),PATH)
        
#모델 다시 불러오기 : 해당 모델의 파라미터만 불러오는 것이기 때문에, 모델이 미리 선언되어 있어야 한다. 
alexnet = AlexNet() #.to(device)
alexnet.load_state_dict(torch.load(PATH))

경로를 설정해서 학습한 모델을 저장한다. 

해당 모델을 다시 불러올 때는 alexnet 모델로 학습한 파라미터들을 불러오는 것이기 때문에, 

선행적으로 모델이 선언되어야 한다. 

 

 

✔ 모델 평가 

correct = 0
total = 0
with torch.no_grad():
    alexnet.eval()
    for data in testloader:
        images, labels = data[0].to(device), data[1].to(device)
        outputs = alexnet(images)
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0) # 개수 누적(총 개수)
        correct += (predicted == labels).sum().item() # 누적(맞으면 1, 틀리면 0으로 합산)
        
print('Test accuracy: %.2f %%' % (100 * correct / total))

라인3에서 평가시에는 requires_grad를 비활성화 한다. 

라인4에서 평가 시에는 dropout 과 같은 정규화 작업을 시행하지 않아야 하므로 eval()을 선언한다. 

 

라인8 설명 : p136 추가 참고 

 

 

 

 


Reference

 

딥러닝을 위한 파이토치 입문, 딥러닝호형 저, 영진닷컴, 2022년 01월 20일

댓글