본문 바로가기
Computer Science/Deep Learning

CNN(합성곱 신경망) ③ [CIFAR-10]

by BaekDaBang 2024. 4. 14.
# 필요한 기본 라이브러리 import
import random
import torch
import numpy as np
import os
import pandas as pd

# 랜덤시드 고정하기
seed = 42
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
if torch.cuda.is_available():
    torch.cuda.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.benchmark = False
torch.backends.cudnn.deterministic = True

 

1. Load CIFAR-10 Dataset

from torchvision.datasets import CIFAR10 ## CIFAR10 데이터를 불러오기 위해 라이브러리 import

trainset = CIFAR10(root='./data', train=True,download=True)## CIFAR10 train set을 불러오기
testset = CIFAR10(root='./data', train=False,download=True)## CIFAR10 test set을 불러오는 과정

x_train = trainset.data
y_train = trainset.targets

x_test = testset.data
y_test = testset.target

 

x_train.shape : (50000, 32, 32, 3)

x_test.shape : (10000, 32, 32, 3)

 

2. Visualize the First 24 Training Images

# 시각화를 위해 필요한 라이브러리 import
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

x_train = trainset.data

# 불러온 데이터 셋 중 처음 24개 이미지에 대한 시각화
fig = plt.figure(figsize=(20,5))
for i in range(36):
    ax = fig.add_subplot(3, 12, i + 1, xticks=[], yticks=[])
    ax.imshow(np.squeeze(x_train[i]))

 

3. Rescale the Images by Dividing Every Pixel in Every Image by 255

# Rescale [0,255] -> [0,1]
x_train = x_train.astype('float32')/255
x_test = x_test.astype('float32')/255

 

4. Break Dataset into Training, Testing, and Validation Sets

# torch.nn.CrossEntropyLoss는 one-hot encoding 내장
# pytorch는 모델에 입력하는 데이터가 tensor 형태로 변경
# pytorch는 (Channel, Height, Width)의 형태로 변경

# train set을 train과 validation set으로 나눔
(x_train, x_valid) = x_train[5000:], x_train[:5000]
(y_train, y_valid) = y_train[5000:], y_train[:5000]

# 모델에 입력하기 위해데이터를 tensor 형태로 변경
x_train, y_train = torch.FloatTensor(x_train), torch.LongTensor(y_train)
x_valid, y_valid = torch.FloatTensor(x_valid), torch.LongTensor(y_valid)
x_test, y_test = torch.FloatTensor(x_test), torch.LongTensor(y_test)

# pytorch는 (Channel, Height, Width)의 형태로 이루어짐
x_train = torch.swapaxes(x_train,1,3)
x_valid = torch.swapaxes(x_valid,1,3)
x_test = torch.swapaxes(x_test,1,3)

# print shape of training set
print('x_train shape:', x_train.shape)

# print number of training, validation, and test images
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')
print(x_valid.shape[0], 'validation samples')

 

5. Define the Model Architecture

%pip install torchsummary ## model을 요약하기 위해 torchsummary 설치
from torchsummary import summary as summary_## 모델 정보를 확인하기 위해 torchsummary 함수 import

# 모델의 형태를 출력하기 위한 함수 
def summary_model(model,input_shape=(3, 32, 32)):
    model = model.cuda()
    summary_(model, input_shape) ## (model, (input shape))
# CNN 모델 구조 정의 (version 1)
from torch.nn import Sequential
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Dropout, ReLU, Softmax

# nn.Sequential 함수는 네트워크를 인스턴스화하는 동시에, 원하는 신경망에 연산 순서를 인수로 전달함.
model_1 = Sequential(
            Conv2d(3,16,kernel_size=2,padding='same'),  ## Conv2d(in_channel, out_channel, kernerl_size, padding, bias)
            ReLU(),
            MaxPool2d(kernel_size=2),    
            Conv2d(16,32,kernel_size=2,padding='same'),
            ReLU(),
            MaxPool2d(kernel_size=2),   
            Conv2d(32,64,kernel_size=2,padding='same'),
            ReLU(),
            MaxPool2d(kernel_size=2),
            Dropout(0.3),
            Flatten(),
            Linear(1024,500),
            ReLU(),
            Dropout(0.4),
            Linear(500,10),
            Softmax()
        ).cuda() ## GPU로 올리기
print(model_1)
summary_model(model_1)
# CNN 모델 구조 정의 (version 2)
import torch.nn 

class Net(torch.nn.Module): 
    def __init__(self):
        super().__init__()

        # 컨볼루션 커널 정의
        self.conv1 = torch.nn.Conv2d(3,16,kernel_size=2,padding='same')
        self.conv2 = torch.nn.Conv2d(16,32,kernel_size=2,padding='same')
        self.conv3 = torch.nn.Conv2d(32,64,kernel_size=2,padding='same')
        # dense 레이어 정의
        self.dense1 = torch.nn.Linear(1024,500) # 1024:(64 * 4 * 4)
        self.dense2 = torch.nn.Linear(500,10)
        self.maxpool = torch.nn.MaxPool2d(kernel_size=2) ## Maxpooling 레이어 정의
        self.flatten = torch.nn.Flatten()## Flatten 레이어 정의
        self.dropout1 = torch.nn.Dropout(0.3)## Dropout 정의 (확률 0.3)
        self.dropout2 = torch.nn.Dropout(0.4)## Dropout 정의 (확률 0.4)
        self.relu = torch.nn.ReLU() ## 활성화함수 정의
        self.softmax = torch.nn.Softmax() ## softmax 함수 정의

        
    def forward(self, x): # forward 정의
        y = self.relu(self.conv1(x))
        y = self.maxpool(y)
        y = self.relu(self.conv2(y))
        y = self.maxpool(y)
        y = self.relu(self.conv3(y))
        y = self.maxpool(y)
        y = self.dropout1(y)
        y = self.flatten(y)
        y = self.relu(self.dense1(y))
        y = self.dropout2(y)
        y = self.softmax(self.dense2(y))
        
        return y
    
