CS231n

[CS231n] Lecture 2. Image Classification

포피이 2023. 2. 3. 11:32
본 포스팅은 Stanford University에서 제공하는 CS231n_2017 유튜브 강의를 토대로 정리한 글입니다.
https://youtu.be/OoUX-nOEjG0

목차

1. 이미지 분류(Image Classification)란?

    1.1 디지털이미지란?

    1.2 이미지에 관해 해결해야할 문제

2. 이미지 분류 모델

    2.1 간단한 이미지 분류 모델 구현

    2.2 데이터 기반 (data driven-approach)

    2.3 NN 모델 

    2.4 KNN 모델

    2.5 KNN 단점

3. 거리 함수(Distance Metric)

    3.1 L1 함수

    3.2 L2 함수

    3.3 L1 vs L2

4. 파라미터와 하이퍼파라미터 (Parameter & Hyper parameter)

5. 교차검증 (cross-validate)

6. 선형 분류 (Linear Classification)

    6.1 Parameteric model 이란?

    6.2 선형 분류

    6.3 CIFAR-10 가중치 행렬

 


1. 이미지 분류(Image Classification)란?

이미지 분류란 입력 이미지(input data)를 정해놓은 카테고리 중 하나인 라벨(label)로 분류하는 문제이다.

이것은 컴퓨터 비전(Computer Vision) 분야에서 매우 중요한 문제이다. 컴퓨터 비전은 시각적 세계를 해석하고 이해하도록 컴퓨터를 학습시키는 인공지능 분야이다. 쉽게 말해 디지털 이미지에서 정보를 자동으로 추출하는 과정이라고 볼 수 있다. 

input : 고양이 사진, label : 고양이, predict : 82% 고양이

1.1 디지털 이미지란?

디지털 이미지0~255의 값을 가지는 픽셀값으로 이루어져 있다. (0~255)의 값은 빛의 세기라고 보면 된다.

하나의 디지털 이미지는 (너비 픽셀 개수, 높이 픽셀 개수, 채널값)으로 구성된다. 

픽셀(pixel)은 picture과 element의 합성어이다. 화면을 구성하는 최소 단위이다.

채널은 색을 표현하기 위한 신호 묶음을 의미하는데 1이면 GrayScale(흑백), 3이면 R(ed),G(reen),B(lue)로 표현한 이미지를 의미한다.

예를 들어 아래 흑백 사진은 (12,16,1)로 표현할 수 있다.

 

GrayScale로 이루어진 디지털 이미지이다.

1.2 이미지에 관해 해결해야할 문제

이미지를 다룰 때 생각해보아야할 문제들이 있다. 다음 케이스들을 살펴보자.

  • Sementic Gap (의미론적 차이) : 인간이 보는 피사체 이미지와 컴퓨터가 바라보는 이미지는 의미론적으로 다르다. 
    컴퓨터는 이미지를 픽셀 값들의 집합으로 바라본다.
  • Viewpoint Variation (시점 다양성) : 촬영하는 카메라 시점이 변화하면 이미지 픽셀 위치와 값도 모두 변하게 된다.
  • Illumination (조명) : 조명, 밝기에 따라 픽셀 값이 달라짐
  • Deformation (변형) : 같은 피사체의 다른 자세에 의한 변형
  • Occlusion (가려짐) : 외부 환경에 의해 물체가 일부분 가려짐
  • Background Clutter (배경 클러터) : Occlusion과 유사하게 외부 환경에 피사체가 섞여 피사체 가려지는 현상
  • Intraclass variation (클래스 내부 클래스의 다양성) : 피사체의 색, 크기, 생김새가 달라도 같은 카테고리 계열은 같은 카테고리로 인식되어야 한다.
  • Scale Variation (크기 다양성) : 같은 카테고리라도 사진 혹은 실제로의 크기가 다양한 현상

2. 이미지 분류 모델

특정 이미지를 input data로 넣었을 때 output으로 원하는 카테고리 label 값을 얻는 모델을 만들어 보자. 

2.1 간단한 이미지 분류 모델 생각해보기

def classify_image(image):
	#알고리즘?
    #고양이의 귀는 끝이 Edge 선 3개가 만나는 부분 or 반원 2개가 만나 이루어짐
    #고양이의 코는 Edge 3개 or 4개가 만나게 됨
    #고양이 눈은 삼각형 or 원으로 이루어짐
    #고양이 몸은 ...
	return class_label

