juuuding

[CS231n] Lecture 2. Image Classification 본문

인공지능/cs231n

[CS231n] Lecture 2. Image Classification

jiuuu 2023. 11. 28. 21:08

 Image Classification

 

 image classification 시 컴퓨터가 해야 할 일은 input 이미지 값을 받고, 저장되어 있는 카테고리로 이 input 이미지를 배정하는 것이다. 예를 들어 class에 dog, cat, truck... 이 있고 아래와 같은 이미지를 입력받았을 때, 이것을 cat으로 분류해 내는 것이 컴퓨터가 해야 하는 일이다.

 

cat class

 

 이러한 image classification을 하는 데에는 "Semantic Gap"이라는 문제가 있다. 우리는 위의 고양이 사진을 볼 때 바로 이것이 고양이라는 것을 알 수 있지만, 컴퓨터는 이 사진을 볼 때는 다음과 같은 숫자들의 집합(pixel 값)으로 본다. 이처럼 고양이를 나타내는 사진의 의미와 픽셀 값들의 집합 사이에는 엄청난 차이가 있는데 이것을 "Semantic Gap"이라고 한다. 

 

컴퓨터의 시점

 

 이러한 문제를 가진 Image Classification을 진행할 때 classification을 힘들게 하는 6가지 어려움이 있다. 그 6가지는 각각 Viewpoint variation, Illumination, Deformation, Occlusion, Background Clutter, Intraclass variation이다.

 

[Viewpoint variation]

 첫번째로 해결해야 하는 문제는 "Viewpoint variation"이다. 객체를 찍고 있는 카메라가 조금이라도 움직이면 모든 픽셀 값이 변한다. 위에서 말한 Semantic Gap으로 인해 컴퓨터는 각 요소에 전혀 다른 픽셀 값만을 보게 되고, 이렇게 모든 픽셀 값이 변한 경우에도 이것이 같은 객체라는 것을 컴퓨터가 인식해야 한다. 

 

[Illumination]

 두번째는 "Illumination"이다. 카메라와 객체의 위치가 고정된 상태더라도 빛의 방향, 세기 등이 바뀌면 컴퓨터가 보는 이미지의 픽셀 값은 달라진다. 이러한 경우에도 컴퓨터가 픽셀 값이 바뀌었지만 아까와 같은 객체라는 것을 인식해야 한다. 

 

[Deformation]

 세번째는 "Deformation"이다. 아래의 사진은 다양한 자세를 취하고 있는 고양이다. 자세는 서로 다르지만 모두 고양이라는 것은 분명하다. 하지만 컴퓨터는 오직 픽셀 값만 볼 수 있기 때문에 같은 고양이가 자세를 달리했을 때, 픽셀 값이 일부분 바뀌어서 다른 객체로 판단할 수 있다. 이러한 경우에도 같은 객체로 인식할 수 있어야 한다. 

 

 

[Occlusion]

 네번째 문제는 "Occlusion"이다. 우리는 아래의 사진들을 보고 고양이라는 것을 알아차릴 수 있다. 심지어 3번째 사진과 같이 꼬리만 보고도 소파 쿠션 아래에 고양이가 있다는 것을 알 수 있다. 하지만 컴퓨터는 아까보다 더 적은 일부의 고양이에 해당하는 픽셀 값만을 가지고 이것이 고양이라는 것을 인식해야한다. 

 

 

[Background Clutter]

 다음 문제는 "Background Clutter"이다. 아래의 사진들과 같이 배경과 앞에 있는 물체의 색이 겹쳐 구분되지 않을 때도 여기에 고양이가 있다는 것을 알 수 있어야 한다.

 

 

[Intraclass variation]

 마지막 문제는 한 class 내에도 다양한 종류의 객체가 있다는 "Intraclass variation" 문제이다. 예를 들면 아래의 고양이들은 모두 고양이지만 모두 다르다. 이처럼 객체의 모양이 달라도 같은 분류(cat)로 인식할 수 있어야 한다. 

 

 

 하지만 숫자를 분류하는 것과는 다르게 고양이, 강아지 등 다른 class들을 인지하기 위한 명확한 알고리즘이 존재하지 않는다. 이 전에는 객체를 인식하기 위해 edges와 corners를 차례대로 찾아 class를 분류하는 방법을 시도하였다. 하지만 이 방법은 잘 작동하지 않고 다른 물체를 인식해야할 때마다 edge와 corner를 찾는 모든 과정을 다시 해야한다는 단점이 있다. 

 

 

 

 

 Data-Driven Approach

 

 앞선 단점들을 보안하기 위해 "Data-Driven Approach"라는 아이디어를 사용한다. 이 아이디어에서는 object의 특징이 무엇인지 직접 기록하지 않아도 되고, 인터넷 사진 같은 데이터를 사용한다. "Data-Driven Approach"의 대략적인 방법은 우선 이미지와 라벨을 입력받고 이 자료들로 물체를 인식하는 방법을 훈련한 classifier 모델을 생성하고, 새로운 이미지를 가지고 모델의 성능을 평가한다. 첫번째로 알아볼 classifier은 "Nearest Neighbor"이다. 

 

