2.1 이미지 분류(Image Classification)

2.1.1 동기(Motivation)

이번 장에서는 이미지 분류(Image Classification) 문제에 대해 소개합니다. 이는 입력 이미지에 대해 정해진 카테고리 집합 중 하나의 라벨을 할당하는 것을 말합니다. 컴퓨터 비전 영역의 핵심 문제 중 하나로, 간단하지만 많은 실전적인 응용이 있습니다. 또한 보기에는 다르지만 많은 컴퓨터비전 문제들은 - 가령, 객체 인식(object detection), 분할(segmentation) - 이미지 분류로 축소될 수 있습니다.

2.1.2 예시(Example)

아래와 같이 이미지 분류 모델에서는 한 장의 이미지를 가지고 4개의 라벨 - {고양이, 개, 모자, 머그컵} - 에 대한 가능성을 예측합니다. 컴퓨터의 입장에서 이미지는 숫자의 3차원 배열일 뿐입니다. 여기서 고양이 이미지는 248 픽셀의 너비, 400 픽셀의 높이, 그리고 RGB의 3가지 채널을 가집니다. 그러므로 이미지는 248x400x3 의 숫자로 표현되고, 총 297,600 개의 숫자를 가집니다. 각각의 숫자는 0(흑)부터 255(백)사이의 정수입니다. 우리의 문제는 약 30만개의 숫자를 “고양이”라는 하나의 라벨로 바꾸는것입니다.

classify

이미지 분류 문제는 주어진 이미지에 대하여 하나의 라벨을 - 또는 여러 라벨에 대한 신뢰도(confidence)의 분포를 - 예측하는 것입니다. 이미지는 0-255 사이의 정수들로 이루어진 3차원 배열 - (너비)x(높이)x3 - 이며, 여기서 3은 RGB의 3가지 채널을 의미합니다.

2.1.3 어려움(Challenges)

사람에게 있어 고양이와 같은 시각적 개념(visual concept)을 인식하는 것은 비교적 사소한 문제이기 때문에, 컴퓨터비전 알고리즘의 관점에서 오는 어려움을 고려해보는 것은 의미가 있습니다. 아래의 리스트는 주요한 어려움을 보여줍니다. 이미지는 명암(brightness values)에 대한 3차원 배열로 표현됨을 기억하세요.

  • 관점의 변화(Viewpoint variation): 같은 물체라도 카메라를 찍는 위치에 따라 물체의 위치가 달라집니다.
  • 크기의 변화(Scale variation): 시각적 클래스(Visual classes)는 종종 이미지상의 영역(extent in the image) 뿐만 아니라 실세계에서의 크기 변화를 보이기도 합니다.
  • 변형(Deformation): 다수의 관심 대상(object of interest)은 단단한 몸통을 가지고 있지 않으며 극단적으로 변형이 될 수도 있습니다.
  • 가려짐(Occlusion): 관심 대상은 다른 물체에 가려질 수 있습니다. 간혹 대상의 일부 - 적은 수의 픽셀 - 만이 보일수도 있습니다.
  • 조명(Illumination conditions): 조명의 효과는 픽셀 단위에서 극명히 드러납니다.
  • 배경의 어수선함(Background clutter): 관심 대상은 주위 환경에 섞여서 분간하기 어려워질 수 있습니다.
  • 클래스 내의 변화(Intra-class variation): 종종 관심대상의 클래스가 상대적으로 방대한 영역을 포함할 때도 있습니다. 가령, 의자와 같은 대상은 많은 종류가 있으며, 각각이 다른 형태를 가집니다.

좋은 이미지 분류 모델은 이러한 모든 변화의 외적(cross product)에 민감해서는 안되고, 동시에 다른 클래스 간의(inter-class) 차이에 민감해야 합니다. 결국, 문제는 “의미론적인 차이”(Semantic Gap)입니다.

challenges

2.1.4 데이터 중심의 접근(Data-driven approach)

이미지를 별개의 카테고리로 분류하는 알고리즘을 어떻게 작성해야 할까요? 숫자들을 정렬(sorting)하는 알고리즘과는 달리, 이미지 속 고양이를 분간할 수 있는 알고리즘을 작성하는것에는 명확한 해법이 없습니다. 따라서 코드로써 관심 카테고리내의 모든 대상이 무엇을 닮았는지 일일이 파악하려는 시도보다는 어린아이의 접근방식을 취할것 입니다: 각 클래스에 대한 수많은 예시들을 제시하면, 컴퓨터는 이러한 예시들을 보고 각각의 클래스에 대한 시각적인 외형(visual appearance)을 익히는 학습 알고리즘을 발전시킵니다. 이는 라벨이 붙은 이미지의 트레이닝 데이터셋을 축적하는것에 의존하기 때문에, 이러한 접근을 두고 데이터 중심의 접근이라고 합니다. 아래는 데이터셋의 예시를 보여줍니다.

