numpy를 이용한 텐서 사용이 익숙하지 않는 사람들을 위한 튜토리얼
Image Classification
이미지를 볼 때 컴퓨터는 거대한 숫자 그리드로 표현한다. 그것을 통해 컴퓨터는 미리 정의된 class 레이블 중 하나를 지정한다.
이 이미지의 경우 800x600 픽셀로 이루어져 있다. 또한, 3채널 즉, RGB로 표현되기 때문에 800x600x3 으로 표현할 수 있다.
컴퓨터가 이 숫자 그리드를 보고 고양이라고 추출하는 것은 매우 어려운 일이다. 컴퓨터가 실제로 보고 있는 픽셀 값과 이미지가 가지는 의미론적 값에는 간격이 존재한다. 이를semantic gap
이라 한다.
- image deformation
같은 이미지라도 바라보는 시선을 변경할 수 있고, 조명의 변화나, 자세, 생김새, 나이, 색 등의 변화로 인해 형태가 달라질 수도 있다.
또한, 고양이의 색깔과 배경의 색이 유사하게 보이는 background clutter 문제가 발생할 수도 있다.
따라서 우리의 알고리즘은 이러한 다양성이나 변화에 대해 robust(강인)해야 한다.
data-driven approach
방법은 이미지와 레이블을 입력하여 값을 출력한 다음, 출력값을 다시 예측이라는 또 다른 함수 모델에 입력하여 예측한다.
- Data-Driven Approach
- 수많은 이미지와 레이블에 대한 데이터셋을 수집한다.
- 데이터를 이용하여 분류기 classifier을 train시키기 위해 머신러닝을 사용한다.
- 새로운 이미지를 분류기에 집어넣어 평가를 진행한다.
이를 통해 좀 더 정확한 예측을 진행할 수 있게 되었다.
Nearest Neighbor
분류기 중 가장 단순한 방식이 Nearest Neighbor
이다. 이는 비어있는 공간이나 예측해야할 픽셀 주변의 값들을 빌려와 채워넣는 것을 말한다.
이 방법은 train 단계에서 모든 데이터와 레이블을 학습한다. 그 후 예측 단계에서 test이미지와 가장 유사한 train 이미지를 찾아 그것의 레이블을 출력함으로써 예측한다.
작은 크기의 데이터셋으로 학습하고자 할 때는 CIFAR-10이라는 데이터셋을 사용한다. 이는 class( airplane, cat, dog… ) 개수가 10개인 데이터셋을 말한다. 5만개의 train 이미지와 1만개의 test 이미지를 각 class에 동일하게 분할하여 제공한다.
test 이미지와 train 이미지가 얼마나 비슷한지 평가를 할 때는 L1 distance 를 사용하는데, 이는 맨허튼 거리라고도 불린다. 이것은 두 이미지를 비교하기 위한 아주 간단하고 쉬운 방법이다.
이미지의 개별 픽셀을 비교하는 방식으로, 각 픽셀을 비교한 후 픽셀 값을 다 더해서 출력한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import numpy as np
class NearestNeighbor(object):
def __init__(self):
pass
def train(self, X, y):
# Xtr = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows becomes 50000 x 3072
# 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 range(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
이것은 Nearest Neighbor classifier의 python 코드다.
Xtr 은 모든 이미지를 1 dimension 으로 flatten 한 image data 이고, ytr 은 모든 이미지에 대한 labe data 이다.
train 함수는 모든 데이터를 기억한다.
그 후 L1 distance 함수를 사용하여 test 이미지를 각 train 데이터셋과 비교하고 train 셋에서 test 이미지와 가장 유사한 이미지를 찾는다.
이 때 데이터셋의 크기가 증가하더라도 train은 모든 데이터를 복사하면 되기 때문에 걸리는 시간이 일정하다. 하지만 predict 함수에서 test 이미지를 데이터셋의 모든 train 이미지와 각각을 모두 비교해야 하기 때문에 계산 시간이 증가한다.
위의 그림에서 점들은 train 데이터를 의미하고, 점의 색상은 class를 나타낸다. train 데이터에서 전체 평명의 각 픽셀에 대해 가장 가까운 점이 무엇인지 계산한 후 클래스에 해당하는 공간 즉,배경을 칠했다.
사진을 보면 색깔 중간중간에 다른 색의 점이 존재한다. 실제로는 주변색과 같아야 하지만 잘못 판단된 것이다. 이 점으로 인해 꽤 큰 공간이 오류가 발생한다.
K-Nearest Neighbors
그래서 K-nearest neighbors 방식으로 업그레이드하여, 가장 가까운 1개의 점이 아닌 점 K개를 찾아 각 이웃 중에서 더 많은 class에 해당하는 것으로 결정된다.
이와 같은 방법을 사용할 때 경계를 부드럽게 하고 더 나은 결과를 가져올 수 있게 된다. 흰색은 주변에 이웃이 없음을 나타내기 위해 흰색으로 표시한 것이다. 이는 간단한 예제를 사용했기 때문에 점의 개수가 작아 나타낼수 있지만, 실제 이미지에서는 수많은 점들이 존재하기 때문에 흰색이 표시되지 않을 것이다.
k-nearest neighbor을 사용할 때 점의 개수를 조밀하게 하기 위해 더 많은 데이터셋을 사용하면 되지만 성능이 좋아지지는 않는다.
k-nearest neighbor classifier은 정확도가 다소 떨어지지만, 그럼에도 정확도를 약간 향상시키는 두 가지 방법이 있다.
- k 값을 증가시킨다. -> 하지만 K를 아무리 증가시켜도 한계가 존재한다.
- 정확도를 높이기 위해 픽셀 사이의 절대값의 합을 취하는 L1 방식을 L2로 변경. -> 두 점의 제곱합의 제곱근, L2 방법을 사용하는 것이다. 더 나은 결과를 가져온다고는 할 수 없으나 더 부드러운 값을 가져올 순 있을 것이다.
하지만, 매우 느리다는 단점과 L1과 같이 이미지 간의 거리를 측정하는 것이 좋은 방법이 아니기 때문에 k-nearest neighbor 방법은 이미지 분류에 사용되지 않는다
Hyperparameters
위와 같이 K값이나 거리 측정법을 사용자가 변화시킬 수 있다. train에서 학습시키는 것이 아니라 사용자가 미리 선택해서 입력시키는 것을 hyperparameters라고 한다.
어느 hyperparameters가 가장 완벽한 분류기인지 선택하기 위한 방법으로는
- 최고의 정확도 또는 최고의 성능 기준 이 방법은 사실 좋지 않다. 예를 들어 nearest neighbor의 경우 k=1로 설정하면 항상 train 데이터를 완벽하게 분류한다. 따라서 이 지표를 사용할 경우 항상 K=1이 사용된다. 하지만 앞서 봤듯이 K>1일 경우가 더 나은 성능을 보인다.
- 전체 데이터셋을 이를 train과 test 데이터로 나눈다. 이 또한 합리적이지 않다. 왜냐하면 우리가 만들고자 하는 알고리즘은 수많은 변화에도 강인해서 모든 곳에 적용할 수 있어야 한다. 하지만 train에 있던 데이터셋을 test로 사용하게 되면 새로운 이미지에 대한 수행을 잘 하지 못한다.
- 전체 데이터셋을 train, 검증셋(validation), test와 같이 3개의 다른 셋으로 나눈다. 위 두가지보다는 좋은 방법이다. train에서 알고리즘을 훈련시키고, 검증 셋에서 알고리즘을 평가한 후, 검증셋에서 가장 잘 수행되는 hyperparameters를 선택한다. 그것을 통해 test 셋에 실행시킨다.
Cross-Validation
교차 검증이라는 hyperparameters를 설정하는 데 사용되는 방법이 있다. 먼저 데이터셋을 train과 test로 나눈다. 그 후 train 데이터셋을 k개로 분할한다. 분할된 k를 1개씩 검증셋으로 사용하여 train을 k번 훈련한다.
이 방법을 통해 얻은 최적의 hyperparameters를 test셋에 적용한다.
대규모 모델이 아니거나 계산 비용이 매우 많지 않은 경우에 자주 사용된다.
이때 k가 너무 커도 과적합 경향을 보이기 때문에, 어느 k가 가장 정확도가 높은지 판단하는 것도 중요하다. 그래프를 볼 때, k가 7일 때 가장 좋은 성능을 보인다.
Summary
- image classification에서는 이미지와 레이블의 training set과 예측 label의 test set을 가진다.
- k-nearest neighbor classifier은 가까운 train image에 대한 레이블을 가져와 예측한다.
- validation set을 이용하여 hyperparameters를 선정할 때, test set은 1번만 실행해야 한다.
Linear Classification
linear classifier에는 x라는 input 데이터와 W라는 매개변수 또는 가중치 weight가 존재하고, 이 두 개를 받는 함수가 존재한다.
linear classifier 에서의 함수 f(x,w) 는 W와 x를 곱하여 Wx를 만든다.
f(x,W) = W*x
이 때, x는 32x32x3의 image이다. 이를 reshape해서 3072x1로 만든다. 그리고, output은 10가지 class에 대한 score를 출력해야 되기 때문에 10x1 이다. 그렇기에 W는 10x3072가 되어야 한다.
이때, train 데이터와 상호 작용하지 않는 편향 벡터 b를 추가할 수 있다.
좀 더 세세하게 구조를 살펴보자.
이와 같이 2x2 image가 있고, 3개의 class가 존재한다고 가정해보자. linear classification 이 작동하기 위해서는 2x2를 열 행렬인 4x4로 만들어야 한다. 그렇다면 w는 3x4이 된다. 그리고, 편향 벡터 b를 더한다.
linear classifier 의 경우 각 이미지를 고차원에서의 한 점으로 판단할 수 있다.
linear classifier 는 linear decision boundary 를 통해 class를 구분한다.
처음에는 decision boundary 를 무작위로 설정하고 train을 통해 적절한 경계를 설정할 수 있다.
하지만 적절한 decision boundary 가 비선형인 경우나, 점들이 비규칙적일 경우 올바른 선을 결정할 수 없기 때문에 문제가 발생한다.
decision boundary는 kooc 강의 - 머신러닝 학습 개론을 통해 배운 것을 참고하는 것을 추천한다.
Refernece
- https://cs231n.github.io/classification/
- https://cs231n.github.io/linear-classify/
- https://velog.io/@leejaejun/AIFFEL-DeepML-CS231n-2%EA%B0%95-Image-Classification-1