고양이의 Edge를 검출해 고양이로 인식할 수 있는 특징을 찾아보자.

고양이 이미지를 고양이라고 인식시키려면 고양이의 특징을 찾아야 할 것이다. 위 그림에서는 고양이의 Edge를 추출한 뒤 고양이로 분류할 수 있는 Edge의 특징들을 찾아 알고리즘으로 만드는 시도를 하였다. 하지만 만약 고양이에 대한 알고리즘을 짜더라도 위 방식은 두 가지 단점이 있다.

  1. 강인하지 않다. (= 예외되는 이미지들이 존재한다면 알고리즘을 수정해야 할 것이다.)
  2. 다른 객체를 인식하는 알고리즘을 짜야 한다면 처음부터 다시 만들어야 한다.

여기서 우리는 "유연하고 확장 가능한 알고리즘"을 만들어야 됨을 알 수 있다.

2.2 데이터 기반 (data driven-approach) 

위의 직접적인 알고리즘 구현 방식 말고 다른 방식을 생각해보자. 컴퓨터에게 분류할 이미지와 정답 값을 주고 학습시킨다면 어떨까? 이 방법론을 데이터 기반 접근 (data - driven - approach) 이라고 한다. 데이터 기반 접근은 3가지 단계로 나타낼 수 있다.

  1. 분류할 데이터 (image)와 정답 데이터 (label) 셋 모으기
  2. 분류기(classifier) 훈련(train)시키기
  3. 새로운 이미지 (test image)로 분류기 성능 평가하기

1. 분류할 데이터 (image)와 정답 데이터 (label) 셋 모은다.

4개의 정답 카테고리 label과 학습 데이터

2. 분류기(classifier)를 훈련(train)시킨다.

def train(images,label):
	#Machine Learning!
	return model

3. 새로운 이미지 (test image)로 분류기의 성능을 평가한다.

def predict(model. test_images):
	#Use model to predict labels
	return test_labels

2.3 NN(Nearest Neighbor) Classifier모델 

최근접이웃 분류기 (NN Classifier)로 이미지를 분류해보자. NN 분류기는 데이터 간 거리 기반으로 아주 간단한 알고리즘이다. 사용할 이미지 데이터셋으로 CIFAR-10을 사용한다. 

CIFAR-10은 32x32x3의 크기를 갖고 있으며, 훈련 데이터셋 5만개, 테스트 데이터셋 1만개로 구성되어 있고 각 데이터셋의 분포도는 거의 비슷하다. 카테고리 라벨은 아래와 같이 총 10종류이다.

최근접이웃 알고리즘은 뜻 그대로 거리 상 가장 근접한 다른 데이터의 라벨 값을 참조하여 라벨값을 추측한다.

거리를 측정하는 함수는 L1 거리 (=맨해튼 거리)를 사용한다. 상황에 따라 L2 거리(유클리드 거리)를 사용하기도 하는데 위 예제에서는 L1 거리를 사용한다. 두 이미지 벡터 간의 각 픽셀 값의 차이를 비교하고 차이를 모두 합산하는 방식으로 계산한다.

이미지 행렬의 성분 차를 합산한다. 값이 클수록 두 이미지 간 차이가 크며, 값이 0에 가까워질수록 두 이미지는 비슷해진다 

이를 코드로 표현하면 다음과 같다.

import numpy as np

class NearestNeighbor(object):
  def __init__(self):
    pass

  #학습데이터 저장
  def train(self,X,y):
    self.Xtr = X
    self.ytr = y

  #X를 입력받고 L1 distance 비교
  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) #L1거리
      #distance = np.sqrt(np.sum(np.square(self.Xtr - X[i,:]), axis = 1)) #L2거리
      min_index = np.argmin(distances) #최소 거리인 인덱스 표현
      Ypred[i] = self.ytr[min_index] #최소거리를 가진 ytr의 index를 바탕으로 예측 
    return Ypred

predict 구현 파트를 보면 알 수 있듯이 1개의 test 이미지를 예측하려면 하려면 5만개의 train 이미지를 비교해야 하기에 시간이 너무 오래걸린다는 단점이 있다.

이제 CIFAR-10 데이터 셋을 불러와 모델을 사용해 보자.

from keras.datasets import cifar10
import time 

#keras에서 제공하는 cifar10 데이터셋
(Xtr, ytr), (Xte, yte) = cifar10.load_data()