[Nearest Neighbor]

 Nearest Neighbor에는 train 단계와 predict 단계가 있다. train 단계에서는 모든 데이터와 라벨을 가지고 학습하고, 이 학습된 모델을 가지고 predict 단계에서 새롭게 입력된 이미지와 가장 비슷한 훈련 이미지를 찾아 label을 예측한다. 이처럼 모델을 학습하거나 테스트할 때 많은 이미지 자료가 필요하다. 이때 사용할 수 있는 dataset 중 하나인 CIFAR10에 대해 알아보자. 

 

 * CIFAR10

  - CIFAR10에는 총 10개의 classes, 50,000개의 훈련 이미지, 10,000개의 테스트 이미지가 있다. class에는 airplane, automobile, bird, cat, deer, dog, frog, horse, ship, truck이 존재한다. 아래의 사진은 nearest neighbors을 사용하여 이미지를 테스트하는 것이다. 사진들은 가장 비슷한 순으로 연결이 되어 있으며 사진을 입력하면 해당 사진과 제일 비슷한 훈련 이미지를 찾아 label을 얻는다.

 

 

 * L1 distance

  - 이미지 쌍을 각각 비교하며 어떤 이미지가 input 이미지와 가장 비슷한지 찾을 때는 Distance Metric을 선택하여 그 방법대로 이미지들을 비교한다. 우선 L1 distance metric부터 알아보겠다. 이 방법은 이미지의 픽셀들을 각각 비교하여 나온 픽셀 값의 차이를 모두 더하여 결과를 내는 방법이다.  

 

 

 식으로 표현하하면 다음과 같이 표현된다.

L1 distance

 

 다음은 L1 distance를 적용하여 nearest neighbor을 수행한 코드이다. 

 

import numpy as np

class NearestNeighbor:
    def __init__(self):
        pass
    
    # 모든 training data 기억
    def train(self,X,y):
        self.Xtr = X
        self.yty = y

	# 각 test image와 비슷한 train image 찾고 label 예측
    def predict(self,X):
        num_test = X.shape[0]  
        Ypred = np.zeros(num_test, dtype=self.ytr.dtype)

        for i in range(num_test):
            distances = np.sum(np.abs(self.Xtr-X[i,:]), axis=1)
            min_index = np.argmin(distances)
            Ypred[i] = self.ytr[min_index]

        return Ypred

 

 이 코드에서 train과 prediction의 시간 복잡도를 계산하면 train O(1), prediction(N)이다. 이것을 봤을 때 train은 빠르게 수행되고, prediction은 느리게 수행되는 것을 알 수 있는데 이는 좋지 않다. 우리는 train은 조금 오래 걸려도 prediction은 빠른 classifier을 원한다. 이 부분은 나중에 배우는 Convolutional Neural Network가 해결해줄 것이다. 

 

 아래의 사진은 Nearest Neighbors를 적용하여 classifier을 한 사진이다. 각 색은 각 카테고리를 나타내며, 점은 데이터를 나타낸다. 파란색 영역을 침범한 초록색 부분을 보면 한 점 때문이라는 것을 알 수 있다. 또, 초록색 한 가운데에 노란색 한 점 때문에 영역을 침범한 것을 볼 수 있다. 이것은 잘못 분류되었을 가능성이 높으며 수정해주어야 한다. 

 

 

 

[K-Nearest Neighbors]

 위의 문제를 해결하기 위해 K-Nearest Neighbors를 사용할 수 있다. K-Nearest Neighbors는 가장 가까운 k개의 점들 사이에서 투표를 진행하여 label을 결정하는 것이다. k의 값이 증가할 수록 영역의 경계가 좀 더 부드러워진다.

 

K-Nearest Neighbors

 

red: incorrect, green: correct

 

 K-Nearest Neighbors를 적용했을 때 위의 그림과 같이 이미지를 입력하면, 내가 설정한 distance metric을 가지고 가장 차이 값이 적은 상위 k개의 투표로 lablel을 예측한다.  

 

 * Distance Metric

 (1) L1(Manhattan) distance 

 

 (2) L2(Euclidean) distance

 

 거리 척도에 따라 결정 경계가 달라지는데 L1의 경우에는 좌표 축에 영향을 받고, L2는 받지 않는다. 공간의 각 요소의 의미가 명확하지 않고 잘 모를 때는 L2, 중요한 의미를 가질 때는 L1을 선택하면 된다.

 

