Contents
CNN은 이미지처리, 자연어처리 등 다양한 분야에서 각광받는 기술이다. 파라미터를 공유하는 개념을 통해서 기존의 연구에서 제안된 단순한 Linear 수준을 넘어서서 매우 우수한 성능을 발휘한다. 이번 글에서는 CNN을 밑바닥부터 구현하는 것을 다룬다.
Import Packages
from sklearn.datasets import fetch_openml
from sklearn.utils import check_random_state
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import torch
%matplotlib inline
Load Data
X, y = fetch_openml('mnist_784', version=1, return_X_y=True)
이번 글에서는 sklearn 패키지에서 제공하는 fetch_openml 데이터를 사용하여 CNN을 학습하고자 한다. 이미지처리에서 사용되는 가장 대표적인 MNIST 데이터를 사용한다. MNIST 데이터는 셔츠, 신발 등의 10가지 카테고리를 가지는 이미지로 구성되어 있으며, 28X28 사이즈로 되어있다.
print(f'X shape: {X.shape}')
print(f'y shape: {y.shape}')
single_sample = X.loc[0,:].values.reshape(28,28)
print(f'Single sample shape: {single_sample.shape}')
# X shape: (70000, 784)
# y shape: (70000,)
# Single sample shape: (28, 28)
처음 입력으로 받은 $X$는 784 차원을 가지고 있다. 이미지의 경우 가로 세로로 구성되어 있기 때문에 784 차원을 reshape함수를 통해 28X28로 변환한다.
train_samples = 60,000
X_train, X_test, Y_train, Y_test = train_test_split(X, y, train_size=train_samples, test_size=10000, random_state=0)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.fit_transform(X_test)
print(f'Training shape: {X_train.shape}')
print(f'Testing shape: {X_test.shape}')
# Training shape: (60000, 784)
# Testing shape (10000, 784)
데이터의 수가 많아서 학습용 이미지 데이터는 6만장, 테스트용 이미지 데이터는 1만장을 추출해서 사용한다. 그 후, StandardSaler를 사용해서 pixel 값을 표준화한다.
Convolutional Layer
class ConvolutionalLayer:
def __init__(self, num_kernels, kernel_shape):
self.num_kernels = num_kernels
self.kernel_shape = kernel_shape
self.k = self.kernel_shape[0]
self.kernel_theta = torch.randn(self.num_kernels, self.kernel_shape[0], self.kernel_shape[1])
def slider(self, image):
h, w = image.shape
for h_idx in range(h - (self.k - 1)): # h: height, w: width
for w_idx in range(w - (self.k - 1)):
single_slide_area = image[h_idx:(h_idx + self.k), w_idx:(w_idx + self.k)]
yield single_slide_area, h_idx, w_idx
def forward(self, images):
assert single_sample.dim() == 2
_, w = images.shape
p = 0
o = (w - self.k) + 1
print('Padding shape: \t', p)
print('Output shape: \t', o)
output = torch.zeros((o, o, self.num_kernels))
for single_slide_area, h_idx, w_idx in self.slider(images):
if h_idx == 0 and w_idx == 0 :
print('Region shape: \t', list(single_slide_area.shape))
print('Kernel shape: \t', list(self.kernel_theta.shape))
print('Single Slide: \t', list(output[h_idx, w_idx].shape))
output[h_idx, w_idx] = torch.sum(single_slide_area * self.kernel_theta, axis=(1, 2))
output = 1. / (1. + torch.exp(-output))
return output
CNN에는 stride, padding, kernel 등의 용어가 존재한다. 기본적으로 kernel이 오른쪽과 아래로 움직이면서 학습하기 때문에 slider라고 작명하였다. 오른쪽으로 먼저 움직인 후, 아래로 움직이는 방식이기에 이와 같은 구조를 지닌다. forward 부분에서 마지막 output에는 sigmoid를 함수를 사용하였다. 만약 다른 non-linear 함수를 사용하고 싶으면 사용해도 무방하다.
'Deep Learning > Computer Vision' 카테고리의 다른 글
[VISION] Semantic Segmentation (0) | 2021.10.20 |
---|---|
[VISION] Convolution Neural Network (0) | 2021.10.20 |
[Regularization] variety methods of Regularization (0) | 2021.10.19 |