Deep Learning/CS231N

[CS231N] Image Classification pipeline

언킴 2021. 7. 4. 15:43
반응형

cs231n의 강의 chapter2에 대한 내용을 요약, 정리할 것이다. 이 장에서는 image classification이 어떤 것인지에 대해서 알아보고, 어려운 점이 생기는 이유와 K-NN기반, Linear기반 이미지 분류에 대해서 다룰 것이다. 이미지는 RGB 3층의 구조를 가지고 있다고 보면된다. ( 3차원의 array ) [ 0, 255 ] 값의 integer 형태를 가지고 있다. 

 

e.g. 300 X 100 X 3

 

일반적으로 구조적 데이터나 비 구조적 데이터를 input 값으로 가진 후 classification을 하면 class 1 or class 2 와 같은 output 형태를 가졌는데, input 값이 구조적, 비 구조적 데이터가 아닌 image를 input 으로 넣으면 cat or dog 형태로 출력이 되는 것이다. 

 

 

Challenges

Viewpoint Variation : 어디에서 image 를 위, 아래, 정면 등 어느 각도로 촬영했는지에 영향을 미칠 수 있다. 

illumination : 빛의 밝기에 따라서 어려움이 생길 수 있다. ( e.g. 색상을 구분해야 하는 경우, 빛의 위치에 따라 변형 )

Deformation : 본래 image와 다른 형태를 지니고 있을 경우. ( 배경과 비슷하게 생긴다면 구분하기가 어렵다 )

 

 

Data - driven approach

images와 labels의 datasets을 준비하고, 머신러닝으로 image classfier를 학습시킨 뒤 test images에 적용 시켜 평가를 하는 형태로 접근할 것이다.

 

1. K-NN based image classification

K-NN( K - nearest neighbor )은 Lazy model로 알려져 있다. K-NN에서 설정해야할 hyperparameter 에는 K, Voting, Distance metric 가 있다. 적절한 K값을 설정하는 것이 중요하고, weight를 어떻게 할지 등 해결해야할 문제다.

 

Distance metric 

L1 distance ( Manhattan )

$d_{1}(\mathbf{I}_{1}, \mathbf{I}_{2}) = \Sigma_{p}|\mathbf{I}^{p}_{1} - \mathbf{I}^{p}_{2}| $

 

L2 distance ( Euclidean )

$d_{2}(\mathbf{I}_{1}, \mathbf{I}_{2}) = \sqrt{\Sigma_{p}(\mathbf{I}^{p}_{1} - \mathbf{I}^{p}_{2})^{2}} $

 

거리를 계산할 때에는 각각의 픽셀 단위로 계산을 하게 된다. 

L1 distance example

CIFAR-10 : datasets

이 datasets은 10개의 label을 가지고, 50,000개의 training images ( 32 X 32 X 3 )10,000개의 test images 를 가진 data sets이다. 나는 sklearn.datasets에 있는 digits data를 활용하여 이미지를 분류해보았다.

import matplotlib.pyplot as plt
from sklearn import datasets, metrics
from sklearn.model_selection import train_test_split
digits = datasets.load_digits()

images, labels = digits.images, digits.target

for i in range(len(labels)):
    plt.subplot(2, 4, i + 1)
    plt.axis('off')
    plt.imshow(images[i], cmap = 'gray' )
plt.show()

 

class Nearest_Neighbor:
    def __init__(self):
        pass

    def fit(self, x, y):
        self.x_train = x
        self.y_train = y

    def predict(self, x, L):
        num_test = x.shape[0]
        y_pred = np.zeros(num_test, dtype = self.y_train.dtype ) 

        if L == 'M' :
            for i in np.arange(len(x)):
                print(i, '\n')

                distance = np.zeros(len(self.x_train))
                for j in np.arange(len(self.x_train)):
                    distance[j] = np.sum(np.abs(self.x_train[j] - x[j]))
                min_index = np.argmin(distance)
                y_pred[i] = self.y_train.iloc[min_index]

        if L == 'U' :
            for i in np.arange(len(x)):
                print(i, '\n')

                distance = np.zeros(len(self.x_train))
                for j in np.arange(len(self.x_train)):
                    distance[j] = math.sqrt( np.sum( (self.x_train.iloc[j] - x.iloc[j])**2, axis = 0 ) )
                min_index = np.argmin(distance)
                y_pred[i] = self.y_train.iloc[min_index]
        
        return y_pred 

k-nn에서 L1, L2 형태로 나누어서 L에 method를 지정하면 되도록 만들었다. 

k 값을 바꾸어 가면서 진행

k값을 나눌때에는 train data의 값이 적기 때문에 cross validation을 통해 hyperparameter를 tuning 한다.

1. k값을 먼저 지정한다.

2. cross validation 을 사용하여 fold수를 정한다.

 

하지만 K-NN 은 images에서 절대 사용하지 않는다 왜냐하면 original, shifted, messed up darkneed등 여러 이미지에 대해서 동일한 거리를 갖는다는 문제가 발생하기 때문이다. 이미지 고유의 특성을 잡지 못한다는 것이다.

 

Linear image classification

32 X 32 X 3의 차원을 10차원으로 바꾸어주는 f를 찾는 것이 주된 목표이다. 

 

 

 

 

위와 같은 f값을 나오게 되면 가장 값이 높은 437.9를 가지고 해당 이미지를 dog로 예측을 하는 것이다. 위 이미지는 원래 고양이지만 개로 잘못 분류했기 때문에 W(weight)를 수정하여 loss 를 줄이는 형태로 최적화를 해주어야한다.