trainset

네 가지 시각적 카테고리(visual categories)에 대한 트레이닝셋의 예시를 보여줍니다. 실전에서는 수천가지의 카테고리가 있으며, 각각의 카테고리에는 수십만장의 이미지가 있습니다.

2.1.5 이미지 분류 파이프라인(The image classification pipeline)

이미지 분류는 한 장의 이미지를 표현하는 픽셀들의 배열을 가지고 라벨을 붙이는 문제입니다. 전체적인 파이프라인은 다음과 같이 구성됩니다.

  • 입력(Input): N개의 이미지 집합 - 각각은 K개의 클래스 중 하나의 라벨이 붙여져 있습니다. - 이 입력됩니다. 이를 트레이닝셋이라고 합니다.
  • 학습(Learning): 트레이닝셋을 이용하여 클래스 내의 대상들이 어떻게 생겼는지를 학습합니다. 이를 분류기 학습 과정 - 또는 모델 학습 - 이라고 합니다.
  • 평가(Evaluation): 마지막으로, 이전에 보여지지 않은(never seen before) 새로운 이미지셋에 대하여 라벨을 예측하게 하고, 이를 이미지의 실제 라벨과 비교함으로써 분류기의 성능을 평가할 수 있습니다. 당연히 예측 결과가 실제 정답(true answer, ground truth)과 많이 일치할수록 좋습니다.

2.2 최근접이웃 분류기(Nearest Neighbor Classifier)

첫번째로, 최근접이웃 분류기(Nearest Neighbor Classifier)로 접근해볼 수 있습니다. 이 분류기는 합성곱 신경망(Convolutional Neural Networks)과는 아무런 관련이 없으며 실전에서 사용하는 일은 매우 드물지만, 이미지 분류 문제의 기본적인 접근법에 대한 아이디어를 얻을 수 있습니다.

2.2.1 이미지 분류 데이터셋 예시: CIFAR-10(Example image classification dataset: CIFAR-10)

CIFAR-10은 인기 있는 장난감 이미지 분류 데이터셋 중 하나입니다. 이 데이터셋은 32픽셀의 높이와 너비를 가지는 6만 장의 작은 이미지로 구성되어 있으며, 각각의 이미지는 10개의 카테고리 - 비행기, 자동차, 새 등 - 중 하나로 분류됩니다. 이 6만 장의 이미지는 5만 장의 트레이닝셋과 1만 장의 테스트셋으로 나누어져 있습니다. 아래에서는 10개의 클래스에 대해 각각 10장의 무작위 이미지 예시를 볼 수 있습니다.

CIFAR-10

왼쪽: CIFAR-10 데이터셋의 이미지 예시입니다. 오른쪽: 첫번째 열은 테스트 이미지를, 그 다음 열부터는 픽셀간의 차이(pixel-wise difference)에 따른 상위 10개의 최근접 이웃(nearest neighbors)을 보여줍니다.

5만 장의 CIFAR-10 트레이닝셋(라벨 당 5천 장의 이미지)이 주어지고, 1만 장의 이미지에 대해 라벨을 붙인다고 가정합니다. 이 때, 최근접 이웃 분류기는 테스트 이미지를 가지고 모든 트레이닝 이미지 하나하나와 비교하여 가장 유사한 트레이닝 이미지의 라벨로 예측할 것입니다. 상단 이미지의 오른쪽에서 10개의 테스트 이미지에 대한 그 결과를 볼 수 있습니다. 10개의 예시 중 오직 3개만 같은 클래스의 이미지를 반환하였고, 나머지 7개의 예시에서는 그렇지 않았음을 확인할 수 있습니다. 예를 들어, 8번째 행에서 말머리의 최근접 트레이닝 이미지는 빨간색 차입니다. 이는 아마도 검은 배경화면이 강했기 때문에 말의 이미지에 차 라벨이 잘못 붙여졌을 것입니다.

아직 두 장의 이미지 - 이 경우, 32x32x3의 두 블록에 불과한 - 를 정확히 어떻게 비교하는지에 대한 세부 사항을 명시하지 않았습니다. 가장 간단한 가능성 중 하나는 화소를 픽셀 단위로 비교하고 모든 차이를 더하는 것입니다. 즉, 두 개의 영상을 벡터 I1,I2로 나타내면 이들을 비교하기 위한 합리적인 방법은 L1 거리(L1 distance)일 수 있습니다:

L1 distance

모든 픽셀간의 차이를 가지고 합을 구합니다. 다음은 이 절차에 대한 시각화입니다:

