본문 바로가기

수업 정리(개인용)/cs231n

CS231n 2017 Lecture 2 : Image Classification

Lecture 1은 Vision 분야에 대한 전반적인 이야기를 소개했다면, 이번 강의는 좀 더 specific하게 classification으로 들어갈 것이다.

 

Image Classification이 어려운 이유는 무엇일까? 사람이 인지하는 방식과 달리 컴퓨터가 보는 건 숫자의 배열일 뿐이다. 저 숫자들을 보고 cat이라는 idea를 얻는 것은 어렵다. 

 

고양이가 가만히 있다 한들, 고양이를 찍은 시점과 광원에 따라서도 픽셀 값들은 달라진다. 심지어 고양이는 가만히 있지도 않는다. 움직이고 모습을 바꾸기도 한다. 때로는 숨어서 일부만 보이기도 한다. 고양이끼리도 나이, 색깔 등에 따라 모양이 천차만별이다. 사람에게는 쉽지만 기계에게는 너무 어려운 문제이다. 

 

Edges를 추출해서 classification 하는 방법이 있지만, 너무 불안정하고 알고리즘도 대상 label에 따라 처음부터 다시 짜줘야 한다(가령 고양이의 특징과 트럭의 특징에 대해 각각의 알고리즘을 만들어야 한다). 그래서 쓰는게 data driven approach이다.

 

일일이 알고리즘을 짜는게 아닌, labeled dataset을 넣어주고 model을 학습시킨다는 아이디어이다.

 

실제로 사용되진 않지만 간단한 알고리즘인 Nearest Neighbor. Train 데이터를 단순히 저장 한 후 test 이미지가 들어오면 가장 가까운 이미지의 label을 붙여준다.

 

NN(Nearest Neighbor)가 CIFAR-10을 분류한 결과이다. 정확도가 높진 않지만, 그래도 결과물을 보면 같은 label끼리 비슷한 모양을 가졌다.

 

이미지 간의 거리는 L1으로 측정하기로 한다. 단순히 원소간 뺄셈을 한 후 절대값을 취해 sum하는 방식이다.

 

이 NN에는 치명적인 단점이 있는데, training은 단순 저장이므로 무척 빠르지만 predicting이 data 크기에 비례해 느려진다는 것이다. 우리는 training이 좀 걸리더라도 predicting이 빠른 모델을 원하는데, 반대로 된 것이다. predict 함수를 보면 for문이 test data의 크기만큼 돌기 때문에 시간 복잡도가 O(N)이다.

 

NN이 이미지를 분류하는 것을 시각화 한 것이다. 어떤 지점의 색을 정할 때 그 지점과 가장 가까운 점의 색을 선택한다. 그런데 이 그림을 자세히 보면, 가운데 주황색 점이 혼자 동떨어져 있다. 이 알고리즘의 목적이 거리가 가까운 이미지들을 군집화 하는 것인데, 어떻게 봐도 초록색의 구역인 곳에 주황색이 칠해져 있으므로 군집화가 잘 되었다고 보기는 힘들다. 왜 이런 일이 발생했을까? 저 지점의 색을 정할 때, 주변에 아무리 많은 초록색 점이 있어도 고려하지 않고 가장 가까운 점이 주황색이므로 주황색을 칠한 것이다. 

 

이러한 결점을 보완한 게 K-Nearest Neighbors(KNN)이다. 가장 가까운 점이 색을 정하는게 아니라, 가장 가까운 K개의 점들을 뽑고 그 중에서 많이 나온 색으로 정한다는 아이디어이다. KNN의 결과를 보면 가운데가 초록색으로 잘 칠해진 것을 알 수 있다. 여기서 흰 여백은 무슨 의미냐는 질문이 들어온다. K개의 점들 중에서 다수인 색을 뽑을 수 없는 경우(투표를 해서 동표가 나온 경우) 하얀색으로 칠했다고 한다. 이 부분을 칠하고 싶다면 랜덤 선택 같은 방식을 사용할 수 있을 것이다. 그냥 NN 방식보다 더 robust하기 때문에 K값은 보통 2 이상을 사용한다.

 

다른 distance를 사용한다는 것은 그 공간에서 다른 geometry나 topology를 가정하는 것이므로 흥미로운 문제라고 한다. 왼쪽은 L1의 관점에서 그린 원이고 오른쪽은 L2의 관점에서 그린 원이다. 왼쪽을 circle이라고 해서 의아할 수 있는데, circle이 결국 한 점에서 거리가 같은 점들을 그려놓은 것이니까 L1 거리 관점에서는 circle이 맞다.