# 모든 이미지가 1차원 배열로 저장된다.
Xtr_rows = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows는 50000 x 3072 크기의 배열.
Xte_rows = Xte.reshape(Xte.shape[0], 32 * 32 * 3) # Xte_rows는 10000 x 3072 크기의 배열.

nn = NearestNeighbor() # nn 모델 객체 생성
nn.train(Xtr_rows, ytr) # 모델 훈련
s = time.time() #시간 체크
Yte_predict = nn.predict(Xte_rows) # 예측
e = time.time()

print('accuracy: %f' % ( np.mean(Yte_predict == yte) ))
print('times: %f'%(e-s))

학습된 NN 모델의 결정경계를 간단하게 알아보자. (위의 코드로 만든 결정경계는 아니다.)

NN알고리즘의 결정경

위를 살펴보면 노란색 점 하나가 초록색 영역 가운데에서 초록색 영역을 침범하고 있다. 이것은 오분류된 데이터로 분류된다. 초록색 점도 왼쪽 위로 삐져나와 파란색 영역을 침범하고 있다. 이것은 노이즈로 분류된다. 

이 문제들을 해결하기 위해 KNN 알고리즘이 등장하였다. 

2.4 KNN(K-Nearest Neighbor) Classifier모델

KNN 알고리즘은 NN과 유사하지만 가장 가까운 이웃을 1개에서 K개로 확장시킨 알고리즘이다. K개 중에서 가장 빈도가 높은 카테고리로 예측하게 된다.

K가 커질수록 일반화가 잘된다는 장점이 있지만 K 값이 너무 크게 된다면 과소적합될 우려가 있다.

KNN은 거리별 가중치를 고려해서 예측한 투표 방식과 단순 득표수로만 예측하는 투표방식이 있다. 대부분 단순 득표수로만 예측하는 투표방식을 사용한다.

KNN 알고리즘의 결정경계, 흰색 배경은 레이블링이 안된 영역

NN 알고리즘의 결정경계와 비교했을 때 KNN의 결정경계가 더 일반화가 잘 된 모델임을 알 수 있다.

하지만 K 값에 따라 예측되는 라벨 값이 달라지기 때문에 K 값을 잘 선택해야한다. K 값을 선택하는 기준이 뭘까?

대부분 모델에 모든 K 값을 집어넣어보고 가장 성능이 좋은 K 값을 선택한다. 이것은 하이퍼파라미터 파트에서 다시 설명하겠다. 

2.5 KNN 단점

이미지 분류 문제에서 KNN은 잘 사용되지 않는다. 이유는 두가지가 있다.

  1. 테스트 시 너무 느리다
    NN 모델 구현 코드 중 predict 함수를 보면 test를 예측하기 위해 하나의 test 데이터당 train 개수만큼 반복시켜야했기에 시간이 오래걸린다는 단점이 있었다. 이는 KNN에서도 동일하게 나타나는 문제이다.
  2. 픽셀간 거리 개념 척도가 이미지의 개념적 유사도(Perceptual distance)를 주진 않는다.
    픽셀간 거리가 같아도 이미지 상으론 꽤나 큰 변화가 있음을 알 수 있다.
  3. 차원의 저주 (Curse of dimensionality)
    차원이 증가할수록 학습하기에 이상적인 데이터 양이 기하급수적으로 늘어나게 된다. 
    이상적인 데이터 셋은 각 차원마다 균일한 분포를 띄어야 한다. 하지만 하나의 차원이 늘어날 때마다 1차원 기준 데이터의 개수를 기존 데이터에 곱한만큼 데이터가 필요하게 된다. 이것은 현실적으로 대부분 불가능하다.

2번의 사례 위 네가지 그림은 모두 다르다고 느끼지만 픽셀간 거리 차이는 모두 같다.
3번의 사례, 차원이 증가할수록 기존 데이터 차원 개수의 배수만큼 필요 데이터가 증가하게 된다.

 

3. 거리 함수(Distance Metric)

    3.1 L1 함수

맨해튼 거리 (Manhatten distance), 택시 거리(taxi distance), L1 Norm 이라고도 한다. 맨해튼은 뉴욕의 거리를 의미하는데 맨해튼 거리의 택시 기사가 경로를 찾는 것이 위 수학 공식의 기하학적 표현과 유사하여 맨해튼 거리라는 이름이 붙었다.

    3.2 L2 함수

유클리드 거리 (Euclidian distance), L2 Norm라고 하며 수학자 유클리드의 이름을 본따 만들어진 이름이다.