L1 distance Visualize

L1 distance(여기서는 하나의 색상 채널에 대해서만)를 이용하여 두 장의 이미지를 픽셀 단위로 비교하고 그 차이를 이용합니다. 두 장의 이미지에서 각각의 원소에 대하여 뺄셈연산이 행해지고 모든 차이는 하나의 숫자로 합산됩니다. 만약 두 장의 이미지가 완전히 같다면 결과는 0이 될 것이고, 많이 다르다면 결과는 매우 클것입니다.

아래에서는 분류기를 코드로 작성하였습니다. 먼저, CIFAR-10 데이터를 4개의 배열 - 트레이닝 데이터/라벨과 테스트 데이터/라벨 - 로써 메모리에 불러들입니다. 하단의 코드에서, Xtr(50000x32x32x3 크기)은 모든 트레이닝셋을 포함하고, 이에 상응하는 Ytr(50000 길이의 1차원 배열)은 0부터 9 사이의 라벨을 가집니다.

Xtr, Ytr, Xte, Yte = load_CIFAR10('data/cifar10/') # a magic function we provide
# flatten out all images to be one-dimensional
Xtr_rows = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows becomes 50000 x 3072
Xte_rows = Xte.reshape(Xte.shape[0], 32 * 32 * 3) # Xte_rows becomes 10000 x 3072

이제 모든 이미지를 행으로 펼쳐 놓았기 때문에, 다음과 같이 분류기를 학습하고 평가할 수 있습니다:

nn = NearestNeighbor() # create a Nearest Neighbor classifier class
nn.train(Xtr_rows, Ytr) # train the classifier on the training images and labels
Yte_predict = nn.predict(Xte_rows) # predict labels on the test images
# and now print the classification accuracy, which is the average number
# of examples that are correctly predicted (i.e. label matches)
print 'accuracy: %f' % ( np.mean(Yte_predict == Yte) )

정확도(accuracy)를 일반적인 평가 기준으로 사용하며, 이는 예측한 것 중 정확히 맞춘 정도를 측정합니다. 앞으로 만들 모든 분류기들은 공통적으로 한 가지 API를 만족하는데, 이는 데이터와 라벨을 학습할 수 있는 train(X,y) 함수를 가지고 있다는 것입니다. 클래스는 내부적으로 라벨, 그리고 데이터로부터 그 라벨이 어떻게 예측되는지에 대한 모델이 있어야 합니다. 또한 새로운 데이터를 가지고 라벨을 예측하는 predict(X) 함수가 있습니다. 물론, 우리는 사물의 알맹이인 실제 분류기 그 자체는 제외하였습니다. 아래에서는 이러한 조건을 만족하는 L1 distance를 가진 단순한 Nearest Neighbor classifier를 구현하였습니다.

import numpy as np

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

  def train(self, X, y):
    """ X is N x D where each row is an example. Y is 1-dimension of size N """
    # the nearest neighbor classifier simply remembers all the training data
    self.Xtr = X
    self.ytr = y

  def predict(self, X):
    """ X is N x D where each row is an example we wish to predict label for """
    num_test = X.shape[0]
    # lets make sure that the output type matches the input type
    Ypred = np.zeros(num_test, dtype = self.ytr.dtype)

    # loop over all test rows
    for i in xrange(num_test):
      # find the nearest training image to the i'th test image
      # using the L1 distance (sum of absolute value differences)
      distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = 1)
      min_index = np.argmin(distances) # get the index with smallest distance
      Ypred[i] = self.ytr[min_index] # predict the label of the nearest example

    return Ypred

이 코드를 돌려보면, 분류기는 CIFAR-10 기준으로 38.6%의 정확도를 보입니다. 무작위로 추측하는것(10개의 클래스가 있으니 10%의 정확도를 보일것) 보다는 좋은 결과를 보이지만, 여전히 사람의 능력(94% 정도로 예상됨) 또는 사람의 정확도에 필적하는 (95%의 정확도를 보인) 최신의 Convolutional Neural Networks에는 한참 못 미칩니다.

2.2.2 L2 distance(The choice of distance)

벡터 사이의 거리를 계산하는 다른 방법들이 많이 있습니다. 그 중 일반적으로 L2 distance를 대체제로써 많이 이용합니다. 이는 두 벡터 사이의 유클리드 거리(euclidean distance)를 계산함에 있어 기하학적 해석을 가집니다. L2 distance는 다음과 같은 형태를 보입니다.

L2 distance

이전과 같이 픽셀 단위의 차이를 계산하지만, 이번에는 그것들을 모두 제곱한 후 합쳐서 마침내 제곱근을 취합니다. numpy에서는, 위의 코드를 그대로 사용하고, L2 distance와 관련하여 한줄의 코드만 바꾸면 됩니다. 그 코드는 다음과 같습니다.