L1 distance는 coordinate system에 의존한다. 위 그림을 보면 단순히 벡터를 회전시켰을 뿐인데 L1 거리가 달라짐을 알 수 있다. 좌표축이 회전한다면 L1 거리도 바뀐다. 반면 L2 distance는 일정할 것이다.  그런 이유로 만약 input vector의 좌표축 각각에 의미가 확실하다면 L1을 쓰는게 나을 것이다. 가령 input vector가 (키, 나이, 몸무게, 학력) 으로 이루어져 있다면 L1을 쓰는게 더 말이 된다. 하지만 이것은 hyperparameter이며 결국 둘 다 써보는게 제일 좋다.

 

Distance를 어떻게 정의하느냐에 따라 KNN을 이미지 말고 다른 data에도 적용할 수 있다. 가령 text classification을 한다고 할 때, 다른 것은 그대로 사용하고 text간의 distance만 새로 정의하면 되는 것이다.

 

다른 distance를 사용했을 때 실제로 어떻게 결과가 변하는지 보여준다. L1을 사용했을 때 decision boundary가 좌표축을 따라 이루지는 경향이 보인다. 이것은 L1이 coordinate system에 의존하기 때문이다. L2는 coordinate system을 별로 신경 쓰지 않는 것처럼 보인다.

 

모델을 구현할 때 K값은 몇으로 할지, 어떤 distance를 쓸지 고민하게 된다. 이런 요인들은 학습을 시킬 수 없기 때문에 우리가 시행착오를 통해 결정해야 한다. 이것들을 hyperparameters라고 부르며, problem-dependent하기 때문에 뭐가 좋다라고 말 할 수 없다.

 

Hyperparameters는 시행착오를 통해 정해야 한다고 했다. 그렇다면 데이터셋을 다 넣은 뒤에 가장 결과가 좋은 값으로 하면 되지 않을까? 하지만 그것은 착각이다. 이렇게 하면 k=1일때 항상 loss가 0이 나온다. 우리는 training의 결과에는 관심이 없고 test 결과에 관심이 있는데, 따라서 train data와 test data를 나누는 게 더 현명한 선택이다.

 

하지만 그렇게 하면 test data에서 좋은 결과가 나오더라도, 완전 처음보는 data에 대해서도 좋은 결과가 나올지 알 수 없다. 그래서 test는 마지막의 마지막으로 아껴두고, validation data를 중간에 끼워서 사용한다. Justin이 논문을 쓸 때에도 test data는 deadline 1주일 전에 사용한다고 한다.

 

과제에서도 다루게 될 Cross-Validation이다. Train data를 fold단위로 나누고, 한 fold 씩을 validation data로 사용한다. Data가 작을땐 유용하나 deep learning에서 많이 사용하지는 않는다고 한다.

 

KNN을 쓰지 않는 이유는 1. Predicting이 느리고 2. 픽셀간의 거리가 중요한 정보가 아니기 때문이다. 저 3개의 사진들은 original과 같은 L2 거리에 있지만 서로가 확연히 다르다.

 

KNN을 안쓰는 또 다른 이유로 curse of dimensionality가 있다. KNN으로 data를 거리가 비슷한 점들끼리 군집화 하려면 그 양이 충분히 많아서 어느정도 빽빽하게 공간을 채우고 있어야 한다. 그런데 빽빽하게 공간을 채우기 위해 필요한 data 수가 차원이 증가함에 따라 지수적으로 증가하는 것이다. 가령 1차원 공간에서는 점이 4개만 있어도 빽빽하지만 2차원 공간에서는 필요한 수가 16개로 늘고, 3차원에서는 64개로 늘어난다.

 

KNN 다음에 배울 linear classifier. Deep learning에서 자주 쓰이는 레고 블럭이고, linear classifier를 잘 이해하는 것이 deep learning에 전반적으로 유용하다고 한다.

 

여기에는 새로운 변수 W가 추가된다. KNN에서는 없던 녀석이다. KNN은 train data를 가지고 있다가 그것을 기반으로 연산해서 결과를 보여줬다면, linear classifier는 train data를 통해 W를 학습시켜 W를 가지고 있고 train data는 가지고 있지 않다. 따라서 더 빠르다. 

 

f라는 함수가 하는 일은 이미지 데이터가 들어오면 그것을 열 벡터로 펼친다음, W와 곱한 뒤, b를 더해주는 것이다. 

 