출처 : https://needjarvis.tistory.com/454

    3.3 L1 vs L2

L1과 L2를 기하학적으로 비교하면 다음과 같다.

L1은 벡터 요소의 절댓값 합이기에 성분 벡터의 변화에 영향을 많이 받는다. 즉 축에 영향을 많이 받는다.

L2는 피타고라스 방식과 같으며 이상치에 민감하다는 특징이 있다.

4. 파라미터와 하이퍼파라미터 (parameter & Hyper parameter)

먼저 파라미터(parameter, 매개변수)에 대해 알아보자.파라미터는 다음과 같은 특징이 있다.

  1. 예측 시 모델에게 요구되는 특성
  2. 데이터로부터 학습되거나 측정됨
  3. 종종 학습 모델의 한 부분으로서 저장됨
  4. 사용자에 의해 조정되지 않음.

즉  모델이 만들어지는 과정에서 데이터로부터 파생된 값을 의미한다. 예를 들면 정규 분포 모델 상에서 평균, 분산 등의 데이터를 파라미터(parameter)라고 한다.

 

반면 하이퍼파라미터(hyperparameter)는 다음과 같은 특징이 있다

  1. 종종 모델 파라미터를 평가할 때 도움을 준다.
  2. 종종 사용자에 의해 정의된다.
  3. 종종 휴리스틱한 방법, 경험에 의한 방법으로 정해진다.
  4. 주어진 예측 모델을 튜닝할 때 사용된다.

즉 모델이 만들어지기 전 사용자가 직접 조정할 수 있는 값을 의미한다. 예를 들면 부스팅 모델의 learning rate 등을 하이퍼 파라미터(hyperparameter) 라고한다.

정리하면 사용자가 값을 조정할 수 있는지의 여부에 따라 파라미터와 하이퍼파라미터가 달라진다.

하이퍼 파라미터를 조정하는 방법은 여러가지가 있지만 모든 하이퍼파라미터를 고려한 후 최적의 성능을 내는 하이퍼 파라미터 값을 고르는 것이 일반적이다. 하이퍼 파라미터는 검증 데이터 셋에서 최적의 성능을 내는 값을 고른 후 딱 한번 테스트 셋에서 모델 성능을 테스트한다. 

5. 교차검증 (cross-validate)

대부분 데이터셋은 훈련 데이터(train data) / 검증 데이터(valid data) / 테스트 데이터(test data)로 분류된다. 

교차 검증은 데이터 분포의 일관성을 위해 만들어진 방법론이다.

데이터는 독립적이며 유일한 하나의 분포에서 나온다는 가정 (I.I.D assumption)을 기반으로 만들어졌다.
학습할 데이터 셋과 검증 데이터 셋 을 고르게 분포시킨다면 수학적으로 데이터의 평균에 가까운 일반적인 값이 나올 것이다.

교차검증은 데이터 셋을 만들 때 테스트 데이터만 고정 시킨 후 데이터를 섞어 가면서 여러 데이터 묶음을 만들어 각 데이터셋을 모델에 적용한 후 결과값을 평균내는 방식을 사용한다.

이 때 데이터를 나누는 단위를 fold라고 하며 k개의 fold로 나눠 검증을 실시한다는 뜻으로 k-fold라고도 한다.

그림에서 주황색이 검증셋, 나머지 초록색이 훈련셋이다. 

코드로 나타내면 다음과 같다.

# Xtr_rows, Ytr, Xte_rows, Yte 는 이전과 동일하게 갖고 있다고 가정하자.
# Xtr_rows 는 50,000 x 3072 행렬이었다.
Xval_rows = Xtr_rows[:1000, :] # 앞의 1000 개를 검증용으로 선택한다.
Yval = Ytr[:1000]
Xtr_rows = Xtr_rows[1000:, :] # 뒤쪽의 49,000 개를 학습용으로 선택한다.
Ytr = Ytr[1000:]

# 검증 셋에서 가장 잘 동작하는 hyperparameter 들을 찾는다.
validation_accuracies = []
for k in [1, 3, 5, 10, 20, 50, 100]:

  # 특정 k 값을 정해서 검증 데이터에 대해 평가할 때 사용한다.
  nn = NearestNeighbor()
  nn.train(Xtr_rows, Ytr)
  # 여기서는 k를 input으로 받을 수 있도록 변형된 NearestNeighbor 클래스가 있다고 가정하자.
  Yval_predict = nn.predict(Xval_rows, k = k)
  acc = np.mean(Yval_predict == Yval)
  print 'accuracy: %f' % (acc,)

  # 검증 셋에 대한 정확도를 저장해 놓는다.
  validation_accuracies.append((k, acc))

 