distances = np.sqrt(np.sum(np.square(self.Xtr - X[i,:]), axis = 1))

위의 코드에서 np.sqrt가 추가 되었음에 확인할 수 있습니다. 하지만 nearest neighbor를 실질적으로 사용할 때는 제곱근 연산이 단조함수(monotonic function)이기 때문에 제외할 수도 있습니다. 즉, 거리의 절대적인 크기를 조정하지만 순서는 보존하므로, 그것이 있든 없든 nearest neighbor은 동일합니다. CIFAR-10에서 L2 distance를 가지고 nearest neighbor classifier를 실행하면, 35.4%의 정확도를 얻을 수 있습니다.(L1 distance 결과보다 약간 낮음)

2.2.3 L1(Manhattan) vs. L2(Euclidean)

두 지표의 차이를 고려하는 것은 흥미로운 일입니다. 특히, L2 distance는 두 벡터 간의 차이에 관한 한 L1 distance보다 훨씬 더 관대합니다. 즉, L2 distance는 하나의 큰 거리보다 많은 중간 정도의 차이를 선호합니다. L1과 L2 distance 또는 이미지 한 쌍 간의 차이에 대한 L1/L2 norm은 p-norm에서 가장 일반적으로 사용되는 특수 케이스입니다.

2.3 k-최근접 이웃 분류기(k - Nearest Neighbor Classifier)

예측을 할 때, 가까운 이미지의 라벨만 사용하는 것이 이상하지 않은가요? 실제로, 이른바 ‘k-Nearest Neighter Classifier‘를 사용했을 때 대부분의 경우에 더 좋은 성능을 보입니다. 그 아이디어는 매우 간단합니다: 트레이닝셋에서 하나의 가장 유사한 이미지를 찾는 대신, 상위 k개의 유사한 이미지들을 찾아서 그것들이 테스트 이미지의 라벨에 다수결 투표(majority vote)하도록 합니다. 직관적으로, k의 값이 높을수록 아래와 같이 동떨어진 점(outliers)에 대한 내성이 높아지는 평탄 효과(smoothing effect)가 생깁니다. k = 1일 때는, nearest neighbor 분류기가 됩니다.

이미지에 관한 한, 절대 k-Nearest Neighbor를 사용하지 않습니다!

  • 테스트가 매우 느립니다.
  • 픽셀에 대한 Distance metrics는 정보를 제공(informative)하지 않습니다.
  • 차원의 저주(Curse of dimensionality)

KNN

Nearest Neighbor(NN)와 5-Nearest Neighbor(KNN)의 차이점을, 2차원 점과 3개의 클래스(빨간색, 파란색, 녹색)를 이용하여 나타내었습니다. 색상이 있는 영역은 분류기의 L2 distance에 의해 구분되는 결정경계(decision boundaries)를, 흰 영역은 애매하게 분류된 점(투표에서 적어도 2개의 클래스가 비기는 경우)들을 나타냅니다. NN의 경우, 파란색 구름 가운데 녹색 점과 같은 동떨어진 점(outlier datapoints)들이 부정확할 가능성이 있는 작은 섬들을 형성합니다. 반면, 5N 분류기는 이러한 불규칙성(irregularities)을 평탄하게 만듭니다. 이는 결과적으로 테스트 데이터에 대하여 보다 나은 일반화(generalization)로 이어질 수 있습니다. 또한 5-NN 이미지의 회색 영역은 nearest neigbors간의 투표가 비길 때 생깁니다.(빨간색 2, 파란색 2, 녹색 1).

실전에서는, 거의 대부분의 경우 k-Nearest Neighbor을 사용할 것입니다. 여기서 k를 어떻게 정할것인가는 또 다른 문제가 됩니다.

2.4 하이퍼파라미티 조정을 위한 검증셋(Validation sets for Hyperparameter tuning)

k-nearest neighbor 분류기는 k에 대한 설정을 필요로 합니다. 하지만 어떤 숫자가 가장 좋을까요? 게다가, distance에도 많은 종류가 있음을 알고 있습니다: L1 norm과 L2 norm 뿐만 아니라 우리가 고려하지 않은 많은 선택지가 있습니다. 이러한 선택은 하이퍼파라미터(Hyperparameter)라고 부르며, 데이터로부터 학습되는 많은 머신러닝 알고리즘을 디자인할 때 자주 등장합니다. 종종 어떤 값/설정을 선택해야 할지 명확하지 않은 경우가 많습니다.

  • k의 값을 어떻게 설정하는 것이 가장 좋은 성능을 보일까요?
  • 어떤 distance function을 이용해야 할까요?