model_2 = Net().cuda() ## GPU로 올리기

print(model_2)
summary_model(model_2,(3,32,32))

 

7. Train

model = Net().cuda()
learning_rate = 0.001

optimizer = torch.optim.RMSprop(model.parameters(),lr = learning_rate)## RMSprop을 최적화 함수로 이용함. 파라미터는 documentation을 참조!

loss = torch.nn.CrossEntropyLoss().cuda() ## 분류문제이므로 CrossEntropyLoss를 이용함
# train the model
import time


train_dataset = torch.utils.data.TensorDataset(x_train,y_train)
trainloader = torch.utils.data.DataLoader(train_dataset, batch_size=32,shuffle=True)
valid_dataset = torch.utils.data.TensorDataset(x_valid,y_valid)
validloader = torch.utils.data.DataLoader(valid_dataset, batch_size=1,shuffle=False)

# 파라미터 설정
total_epoch = 35
best_loss = 100

for epoch in range(total_epoch):
    start = time.time()
    print(f'Epoch {epoch}/{total_epoch}')

    # train
    train_loss = 0
    correct = 0
    for x, target in trainloader:## 한번에 배치사이즈만큼 데이터를 불러와 모델을 학습함
        
        optimizer.zero_grad()## 이전 loss를 누적하지 않기 위해 0으로 설정해주는 과정
        y_pred = model(x.cuda())## 모델의 출력값
        cost = loss(y_pred, target.cuda())## loss 함수를 이용하여 오차를 계산함
    
        cost.backward()# gradient 구하기
        optimizer.step()# 모델 학습
        train_loss += cost.item()
        
        pred = y_pred.data.max(1, keepdim=True)[1] ## 각 클래스의 확률 값 중 가장 큰 값을 가지는 클래스의 인덱스를 pred 변수로 받음
        correct += pred.cpu().eq(target.data.view_as(pred)).sum()# pred와 target을 비교하여 맞은 개수를 구하는 과정.
                                                                  # view_as함수는 들어가는 인수의 모양으로 맞춰주고, .eq()를 통해 pred와 target의 값이 동일한지 판단하여 True 개수 구하기
                                                                  
    train_loss /= len(trainloader)
    train_accuracy = correct / len(trainloader.dataset)

    
    # eval (validation 데이터를 이용하여 모델을 검증)
    eval_loss = 0
    correct = 0
    with torch.no_grad():  ## 학습하지 않기 위해
        model.eval()# 평가 모드로 변경
        for x, target in validloader:
            y_pred = model(x.cuda())## 모델의 출력값
            cost = loss(y_pred,target.cuda())## loss 함수를 이용하여 test 데이터의 오차를 계산함
            eval_loss += cost
            
            pred = y_pred.data.max(1, keepdim=True)[1]## 각 클래스의 확률 값 중 가장 큰 값을 가지는 클래스의 인덱스를 pred 변수로 받음
            correct += pred.cpu().eq(target.data.view_as(pred)).cpu().sum()# pred와 target을 비교하여 맞은 개수를 구하는 과정
            
        eval_loss /= len(validloader)
        eval_accuracy = correct / len(validloader.dataset)
        
        ## validation 데이터의 loss를 기준으로 이전 loss 보다 작을 경우 체크포인트 저장
        if eval_loss < best_loss:
            torch.save({
                'epoch': epoch,
                'model': model,
                'model_state_dict': model.state_dict(),
                'optimizer_state_dict': optimizer.state_dict(),
                'loss': cost.item,
                }, './bestCheckPoint.pth')
            
            print(f'Epoch {epoch:05d}: val_loss improved from {best_loss:.5f} to {eval_loss:.5f}, saving model to bestCheckPiont.pth')
            best_loss = eval_loss
        else:
            print(f'Epoch {epoch:05d}: val_loss did not improve')
        model.train()
        
    print(f' - {int(time.time() - start)}s - loss: {train_loss:.5f} - acc: {train_accuracy:.5f} - val_loss: {eval_loss:.5f} - val_acc: {eval_accuracy:.5f}')

 

8. Load the Model with the Best Validation Accuracy

# Load Checkpoint
best_model = torch.load('./bestCheckPoint.pth')['model']  # 전체 모델을 통째로 불러옴, 클래스 선언 필수
best_model.load_state_dict(torch.load('./bestCheckPoint.pth')['model_state_dict'])  # state_dict를 불러 온 후, 모델에 저장

 

9. Calculate Classification Accuracy on Test Set

correct = 0
with torch.no_grad(): ## 학습하지 않기 위해
    best_model.eval()
    y_pred = best_model(x_test.cuda())
        
    pred = y_pred.data.max(1, keepdim=True)[1]
    correct = pred.cpu().eq(y_test.data.view_as(pred)).cpu().sum()
        
    eval_accuracy = correct / len(y_test)

print(f"Test accuracy: {100.* eval_accuracy:.4f}")

'Computer Science > Deep Learning' 카테고리의 다른 글

하이퍼파라미터 튜닝 ①  (1) 2024.04.17
CNN(합성곱 신경망) ④ [Digits]  (0) 2024.04.17
CNN(합성곱 신경망) ② [MNIST]  (0) 2024.04.14
CNN(합성곱 신경망) ①  (1) 2024.04.13
딥러닝과 신경망 ②  (0) 2024.04.12