K 개수 별 모델의 정확성과 교차검증 결과를 본다면 어떤 하이퍼파라미터가 가장 좋은지, 성능 분산이 어떻게 되는지 파악 할 수 있다. 

K = 7일때 성능이 가장 좋다.

6. 선형 분류 (Linear Classification)

선형 분류기(Linear Classifer)는 신경망 (Neural Network,NN)을 구성할 때 층을 구성하는 가장 기본적인 알고리즘이라고 생각하면 된다. 

쉽게 말하면 레고블럭을 위로 쌓을 때, 레고블럭을 선형 분류기라고 하면 쌓은 탑 전체 모습은 신경망이라고 볼 수 있다.

6.1 Parameteric model 이란?

Parameteric model은 파라미터 수가 정해진 모델이다. 따라서 모델의 형태가 정해져 있고 모델의 파라미터를 학습시키면서 모델을 발전시키는 형태의 모델이다. Linear regression, Neural Network 등이 해당한다.

Parametric model은 두 가지 조건이 있다.

  1. 입력 이미지 (X)가 존재
  2. 가중치 혹은 파라미터 (W)가 존재
  3. 특정 함수 f(x,W) 를 통해 결과 도출

None-Parametric model은 파라미터 수가 명확하게 정해지지 않은 모델이다. 데이터에 대한 사전 지식이 없을 때 주로 사용한다. DecisionTree, RandomForest 등이 있다.

6.2 선형 분류

가장 간단한 Parametric model이 선형 분류기이다. 입력 이미지(x)와 가중치(W)를 단순히 곱한 값이다.

선형 분류기의 과정을 다음 그림으로 예시를 들어 (32x32x3)의 고양이 사진을 10개의 클래스로 분류한다고 가정하자.

32x32x3의 입력 데이터(x)는 32x32=(3072,1)인 열행렬로 바뀌게 되고 이 값이 가중치행렬(10,3072)와 내적 연산된다.

가중치 행렬이 (10,3072)인 이유는 결과 데이터가 (10,1)로 이루어져야 하기 때문이다.

b는 편향(Bias)를 의미하고 입력 데이터와 직접적 연관은 없지만 특정 값에 우선권을 부여한다는 특징이 있다.

예를 들면 고양이 클래스가 많고 강아지 클래스가 적다면 고양이 클래스 쪽으로 값이 커지도록 b가 설정된다.

선형 분류 계산

계산 결과 강아지 점수가 제일 높게 나와 강아지로 분류되었지만 답은 고양이이다. 안타깝게도 틀린 문제이다.

6.3 CIFAR-10 가중치 행렬

학습된 CIFAR-10의 가중치 행렬을 시각화 해보면 다음과 같다.

CIFAR-10의 가중치 이미지

선형 분류기 특성상 하나의 카테고리에 하나의 가중치 행렬 값을 만들기 때문에 훈련련 이미지의 평균 값으로 적용된다. 눈으로 봐도 일반적으로 생각하는 label 이미지와는 다르다는 것을 알 수 있다.

 

이미지 값들을 2차원 평면상에 투영해 나타내면 아래 그림과 같다. 

직선은 그림을 분류하는 라벨 기준 값, 각 이미지는 좌표공간상 점으로 볼 수 있다. 이를 3D로 표현하면 각 평면들이 카테고리를 나누는 기준이 됨을 알 수 있다.


 

ㅎReference

CS231n 최신 강의 노트 (한글판) : http://aikorea.org/cs231n/classification/

Reference1: Machine Learning Mastery (What is the Difference Between a Parameter and a Hyperparameter?)

https://process-mining.tistory.com/131


 

Kovi는 SSDC(Samsung Software Developer Community)를 기반으로 만들어진 커뮤니티입니다. ML, DL, Computer Vision, Robotics에 관심 있고 열정 있는 사람들이 모여 함께 활동 중입니다.

 

Kovi Instagram : https://www.instagram.com/kovi.or.kr/

Kovi SSDC : https://software.devcommunities.net/community/communityDetail/98

 

이 포스팅은 Kovi 커뮤니티 스터디의 일환으로 작성되었습니다.

posted by. Panda99 & Daevi