[Hyperparameters]

 우리가 k-nn을 사용하려면 결정해야 하는 2가지 사항이 있다. 어떤 k 값을 사용할지, 어떤 distance metric을 사용할지 결정해주어야 한다. hyperparameter은 train data로 학습하는 것이 아니기 때문에 학습 전에 직접 결정해야 한다. 어떤 hyperparameter을 사용할지는 문제가 어떤 문제냐에 따라 달려있으며, 모든 것을 시도해보고 가장 잘 작동하는 것을 골라야 한다. 다양한 hyperparameter를 시도하고 그 중 최고를 선택해본다는 것은 무슨 의미일까?

 

 첫번째로 가장 단순하면서 끔찍한 방법은 다음과 같다. 내가 가진 training data에 완벽히 잘 작동하는 hyperparameter을 선택하는 것이다. 이 방법을 사용하면 training data에서는 정확하겠지만, 실제 unseen data에서는 잘 작동하지 않는다. 

 

 

 두번째는 data를 train, test 두 영역으로 나눈 후 train data로 훈련하고, test data에서 가장 잘 작동하는 hyperparameter을 선택하는 것이다. 하지만 test data는 우리가 보지 못한 실제 데이터를 대표할 수 없기 때문에 이 방법은 좋지 않다. 

 

 

 세번째 방법은 data를 train, validation, test 세 영역으로 나눈 후 train data로 훈련하고, validation data로 최적의 hyperparameter을 찾은 후 test data에서 평가하여 가장 좋은 성능으로 평가된 hyperparameter을 선택한다. 알고리즘은 training set의 label을 보며 학습을 하고, validation set의 label은 오직 성능을 평가할 때만 확인할 수 있다. 

 

 

 네번째 방법은 Cross-Validation 방법으로 data를 fold로 나눈 후 각 fold를 validation set으로 시도해보며 결과의 평균을 내는 것이다. 아래의 예시는 5-fold validation인데, 처음에는 앞의 4개 fold로 train을 하고 fold5를 사용하여 가장 좋은 hyperparameter을 선택하고 test data로 평가한다. 그 다음은 fold1,2,3,5로 train을 하고 fold4를 사용하여 hyperparameter을 선택한 다음 test data로 평가한다. 이런 식으로 계속 진행하며 최적의 hyperparameter을 정한다. 하지만 이 방법은 계산량이 아주 많아 딥러닝에서는 잘 사용되지 않으며, dataset이 작을 때 유용하게 쓰인다. 

 

 

 

 이것은 5-fold validation의 결과이고 각 점은 하나의 결과들이고 이어져 있는 line은 평균을 이은 것이며 bars는 표준편차를 의미한다. 이것으로 이 데이터에서는 k가 약 7일 때 가장 잘 작동한다고 볼 수 있다. 

 

 하지만 k-nn은 이미지에서 잘 사용되지 않는다. 그 까닭은 우선 test time이 굉장히 느리고, L1/L2 같은 distance metric이 이미지 간 "지각적 유사성"을 측정하는 척도로 적절하지 않다. 아래의 사진들은 original 사진에서 조금씩 왜곡을 한 사진들인데, 여기서 오른쪽 3개의 이미지와 original 이미지의 L2 distance는 모두 같다. (일부러 같게 설정)

 

 

 또 k-nn이 이미지에서 잘 사용되지 않는 이유는 "차원의 저주" 때문이다. 차원이 증가할수록 필요한 트레이닝 샘플이 기하급수적으로 증가하는데 이는 좋지 않은 현상이다. 

 

 

 

 

 Linear Classification

 

 Linear Classification은 아주 간단하고 NN과 CNN에 아주 중요한 기반 알고리즘이다. 그렇기 때문에 NN을 레고 블럭, linear classifier을 기본 블럭이라고도 표현한다. 다음은 이미지를 입력하면 이미지에 대한 설명이 출력되는 image captioning인데 여기서 이미지를 인식할 때는 CNN, 언어를 인식할 때는 RNN을 사용한다. 그리고 우리는 그저 CNN, RNN 이 두 레고 블럭을 이어 붙이면 이러한 문제를 해결할 수 있다. 

 

 

 