연산의 결과는 score를 의미하고, 높은 score에 해당하는 label을 뱉는다. b는 bias, 편향을 의미한다. W는 데이터와 곱연산을 하기 때문에 데이터에 의존적이지만, b는 덧셈 연산을 하기 때문에 데이터와는 별개로 score에 영향을 끼친다. 가령 고양이와 개의 이미지 데이터가 있는데, 고양이가 80%의 비율을 차지한다고 하자. 그렇다면 고양이 score에 더해지는 b값이 올라갈 것이다. 이처럼 b는 데이터의 편향을 학습할 수 있다.

 

CIFAR-10으로 linear classifier를 학습시킨 후, w를 visualization 한 결과이다. plane에 해당하는 W(W_plane)는 plane을 닮아있고, car에 해당하는 W(W_car)는 car를 닮아있다. 왜 W가 데이터를 닮는지에 대한 설명은 없어서 따로 알아보고 생각도 해본 결론은,

 

1. 우선 W_car는 car와 곱해진 값이 최대가 되고, 다른 데이터, 이를테면 dog와 곱해진 값은 최소가 되도록 학습했을 것이다.

 

2. 그렇기 때문에 W_car를 reshape해서 위와 같이 하나의 이미지의 관점으로 봤을때, car의 픽셀 값이 높은 부분에서 W_car의 픽셀 값도 높아지고, 낮은 부분에서 낮아지는 방향으로 학습할 것이다. 그래야 곱해서 값이 크게 나오기 때문이다. 물론 모든 부분에서 W_car의 픽셀 값이 높다면 car의 score가 더 커지겠지만, 그러면 dog이랑 곱했을 때도 score가 커진다. 이런 이유로, 전체적인 픽셀의 분포가, 즉 표현해 내는 이미지의 shape이 비슷할 수 밖에 없다.

 

3. 다른 관점에서 보자면 W_car와 car는 벡터이고 둘이 내적 연산을 하는데, 그렇다면 두 벡터 사이의 각이 0에 가까울 수록 내적 값이 커질 것이다. 또한 그래야만 car가 아닌 dog 벡터와 내적했을때 값을 줄일 수 있을 것이다. 따라서 W_car와 car 벡터는 방향이 비슷할 수 밖에 없다.

 

여기서 linear classifier의 단점이 드러난다. W_car가 학습한 car의 모양은 어떤 모양일까? 세상에 저런 차는 존재하지 않는다. W_car는 car 전체를 혼자서 분류해야 하기 때문에, 데이터 전체에 있는 car들의 평균적인 모습을 하게 된다. W_horse를 보면 머리가 양 쪽에 두 개 달린 모습을 하고 있는데, 이것은 왼쪽을 보고 있는 말과 오른쪽을 보고있는 말을 동시에 닮으려고 학습한 결과이다. 이것이 단층 네트워크의 한계이다.

 

결국 이 linear classifier가 하는 일은, 데이터들을 공간 상의 점으로 표현했을 때, 하나의 class와 다른 class를 분리하는 문제를 푸는 것이다.

 

그런데 문제는 decision boundary가 선형이기 때문에 위와 같은 데이터는 분류할 수가 없다. 가장 왼쪽의 그림은 0 이상의 값을 가진 픽셀 수를 홀과 짝으로 나누어서 색칠해 놓은 것이다. 두 그룹을 나누는 선을 그릴 수가 없다. 이런 픽셀 수가 홀수인지 짝수인지의 문제는 더 확장될 수 있는데, 가령 이미지 안에 고양이가 홀수 마리 있는지 짝수 마리 있는지 같은 것들이 linear classifier가 상당히 고전하는 부분이다.

 

오른쪽 그림을 multimodal data의 예시로 들었는데, 이처럼 같은 class의 data가 서로 다른 공간에 있을 때, 이것을 분리하는 선을 그릴 수가 없다. 위에서 W_horse가 오른쪽을 보고 있는 말 사진과 왼쪽을 보고있는 말 사진을 동시에 학습하려 하다 실패한 것을 예시로 들 수 있다.

 

cat, car, frog의 score를 보면, W_car는 훌륭하게 역할을 해냈고 W_cat은 그에 못미치며, W_frog은 최악의 예측을 한 것을 알 수 있다. 하지만 우리가 좋은 W를 선택하기 위해서는 좋은 W와 나쁜 W를 구분해내고 나아가서 goodness를 수치로 나타낼 수 있어야 한다. Lecture 3에서는 loss function과 optimization에 대해 배울 것이다.