이는 학습되는 것이 아닌, 학습 전 미리 설정해주는 하이퍼파라미터입니다.

  • 아이디어 1 : 전체 데이터에 대한 최적의 하이퍼파라미터를 선택합니다. 나쁨: K=1일 때 트레이닝 데이터에 항상 완벽하게 동작합니다.
  • 아이디어 2 : 전체 데이터를 트레이닝/테스트 데이터로 분할하고, 테스트 데이터에 대한 최적의 하이퍼파라미터를 선택합니다. 나쁨: 새로운 데이터에 대해서 알고리즘이 어떤 성능을 보일지 알 수 없습니다.
  • 아이디어 3 : 전체 데이터를 트레이닝/검증/테스트(train/val/test) 데이터로 분할합니다. 검증 데이터를 통해 하이퍼파라미터를 선택하고, 테스트 데이터를 통해 평가합니다. 괜찮다!
  • 아이디어 4 : 교차검증(Cross-Validataion) - 전체 데이터를 fold로 분할한 후, 각 fold를 번갈아가며 검증(validation)하고 그 결과를 평균 냅니다. 작은 데이터셋에는 유용한 방식이지만, 딥러닝에서 그리 자주 사용되지는 않습니다.

무엇이 가장 좋은 결과를 보이는지는 사실 여러 값들을 시도해봐야 알 수 있습니다. 괜찮은 아이디어이고, 실제로도 그렇게 할 것입니다. 하지만 이는 매우 신중하게 이루어져야 합니다. 특히, 하이퍼파라미터(hyperparameters)를 살짝 수정하는(tweak) 목적으로는 테스트셋을 사용할 수 없습니다. 기계학습 알고리즘을 디자인할 때, 테스트셋은 최후의 마지막까지 절대 건드려서는 안되는 매우 중요한 자원으로 생각해야 합니다. 만약 테스트 셋을 사용해버린다면, 테스트셋에서는 잘 작동하도록 하이퍼파라미터들을 조정할 수도 있지만, 모델을 실제로 사용했을 때(deploy) 성능이 크게 저하되는 것을 볼 수 있을 것입니다. 실전에서는, 이를 테스트셋에 대한 과적합(overfit)이라고 말합니다. 만약 테스트셋을 이용하여 하이퍼파라미터를 조정한다면, 테스트셋을 트레이닝셋으로 사용해버리는 꼴이기 때문에 실제로 모델을 사용했을 때 관찰되는 성능에 비해 지나치게 낙관적인 결과를 보여줄 것입니다. 하지만 학습이 끝난 이후 성능은 볼품 없을 것입니다. 만약 테스트셋을 마지막 순간까지 간직하다가 단 한 번만 사용한다면, 이는 당신의 분류기의 일반화(generalization)를 측정하는 좋은 대용품이 될 것 입니다.

최후의 마지막 순간에 단 한 번 테스트셋을 사용하여 평가합니다.

다행히도, 하이퍼파라미터를 조정하는 올바른 방법이 있으며, 테스트셋에는 전혀 손대지 않습니다. 그 아이디어는 트레이닝셋을 두 개로 나누는 것입니다: 약간 더 작아진 트레이닝셋(training set)과 검증셋(validation set)이라고 부르는 것입니다. 가령, CIFAR-10에서 학습용 이미지 49,000개를 사용하고, 검증(validation)을 위해 1,000개를 남겨둘 수 있습니다. 이 검증셋는 기본적으로 하이퍼파라미터 조정을 위한 가짜 테스트셋으로 사용됩니다.

다음은 CIFAR-10에서 validation set이 어떻게 표현되는지를 보여줍니다.

# assume we have Xtr_rows, Ytr, Xte_rows, Yte as before
# recall Xtr_rows is 50,000 x 3072 matrix
Xval_rows = Xtr_rows[:1000, :] # take first 1000 for validation
Yval = Ytr[:1000]
Xtr_rows = Xtr_rows[1000:, :] # keep last 49,000 for train
Ytr = Ytr[1000:]

# find hyperparameters that work best on the validation set
validation_accuracies = []
for k in [1, 3, 5, 10, 20, 50, 100]:
  
  # use a particular value of k and evaluation on validation data
  nn = NearestNeighbor()
  nn.train(Xtr_rows, Ytr)
  # here we assume a modified NearestNeighbor class that can take a k as input
  Yval_predict = nn.predict(Xval_rows, k = k)
  acc = np.mean(Yval_predict == Yval)
  print 'accuracy: %f' % (acc,)

  # keep track of what works on the validation set
  validation_accuracies.append((k, acc))