[Parametric Approach]

 linear classification은 "Parametric model"의 가장 단순한 형태이다. parametric model에는 두가지 요소가 존재하는데 입력 이미지 x, 파라미터(가중치) w이다. 두 요소 x, w를 가지고 함수를 작성하여 10개의 숫자를 출력해야하는데, 이 10개의 숫자는 각각 10개 카테고리에 대한 스코어를 의미한다. 만약 아래 input 이미지에 대한 결과에서 cat score가 가장 높게 나왔다면, 해당 이미지는 고양이일 확률이 가장 높다는 의미다. 

 

 

 위와 같이 이미지가 32x32x3 이면 W는 10x3072(32x32x3), x는 3072x1, 결과 값은 10x1로 이루어진 행렬로 나타난다. 여기서 만약 내가 가진 dataset이 unbalanced 하다면 bias(10x1)라는 parameter을 넣을 수도 있다. 예를 들어 만약 dataset에 dog class data보다 cat class data가 훨씬 더 많으면 해당 이미지가 cat으로 분류될 확률이 더 높으니, cat의 bias를 더 크게 더해주어 고양이로 판단할 확률을 높여주는 것이다. 

 

 

 3072 픽셀을 나타내기엔 너무 많기 때문에 간략하게 입력 이미지의 픽셀 수를 4로 가정하고, class는 cat, dog, ship 총 3가지가 있다고 하고 이것에 대한 score을 계산해보자. 우선 W는 각 class 별로 총 입력 이미지 픽셀 수만큼의 열을 가지고, 입력 이미지의 픽셀은 열벡터로 펴서 계산한다. 그리고 bias는 class 당 하나의 상수 값으로 이루어져 있다. 이 예시로 각 class에 대한 score을 계산하면 cat -96.8, dog 437.9, ship 61.95가 나오며, 이는 입력 사진이 강아지일 확률이 가장 높다는 의미가 되므로 parameter 설정을 잘못 하였다고 판단할 수 있다. 

 이러한 관점에서 보면 linear classfication은 템플릿 매칭과 비슷한데, w의 각 행은 각 이미지에 대한 템플릿으로 볼 수 있고 해당 행의 벡터와 입력 이미지의 열 벡터를 간의 내적을 계산한다. 여기서 내적은 클래스 간 템플릿의 유사도를 측정하는 것과 비슷하다.  

 

 

[Interpreting a Linear Classifier]

 * 템플릿 매칭

  - 템플릿 매칭의 관점에서 linear classification을 해석해보자. 아래의 그림은 CIFAR-10에서 훈련된 linear classifier의 가중치를 사진으로 표현한 예시다. 맨 왼쪽은 plane class에 대한 템플릿이다. 이 이미지를 보면 classifier가 비행기를 분류할 때 푸르스름한 것을 찾는다고 할 수 있다. 참고로 linear classifier은 한 카테고리 당 단 하나의 템플릿으로 학습할 수 있다는 문제가 있다. 그렇기 때문에 한 클래스 내에 다양한 특징들이 존재할 수 있지만 이를 평균화 시키기 때문에 다양한 모습이 있어도 카테고리를 인식하기 위한 템플릿은 단 하나밖에 없다. 이 문제는 아래의 horse 템플릿에서 잘 볼 수 있다. 자세히 보면 말의 머리가 두개인데, 이는 여러 특징을 평균화하여 한 템플릿 안에 담아야 하기 때문에 발생하는 문제이다. 하지만 Neural Network 같이 한 클래스 당 한 템플릿만 학습할 수 있다는 제약이 없는 경우라면 더 높은 정확도를 가진 결과를 낼 수 있다. 

 

 

 * 고차원 공간의 한 점

  - 이미지를 고차원 공간의 한 점이라고 생각하자. linear classifier은 이미지들의 class를 구분 지어주는 linear decision boundary를 긋는 역할을 한다. 아래의 파란선으로 예를 들자면, classifier은 이 파란선을 학습해 비행기와 다른 class들을 구분할 수 있다. 

 하지만 이처럼 linear classifier을 고차원 공간의 한 점으로 보면 다음의 문제가 발생한다. 아래의 그림과 같은 경우에 단 하나의 선으로 해당 class들을 구분짓기 어렵다는 것이다. 

 

 

 요약하자면 linear classifier은 단순한 행렬과 벡터의 곱 형태이고, 템플릿 매칭과 관련이 있다. 이 관점에서는 각 카테고리는 하나의 템플릿으로 학습을 하고, 가중치 행렬 w을 학습시키고 나면 새로운 학습 데이터에도 score을 매길 수 있다. 아직 가중치 행렬 w를 구하는 방법은 배우지 않았고, 다음 시간에 배워볼 예정이다.