[Python] pytorch를 활용한 CNN 실습

거친코딩·2021년 5월 27일
0

Python Data Analysis

목록 보기
3/3
post-thumbnail

라이브러리 import

import numpy as np
import torch
import torch.nn as nn # layer들을 호출하기 위해서
import torch.optim as optim # optimization method를 사용하기 위해서
import torch.nn.init as init # weight initialization 해주기 위해서
import torchvision.datasets as dset # toy data들을 이용하기 위해서
import torchvision.transforms as transforms # pytorch 모델을 위한 데이터 변환을 위해
from torch.utils.data import DataLoader # train,test 데이터를 loader객체로 만들어주기 위해서 

batch_size = 256
learning_rate = 0.0002
num_epoch = 30


mnist train 및 test 데이터 load

mnist_train = dset.CIFAR10("./", 
                           train=True, 
                           transform=transforms.ToTensor(), # torch안에서 연산을 해주기 위한 형태로 변환
                           target_transform=None,
                           download=True)
mnist_test = dset.CIFAR10("./", 
                           train=False, 
                           transform=transforms.ToTensor(), # torch안에서 연산을 해주기 위한 형태로 변환
                           target_transform=None,
                           download=True)

# row데이터가 아닌 torch 객체가 나옴
print(mnist_train)
>Dataset CIFAR10
    Number of datapoints: 50000
    Root location: ./
    Split: Train
    StandardTransform
Transform: ToTensor()


# row데이터 조회
print(mnist_train.__getitem__(0))
>(tensor([[[0.2314, 0.1686, 0.1961,  ..., 0.6196, 0.5961, 0.5804],
         [0.0627, 0.0000, 0.0706,  ..., 0.4824, 0.4667, 0.4784],
         [0.0980, 0.0627, 0.1922,  ..., 0.4627, 0.4706, 0.4275],
         ...,
         [0.8157, 0.7882, 0.7765,  ..., 0.6275, 0.2196, 0.2078],
         [0.7059, 0.6784, 0.7294,  ..., 0.7216, 0.3804, 0.3255],
         [0.6941, 0.6588, 0.7020,  ..., 0.8471, 0.5922, 0.4824]],
...


# train data[0] shape 및 데이터 크기 확인
print(mnist_train.__getitem__(0)[0].size(),mnist_train.__len__())
>torch.Size([3, 32, 32]) 50000

# test data[0] shape 및 데이터 크기 확인
print(mnist_test.__getitem__(0)[0].size(),mnist_test.__len__())
>torch.Size([3, 32, 32]) 10000

Data loader 객체 생성

# Data loader 객체 생성 
# 데이터 batch로 나눠주고 shuffle해주는 데이터 loader 객체 생성
train_loader = DataLoader(mnist_train,
                          batch_size=batch_size,
                          shuffle=True,
                          num_workers=2,
                          drop_last=True)
test_loader = DataLoader(mnist_test,
                          batch_size=batch_size,
                          shuffle=False,
                          num_workers=2,
                          drop_last=True)

CNN 모델 구축

class CNN(nn.Module):
  def __init__(self):
    super(CNN,self).__init__()
    self.layer = nn.Sequential(
        nn.Conv2d(3,16,3,padding=1), # in channel:3, out channel:16, kernel_size=3 
        nn.ReLU(),
        nn.Conv2d(16,32,3,padding=1), # in channel:16, out channel:32, kernel_size=3
        nn.ReLU(),
        nn.MaxPool2d(2,2), # 32x16x16
        nn.Dropout(0.5),

        nn.Conv2d(32,64,3,padding=1), # in channel:32, out channel:64, kernel_size=3 
        nn.ReLU(),
        nn.Conv2d(64,128,3,padding=1), # in channel:64, out channel:128, kernel_size=3
        nn.ReLU(),
        nn.MaxPool2d(2,2), # 128x8x8
        nn.Dropout(0.5),

        nn.Conv2d(128,256,3,padding=1), # in channel:128, out channel:256, kernel_size=3 
        nn.ReLU(),
        nn.Conv2d(256,256,3,padding=1), # in channel:256, out channel:256, kernel_size=3
        nn.ReLU(),
        nn.MaxPool2d(2,2), # 256x4x4
        nn.Dropout(0.5)
    )
    self.fc_layer = nn.Sequential(
        nn.Linear(256*4*4,200), # input node : 256*4*4, output node : 200
        nn.ReLU(),
        nn.Dropout(0.5),
        nn.Linear(200,10)
    )

  def forward(self,x):
    out = self.layer(x) # out = (256 , 4 , 4)
    # .view는 reshape과 같은 역할
    out = out.view(batch_size,-1) # (256 , 4 , 4) => (batch, 256 x 4 x 4)
    out = self.fc_layer(out)
    return out

model = CNN().cuda()

loss와 optimizer 객체 생성

loss_func = nn.CrossEntropyLoss() # 크로스엔트로피 loss 객체, softmax를 포함함
optimizer = optim.Adam(model.parameters(), # 만든 모델의 파라미터를 넣어줘야 함
                       lr=learning_rate)

학습

for epoch in range(num_epoch):
  for idx,(image,label) in enumerate(train_loader):
    x = image.to(torch.device('cuda'))
    y_ = label.to(torch.device('cuda'))

    # train데이터 셋 feedforwd 과정
    output = model.forward(x)

    # loss 계산
    loss = loss_func(output,y_)

    # optimizer 초기화 및 weight 업데이트
    optimizer.zero_grad() # 그래디언트 제로로 만들어주는 과정
    loss.backward() # backpropagation
    optimizer.step()

    if idx % 100 == 0:
      print('epoch : ',epoch)
      print('loss : ',loss.data)
      print('-----------------')
>epoch :  0
loss :  tensor(2.3026, device='cuda:0')
-----------------
epoch :  0
loss :  tensor(2.0643, device='cuda:0')
-----------------
epoch :  1
loss :  tensor(1.9147, device='cuda:0')
-----------------
epoch :  1
loss :  tensor(1.7581, device='cuda:0')
-----------------
epoch :  2
loss :  tensor(1.6416, device='cuda:0')
-----------------
epoch :  2
loss :  tensor(1.6185, device='cuda:0')
...
...
...

학습한 모델 구조 확인

# 모델이 가지고 있는 weight구조를 보여줌
param_list = list(model.children())
print(param_list)
>[Sequential(
  (0): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (1): ReLU()
  (2): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (3): ReLU()
  (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (5): Dropout(p=0.5, inplace=False)
  (6): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (7): ReLU()
  (8): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (9): ReLU()
  (10): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (11): Dropout(p=0.5, inplace=False)
  (12): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (13): ReLU()
  (14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (15): ReLU()
  (16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (17): Dropout(p=0.5, inplace=False)
), Sequential(
  (0): Linear(in_features=4096, out_features=200, bias=True)
  (1): ReLU()
  (2): Dropout(p=0.5, inplace=False)
  (3): Linear(in_features=200, out_features=10, bias=True)
)]

모델 성능 확인

model.eval() # test시에는 dropout을 꺼준다.
correct = 0
total = 0

for image, label in test_loader:
  x = image.to(torch.device('cuda'))
  y_ = label.to(torch.device('cuda'))

  output = model.forward(x)
  _, output_index = torch.max(output,1) # output을 인덱스 1방향으로 최고를 뽑아줌
  total += label.size(0)
  correct += (output_index == y_).sum().float()

print('Acc : {}'.format(100*correct/total))
>Acc : 74.00841522216797
profile
데이터 분석 유튜버 "거친코딩"입니다.

0개의 댓글