이 과정이 끝날 때쯤에는 어떤 값이 가장 잘 작동하는지 나타내는 그래프를 그릴 수 있을 것입니다. 그 다음 이 값을 고수한 채 실제 테스트셋에서 한 번 평가합니다.

트레이닝셋을 트레이닝셋과 검증셋으로 나눈 후, 검증셋을 사용하여 모든 하이퍼파라미터를 조정합니다. 마지막에 테스트셋에 대해 단 한 번 실행한 결과를 최종 성능으로 보고합니다.

2.4.1 교차 검증(Cross-validataion)

트레이닝 데이터와 검증 데이터의 크기가 작을 경우, 하이퍼파라미터 조정을 위한 보다 정교한 방법인 교차 검증(cross-validataion)을 사용합니다. 이전의 예처럼, 1000개의 데이터점을 임의로 선택하여 검증셋과 나머지 트레이닝셋으로 사용하는 대신, 서로 다른 검증셋에 대해 반복하고 이들 전체에 걸쳐 성능을 평균함으로써 특정 k 값이 얼마나 좋은 성능을 보이는지에 대한 더 좋은(less noisy) 결과를 얻을 수 있습니다. 가령, 5-fold 교차 검증에서는 트레이닝 데이터를 5개의 동일한 크기로 나누고, 그 중 4개를 학습에 사용하고, 1은 검증을 위해 사용합니다. 그런 다음 validation fold를 바꾸어 가며 반복하고, 성능을 평가하며, 모든 fold에 걸쳐 성능을 평균합니다.

cvplot

파라미터 k에 대한 5-fold 교차 검증 실행의 예를 보여줍니다. k의 각 값에 대해 4 fold씩 학습하고 5번째에 평가합니다. 따라서, 각 k에 대한 validation fold에서 5개의 정확도(accuracy)을 알 수 있습니다.(y축은 정확도, 각 결과는 점으로 표현) 경향선(trend line)은 각 k에 대한 결과 평균을 통해 그려지며, 에러 막대는 표준 편차를 나타냅니다. 이 경우, 교차 검증에서는 이 특정 데이터 집합에 대해 약 k = 7의 값이 가장 잘 작용함을 보여줍니다.(그림에서 피크) 만약 우리가 5 fold 이상 사용한다면, 우리는 더 부드러운(less noisy) 곡선을 볼 수 있을 것입니다.

2.4.2 실전(In practice)

실전에서 교차 검증은 계산적으로 비용이 많이 들기 때문에 사람들은 single validation split을 할 때는, 교차 검증을 사용하지 않는 것을 선호합니다. 일반적으로 트레이닝 데이터의 50%-90%를 학습에, 나머지를 검증에 사용합니다. 이는 여러 변수에 의해 달라질 수 있습니다. 가령, 하이퍼파라미터의 개수가 많은 경우, 더 큰 validation split을 사용하는 것이 선호됩니다. validation set의 예시가 적은 경우(수백 개 정도), 교차 검증을 이용하는 것이 안전합니다. 실제로 볼 수 있는 일반적인 fold의 수는 3-fold, 5-fold 또는 10-fold 교차 검증입니다.

crossval

일반적인 데이터 분할(data split)을 보여줍니다. 트레이닝셋과 테스트셋이 주어지고, 트레이닝셋은 fold(여기서는 5 fold)로 나뉩니다. fold 1-4가 트레이닝셋이 되고, fold 5(노란색)는 validation fold가 되어 하이퍼파라미터를 조정하는 데 사용됩니다. 교차 검증은 한 걸음 더 나아가서 fold 1-5에서 validation fold를 바꾸어가며 반복합니다. 이를 두고 5-fold cross-validation이라고 부릅니다. 모델이 학습을 완료하고 모든 최상의 하이퍼 파라미터가 결정되면, 모델은 테스트 데이터(빨간색)에서 단 한 번 평가됩니다.

2.4.3 최근접이웃 분류기의 장단점(Pros and Cons of Nearest Neighbor classifier)

최근접이웃 분류기(Nearest Neighbor classifier)의 몇 가지 장단점을 고려해볼 필요가 있습니다. 분명한 이점은 적용과 이해가 매우 간단하다는 것입니다. 또한, 분류기는 트레이닝 데이터를 저장하고 색인화(index)하는 데만 필요하므로 학습하는 데 시간이 걸리지 않습니다. 그러나 테스트 데이터를 분류하려면 모든 트레이닝 데이터를 비교해야 하기 때문에 테스트 시간에 어마어마한 계산 비용을 지불해야 합니다. 이는 단점이 되는데, 우리는 테스트 시간 효율을 학습 시간의 효율보다 더 많이 신경 쓰기 때문입니다. 깊은 신경망(deep neural networks)에서는 이 절충(tradeoff)을 반대의 방식으로 바꿉니다: 학습에 매우 높은 비용을 지불하지만 일단 학습이 끝나면 새로운 테스트 데이터를 분류하는 것은 매우 적은 비용으로도 가능합니다. 사실, 이러한 방식이 실제로 훨씬 더 바람직합니다.

이와는 별개로, Nearest Neighbor classifier의 연산 복잡성(computational complexity)은 활발한 연구 영역이며, 데이터셋에서 nearest neighbor 조회(lookup)를 가속화할 수 있는 몇몇 Approximate Nearest Neighbor(ANN) 알고리즘과 라이브러리가 있습니다.(FLANN) 이러한 알고리즘은 nearest neighbor 검색 정확도와 공간/시간 복잡도를 절충(tradeoff)할 수 있도록 하고, 대개 kdtree를 구축하거나 k-means 알고리즘을 실행하는 등의 전처리(pre-processing)/인덱싱(indexing) 단계에 의존합니다.

Nearest Neighbor Classifier는 일부 환경(특히 데이터가 저차원인 경우)에서는 좋은 선택이 될 수 있지만, 실제 이미지 분류에서 사용하기에는 적합하지 않습니다. 문제는 이미지가 고차원(화소가 많음)이고, 고차원 공간에서는 거리가 직관에 반할 수도 있다(counter-intuitive)는 것입니다. 아래는 위에서 사용한 픽셀 기반의 L2 similarities가 지각적 유사성(perceptual similarities)과 매우 다르다는 점을 보여줍니다:

samenorm

고차원 데이터(특히 이미지)에 대해서 픽셀 기반 거리는 매우 직관적이지 않을 수(unintuitive) 있습니다. 원본 영상(왼쪽)과 그 옆에 있는 세 개의 다른 이미지는 L2 pixel distance를 기준으로 동일하게 멀리 떨어져 있습니다. 픽셀 기반 거리(pixel-wise distance)는 지각적(perceptual) 또는 의미적 유사성(semantic similarity)과는 전혀 상응하지 않습니다.

아래의 시각화를 통해 이미지 비교에 있어 픽셀 차이(pixel difference)를 사용하는 것이 부적절하다는 것에 대한 확신을 얻을 수 있습니다. t-SNE라고 불리는 시각화 기법(visualization technique)을 사용하여 CIFAR-10 이미지를 2차원으로 구현하고, 이미지간의 양방향 거리(pairwise distance)가 가장 잘 보존되도록 할 수 있습니다. 이 시각화에서, 근처에 표시된 이미지는 위에서 본 L2 pixel distance에 따라 매우 가까운 것으로 간주됩니다.

pixels embed cifar10

t-SNE로 CIFAR-10 이미지를 2차원으로 구현(embed)하였음을 볼 수 있습니다. 인접한 이미지는 L2 pixel distance를 기준으로 근접해 있는 것으로 간주됩니다. 의미적인(semantic) 클래스 차이보다는 배경(background)의 영향이 강하다는것에 주목합니다.

서로 가까이 있는 이미지는 의미적 정체성(semantic identity)보다는 이미지의 일반적인 색 분포나 배경의 유형에 훨씬 더 큰 비중을 둡니다. 가령, 개 주변에 개구리가 있는데, 이는 둘 다 흰배경이 있기 때문입니다. 이상적으로는 10개 클래스의 모든 이미지가 클러스터를 형성하고, 무관한 특성(irrelevant characteristics)이나 배경과 같은 변화(variations)에 관계없이 서로 가까운 곳에 있게 하는 것이 바람직합니다. 하지만, 이렇게 하기 위해서는 단순히 raw pixels뿐만 아니라 더 많은 것이 필요할 것입니다.

2.5 요약(Summary)

2.5.1 In summary

  • 단일 카테고리의 라벨이 붙은 이미지셋이 주어졌을 때, 이미지 분류의 문제점을 알아보았습니다. 또한 새로운 테스트셋에 대한 카테고리를 예측하고 그 정확도를 측정하는 방법을 알아보았습니다.
  • Nearest Neighbor Classifier이라 불리는 단순한 분류기를 알아보았습니다. 그리고 분류기와 관련있는 여러 하이퍼파라미터(k의 값, 사용하는 distance의 종류)의 예를 보았고, 이를 선택하는 명료한 방법이 없다는 것도 알았습니다.
  • 하이퍼파라미터를 설정하는 바람직한 방법은 트레이닝셋을 두 개로 나누는 것 - 트레이닝셋과 가짜 테스트셋(검증셋) - 입니다. 그리고 여러 하이퍼파라미터들을 바꿔가며 검증셋에 대해 가장 좋은 결과를 보인 값을 선택하는 방법입니다.
  • 트레이닝셋이 부족한게 문제라면, cross-validation 방법을 사용하는 것을 고려해볼 수 있습니다. 이는 어떤 하이퍼파라미터가 가장 좋은 결과를 보이는지에 대한 noise를 줄여줍니다.
  • 가장 좋은 결과를 보이는 하이퍼파라미터를 찾았다면, 이를 고정하고 실제 테스트셋로 단 한번의 평가(evaluation)를 진행합니다.
  • Nearest Neighbor는 CIFAR-10을 기준으로 약 40%의 정확도를 보였습니다. 구현하기는 쉽지만 모든 트레이닝셋을 저장해야하며 테스트 이미지에 대해서 평가를 할 때 많은 비용이 듭니다.
  • 마지막으로, raw pixel에 L1 또는 L2 distance를 사용하는것은 부적절하다는것을 알 수 있습니다. 이는 distance가 이미지의 내용적 의미(semantic content)보다는 배경이나 색 분포에 더 관련이 있기 때문입니다.

3장에서는 이러한 문제점들을 해결하는 방법을 다루고 최종적으로 90%의 정확도를 보이는 해법을 제시합니다. 학습이 완료된 이후에는 트레이닝셋을 완전히 폐기(discard)해도 되고, 테스트 이미지를 밀리초 이내에 평가할 수 있게 됩니다.

2.5.2 실전에서 kNN을 적용할 때(Summary: Applying kNN in practice)

kNN을 실전에서 적용할 때는 아래과 같은 과정을 거칩니다. 이미지에 사용하기 보다는, 기준(baseline)으로만 사용하기를 권장합니다.

  1. 데이터 전처리: 데이터의 특징(이미지에서는 하나의 픽셀)들이 평균 0과 단위분산(unit variance)을 가지도록 정규화합니다. 보통 이미지의 픽셀은 균일homogeneous)하고 분포(distribution)가 넓게 펼쳐져있지는 않습니다.
  2. 상당히 고차원의 데이터를 가지고 있다면, PCA라고 불리는 차원감소(dimensionality reduction) 기법 혹은 Random Projection을 사용해보는 것을 권장합니다.
  3. 트레이닝셋을 트레이닝/검증셋으로 임의로 분할합니다. 경험으로 보건데, 대개 70-90% 의 데이터가 트레이닝셋으로 분할됩니다. 이 설정은 하이퍼파라미터의 개수와 이것이 얼마만큼의 영향을 미칠지에 대한 예측에 따라 달라집니다. 예측해야 되는 하이퍼파라미터의 숫자가 많을 경우, 이를 효과적으로 예측하기위해 과할 정도로(err on the side of) 검증셋의 비율을 많이 늘려야 합니다. 만약 검증셋의 크기가 신경 쓰인다면, 트레이닝셋을 fold로 분할해서 cross-validation을 하는것이 가장 좋습니다. 만약 어느 정도의 연산량(computational budget)을 감당할 수 있다면 항상 cross-validation을 사용하는것을 권장합니다.(fold가 많을수록 좋지만, 더 많은 연산량을 요구합니다)
  4. 여러 k값 들과(더 많을수록 좋습니다) 다양한 종류의 distance(L1과 L2가 좋은 선택지입니다)중 최적값을 찾기 위해, 검증데이터로(cross-validation에서는 모든 fold로) kNN 분류기를 학습하고 평가합니다.
  5. kNN 분류기의 작업시간이 너무 오래걸리는 경우, 이를 가속화하기 위해 Approximate Nearest Neighbor 라이브러리(FLANN)를 사용보는 것도 나쁘지 않습니다. 다만, 정확도는 다소 감소할 수 있습니다.
  6. 최적의 하이퍼파라미터를 찾아냈다면, 이를 전체 트레이닝셋(트레이닝데이터+검증데이터)으로 학습시켜야 하는지 트레이닝데이터만 가지고 학습을 시켜야하는지에 대해 궁금할 것입니다. 가령, 트레이닝셋에 검증데이터를 다시 집어넣는다면(fold) 최적의 하이퍼파라미터가 바뀔 수도 있습니다.(데이터의 크기가 더 커지므로) 실전에서는 최종 분류기에 검증데이터를 사용하지 않는것이 더 깔끔하며, 하이퍼파라미터를 측정하면서 검증데이터는 불타버리는것(burned)으로 간주합니다. 테스트셋에 대해 가장 좋은 성능을 보이는 모델에 대해 정확도(accuracy)를 보고하고 그 결과를 데이터에 대한 kNN 분류기의 성능(performance)으로 정의합니다.

2.5.3 읽어보면 좋은것들(Further Reading)

관심이 있다면 향후 읽어볼만한 것들입니다: