페이지

2018년 3월 27일 화요일

laradock on mac


mysql bash -> hostname -I

.env DB_HOST SETTING

php artisan make:auth



php artisan migrate

CHAPTER12 다중 계층에서의 오차의 역전파

다음은 3개 계층(입력 계층, 은닉 계층, 출력 계층)으로 구성된 간단한 신경망입니다.


 입력          입력계층               은닉계층            출력계층          출력


--->             (1)  --->               (1)     ------>         (1)     ---->


오른쪽 끝의 최종 출력 계층부터 보겠습니다. 출력 계층의 오차를 이용해 출력 계층의 연결된 노드들의 가중치를 업데이트하게 됩니다. 이를 조금 더 일반화해보면 출력 계층의 오차는 e(output)으로, 여기에서는 가중치 who로 표현할 수 있습니다. 물론 e(output)은 가중치 비율에 따라 나뉘어 전달될 것입니다.
이렇게 시각화해봄으로써우리는 새로 추가된 계층에 대해 어떻게 하면 좋을지 감을 잡을 수 있을 것 같습니다. 즉 은닉 계층의 노드으 ㅣ출력 값과 관련된 오차를 e(hidden)이라고 하고 이 오차를 입력 계층과 은닉계층을 연결하는 가중치 wih에 대해 그 비율에 맞게 나누어 주면 되는 것입니다. 다음 그림에 이를 표현햅습니다.

만약 계층이 더 많이 있다면 이처럼 최종 출력 꼐층으로부터 역방향으로 동일한 과정을 반복하면 될 것입니다. 이처럼 오차 관련 정보가 뒤쪽으로 계속해서 전파되므로 역전파라고 부르는 것입니다.

출력 계층의 경우에는 출력 계층의 노드의 결과 값의 오차인 e(output)을 사용했지만, 은닉 계층의 노드에서 e(hidden)은 어떤 오차 값으 ㄹ사용하면 될까요? 만약 이런 의문이 들었다면 지금까지의 내용을 제대로 이해하고 있는 것이라고 보룻 었을 것 같습니다. 중간에 위치하는 은닉 계층은 사실 명백한 오차를 가지고 있지 않기 때문입니다. 앞에서 배웠던 내요을 다시 상기해볼까요? 은닉 계층의 각각의 노드는 직전 계층으로부터 입력을 받아 적절한 출력값을 다음 계층으로 전달하게 됩니다. 이때 이 출력 값이란 직전 계층의 입력 값에 가중치를 적용한 다음이를 모두 더한 값에 활성화 함수를 적용한 값입니다. 그럼 도대체 어떻게 오차를 구해낼 수 있는 것일까요?

은닉 노드에 대해서는 목표로 하는 출력 값이 없습니다. 오직 최종 출려 ㄱ계층의 노드만이 학습데이터로부터 얻은 실제값, 즉 목표로 하는 출력 값을 가지고 있다는 것이죠. 앞으로 그림을 보면 다시 한번 생각해보기 바랍니다. 은닉 계층의 첫 번째 노드는 2개의 연결 노드를 가지는데 이들은 출력 계층의 2개의 노드로 각각 연결됩니다. 그리고 우리는 출력 계층의 노드에서의 오차를 이 연결 노드에 나누어줄 수 있다는 점을 알고 있습니다. 이 말은 결국 중간의 은닉 계층의 노드로부터 오는 2개의 연결 노드 각각에 대해 어떤 오차가 존재한다느 말입니다. 우리는 이러한 2개의 연결노드의 오차를 재조합함으로써 은닉 계층의 노드의 에러로 사용할 수 있습니다. 즉 중간 계층의 노드는 목표로 하는 출력 값을 가지지 않기 때문에 이처럼 차선의 방법을 사용하는 것입니다. 이와 같은 아이디어를 다음 그림에 표현해봤습니다.

그림을 보면 좀 더 명확해질 것입니다. 우리에게 필요한 것은 은닉 계층의 노드들에 대한 오차입니다. 이 오차를 이용해 직전 계층과의 연결 노드에 존재하는 가중치를 업데이트할 것이기 때문입니다. 은닉 계층의 노드의 오차를 e(hidden)이라고 하겠습니다. 아직까지 우리는 실제 이 오차의 값이 얼마인지에 대한 답을 가지고 있지 않습니다. 그 이유는 (반복해서 말하지만) 학습 데이터로부터 얻을 수 있는 목표 값은 (으닉 계층이 아니라) 오직 최종 출력 계층의 노드에 대한 것이므로, 으닉 계층에서의 오차를 목표 값과 실제 값 간의 차이라고 정의할 수 없기 때문입니다.

학습 데이터들은 최종 노드의 결과 값이 가져야 할 목표 값에 대해서만 말해줍니다. 이 외의 노드들의 결과 값에 대해서는 아무것도 말해주지 않습니다. 이것이 이 퍼즐의 핵심입니다.

우리는 앞에서 본 대로 오직의 역전파를 이용해 연결 노드에 대해 나뉜 오차를 재조합해야 합니다. 따라서 은닉계층의 첫 번째 노드의 오차는 이 은닉계층에서 다음 계층으로 연결되는 모든 연결 노드에 있는 나뉜 오차들의 합이 됩니다. 앞의 그림에서 보면 e(output.1)은 w11과 연결되어 있으면 e(output2)는 w12와 연결되어 있습니다. 이를 수식으로 써보면 다음과 같습니다.

e(hidden1) = 연결 노드 w11, w12로 나뉘어 전달되는 오차의 합
               = e(output1) * w11 /(w11 + w21) + e(output2) * w12/(w12 + w22)

수식으로만 보면 이해가 어려울 수 있으니 실제 숫자를 대입해서 보겠습니다. 다음 그림은 오차가 역전파하는 과정을 실제 숫자와 함께 표현한 것입니다.

앞의 그림에서 출력 계층의 첫 번째 노드의 오차 0.8은 이와 연결된 2개의 가중치 2.0과 3.0에 비례해 각각 0.32와 0.48로 나뉘어 전달된다는 것을 확인할 수 있습니다. 출력 계층의 두 번째 노드의 오차 0.5는 연결된 2개의 가중치 1.0과 4.0에 비례해 각각 0.1과 0.4로 나뉩니다. 따라서 은닉 계층의 첫 번째 노드의 오차는 0.32와 0.1의 합인 0.42가 되고 두번 째 노드의 오차는 0.48과 0.4의 합인 0.88이 되는 것입니다.
다음 그림은 한 단계 더 나아가 은닉 계층의 오차 값을 이용해 입력 계층이 오차를 구하는 것을 보여줍니다.

핵심정리
- 인공 신경망에서 학습이란 연결 노드의 가중치를 업데이트하는 과정을 의미합니다. 가중치의 업데이트는 오차에 의해 주도되는데, 오차는 학습데이터로부터 주어진 정답과 출력값 간의 차이를 의미합니다.
- 출력 노드의 오차는 실제 값(정답)과 출력 값 사이의 차이를 의미합니다.
- 중간 계층의 존재하는 노드들의 오차는 명백하지 않습니다. 한 가지 접근 방법은 출력 계층의 노드들의 오차를 이와 연결된 가중치의 크기에 비례해 누눠서 역전파하고 이를 재조합하는 방법입니다.




2018년 3월 26일 월요일

CHAPTER 11 여러 노드에서의 오차의 역전파

이번에는 2개의 출력 노드를 가지는 그림을 보겠습니다.
                                                              결과값의 오차


i1  ->  계층1(1)  -> (w1.1)->  계층2(1)  -> o1         e1
                     -> (w1.2)
         
                     -> (w1.2)
i2  ->  계층1(2) ->  (w2.2) ->  계층2(2)  ->o2         e2

2개의 출력 노드 모두 오차를 가질 수 있습니다. 특히 우리가 아직 네트워크를 학습시키지 않은 경우에는 거으 ㅣ무조건 오차를 가지고 있겠죠. 그러므로 2개의 오차 모두 가중치를 어떻게 업데이트해야 할지에 대한 정보를 줘야 합니다. 우리는 앞에서 했던 대로 출력 노드의오차를 앞 단의 각 가중치에 비례해 나누어 주는 접근 방법을 활용할 수 있습니다.

출력노드가 여러 개라고 해서 변하는 것은 아무것도 없습니다. 그저 첫 번째 출력 노드에서 했던 작업을 두 번째 출력 노드에서 동일하게 반복하면 되는 것입니ㅏㄷ. 어떻게 이렇게 간단할 수 있냐고요? 그 이유는 하나의 출력 노드로의 연결은 다른 출력 노드로의 연결과 완전 별개이기 때문입니다. 각각의 연결 간에 는 전혀 의존 관계가 존재하지 않는다느 ㄴ말입니다.

앞의 그림을 다시 한번 보면 첫 번째 출력 노드의 오차를 e1이라고 표기했습니다. 이 초차는 학습데이터 t1에 의해 제공된 실제 값과 우리가 계산한 ㅜㅊㄹ력 값 o1사이의 차이를 의미합니다. 다시 말해 e1 = t1 -01입니다. 그리고 두 번째 출력 노드에서의 오차는 e2라고 표기해습니다.

그림을 자세히 보면 e1은 w11과 w21의 가중치의 값에 비례해서 나눠어 연결된 노드로 전달됩니다. 이와 유사하게 e2는 w12와 w22의 값에 비례해 나뉩니다.

좀 더 이해가 쉽도록 이를 수식으로 표현해 보겠습니다. 오차 e1은 w11과 w21의 업데이트에 영향을 주게 됩니다. 그러므로 w11을 업데이트 하기 위해 사용되는 e1의 일부는 다음과 같이 표현 가능합니다.

w11 / (w11 + w21)

그리고 w21을 업데이트 하기 위해 사용되는 e1의 일부는 다음과 같이 표현할 수 있습니다.

w21 /( w21 + w11)

이러한 수식의 의미는 결국 무엇일까요? 오차 e1은 나뉘어 전달될 때, 작은 가중치를 가지는 연결 노드보다 큰 가중치를 가지는 연결 노드에 더 많이 전달된다는 것입니다.
만약 w11 = 6이고 w21 = 3이라는 값을 가진다고 하면 w11은 w21보다2배 큽니다. 이때 w11을 업데이트하기 위해 전달되는 오차 e1의 일부는 6 / (6 +3) =6 /9 = 2/3 가 됩니다. 그럼 1/3이 남는데요. 실제로 오차 e1에서 w21을 업데이트 하기 위해 전달되는 부분은 3/ (6 +3) = 3/ 9 = 1/3입니다.

만약 가중치가 같다면 1/2씩 전달되게 될 것입니다. 예를 들어 w11 = 4, w21 = 4라면 약쪽으로 나눠어 전달되는 오차는 2개 모두 4 /( 4+4) = 4/8 = 1/2이 될 것 입니다.

지금까지 공부한 내용을 정리해보겠ㅅ브니다. 우리는 오차를 이용해서 네트워크 내의 매개변수들의 값(가중치)을 조정해나간다는 사실을 알게 되었습니다. 최종 출력 계층으로부터 그 직전 계층으로 가는 연결 노드으 ㅣ가중치를 업데이트하는 방식을 살펴봤는데 여러개의 출력 노드가 있는 경우에도 그 각각으 ㅣ출력노드를 개별적으로 처리하면 될 뿐, 복잡해질 것이 전혀 없다는 사실을 알게 되었습니다.
그렇다면 2개 보다 더 많은 꼐층을 가지는 신경망에서는 어떻게 하면 될까요? 다시 말해 최종 출력 계층에 인접하는 계층이 아니라, 멀리 떨어져 있는 꼐층과 관련된 가중치는 어떻게 업데이트를 해야 할 까요? 이데 대해서는 다음장에서 살펴보겠습니다.


CHAPTER 10 여러 노드에서 가중치 학습하기

이 책 앞부분에서 선형함수의 매개변수인 기울기의 값을 조정해감으로써 선형분류자를 업데이트해나갔던 것을 기억할 겁니다. 그때 오차라는 개념을 공부한 바 있습니다.
오차는 예측 값고 ㅏ실제 값(정담)과의 차이를 의미하는데, 우리는 이 오차에 기반을 두고선형 분류자를 정교화해나갔습니다. 오차와 기울기의 관계가 매우 단순했기 때문에 이를 조정해가는 ㅓㄳ은 별로 어려운 과정은 아니였습니ㅏㄷ.
그렇다면 여러 개의 노드가 결과 값과 오차에 영향을 주는 경우에는 가중치를 어떻게 업데이트해야 할까요? 이를 그림으로 표현하면 다음과 같습니다.

                     <---- p="">(1) ->W1.1(3.0)->   (1)  -> 결과 값의 오차
(2) -> W2.1(1.0) ->
                      <---- p="">
결과 노드에 영향을 주는 노드가 한 개인 경우에는 월씬 간단했지만, 이와 같이 2개의 노드를 가지는 경우에는 결과 값의 오차를 어떻게 활용해야 할까요?

오차를 하나의 가중치 업데이트에만 사용하는 것은 합리적이지 못합니다. 나머지 하나의 가중치를 무시하는 것이기 때문이죠. 오차가 발생하는데에는 이 다른 연결 노드분도 공헌을 했다는 사실을 무시할 수 없다는 말입니다.
물론 수많으 연결 중에 단 하나의 연결만 해당 오차의 발생에 영향을 미치느느 경우가 있을 수는 있겠지만, 이런 가능성은 매우 낮습니다. 설령 우리가 이리미 정확한 값을 가지게 된 가중치의 값을 변경해 상황을 악화시키게 된다고 하더라도 이런상황은 다음번의 업데이트를 통해 개선될 것입니다.

한가지 방법은 다음 그리과 같이 모든 연결된 노드에 대해 오차를 균일하게 나누어 분배하는 것입니다.

                     <----1 p="">(1) ->W1.1(3.0)->   (1)  -> 결과 값의 오차
(2) -> W2.1(1.0) ->
                      <----1 p="">
또 다른 방법은 오차를 나누어 분배하지만 차별을 두는 것인데, 더 큰 가중치를 가지는 연결에 더 큰 오차를 분배하는 것입니다. 더 큰 가중치를 가진다는 것은 그만큼 오차의 형성에 더 큰 영향을 줬다는 의미이기 때문입니다. 이를 그림으로 표현하면 다음과 같습니다.

                     <----3 p="">(1) ->W1.1(3.0)->   (1)  -> 결과 값의 오차
(2) -> W2.1(1.0) ->
                      <----1 p="">
이 그림에서 2개의 노드는 한 노드에 서로 다른 가눙치로 영햐응ㄹ 줬습니다. 각 연결의 가중치는 3.0과 1.0 입니다. 만약 오차르 ㄹ이들 가중치에 비례해 나눠준다면 오차의 3/4이 위쪽 가중치를 업데이트하는 데에 사용되고 나머지 1/4이 아래쪽으 ㅣ가중치를 업데이트하는데에 사용될 것입니다.

이방법은 노드가 더 많아지더라도 동일하게 적용 가능합니다. 만약 100개의 노드가 다음 계층의 노드에 연결되어 있다고 한다면 우리는 오차를 100개의 연결에 나누어주되 그 값은 각각의 가중치에 따라, 즉 각각의 견결이 오차에 영향을 주는 정도에 비례해서 전달하면 되는 것입니다.

따라서 우리는 가중치를 두 가지 방법을 ㅗ활용한다는 점을 확인할 수 있습니다. 우선 앞에서 여러 사례를 살펴본 바오 ㅏ같이 신호를 하나의 계층에서 다음 계층으로 전파하는데에 가중치를 이용합니다. 두 번째로 오차를 하나의 계층에서 직전 계층으로, 즉 역으로 전파하는 데에도 가중치를 이요합니다. 첫 번째 방식은 앞에서 이비본 전파법이고 두 번째 방법을 역전파(backprogagation)라고 부릅니다.

만약 출력 계층의 2개의 노드를 가진다면 우리는 두 번째 노드에서 대해서도 동일한 작업을 하게 됩니다. 두 번째 노드의 결과 값 역시 그 자체의 오차를 가지므로 연결되는 노드에 대해 이 오차를 분배해주면 되는 것입니다. 다음 장에서 이에 대해 상세히 살펴보게습니다.

CHAPTER 8 머신러닝의 다양한 문제점 해결하기

이 장에서는 머신러닝 시스템의 성능이 잘 나오지 않을 때 고려할 만한 사항을 살펴보겠습니다. 머신러닝으로 문제를 해결한다는 것은 데이터에 맞는 모델, 적립한 손실함수, 최적화 방법, 평가 방버을 찾는 과정입니다. 처음에서 성능이 잘 나오지 않더라도 너무 실망히지 마시고 개선 방안을 찾아내면 됩니다.

8.1 모델 문제
지금부터 8.2절 '데이터 문제'에서 다룰 데이터 처리, 8.3절 '속도 문제  '에서 다룰 속도 향상 외에 모델 자체에서 비롯된 문제를 해결해서 모텔의 성능을 향상하는 방법을 크게 둘로 나눠 설명합니다. 첫 번째는 학습할 때는 잘 동작했는데 실제로 사용하니 성능이 생각보다 잘 나오지 않는 과학습(오버피팅, 과적합, 과적응) 문제를 해결하는 방안을 알아보고, 두 번째는 데이터에 적합한 모델을 효과적으로 찾는 방법에 대해 알아보겠습니다.

8.1.1 과학습
머신러닝 시스템 시스템을 기존 데이터로 학습시킨 후 평가했을 때는 좋은 성능이 나와 학습이 잘되었다고 판단했는데, 새로운 데이터에서 예상대로 성능이 나오지 않는 경우의 원인은 대부분 과 학습 때문입니다. 과학습은 말 그대로 모델이 과하게 학습 데이터에 집중한 나머지 필요 이상으로 패턴을 학습한 경우입니다. 다음 그림과 같은 경우를 들 수 있습니다.

그림 8-1 과학습의 예. 거시적으로는 선형 패턴(점선으로 표시)을 가지는 데이터인데 필요 이상으로 복잡하게 학습한 경우(실선으로 표시)

[그림 8-1]은 과학습의 한 예입니다. 그래프에서 x로 표시된 점은 관착된 데이터입니다. 얼핏 봐도 데이터가 왼쪽 아래부터 오른쪽 위까지의 선형 패턴을 가집니다. 이 데이터를 기반으로 X값이 7일 때의 Y 값을 예측한다면 11 정도가 될 겁니다. 그런데 전체적인 패턴을 무시한 채 학습 데이터를 완벽하게 예측하는 것에만 중점을 두어 모든 점을 지나는  선을 모델로 만들게 되었습니다. 그 결과 실선과 같은 과학습된 모델을 가지게되고 X값이 7일 때의 Y값을 제대로 예측할 수 없게 된 겁니다.

그렇다면 이문제를 어떻게 해결해야 할까요? 그리고 이런 현상이 일어날지 어떻게 미리 알 수 있을까요? 2.1.5.2절 '정규화'와 2.4.1절 '모델의 일반화 특성 평가'에서 이론상으로 다룬 바 있습니다. 이제부터 과학습을 해결하는 실용적인 방법을 알아보겠습니다.

8.1.1.1 학습- 평가 데이터 나누기

과학습 문제를 발견하는 가장 효과적인 방법은 전체 데이터의 일부분만으로 모델을 학습시키고 나머지 데이터를 이용해 모델을 평가해서 얼마나 데이터의 일반적인 패턴을 잘 학습하는지 판단 하는 겁니다. 일반적인 패턴을 잘 파악하지 못하는 모델은 그렇지 않은 모델에 비해 학습용 데이터에서는 좋은 성능을 보이지만, 평가용 데이터에서는 성능이 잘 나오지 않는 현상을 보이게 됩니다. 자세한 내용은 2.4.1절 '모델의 일반화 특성 평가'를 참조하세요

8.1.1.2 정규화
모델의 정규화는 바로 이런 과학습 문제를 해결하기위해 등장했습니다. 정규화는 데이터를 설명할 수 있는 가장 간단한 가정만을 사용한다는 '오컴의 면도날 가정'을 이용하여 과학습을 막습니다. [그림 8-1]을 보면 데이터의 패턴을 설명하기에는 점선이 실선으로 표시된 복잡한 모델보다 더 간단합니다. 이렇게 데이터의 패턴을 복수의 가정으로 설명할 때는 데이터의 패턴에서 심하게 벗어나지 않으면 되도록 간단한 가정을 사용하는 것이 좋습니다.
2.1.5.2절 '정규화'에서 설명했듯이 '데이터의 패턴에서 너무 벗어나지 않는 것'과 '더 간단한 모델을 사용하는 것'의 균형은 정규화 파라미터로 결정합니다. 그렇다면 그 파라미터를 어떻게 결정해야 할 까요? 2.4.1절 '모델의 일반화 특성 평가'에서 설명한 것과 같이 정규화 파라미터를 결정하는 데이터셋을 따로 빼놓고 학습하는 방법을 많이 사용합니다.
정규화 파라미터가 실제로 어떻게 영향을 미치는지 간단한 예제를 통해 알아보겠습니다. 사이킷런의 linear_model.Ridge 클래스는 정규화 파라미터를 지원하는 선형 회귀 클래스입니다. 클래스의 원형은 다음과 같습니다.

class sklearn.linear_model.Ridge(alpha=1.0, fit_intercept=True, normalize=False, copy_X=True, max_iter=None, tol=0.001, solver='auto', random_State=None)

여기서 정규화와 관련된 파라미터는 alpha인테, 값이 클수록 정규화의 강도가 더욱 강해집니다.
실제로 어떻게 문제가 발생하는지 시각적으로 보여드리기 위해 2차 함수를 따르는 데이터를 만든 후 10차 함수 형태의 모델을 사용하는 경우를 알아보겠습니다(현샐에서는 데이터가 몇 차원 함수를 따르는지 알 수 없으므로 임의로 높은 차원을 가정합니다). 여기서는 구현보다는 어떻게 되는지 설명에 집중하기 위해 자세한 코드는 생략하도록 하겠습니다.

데이터는 다음과 같은 가우스 분포도 생성되었습니다.
y = x*x -2x -1 + 노이즈

그리고 우리 모델은 10차 함수 형태까지 학습할 수 있는 능력을 가진 10차 다항함수를 사용했습니다. 수식으로 나타내면 학습과정에서 상수 부분까지 모두 11개의 파라미터(w10, w9,...w0)를 학습하게 됩니다.

모델이 표현할 수 있는 한계(10차 함수)가 실제 데이터(2차 함수)보다 훨씬 높죠? 이런 경우에 과학습이 심하게 발생할 수 있습니다. 과학습이 나타나는 현상을 실제로 ㄹㄴ덤한 데이터를 만들고 학습해서 시각화해보겠습니다. 먼저 정규화 없이 그냥 모델을 단순하게 학습시킨 결과를 살펴보겠습니다.

[그림 8-2]를 보면 단순히 오목하게 생긴 2차 함수의 패턴을 학습하면 되는데 모델이 필요 이상으로 복잡해서 굉장히 구불구불한 모양으로 학습된 것을 볼 수 있습니다. 똑같은 데이터에 정규화 파라미터 alpha값을 증가시켜 보겠습니다.

그림 8-3 정규화가 있을 때(alpha=0.1)의 변화
[그림 8-2]에 비해 곡선이 훨씬 부드러워졌습니다. 다시 말해, 모델이 표현 가능한 범위보다 좀더 간단한 모델을 사용하도록 강제된 것을 확인할 수 있습니다.

그림 8-4 정규화가 좀 더 강할 때(alpha =1)
[그림 8-4]는 [그림 8-3]보다 더욱 강하게 정규화 값을 설정한 경우입니다. 곡선이 좀 더 부르러워져서 더 간단한 모델이 되었습니다.

이렇게 정규화 파라미터를 조절하면서 필요 이상으로 복잡한 패턴을 학습하지 않도록 머신러닝 모델을 조절할 수 있습니다. 그렇다면 적절한 파라미터 값은 어떻게 찾을 수 있을까요?

그림 8-5 검증용 데이터를 나누어 정규화 파라미터 정하기

1. 데이터를 학습 및 검증용(A)과 테스트(B)으로 나눕니다.
2. A를 다시 학습용(C)와 검증용(V)로 나눕니다.
3. 학습용 데이터에 대해 정당한 정규화 파라미터로 학습을 수행한 후 검증용 데이터를 사용해 성능을 측정합니다. 반봅해서 V에서 가장 성능이 좋은 정규화 파라미터를 찾습니다.
4. 과정 3에서 찾은 정규화 파라미터를 이용해서 A에 대해 학습을 수행합니다.
5. 모델 자체에 대한 평가는 B로 하면 됩니다.

과정 2부터 4까지는 교차 검증을 이용해도 됩니다. 교차검증은 2.4.1.2절 '교차검증'을 참조하기 바랍니다.

8.1.1.3 학습을 일찍 끝내기
정규화와 비슷하지만 훨씬 더 간단한 방식이 있습니다. 이 방식은 딥러닝에서 주로 사용되지만, 그 외의 분야에서도 많이 쓰이고 있습니다. 우선 아래 그래프에서 과학습이 되는 시점에 주안점을 두어 살펴보고 이야기를 더 진행하겠습니다.

그림 8-6 머신러닝 모델을 학습할 때 일반적으로 보게 되는 학습 데이터와 테스트 데이터에서의 손실 곡선

[그림 8-6]은 머신러닝 모델을 학습할 때 보게 되는 일반적인 손실 그래프입니다. 위에 있는 고선이 테스트 데이터에서의 손실, 아래 있는 곡선이 학습 데이터에서의 손실입니다. 학습 데이터에서의 손실은 학습을 진행할수록 줄어드는데, 테스트 데이터에서의 손실은 학습데이터에 모델이 과하게 최적화된 이후 오히려 늘어나게 됩니다. 손실이 늘어나기 시작하는 지점이 바로 과학습의 시작점입니다. 이 지점 이전까지는 학습 효과가 좋았으므로 과학습이 나타나는 시점까지만 학습하면 과학습을 예방할 수 있게 됩니다. 물론 '어느 시점'에 그만둘지 결정하는 것은 쉬운 일이아닙니다. 하지만 정규화가 쉽게 되지 ㅏㅇㄶ는 모델에는 이 방식을 더 유욯하게 사용할 수 있습니다.
딥러닝으로 유명한 힌튼 교수는 '일찍 끝내기(early stopping)는 아름다운 공짜 점심'이라고 표현했습니다. 아주 쉽고 거의 공짜로 이득을 본다는 뜻이죠. 실제로 현업에서도 학습을 완전히 수행하기보다는 최대 몇 번까지 반복한다고(예를 들어 100번) 적당히 정해놓고 학습을 하는 식으로 많이 사용합니다.

8.1.1.4 드롭-아웃(딥러닝 기법)
딥러닝에는 뉴렐넷의 과학습을 예방하는 방법으로 드롭-아웃(drop-out)을 널리 사용합니ㅏㄷ. 본 개념을 먼저 살표고벴습니다.

드롭-아웃은 딥러닝 모델으 ㄹ학습할 때 레이어와 레이어를 잇는 연결 중에서 일정한 확률 p로 몇 가지 연결을 무작위로 끊은 채 학습합니다. 즉, 학습이 진행될 때(파라미터를 업데이트 할 때) 마다 연결이 조금씩 달라진 상태로 딥러닝 모델을 학습하게 됩니다.

1. 아래와 같은 딥러닝 모델이 있다고 합시다. 동그라미는 레이어고, 선은 그것을 잇는 가중치 연결입니다.

2. 학습중 일부 업데이트는 아래와 같이 확률 p에 따라 레이어 연결을 임의로 몇 개 누락시키고 업데이트합니다.

3. 또 다른 업데이트는 다른 패턴으로 임의로 몇 개 누락시키고 업데이트 합니다.

4. 학습이 모두 끝난 후 모델을 실제로 사용할 때는 모든 연결을 사용하지만 p 만큼 연결의 강도를 약화시켜서 사용합니다.

드롭-아웃을 이용한 딥러닝 모델 학습이나 학습된 모델을 사용하는 방법 자체는 앞에서 설명한 것처럼 상당히 간단합니다. 연결을 무작위로 끊으면서 학습하고, 학습된 모델을 사용할 때는 연결 강도를 조절하면 됩니다. 또한 텐서플로에서 라이브러리로 제공하므로 그냥 가져다 쓰면 됩니다. 하지만 왜 이렇게 하는 것이 정규화에 도움이 되는지 이해하기 쉽지 않을 겁니다. 그 이유를 순서에 입각하여 살펴보면 다음과 같습니다.

1. 학습 시 연결을 임의로 몇 개를 끊으면 모델이 더 '간단하게'됩니다.
2. 간단한 모델로 학습하면 원래 모델보다 조금 제한된 모델로 학습이 이루어지게 되고 결과적으로 필요 이상으로 모델이 데이터의 복잡한 패턴을 학습하는 것을 방지하는 효과를 발휘하게 됩니다.
3. 이 과정을 반복하면 간단한 모델들의 밈의 조합을 이용해서 데이터를 설명하려는 시도를하게됩니다.
4. 그 결과 모델은 피처와 레이어 사이의 연결 가능한 모든 레이어 간의 조합에 대해 학습을 수행하는 것이 아니라 적은 연결로 전체를 설명하는 방향으로 학습하게 됩니다.

이 과정은 앞에서 설명한 정규화와 비슷하게 모델을 단순화시키는 효과를 볼 수 있습니다. 드롭-아웃은 구현이 쉬우면서도 딥러닝 모델의 성능을 늘리는데 매유 효과적입니다. 만일 딥러닝기법을 사용한다면 도입을 꼭 고려해보기 바랍니다. 참고로 텐서플로에서는 이 기능을 깁본으로 지원합니다.

8.1.2 좋은 모델을 좀 더 수월하게 찾는 방법
머신러닝은 모델에 따라 성능이 크게 좌우됩니다. 딥러닝이 발전하고 데이터양이 증가하면서 모델 자체에 대한 고민은 예전보다 적어진 듯 보이지만, 그럼에도 더 좋은 성능을 얻으려면 더 데이터에 적합한 모델을 이용하여 학습해야 합니다. 따라서 모델의 중요성은 아무리 강조해도 지나치지 않습니다.

이절에서는 데이터에 적합한 모델을 효과적으로 찾는 방법에 대해 알아보겠습니다. 1장과 2장에서도 잠깐 어급했지만'머신러닝을 적용한다'는 것은 '데이터에 적합한 모델과 학습 방법을 차즌ㄴ 일련의 과정을 적용한다'는 뜻입니다. 특히 적합한 모델을 찾는 것은 핵심입니다.

그렇다면 어떻게 하면 적합한 모델을 쉽게 찾을 수 있을 까요? 다음과 같은 방법을 생각할 수 있습니다.

- 간단한 모델부터 적용하기
- 데이터와 모델 시각화 하기
- 모델의 최대 성능 가늠하기

8.1.2.1 간단한 모델부터 적용하기
가장 중요한 원칙은 처음부터 복잡한 모델을 곧바로 적용하는 것이 아니라 간단한 모델을 적용시켜서 성능을 확인해보는 것입니다. 어차피 복잡한 모델이 더 좋은 성능을 낼 확률이 높은데 왜 굳이 시간을 낭비하는지 의문이 들 수도 있을 겁니다. 간단한 모델 부터 테스트해보는 데는 다음과같은 이유가 있습니다.

간단한 모델은 구현이쉽고 학습도 쉽습니다.
대부분의 머신러닝 라이브러리는 선형 휘귀, 로지스틱 휘귀, 레이어가 1개인 뉴런넷 모델 등 간단한 모델을 제공하고 있어 손쉽게 시도할 수 있고 학습도 굉장히 빠릅니다. 또한 적은 학습과 정 튜닝으로 최대의 성능을 쉽게 확인할 수 있습니다. 복잡한 모델은 구현, 학습, 그리고 파라미터 튜닝에 오랜 시간이 걸립니다.

간단한 모델의 성능은 다른 모델이 얼마나 잘 동작하는지에 대한 지표가 됩니다.
간단한 모델을 실제 시스템에 사용하지 않더라도 그 성능을 더 복잡합 모델의 성능 지표로 삼을 수 있습니다. 복잡한 모델의 1차 구현물이 간단한 모델의 성능보다 월등히 좋지 않다면 뭔가 개선 방법을 찾아야 합니다. 반대로 간단한 모델보다 성능이 좋다면 모델이 잘 작동한다고 판단하고 튜닝에 돌입하면 됩니다.

간단한 모델은 원인을 파악하기가 상대적으로 쉽습니다.
모델의 성능이 떨어지는 원인은 다양합니다. 데이터 처리 버그, 모델의 학습방법, 아니면 그냥 문제 자체가 예측이 어려운 경우일 수도 있습니다. 이유가 뭐든 간단한 모델일 때보다 복잡한 모델에서 문제의원인을 찾기가 상대저그로 어렵다는 건 두말할 필요 없을 겁니다. 먼저 간단한 모델을 사용해서 전체가 잘 동작하는지 검증한 후 복잡한 모델을 적용하기 바랍니다.

8.1.2.2 데이터와 모델 시각화하기
데이터를 시각화해보는 것도 적합한 모델을 찾는데 도움이 됩니다. 하지만 추가 노력이 들기 때문에 생략하는 경우도 적지 않습니다. 전체 데이터를 완전히 시각화하지 않더라도 패턴을 살펴볼 수 있는 수준이면 도움이 됩니다. 그 이유는 다음과 같습니다.

데이터 이상 파악
예를 들어 일반적인 선형 회귀를 해보려고 생각하고 있었는데, 데이터를 시각화해보니 데이터가 선형적인 양상이 아니라 로그 스케일을 따른다든가, 소수점 단위를 예상하고 있었는데 음수가 나온다든가, 혹은 기본값이 특이하게 들어 있는 경우를 생각할 수 있습니다. 실숫값을 기대하고 있었는데 정숫값만 존재하거나 카테고리 ID가 들어오는 경우처럼 데이터 자체에 대한 가정에 문제가 잇는지 등도 파악하기 좋습니다.

데이터 특성 파악
데이터를 분석할 때 가장 기본적인 것은 데이터가 정규 분포를 따른다고 가정하느 것입니다. 대부분의 경우에는 큰 무리가 없지만, 가끔 데이터가 정규분포를 크게 벗어난느 경우가 있습니다. 예를 들어[그림8-7]과 같이 데이터가 한개 의 정규분포(가우스분포)를 따르지 않는 경우입니다. 이 경우에는 2개의 정규분포를 포함하는 머신러닝 기법이 적합합니다.

모델 동작 방식 이해
데이터를 시각화 하는 것과 함께 모델의동작 결과를 시각화하는 것도 많은 도움이 됩니다. 예를 들어 분류 모델의 경우에는 모델이 각 데이터 포인트를 어떻게 분류하는지, 희귀모델의 경우에는 모델이 출력하는 결괏값이 어떻게 분포된느지 시각화하면 모델이 어떤 방시긍로 동작하는지 이해하는 데 도움이 됩니다.

시각화는 이책의 여러붑ㄴ에서 쓰였는데, 8.2.3.2 절'데이터의 값이 치우쳐 있을 때'에서는 데이터를 시각화에서 데이터의 편중 정도를 파악하고, 8.1.1.2절 '정규화'에서는 모델을 시각화해서 실제로 정규화가 모델에 어떻게 영향을 미치는지 살펴 보았습니다.

아래 URL에 방문하면 사이킷런에서 사용할 수 있는 다양한 시각화 예제를 확인할 수 있습니다.

http://scikit-learn.org/stable/suto_examples/

|2차원 이상의 데이터 시각화하기|
2차원 이상의 데이터를 시각화하는 일은 쉽지 않습니다. 데이터들의 상관관계를 이용해서 2차원으로 관곌르 재정의해서 그리는 방법이 있는데, 데이터의 절대좌표를 직접 입력하는 것이 아니라 한 데이터의 위치가 다른 데이터와 얼마나 다른지 상대거리를 이용해서 시각화하게 됩니다. 그리고 데이터의 절대거리보다는 근처에 있는 점들과의 관계를 보존하는 방법으로 시각화합니다. 이런 경우에 t-SNE 같은 방법이 특히 많이 이용됩니다. 예를 들어 텐서플로 튜터리얼에서 t-SNE를 사용하여 단어 벡터들을 시각화한 예를 착을 수 있습니다. 더 자세한 사항은 해당 튜터리엉ㄹ을 참고하세요. 대표적으로 Isomap, L.I.E, MIDS와 같은 방법이 있습니다. 자체한 사항은 사이킷런 홈페이지를 참고하세요.

8.1.2.3 모델의 최대성능 가늠하기
구현한 모델이 99.99% 정확도를 보인다면 더할 나위 없겠죠, 반대로 성능이 너무 좋지 않나면 더 적극적으로 새로운 모델을 찾아봐야 할 겁니다. 그러면 과연 성능이 얼마나 좋은지 어떻게 판단 할 수 있을까요? 지금 얻은 성능의 수치는 낮지만 사실 엄청나게 잘하고 있는것 아닐까요? 단순히 성능 수치만으로는 애매한 부분이 있기 때문에 가능한  한 최고 성능르 가늠해보고 현재 어느 정도 수준인지 판단하는 것이 중요합니다.

물론 최고 선을을 가늠하는 것은 쉽지 않은 일입니다. 대에 따라 다르겠지만 다음과 같은 시나리오를 생각할 수 있습니다.

머신러닝 시스템과 사람의 성능 비교
사람의 직접 해당 일을 수행했을 때 얻을 수 있는 정확도 등의 예측 성능은 좋은 지표가 됩니다. 예를 들어 몇 명의 수동으로 이미지에 보이는 몰체를 태깅하거나 분류한 다음 평균 성능을 평가하여 머신러닝 시스템이 얼마나 잘 동작하는지 가늠해보는 겁니다. 예를 들어 아마존 메커니컬 피크는 수많은 사람에게 태깅을 부탁하고 소액을 지불하는 크라우드 소싱을 이용합니다. 만일 사람조차도 공통 의견을 만들기가 쉽지 않다면 머신러닝 시스템도 좋은 성능을 내기 쉽지 않을 겁니다.

이론상 성능의 한계나 보장된 값이 존재할 때
데이터에 따라 다소 제한적이긴 하지만 보장된 성능이 존재하는 경유가 있습니다. 예를 들어 제품의 불량률이 정해져 있고, 센서가 얻을 수 있는 불량에 대한 정보에 한계치가 있다면, 이 두요소에 의존하여 불량을 판볻하는 시스템의 성능에는 한계가 있겠죠. 이와 같은 정보를 미리 알면 현재 머신러닝 시스템이 얼마나 잘 동작하는지 알 수 있습니다.

8.2 데이터 분제
학습 데이터가 어떻게 구성되어 있는지에 따라 학습 성능이 크게 달라집니다. 이 장에서는 데이터가 너무 많거나 너무 적거나, 아니면(가장 일반적인) 치우침이 심할 때 어떻게 하면좋을지 살펴보겠습니다. 참고로 8.1.2.2절 '데이터와 모델 시각화하기'에서 언급한 데이터 시각화도 이런 데이터의 특성을 이해하는데 도움이 됩니다.

8.2.1 데이터가 너무 많을때
앞서 머신러닝에서 데이터가 많을 수록 좋다고 언급했습니다. 이론상으로는 데이터가 많을 수록 성능이 좋은 모델을 얻을 수 있지만, 데이터가 많으면 처리 시간이 오래 걸리기 때문에 문제가 될 수 있습니다. 특히 같거나 비슷한 데이터가 많이 들어오는 경우를 생각해 봅시다. 예를 들어 1분마다 물체의 움직임을 감지하여 데이터를 송신하는 센서를 이용하여 물체의 이동 곙로를 학습하는 모델을 만들려고 할 때 물체가 거의 정지해 있다면 대부붕의 데이터가 움직임 없음(0)으로 채워질 겁니다. 또 다른 경우는 특정 분류 항목의 데이터가 너무 많아서 전체 적으로 학습이 오래 걸리는데 그렇지 않은 항목은 적은 경우가 있습니다. 예를 들어 사진 데이터에서 하늘이나 구름 사진은 어첨 많은데 휘귀한 동뭀진은 적은 경우가 있습니다. 이를 해결하기 위해 다음과 같은 방법을 생각해 볼 수 있습니다.

과소표집
과소표집(언더샘플링)은 전체 데이터셋에서 데이터를 무작휘 확률로 선택해서 선택된 데이터로 이우러진 작아진 데이터셋을 사용하는 방식입니다. 데이터를 무작위로 선택하는 방법은 다양하지만, 가장 중요한점은 데이터의 특성과 상관없이 뽑아야 한다는 것입니다. 예를 들어 사용자 구매 이력 데이터에서 50%확률로 데이터를 뽑는것은 괜찮지만, 사용자 이름 가나다순으로 정렬된 데이터셋의 앞부분 절반만 사용하는 것은 데이터으 ㅣ특성을 바꿀 수 있기 때문에 안됩니다.

중요도 표집
중요도 표짐(중요도 샘플링)은 데이터의 중요도에 따라 선택 확률을 변도하여 샘플링하는 기법이다. 무작위 확률로 선택하다 보면 특정 경우에 해당하는 데이터가 거의 없어지는 문제가 발생할 수 있습니다. 예를 들어 이미지 분류 문제를 푼다고 가정합시다. 학습용 데이터에서 '하늘'에 해당하는 이미지는 엄청 많은데 '오리너구리'에 해당하는 이미지는 적다고 합시다. 이런 경우 이미지를 무작위로 선택하면 오리너구리 이미지는 정말로 적은 수만 남게 됩니다. 그러면 오리너구리에 대한 학습이 제대로 이루어지지 못하겠죠. 이런 경우에는 데이터의 중요도에 따라 선택확률을 변동시키는 방법이 더 적합합니다. 예를 들어 하늘에 해당하는 사진은 10%의 확률로 뽑고 오리너구리 사진은 너무 개수가 적으니 80%의 확률로 뽑는 방법을 고려 할 수 있습니다.

피처 선택
'피처 선택'은 중요한 피처만 선택해서 전체 학습률과 성능을 증가시키는 방법입니다. 피처가 많으면 학습에 사용하는 데이터가 많아 학습률이 느려지고,  모델이 복잡해져서 과학습을 할 우려가 있습니다. 피처를 고르는 방법으로 '카이제곱 피처 선택법', '상호-정보 피처 선택법', '검증셋에서의 성능'이 주로 사용됩니다. 어떤 방법을 사용하든 성능에 도움이 되는 피처는 고르고 그렇지 않은 피처는 삭제하는 방향으로 진행됩니다.

1. 카이제곱 피처 선택법(이하 카이제곱 선택법): 피처와 성능 간의 통계학적 독립성을 테스트하는 방법입니다. 성능과 연관이 많은 피처는 나두고 그렇지 않은 피처는 제거합니다.
2. 상호-정보 피처 선택법(이사 상호 정보 선택법):중요한 피처만 선택하는 것은 카이제곱 선택법과 같지만, 실제로 계산하는 방법과 의미는 약간 다릅니다. 카이제곱 선택법이 각 피처가 모델의 성능에 얼마나 통계적으로 유의미한 기여를 하느냐를 검토한다면, 상호-정보 선택법은 선택한 피처 한 쌍이 서로 예측하는 데 얼마나 도움이 되느냐를 검토합니다. 결과적으로 상호-정보 선택법은 카이제곱 선택법보다 좀 더 자주 나오는 피처를 선택합니다.

3. 검증셋에서의 성능: 학습용 데이터에서 검증용 데이터를 따로 분리하여 피처의 일부만을 사용해서 모델을 학습한 후 검증셋에서의 성능 평가를통해 어떤 피처가 좋을지 측정합니다.
앞의 방법을 통해 전체 피처 셋에서 피츠를 하나씩 제외하거나, 아니면 아무것도 없는 상태에서 가장 많이 도움 되는 피처를 하나씩 추가하는 식으로 사용할 피처를 결정합니다.

8.2.2 데이터가 너무 적을때
데이터가 적을 때 할 수 있는 일은 그렇게 많지 않습니다. 다음과 같은 방법을 통해 약간이나마 개선해볼 수는 있습니다.

8.2.2.1 레이블된 데이터는 별로 없지만 일반적인 데이터가 많은 경우(표현형 학습)
이런 경우에는 먼저 데이터의 일반적인 특성을 배우는 학습을 휴행하여 얻어진 정보를 이용해서 추가로 학습하ㅕㄴ 어느 정도 효과를 볼 수 있습니다.

예를 들어 제품 리뷰를 받는 사이트에서 제품에 대한 리뷰가 호의적이거나 적대적인지 판단하는 모델을 만든다고 가정해 봅시다. 이 모델을 학습시키면 각 리뷰에 대해 '호의적' 또는 '적대적' 레이블이 붙어 있어야 합니다. 사용자가 리뷰를 작성할 때는 호의적 또는 적대적이라고 명시하지 않으므로 이런 데이터셋을 만들려면 사람이 수작업으로 각 리뷰가 어떤 성격인지 일일이 체크해야 합니다(별점 데이터가 있다면 4점 이상이면 호의적, 2점 이하면 적대적이라고 레이블하기도 하지만, 이 경웅에도 문장 단위의 호의적 또는 적대적 레이블은 어렵습니다). 이런 수작업 레이블이 없는 이뷰는 손쉽게 많은 양을 얻을 수 있습니다. 그렇다면  이러한 리뷰를 통해 리뷰의 일반적인 패턴(예를 들면 어떤 단어가 많이 나오는지 파악해서 단어의 의미를 추론)을 먼저 추출해서 리뷰를 잘 표현할 수 있는 간명한 표현ㅅ형을 만든 다음, 실제 레이블을 가진 리뷰를 표현형으로 변환한 뒤 이를 이용해 분류를 합니다. 이렇게 데이터 자체에 대해 알고 있는 정보의 도움을 받아서 성능을 향상할 수도 있습니다.
이러한 과정을 딥러닝에서는 표현형학습 혹은 비지도 선행학습 등의 분야에서 다룹니다. 유명한 방식으로는 오토인코더나 토픽 모델링이 있습니다. 이 중 토픽 모델링은 5.2절 '토픽 모델링'에서 다뤘습니다.

8.2.2.2 전이학습
전이학습은 성격이 다른 데이터셋(예를 들면 이미지와 텍스트 데이터)을 이용해서 학습시킨 모델을 현재 데이터셋에 적용하는 방법입니다. 넓은 의미로는 다른 데이터셋에서 얻은 정보를 이용해서 현재 문제의 성능을 향상시키는 방법도 포함합니다. 앞서 다룬 방법에서는 데이터 성격이 모두 같았지만, 전이 학습에서는 데이터 성격이 다릅니다. 예를 들어 리뷰 데이터 분석을 하는 경우 백과사전이나 제품의 이미지 등을 이용해 모델을 학습시킨 후, 그 모델을 이용해 리뷰가 호의적인지 적대적인지 예측하는 겁니다.

이렇게 다른 성격의 데이터를 이용하여 학습시킨 모델을 활용하는 방법은 생각보다 쉽지 않습니다. 다행이 딥러닝에서는 중간 레잉어를 공유하는 방식으로 생각보다 쉽게 이런 정보를 이용할 수 있습니다. 더 자세한 내용은 이 책의 범위를 벗어나므로 이런 정보가 있다는 정도만 알아두기 바랍니다.






2018년 3월 17일 토요일

CHAPTER 7 이미지 인식 시스템 만들기

이미지 인식은 전자상거래 사이트의 상품인식, 디지털 카메라 및 구글 포토의 얼굴 인식, 자율 주행 자동차의 도로상황 파악 등 다양한 곳에서 사용됩니다. 또한 최근 딥러닝의 발달로 인식 성능과 처리 속도가 놀랍게 향상되어 응용범위가 확대되고 있습니다.

이 장에서는 이미지 인식의 기본 개념과 자주 사용되는 피처에 대해 알아보고, 이미지에 담긴 물체의 카테고리를 정하는 물체 분류와 이미지에 담긴 물체를 인식하는 물체인식 기법을 소개합니다. 또한 이미지 인식에서 최근 각광받고 있는 딥러닝 기법인 CNN(합성곱 신경망)에 대해서도 살펴봅니다.

7.1 이미지 처리 기본 개념
이 절에서는 이미지 처리에서 사용하는 기본 개념인 픽셀, 필터링, 합성곱에 대해 알아보겠습니다.

7.1.1 픽셀
디지털 이미지는 픽셀로 구성되어 있습니다. 화면 크기가 17인지, 해상도가 1920*1080픽셀이라는 표현에는 아마 다들 익숙할 겁니다. 픽셀은 컴퓨터 모니터에서 표시할 수 있는 가장 작은 단위라고 생각하면 됩니다. 픽셀은 밝기의 강도(intensity)와 컬러 채널값을 가집니다.

그레이스케일 이미지에서 각 픽셀은 흰색(강도 255), 검은색(강도 0), 다양한 강도의 회색(1~124)으로 채워져 있습니다. 컬러 이미지는 픽셀 하나가 R,G,B 세 채널로 구성되고 각각 0~255의 강도를 가집니다. 예를 들어 빨간색은 [255,0,0], 녹색은 [0, 255,0], 파란색은 [0, 0, 255]이런식입니다. 따라서 채널별로 높이 m픽셀과 넓이 n픽셀을 가지는 이미지를 m*n행렬로 표현할 수 있습니다. 채널이 하나인 그레이 스케일 이미지는 m*n*1행렬로, 컬러 이미지는 m*n*3 행렬로 표현할 수 있습니다.
이미지를 픽셀 좌표(x,y)의 강도값을 변환하는 함수로 볼 수도 있습니다. 즉 I(x,y) = 강도값인 함수가 됩니다. 이 함수를 이미지 강도함수 혹은 강도함수라고 합니다.

7.1.2 필터링
기존 이미지의 픽셀값을 선형적으로 조합하여 새로운 픽셀값으로 변환한 뒤 그 픽셀들로 새로운 이미지를 생성하는 것을 필터링이라고 합니다. 필터링은 결괏값이 저장될 픽셀 좌표의 +-1, +-2... 범위의 ㅍ픽셀 정보를 조합하는 방식을 사용합니다. 예를 들어 가로3개*새로3개= 9개의 픽셀 정보를 조합한다면 3*3 크기의 원도우(혹은 커널)를 사용합니다. 자주 사용되는 원도우 크기로는 3*3와 5*5가 있습니다.
대표적인 필터링 방식으로 이동평균 필터링이 있습니다. (그림 7-3). (2n+1)*(2n+1)크기의 원도우를 사용하여 이동평균 필터링을 적용할 경우, 목표 픽셀에서 +-n위치의 값을 모두 ㄷ더한 후 (2n+1)(2n+1)(원도우의 넓이)로 나누면 됩니다. 예를 들어 [그림 7-3]의 첫 번째 이미지는 새 이미지의 G의 (1,1) 픽셀값을 정하기 위해 이전 이미지 F의 (0,0), (0,1), (0,2), (1,0), (1,1), (1,2),(2,0), (2,1), (2,2) 픽셀값을 모두 더한 후 9로 나누었습니다. 이 작업을 이미지 F의 모든 픽셀에 대해 반복합니다.
하지만 이미지 G의 (0,0)픽셀을 생성하려면 이미지 F의 (-1,-1), (0,-1), (1,-1), (0,-1), (0,0), (0,0), (1,-2), (1,0), (1,1)픽셀값이 필요한데, -로 시작하는 픽셀은 존재하지 않습니다. 이와 같이 이미지의 네 가장자리 픽셀은 원도우 안의 픽셀값이 비어 있기 때문에 별도로 처리합니다. 네 가장자리의 픽셀값을 처리하는 방ㅂ버으로 이미지 바깥 값을 0으로 채우는 제로 패딩(zero-padding)과 이미지 바깥 값을 가장 가까운 가장자릿값으로 처리하는 가장자릿ㄱ밧 복제(edge value replicaiton)가 있습니다. 그림으로 나타내면 [그림 7-4]와 같습니다. 일반적으로는 제로 패딩을 많이 사용합니다. 이동평균 필터링은 픽셀을 주벼 ㄴ픽셀값의 평균으로 변환하므로 더 부드러운(스무딩된) 이미지를 생성합니다. 이동평균 외에도 원도우 안의 픽셀 주 최댓값으로 픽셀을 생성하는 최댓값필터링, 단순히 주변 값들의 편균을 구하는 대신 거리에 따라 차등을 주는 가우스 필터링(혹은 가우스 원도우), 이미지의 경계선을 얻어내는 엣지 필터링 등이 있습니다. 이러한 필터링 방식은 다음 절에서 설명하는 합성곱 원도우를 용도에 맞게 설정하여 구현할 수 있습니다.

7.1.3 합성곱
필터링 방식은 합성곱(convolution)의 특별한 경우입니다. 사실 이미지 처리에서의 필터링은 합성곱의 적용이라고 생각해도 됩니다. 합성곱은 함수와 이동한 함수의 값을 곱한 다음, 구간에 대해 적분하여 새로운 함수를 구하는 연산입니다. 연산 기호는 *입니다. 함수 f와 함수 g의 합성 곱 f*g를 식으로 표현하면 다음과같습니다.
(f*g)(t) = 적분(f(임의의값)g(함수입력값 - 암의의값)d*암의의값

함수의 이동은 함수의 그래프를 일정 방향으로 평행이동 혹은 대칭이동하는 것 입니다. 중학교에서 배운 이차함수의 이동을 떠올리면 이해하기 쉬울 겁니다. 함수 y = f(x)에 대한 이동을 식으로 표현하면 다음과 같습니다.

- p 만큼 평행이동 : y = f(x-p)
- x 축 대칭 이동 : -y = f(x)

따라서 합성곱은 함수 g를 임의의 축으로 대칭이동 하고 t마큼 평행이동한 후 , f(임의의 값)와 곱하고 그 결괏값을 적분하는 연산입니다. 여기서 적분 범위는 함수 f와 g의 범위에 따라 달라집니다. 대칭이동은 반전이라고 합니다. 합성곱은 적분을 하는 것으로 입력값 t와 적분 구간의 정보를 동시에 고려하는 값을 얻게 되므로 연속된 값으로 이루어지는 신호 처리, 시계열 분석 등 다양한 분야에 사용됩니다.

7.1 절에서 언급한 대로 이미지는 함수로 볼 수 있으므로 이미지를 합성곱 계산의 입력으로 사용할 수 있습니다. 이미지 함수는 연속함수가 아닌 이산함수이므로 적분대신 총합을 사용합니다. 또한 전 구간의 값을 더하는 것이 아니라 원도우 안의 값만 더하므로 위 식이 다음과 같이 바뀝니다.

f*g(n) = -M에서 M의 총합(f(n-m)g(n))

n: 원도우의 중심
2M: 원도우의 한변의 길이

위 식을 말로 표현하면 다음과 같습니다.
1. f로 정의된 운도우 안의 값이 x,y 좌표 반전
2. 1에서 만든 원도우로 이미지g를 흟으면([그림 7-3]의 원도우 이동 참조) 원도우 안의 값과 원도우를 적용할 이미지 g부분의 강도값의 내적을 계산
3. 2에서 생성된 값으로 새로운 픽셀값 생성

그림으로 표현하면 [그림 7-6]과 같습니다. 원도우를 반전하는 것으로 상화좌우가 바뀐 것을 볼 수 있습니다. 새 합성곱 이미지의 좌표(1,1)안에 들어갈 강도값을 계산하기 위해 원래 이미지의 좌표(1,1)이 원도우의 중심이 되도록 포갭니다. 이때 앞에서 살펴본 제로 패딩으로 가장자리 값을 채움니다. 합성곱 이미지의 (1,1)좌표의 강도값은 다음과 같습니다.

i * 5 + h * 6 + g * 0 + f * 8 + e * 9 + d * 0 + c * 0 + b * 0 + a * 0

합성곱을 이미지에 적용할 땐느 좌우대칭 필터를 사용하는 경우가 대부분이므로 반전의 영향을 미치지는 않습니다. 또한 7.4절 '딥러닝을 이용한 이미지 인식'에서 살펴볼 CNN(합성곱 신경망)도 원도우를 반전하지 않습니다. 하지만 이미지를 이동하는 필터라면 반드시 반전을 해야 원하는 결과를 얻을 수 있습니다. 원도우 안에 있는 픽섹값들을 합하여 하나의 픽셀로 만드는 이유는원래 이미지에 있던 여러 픽셀의 정보를 하나로 모으기 위해서입니다.

합성곱을 이용한 계산은 원도우를 어떻게 지정하냐에 따라 이동뿐만 아니라 블러, 샤프닝 등 다양한 효과를 이미지에 적용할 수 있습니다. GNU 이미지 편집 프로그램(GIMP)사이트 에서 다양한 원도우에 의한 합성곱 결과를 확인할 수 있습니다.

7.2 이미지 인식
이미지 인식 태스크에 대해 알아보겠습니다. 이미지 인식 태스크는 크게 다음과 같이 나뉩니다.

- 이미지 분류(image classification):이미지에 특정 물체가 존재하는지 여부를 판단합니다. 예를 들어'[그림 7-7]에 고양이가 존재하는가?'라는 물음에 '그렇다', '아니다'로 분류하는 것이죠
- 이미지 검출(image detection):이미지에 어떤 물체가 존재하며, 어디에 존재하는지 판단합니다. '[그림 7-7]'에 무엇이 있는가? 그리고 그것이 어디에 있는가?' 라는 더 구체적인 질문에 대해 답을 해야 합니다.

7.2.1 이미지 분류
어떻게 해야 위 이미지가 고양이와 관련되었다고 할 수 있을까요? 여러 개의 비슷한 고양이 이미지를 이용하여 분류기를 학습시키면 됩니다. 5장에서문서를 이루는 단어들을 이용하여 피처를 생성하고 문서를 분류하는 방법을 배웠습니다. 이미지도 마찬가지로 이미지를 이루는 픽셀을 이용하여 피처를 생성할 수 있습니다. 피처는 크게 전역 피처와 지역피처로 나눌 수 있습니다. 전역 피처는 하나의 이미지에서 한만 얻을 수 있으며 이미지의 강도 히스토그램이 그 예입니다. [그림7-8]은 이미지(왼쪽)에서 추출한 강도 히스토그램(오른쪽)을 보여주고 있습니다. 강도 히스토그램의 x축은 강도값(0~255), y축은 그 강도값을 가지는 픽셀 수 입니다.
하나의 이미지에서 얻을 수 있는 지역 피처의 종류는 다양합니다. 대표적인 지역 피처로 이미지안 물체의 코너를 들 수 있습니다. 코너에 대해서는 7.3.2 절 '코너'에서 자세히 설명할 겁니다. 이미지에서 전역 피처와 지역 피처를 추출한 뒤 이를 이용하여 이미지를 군집화하거나 분류기를 만들어 이미지 분류하게 됩니다.

7.2.2 이미지 검출
이미지 검출은 이미지에 존재하는 물체가 무엇인가, 어디에 있는지 인식합니다. 분류와 달리 어떤 물체인지에 대한 정보가 없으므로 인식하려면 우선 이미지에서 한 물체를 이루는 픽셀들을 분할해야 합니다. 이미지 분할은 이미지 내부에 있는 관련 픽셀들을 모아 그룹을 만드는 것으로, 픽셀 군집화로 생각할 수 있습니다. 그러므로 4장에서 살펴본 군집화 알고리즘을 사용할 수 있습니다. 이때 주로 사용되는 피처는 픽셀의 강도와위치 입니다.

예를 들어 파워포인트의 배경 제거 기능(그밀 7-9)은 이미지 분할의 예입니다. 파워포인트에서는 이미지의 배경을 제거하는 기능을 제고하는데 이때 그랩컷(GrabCut)기법을 이용한 이미지 분할이 사용됩니다. 그랩컷은 선택한 영역의 중앙에 사용자가 인식하고 싶은 물체가 있다고 가정하고, 그 물체 주위로 사각형을 그립니다. 그 후 사용자로부터 보조 입력을 받아 더욱 정확한 배경 범위를 찾습니다. 사용자의 보조 입력을 받기 때문에 그랩컷을 대화형 전경 추출법(interactive foreground extraction)이라고 부릅니다.

7.3 이미지 인식에 사용하는 피처
머신러닝으로 모델을 학습시킬 때 무엇을 피처로 삼아 학습해야 할지 알려줄 필요가 있습니다. 5장에서 문서를 분류할 때는 단어 빈도, TF-IDF등 텍스트와 관계된 피처를 사용했습니다. 이미지 분류에서도 이미지에 특화된 피처를 사용하는데, 이 절에서는 윤곽선, 코너, SIFT등의 이미지 인식과 검출에 사용하는 고전적인 피처에 대해 살펴보겠습니다.

7.3.1 윤곽선
흑백만화나 수묵화 등의 이미지는 색이나 질감에 대한 정보 없이 선으로만 이루어져 있는데도 사람들은 그 이미지에 있는 물체를 쉽게 판별합니다. 이는 사람이 윤곽선(edge)혹은 실루엣을 통해 물체를 인식하기 때문입니다. 그래서 이미지 안에 있는 물체를 인식하고자 이미지 안에 있는 윤곽선을 검출하는 방법에 대한 많은 연구가 있었습니다. 윤곽선을 검출하려면 이미지에서의 픽셀 강도값의 급격한 변화(혹은 불연속성)를 검출하면 됩니다.[그림 7-11]을 보면 이해하기 쉬울 겁니다.
가장 왼쪽의 이미지에서 윤과석을 찾는다고 생각해봅시다. 윤곽선은 검은 직석과 흰색 바탕의 경계선입니다. 회색 선이 지나가는 픽셀들의 강도값을 보면, 흰색(255)에서 검은색(0)이 되었다가 횐색(255)이 됩니다. 강도값을 함수로 나타낸 것이 가운데 이미지입니다. 이 강도 함수를 1차 미분하면 흰색에서 검은색이 되는 부분, 검은색에서 다시 흰색이 되는 부분에 미분의 최솟값과 최댓값(이 둘을 합쳐 극값이라고 합니다)이 나옵니다. 즉, 강도함수의 극값이 존재하는 곳에 윤곽선이 존재하고, 이 극값은 회색 선에 수직으로 존재합니다. 윤곽선 검출에 가장 널리 사용되는 캐니 윤곽선 검출기(canny edge detector)도 위 성질을 이용합니다. 1차 미분값은 노이즈에 굉장히 약하기 때문에 캐니 윤곽선 검출기는 가우스 값으로 채워진 원도우에 합성곱을 적용하여 노이즈를 줄이고, 여러 윤곽선 후보를 이용하여 최종 윤곽선을 만들때 복수의 임계치를 이용하여 검출 정확도를 높입니다. 캐니 윤곽선 검출기는 13장에서 살펴볼 이미지 라이브러리인 OpenCV를 비롯한 다양한 이미지 처리 라이브러리를 이요하여 쉽게 구현할 수 있습니다.

7.3.2 코너
[그림 7-8]에서 살펴본 이미지의 강도 히스토그램이나 [그림 7-10]의 윤곽선을 이용하면 이미지를 잘 분류할 수 있을 것 같습니다. 하지만 같은 장소를 찍은 사진이라 하더라도 시간대나 날씨에 따라 사진을 구성하는 색이 다릅니다. 윤곽선은 물체의 각도가 조금만 달라져도 완전히 바뀌므로 다양한 상황에서의 물체 인식에는 적합하지 않습니다.

그렇다면 어떻게 다양한 상황에서도 같은 물체로 인식할 수 있을까요? 이미지를 더 정확히 인식하려면 학습에 사용되는 피처가 회전 불변성(rotation invariance), 크기 불변성(scale invariance), 평행이동 불변성(translation invariance)을 만족시켜야 합니다.

- 회전 불변성: 같은 물체가 있는 이미지를 찾을 때는 (이미지 매칭)물체 방향의 변화에 영향을 받지 않아야 합니다.
- 크기 불변성: 이미지의 척도 변화에도 영향을 받지 않아야 합니다.
- 평행이동 불변성: 한 이미지 안에서 물체가 움직여도 같은 물체라고 인식할 수 있어야 합니다.

강도 히스토그램과 같이 이미지 전체에서 뽑아내는 전역 피처나 이미지 전체의 윤곽선만으로는 위 성질을 만족시키기 어렵습니다. 따라서 이미지 인식에서는 이미지의 일부분에서 뽑은 지역 피처를 많이 이용합니다.

회전 불변성과 평행이동 불변성을 만족시키면서(크기 불변성은 만족시키지 못합니다) 이미지에서 대량으로 얻을 수 있는 대표적인 지역 피처로 코너(corner)가 있습니다. 이미지에 있어서 코너는 선이 꺽이는 모든 곳에 존재하므로 많이 얻을 수 있고, 또한 한 이미지에 하나만 있는 전역 피처가 아닌 이미지의 부분에서 얻는 지역 피처이므로 물체의회전에 영향을 덜 받습니다. 다음 그림은 [그림 7-10]의 이미지에서 코너를 찾은 것입니다.
캐릭터의 눈썹 끝, 눈, 코에 코너가 존재한다는 것을 알 수 있습니다. 따라서 캐릭터가 회전하더라도 이미지에서 눈썹, 눈, 코를 검출할 수 있을 것이고 윤곽선보다는 더 강한 피처가 될 겁니다.
그럼 어떻게 코너를 검출할 수 있을까요? 7.3.1절 '윤곽선'에서 윤곽선을 찾을 때 강도의 변화를 검출했습니다. 코너도 마찬가지로 강도의 변화를 검출하는데, 여러 방향에서 강도의 변화가 일어나는 곳을 검출합니다.
[그림 7-13]에서는 이미지의 영역을 평면, 윤곽선, 코너로 나누었습니다. 작은 사각형(원도우)을 움직이면서 강도 변화를 관찰하느데, 평면인 경우는 원도우를 모든 방향으로 움직여도 강도 변화가 없습니다(상하좌우가 다 검정색입니다). 윤곽선인 경우는 윤곽선의 방향([그림 7-13]에서 수직선)을 따라 움직이면 강도 변화가 없습니다. 하지만 코너의 경우 어느 방향으로움직여도 강도 변화가 나타납니다.
이 성질을 이용하여 코너를 검출하는 대표적인 기법으로 해리스 코너 검출기(Harris corner detection)가 있습니다. 헤리스 코너 검출기는 x축 미분값,  y축 미분값, 그리고 x축 미분값 * y축 미분값을 이용하여 2*2의 정방행렬을 만든 후 , 그행렬을 고윳값 분해하여 고유벡터가 고윳값을 찾습니다.

행렬의 고윳값 분해는 6.4.1절 '평균 제곱근 편차'에서 설명한 대로 행렬을 이루는 기본 요소를 찾는 방법 중 하나입니다. 특잇값 분해와 달리 고윳값 분해는 선형독립인 정방행렬에만 적용할 수 있습니다. 선형독립인 행렬 A는 간단히 말해 v가 O벡터일 경우만 Av = O를 만족하는 행렬입니다.

정방행렬 A와 A의 고유벡터 v, 고윳값 Y의 관계를 수식으로 표현하면 다음과 같습니다.
AY = Yv
즉, 고유벡터란 행렬 A가 곱해져도 그 방향(v)이 변하지 않고 크기(Y)만 변하는 벡터를 말합니다. 행렬 A가 정방행렬이고 선형 독립일 경우 다음과 같이 분해할 수 있습니다.

강도함수의 x축, y축 미분값으로 이루어진 행렬이 이미지 안의 강도값의 변화를 나타낸다는 점을 생각해보면 그 행렬을 분해한 고유벡터는 변화의 축(방향)이 되고 고윳값은 강도 변화의 크기라고 볼 수 있습니다. 그리고 앞에서 말했듯이 해리스 코너 검출기는 2*2의 정방행렬을 분해하므로 두 고유벡터와 두 고윳값이 나올 겁니다. 이 과정에서 얻은 두 고윳값을 이용하여 이미지 부분을 평명, 윤곽선, 코너 중 하나로 결정합니다. [그림 7-14]를 보면 이해하기 쉬울 겁니다. 한 고윳값이 다른 한 고윳값보다 매우 클 경우, 즉 한쪽 방향으로만 강도가 급격히 변할 경우 윤곽선이 됩니다. 두 고윳값이 모두 클 경우, 즉 모든 방향으로 강도가 급격히 변할 경우 코너, 두 고윳값이 둘 다 작으면 평면이 됩니다. 헤리스 코너 검출기로 캐니 윤곽선 겸추기와 마찬가지로 특별한 구현 없이 라이브러리로 바로 사용할 수 있습니다.

7.3.3  SIFT
SIFT(Scale-Invariant Feature Transform:크기 불변 피처 변화)는 크기 불변성, 회전 불변성, 평행이동 불변성을 동시에 만족시키는 피처를 생성하는 기법입니다. 7.3.2절 '코너'에서 회전불변성, 크기 불변성, 평행이동 불변성을 만족시키며 대랴응로 얻을 수 있는 피처가 이미지 인식에 유용하다고 언급했습니다. 그리고 코너가 크기 불변성을 만족시키지 않는다는 말도 잠깐 했습니다. 왜 그런지는 다음 그림을 보겠습니다.
[그림 7-15]는 같은 크기의 두 이미지를 보여조고 있는데, 왼쪽에는 토끼가 한 마리가 있고, 오른쪽에느 토끼가 세 마리 있습니다. 사람은 오른쪽 이미지에 있는 토끼와 왼쪽 이미지에 있는 토끼가 같다는 것을 금방 알 수 있지만, 컴퓨터로 이미지 처리를 하면 이미지 안의 물체 사이즈(혹은 이미지 척도(scale))와 상관없이 이미지 크기에 따라 원도우 크기(그림에서는 사각형으로 표시했습니다)가 정해지므로 두 이미지에서 검출하는 코너가 완전히 달라집니다.
이 문제를 해결하는 가장 쉬운 방법은 한 이미지의 확대/축소 버전을 여러개 만든 후(이를 이미지 피라미드(image pyramid)라고 합니다) 이미지를 비교하는 겁니다.[그림 7-15]의 오른쪽 이미지를 확대하다 보면(혹은 척도를 줄이다 보면)언젠가는 왼쪽 이미지에 있는 토끼와 크기가 같아지겠죠.
한편 아우스 원도우를 이용한 필터링(블러)처리 결과와 이미지의 척도(스케일)이 작아지는 효과, 즉 이미지 안의 물체가 커지는 것이 비슷한 효과를 낸다는 점에 착안하여 가우스 함수를 이용하여 각 지역마다 다른 척도를 찾는 방법이 제안되었습니다. 대표적인 방법으로 LoG(laplacian of Gaussian(가우스 라플라스)와 DoG(differece of Gaussian(가우스 차))가 있습니다.
LoG와 DoG는 모두 가우스 원도우를 이용하여 이미지에 블러효과를 준 후 그렇게 얻어진 이미지의 강도합수를 미분하여 지역 극값을 찾습니다. 지역 극값을 찾는것으로 이미지 강도의 급격한 변화가 일어나는 점을 찾을 수 있게 되고, 이 점들이 지역 피처를 추출할 후보가 됩니다. 이때 다양한 척도에서의 극값을 검출하기 위해 다른 표준편차값을 가지는 복수의 가우스 운도우를 이용합니다. [그림 7-16]은 다른 표준편차를 가지는 가우스 원도우를 이용해서 이미지를 처리한 것을 보여줍니다. 표준편차가 클수록 이미지가 흐릿해지는데, 이는 이미지가 커지는 것과 같은 효과로 생각할 수 있습니다.
이렇게 다양한 표준편차를 가지는 가우스 원도우로 생성된 여러 이미지(즉, 척도가 다른 이미지)의 특징(x, y)좌표에서 일관되게 극값이 검출된다면, 그 위치는 이미지의 척도에 영향받지 않는다고 여길 수 있습니다. 이 좌표를 특징점(keypoint)이라고 합니다. 그리고 가장 큰 극값을 얻은 이미지의 척도(즉, 가우스 원도우의 표준편차)가 그 특징점의 척도가 됩니다. 그결과 각 특징점과 그와 연결된 척도를 얻게 됩니다.

이렇게 척도에 영향받지 않는 특징점을 찾은 후에는 특징점의 방향을 찾습니다. 특징점의 방향을 고려하면 회전한 물체도 인식할 수 있게 됩니다. 특징점과 그 주변의 회전 방향을 찾기 위해 각 특징점의 척도에 해당하는 이미지를 이용하여 주변 이미지의 강도 함수를 x축 y축으로 미분한 후 변화가 가장 급격한 곳을 찾아 그 특징점의 방향으로 정합니다.[그림 7-17]에서 볼 수 있듯이 SIFT는 각 특징점에 대해 16개 주변 구역을 정한 뒤 각 구역마다 8개의 방향을 정하므로 특징점 하나는 128개의 값을 가지게 됩니다. 이러한 특징점의 주변 값들을 특징량(keypoint descriptor)이라고 합니다. 두 이미지를 비교할 때는 두 이미지 안의 특징점의 특징량을 이용해서 유사도 계산(옐르 들면 유클리드 거리 계산)을 하게 됩니다.
[그림 7-18]에서는 SIFT를 이용해 왼쪽의 기차와 개구리를 가운데 이미지에서 찾는 예를 보여줍니다. 개구리와 기차가 다른 물체 뒤에 숨어 있고 놓인 방향이 달라도 특징점(개국리 다리, 기차 바퀴 등)을 이용해서 성공적으로 찾앗습니다. 또한 각 특징짐마다 사용하는 척도가 다르므로 실제 피처를 뽑는 이미지 범위(사각형의 크기)가 다른 것도 볼 수 있습니다. SIFT기법은 2004년에 소개된 이후 많은 곳에서 사용되었지만, 특허 등록이 되어 있어 2016년 현재 상업적인 용도로는 사용할 수 없습니다. 대신 Brisk(Binary Robust Invariant Scalable Keypoints)나 Kaze 등을 사용하면 됩니다. 두 알고리즘 모두 OpenCV에 라이브러리로 구현되어 있으므로 어렵지 않게 사용할 수 있습니다.
7.3.4 주성분 분석
주성분 분석(PCA(principal component analysis))은 데이터에서 의미 있는 축을 찾아낸 후 그 축을 이용하여 고차원 데이터를 저차원으로 사영하는 방법입니다. 데이터에서 차원 수만큼 축이 존재하는데 주성분 분석 기법은 이들 중 가장 중요한 축, 즉 데이터의 특징을 가장 잘 표현할 수 있는 축부터 순서대로 찾아냅니다.
예를 들어[그림7-19]에서 데이터의 차원을 축소한다고 생각해봅시다. x축은 키, y축은 몸무게, 각 점은 해당 키와 몸무게를 가진 사람이라고 합시다. 이 데이터는 키와 나이라는 2가지 차원을 가집니다. 각 데이터는 z-점수 표준화 했습니다.

이 데이터를 검은 축과 회색 축 중 하나를 골라 사영한다고 생각해 봅시다. 회색 축 위의 점들은 떨어져 있는 반면, 검은 축 위의 점은 다닥다닥 붙어 있게 됩니다. 위 데엍에서 사람들의 키와 몸무게보다 더 다양하기 때문입니다.(즉, 키의 분산의 크기 때문입니다). 따라서 이 데이터를 1차원으로 축소할 때는 회색축을 이용해야 데이터의 특징을 더 잘 보존할 수 있습니다. 주성분 분석은 이와 같이 분산이 큰 순서대로 축을 찾아내면서 데이터의 차원을 줄여가는 방식입니다.  각 차원의 분산을 이용하기 위해 공분산행렬을 계산한 후 그 행렬을 고유벡터 분해하여 축을 찾습니다. 공분산행렬에 대해서는 4.5.2절 '마할라노비스 거리'를 차모하세요. 공분산행렬은 늘 정방행렬이고 대칭행렬입니다. 공분산행렬을 7.3.2절 '코너'에서 설명한 것처럼 고유벡터로 분해하는 것으로 데이터를 설명하는 축, 즉 성분들을 구하게 됩니다.

이미지 인식에 주성분을 이용하는 이유는 복수의 이미지에서 주성분을 뽑아내면 그 이미지들의 공통된 특징을 찾을 수 있기 때문입니다. 예를 들어 사람 얼굴의 경우, 세세한 부분은 다르지만 눈이 둘, 코가 하나, 입이 하나라는 공통점이 있습니다. 그리고 개개인의 특징은 눈 크기나 이마넓이 차이 등으로 분산할 수 있습니다.

이 아이디어를 바탕으로 한 것이 고유 얼굴 검출(eigenface detection1991)입니다. 고유 얼굴 검출은 대부분의 얼굴 이미지를 공통된 주성분으로 분해할 수있다는 가정을 바탕으로 얼굴 이미지를 설명할 수 있는 주 고유 얼굴(즉, 다양한 얼굴 데이터를 가장 잘 설명할 수 있는 주성분)을 찾아낸 후 고유 얼굴의 선형 조합을 이용하여 원래 얼굴 이미지를 나타냅니다.

고유텍터, 즉 주성분을 많이 이용할수록 차원을 덜 축소하게 되므로 고유 어굴을 조합한 이미지가 원래 이미지와 가깝게 됩니다.[그림 7-20]은 사용하는 주 성분수(K)를 4개, 128개, 256개로 바꾸었을 때 복원된 얼굴 이미지의 변화를 보여줍니다. 차이점을 확실히 알 수 있습니다.

하지만 주성분을 많이 쓴다고 좋은 것은 아닙니다. 예를 들어 이미지에서 '머그컵'이 있는지 여부를 인식하려고 할 때 주성분을 많이 사용하면 무늬가 있는 머그겁과 없는 머그겁을 구별하게 될 것이고, 그러면 일반화를 할 수 없어서 시스템의 목적에는 맞지 않게 됩니다. 분류하려는 이미지에 따라서 K값을 적절히 정하는 것이 중요합니다. PCA의 구현 방법에 대해서는 13장의 고유 얼굴 검출 예제에서 살펴봅니다.

7.4 딥러님을 이용한 이미지 인식
이 절에서는 딥러닝을 이용한 이미지 인식에 대해 알아보겠습니다. 모든 머신러닝 문제에서 그렇듯 '어떤 피처를 뽑아 학습시키느냐'가 모델의 성능을 좌우합니다. 7.3절 '이미지 인식에 사용하는 피처'에서는 이미지 인식 시스템을 만들 때이미지에서 무엇이 중요한지 고려해서 피처를 사람이 직접 하나하나 정의했습니다. 즉, 사람이 '윤곽선이 중요할 것이다', '코너가 중요할 것이다'라고 생각하고 피처를 뽑았습니다. 그런데 딥러닝을 이용하여 머신러닝을 할 때는 이렇게 수동으로 정의한 피처를 사용하지 않습니다. 학습과정에서 어느 것이 중요한 피처인지 모델이 스스로 학습합니다. 이것이 딥러닝과 전통적인 머신러닝 간의 가장 큰 차이입니다.

7.4.1 CNN 소개
CNN(convolutional netural network, 합성곱 신경망)은 딥러닝 기법 중에서도 이미지 인식에서 강력한 성능을 발휘합니다. CNN의 기본 개념은 편지봉투에 쓰인 우편번호를 인식하기 위해 1989년 레쿤에 의해 제안되었습니다. 그 후 1998년에 초기 CNN인 LeNet-5가 소개되었지만 컴퓨팅 리소스의 한계로 고해상도 이미지 분류에 좋은 성능을 보이지 못한 탓에 당시에는 주목받지 못했습니다.

그 후 컴퓨팅 하드웨어의 계산 능력 향상과 학습 데이터의 증가로 2012년 이미지넷 챌린지에서 알렛스넷(AlexNet)이 기존 모델과는 비교도 할 수 없는 놀라운 성능을 보여준 후 CNN은 이미지 인식의 표준 모델로 자리잡았습니다. 알렉스넷의 아키텍처를 살펴보면 CNN의 기본 개념에 대해 알 수 있습니다. 알렉스넷의 아키텍처는 [그림 7-21]과 같습니다.

알렉스텟은 합성곱 레이어 5개와 완전 연결(fully-connected)레이어 3개로 이루어져 있습니다. 위쪽 레이어와 아래쪽 레이어로 나눤 이유는 알렉스넷이 GPU 2개를 사용하여 만들어졌기 때문입니다. 입력은 가로 224 * 세로 224 크기 이미지입니다. 따라서 224 * 224 * 3(컬러 채널 RGB)행렬로 표현됩니다. 출력은 0부터 1사이의 실숫값 요소로 이루어지는 1000*1 크기의 벡터인데, 요소 하나가 클래스 하나에 속하는 가능성을 나타냅니다. 즉, 알렉스넷은 이미지 하나를 클래스 1000개 중 하나로 분류합니다. 기존 머신러닝과 다른 점은 합성곱 레이어를 통해 피처를 생성하는 겁니다. 즉, 이미지에서 피처를 추출하여 모델의 입력으로 사용하는ㄱ ㅔ 아니라 이미지 자체를 그대로 모델의 입력으로 사용합니다. 그리고 학습과정에서 이미지의 어떤 부분에 중점을 둘지 배우게 됩니다.

7.4.2 합성곱 레이어
합성곱 레이어는 필터를 이용해 입력값을 변형하는 레이어입니다. 7.1.2절 '필터링'에서 필터 원도우를 이미지에 적용하여 이미지를 변환한다는 것을 배웠습니다. CNN의 합성곱 레이어도 비슷한 역할을 수행하지만 7.1.2절의 필터와는 달리 이미지의 행렬을 다른 모형의 행렬로 변경합니다. 예를 들어 [그림 7-22]에서 볼수 있듯 알렉스 넷의 가장 최초의 합성곱 레이어는 11 * 11* 3 크기의 원도우를 사용해 224 * 224 * 3 크기의 이미지를 55* 55* 96 크기로 변경했습니다. 이 행렬의 넓이와 높이는 이미지의 워치와 관련된 특징을 잡아내고 깊이는 이미지의 다양한 피처를 잡아냅니다. 이렇게 하여 입력 이미지의 모든 부분의 정보를 조합한 피처를 96개(깊이의 수) 생성합니다. ConvertJS페이지의 Activation란이 이렇게 생성된 피처들을 보여줍니다. 피처 수를 정하는 데는 특별한 기준이 없습니다. CNN의 성능을 높이기 위해 피처 수, 레이어 수 및 레이어 구조를 어떻게 바꾸어야 하는지 활발하게 연구되고 있습니다.

합성곱은 7.1.2절 '필터링'에서 설명한 필터링 및 7.1.3절 '합성곱'에서 설명한 합성곱 처리와 마찬가지로 원도우를 옮겨가며 구합니다. 이때 원도우를 몇 픽셀씩 옮길 것인지 지정할 필요가 있는데 이를 스트라이드(stride)라고 합니다. [그림 7-23]에서 스트라이드 1인 경우와 2인 경우 원도우를 어떻게 옮기는지 보여줍니다. 알렉스넷은 스트라이드 4, 원도우를 4픽셀씩 옮겨가며 합성곱을 구합니다. 이미지의 가장자리는 [그림 7-4]에 살펴본 제로 패딩을 사용했습니다.

7.4.3 폴링
합성곱 레이어의 결과를 그대로 다음렝이어로 넘길 수도 있지만, 일반적으로는 샘플링으로 볼수 있는 폴링(pooling)단계를 거칩니다. 즉, 생성된 모든 정보를 사용하는게 아니라 다운샘플링된 정보를 사용하는 것으로 과학습을 막고 노이즈에 강한 피처를 생성합니다. [그림 7-24]는 원도우 크기 2 * 2, 즉 스트라이드 2를 이용한 최댓값 폴링(max pooling)과 평균값 폴링(average poooling)을 나타냅니다. 최댓값 폴링은 원도우 안의 가장 큰 값을 뽑는 것이고, 평균값 폴링은 원도우 안의 값들의 평균을 이용하는 겁니다. [그림 7-24]에서 최댓값 폴링의 결과 이미지의 (0,0) 픽셀은 (12, 20, 8, 12)의 최대값인 20으로 채워졌고, (0,1) 픽셀은 (30, 0,2,0)의 최댓값인 30으로 채워졌습니다. 평균값 폴링의 경우 (0,0) 픽셀은 (12, 20, 8, 12)의 평균값인 13으로 채워진 것을 알 수 있습니다. 이렇게 폴링을 이용해 합성곱 레이어의 정보를 압축하여 다음 레이어로 넘기게 됩니다.
그럼 평균값 폴링과 최댓값 폴링 중 어떤 것을 이용해야 할까요? 7.3절 '이미지 인식에 사용하는 피처'에서 살펴보았듯 이미지 인식에서는 이미지의 특징점을 찾은 후 그 주변의 특징량을 이용합니다. 합성곱 레이어의 결괏값이 클수록 이미지 인식에서 중요한 역할을 합니다(강도함수의 극값이 클수록 종요한 것과 마찬가지죠). 따라서 활성화된 결괏값 중 최댓값을 활용하는 최댓값 폴링이 좋은 성능을 낸다고 알려져 있습니다.

7.4.4 활성화 함수
신경망 모델에서 사용되는 비선형합수(activation function)라고 합니다. 비선형합수는 선형합수, 즉 직선으로 표현할 수 없는 데이터 사이의 관계도 표현할 수 있으므로 [그림 7-25]에서 선형함수, 대표적인 활성화 함수인 시그모이드 함수, 하이퍼볼릭 탄젠트, ReLU(rectified linear unit)함수를 볼 수 있습니다.

- 선형함수 : y = x
- 시그모이드 함수 : y = 1 / ( 1 + exp(-x))
- 하이퍼볼릭 탄젠트 함수 : y = (exp(x) - exp(-x))/(exp(x) + exp(-x))
- ReLU 함수 : y = max(0,x)

알렉스넷 이휴 합성곱 신경망 모델에서는 더 빠른 계산을 위해 ReLU를 이용합니다. ReLU는 입력값이 0보다 작을 때는 무시하고 , 0보다 클 때는 입력값을 그대로 사용하는 것으로 간단하게 비선형함수를 구현할 수 있고 괜찮은 성능을 보장하므로 자주 사용됩니다.

7.4.5 완전연결 레이어
완전연결 에이어는 일반적인 신경망과 같은 방식으로 이전 레이어의피처와 다음 레이어 사이의 모든 연결을 고려합니다. 즉, 원도우를 이용한 필터나 폴링으로 인한 변형 없이 입력 데이터를 그대로 이용합니다.
CNN은 합성곱 레이어 폴링을 반복하는데 이 과정에서 이미지의 강한 지역 피처들의 특징을 합성하여 전역적인 특징도 표현하게 됩니다. 알렉스넷에서는 하나의 이미지가 클래스 1000개의해당하는 확률을 출력하므로 최종 결과는 7.4.1절 'CNN 소개'에서 보았듯 이미지의 클래스 확률을 나타내는 1000*1 크기의 벡터입니다. [그림 7-26]에서 입력 이미지를 합성곱 레이어를 이용하여 변환한 뒤 와전연결 레이어에 통과시킨 결과 고양이 카페고리에 속할 확률이 가장 높게 나왔습니다. 따라서 이 이미지는 고양이로 분류됩니다.

7.5 마치며
이 장에서는 이미지 인식에 필요한 기본 개념과 주요 기법 및 알고리즘에 대해 고부했습니다. 특히 이미지 연구에서 좋은 성능을 보이는 CNN에 대해서도 가단히 설펴봤습니다. 이미지 인식의 필수 개념인 회전 불변성, 크기 불변성, 평행이동 불변성에 대해 이해하고 전통적인 이미지 치러체 대해 이해하여 합성곱 레이어와 폴링을 사용하는 이유를 알게 되었습니다.
이장에서 소개한 대부분의 기법은 다양한 프로그래밍 언어의 라이브러리로 구현되어 있습니다. 이에 대해서는 13장에서 살펴보겠습니다.












2018년 3월 11일 일요일

CHATER 6 영화 추천 시스템 만들기

영화 추천 시스템은 정보 필터링 시스템의 일종으로,각 정보 (상품, 신문기사, 친구 등)에 대한 사용자 점수나 선호도 등을 예측합니다. 아마존을 비롯한 거의모든 전자상거래 사이트에서는 사용자에게 상품을 추천합니다. 뉴스 포털에서 제공하는 사용자는 사용자별 추천 기사는 이제 너무나도 익합니다. 이렇게 추천 시스템은 오늘날 인터넷 기반 서비스에서 없어서는 안 될 중요한 서비스를 제공합니다. 이 장에서는 그중에서 넷플릭스 프라이즈(Netflix Prize)로 널리 알려진 영화 추천 시스템에 대해 알아봅시다.

6.1 영화 추천 시스템
영화 추천 시스템은 사용자가 해당 영화에 별점을 몇 개 줄 것인지 예측하는 문제입니다. 우선 추천 시스템에 쓰일 만한 데이터를 생각해 볼까요? [표 6-1]과 같이 사용자가 영화에 준 별점 데이터가 있어야 합니다.

표 6-1 사용자 별점 데이터
사용자 ID        abcd
영화 ID          00001
별점               4
별점을 준 일시      2012-03-02

[표 6-1]에 있는 정보만으로는 00001이 어떤 영화인지 알 수 없으므로 사용자가 왜 영화 0001에 별점 4를 줬는지 알 수 없습니다. 영화의 내용을 알기 위해서는 별도로 [표6-2]와 같은 영화 정보도 있어야 합니다.

[표 6-2 영화 데이터]
ㄹㅇㅁㄴㄹㄴㄹㅇㄴㄹ


회귀 모델로 영화의 특징을 이용해서 사용자의 별점을 예측하는 경우를 생각해 봅시다. 영화의 특징으로는 영화 제목, 영화 장르, 상영개시일 등이 있습니다. IMDB 같은 지식 베이스를 이용하면 등장하는 배우나 영화 장르 같은 정보를 이용할 수 있습니ㅏㄷ. 이를 이용하여 회귀식을 작성한다면 '영화수 * 영화의 특징 수 * 사용자 수'만큼의 변수를 고려해야 하므로 모델이 복잡해집니다.

한 사용자의 취향은 그 사용자가 보는 영화 내용으로 알 수 있습니다. 예를 들어 어떤 사용자가 해리포터 1편부터 4편까지 보았다고 할 때 5편을 추천하는 건 당연하겠죠, 또한 비스산 판타지 소설 기반의 영화인 나니아 연대기를 추천해도 좋을 겁니다. 이렇게 상품 내용에 기반하는 방식을 내용 기반 추천 시스템이라고 합니다.

또한 비슷한 영화 취향을 지닌 사용자들은 비슷한 영화를 볼 겁니다. 만약 사용자 1이 스파이더맨, 아이언맨, 어벤져수, 닥터 스트레인지를 보았고, 사용자 2가 스파이더맨, 아이언맨, 어벤져스를 보았다면, 사용자 2에게 닥터 스트레인지를 추천해도 될 겁니다. 이렇게 다른 사용ㅈ 정보를 이용하는 방법이 협업 필터링입니다.

이 장에서는 내용 기반 추천 시스템에서 유사도 계산에 사용하는 자카드 계수와 코사인 유사도, 협업 필터링에 사용하는 수학적 기법인 행렬 분해에 대해 알아봅시다.

6.2 유사도 계산
유사도란 두 객체가 얼마나 유사한지 나타내는 척도입니다. 4.5절 '유사도 계산'에서는 수치 데이터의 유사도를 측정하는 방법에 공부했습니다. 여기서는 두 문서 간의 유사도 평가와 협업 필터링에 자주 사용하는 자카드 계수와 코사인 유사도, 그리고 단어의 유사도 평가에 사용하는 편집거리에 대해 알아봅시다. 자카드 계수와 편집 거리는 문서 안의 문자열을 그대로 사용하여 유사도를 계산할 수있습니다. 코사인 유사도는 문서 안의 문자열의 빈도를 사용합니다.

- 자카드 계수: 두 집합이 공유하는 원소 수에 기반한 유사도
- 코사인 유사도: 두 벡터 사이의 각도에 기반한 유사도
- 편집거리: 문자열을 편집하는데 필요한 연산 수에 기반한 유사도

6.2.1 지카드 계수
자카드 계수(Jaccard coefficient)는 두 집합의 유사도를 측정하는 계수입니다. 집합 S와 T가 있을 때, 두 집합의 자카드 계수는 두 집합의 교집합의  원소수를 합집합의 워소수로 나눈값입니다. 식으로 표현하면 다름과같습니다.


식 6-1 자카드 계수

| S 교집합 T   |
| ____________  |
| S 합집확 T   |

각 영화 줄거리의 유사도를 비교하여 사용자가 구매한 영화와 비슷한 내용의 영화를 추천한다고 생각해 봅시다. 영화 줄거리에 출현하는 단어와 전체 단어 사이에는 다음과 같은 관계가 있습니다.

- P00: 영화 1과 영화 2의 줄거리에 사용되지 않은 단어
- P01: 영화 1 줄거리에만 사용된 단어
- P10: 영화 2 줄거리에만 사용된 단어
- P11: 영화 1과영화 2 줄거리에 동시에 사용된 단어

예를 들어 '해리포터와 마법사의 돌'(영화1)과 '해리포터와 불의 잔'(영화2)의 내용을 비교한다고 할 때, P01은 마법사의 돌, P10은 불의 잔, P11은 해리포터, 론, 헤르미온느, P00은 아이언맨, 스트레인지, 미녀와 야슈등이 될 겁니다.

단순히 생각해보면 영화 1과 영화 2의 유사도는 P11/(P00+P01+P10+P11)이 될 것 같습니다. 이렇게 계산하는 유사도를 단순 일치계수(simple matching coefficient)라고 합니다. 즉, 두 영화 줄거리에 공통으로 사용되는 단어를 모든 단어 수로 나누는 거죠, 하지만 한 영화의 줄거리 소개에 사용되는 단어 수가 모든 단어 수보다 월등히 적으므로 워 식을 사용할 경우 P00의 값이 다른 값에 비해 굉장히 크게 됩니다.

협업 필터링에서도 비슷한 문제가 생깁니다. 예를 들어 한 사용자가 구매하는 상품 수가 온라인 쇼핑몰에 존재하는 전체 상품 수에 비해 월등히 적으므로 두 사용자 중 어느 쪽도 구매하지 않은 상품수 (P00)가 많아집니다. 이렇게 데이터 하나에 존재하는 피처 수가 가능한 피처 수에 비해 월등하게 적은 경우 데이터가 희박하다고 표현합니다. 지 카드 계수는 이렇게 희박한 데이터 간의 유사도를 측정하는 데 유용합니다.

6.2.2 코사인 유사도
코사인 유사도(cosine similarity)는 두 벡터 사이의 각도를 -1부터 1사이의 값으로 나타내는 척도입니다. 두 벡터가 같은 방향(두 벡터 사이의 각도가 0도)이면 1, 두 벡터가 완전 반대 방향(두 벡터 사이의 각도가 180도)이면 -1이 됩니다. 값이 1일 경우 벡터 간의 유사도가 크다는 거고, -1일 경우 유사도가 매우 작다는 겁니다. 정의는 다음과 같습니다.

식 6-2 코사인 유사도


각도와 유사도는 무슨 관계가 있을까요? 문서에 나오는 단어 빈도를 사용하여 유사도를 측정한다고 생각해봅시다. [표6-3]은 각 문서에 출현하는 단어 수를 보여줍니다.

표 6-3
문서당 단어 빈도
                      단어1       단어2
문서1            4               3
문서2           2                1
문서3           1                3

위 표를 다음과 같은 벡터로 나타낼 수 있습니다.

문서1 = (4,3)
문서2 = (2,1)
문서3 = (1, 3)

그림으로 나타내면 [그림 6-1]과 같습니다. 그림에서 볼수 있듯이 코사인 유사도는 벡터의 크기를 무시하고 각도를 이용하여 유사도를 계산합니다.

문서 2와 문서3 중 어느 문서가 문서 1에 가까운지 살펴보겠습니다.

sim(문서1, 문서2) = (4*2 + 3*1)/루트(4*4 + 3*3)루트(2*2 + 1*1) = 0.98
sim(문서1,  문서3) = (4*1 + 3*3)/루트(4*4 + 3*3)루트(1*1 + 3*3) = 0.82

문서 2가 문서 3보다 문서 1에 더 가깝다는 것을 알 수 있습니다. 이때 연산 횟수가 많을 수록 거리가 멀다고 정의합니다. 문자열에 대해 가능한 연산은 문자 삽입(insertion), 삭제(deletion), 대체(substitution), 전치(transposition)가 있습니다. 편집 거리는 허용하는 연산에 따라 종류가 나뉘는데, 예를 들어 대체 연산만 허용하는 해밍 거리와 삽입, 삭제, 대체 연산을 허용하는 레벤슈타인 거리 등이 있습니다. 문자열 비교 시 가장 자주 사용하는 거리는 레벤슈타인 거리 입니다.

옐르 들어 다음과 같은 문자열이 있다고 합시다.
S1 = abcd
S2 =acfdg

S1을 S2로 만들려면 다음과 같은 과정을 거칩니다.

1. b 삭제
2. f 삽입
3. g 삽입

3번의 연산을 거쳤으므로 편집 거리(S1, S2)는 3이 됩니다.

그럼 이런 편집거리는 어디에 사용할 수 있을까요? 아래와 같은 영화 제목을 생각해 봅시다.

- 영화1: 스파이더맨1
- 영화2: 스파이더맨2
- 영화3: 아이언맨1

영화 1과 2는 편집 거리가 2(1삭제 후 2삽입)인 반면, 영화 1과 3은 편집 거리가 7('스, 파, 이, 더' 삭제 후 '아, 이, 언' 추가)이라는 것을 알 수 있습니다. 편집 거리는 이렇게 시리즈몰의 제목을 찾는데 유용합니다. 또한 문서의 안의 오탈자를 고려하여 유사도를 측정하는데도 유용합니다. 예를 들어 '해리포터'와 '헤리포터'의 경우 다른 문자열리지만 편집 거리가 2로 작으므로 오탈자로 인해 차이가 생겼다고 보고 같은 문자열로 취급하는 식입니다.

6.3 내용 기반 추천 시스템
내용 기반 추천 시스템은 사용자가 과거 좋은 별점을 준 영화와 비슷한 영화를 추천합니다.
그럼 어떤 영화가 비슷한 영화일까요? 단순히 생각하면 영화 내용이  같으면 될 것 같지만 모든 문장이 같을 순느 없을 테니 영화 내용 소개 문서 안에서 사용된 단어가 비슷하면 되겠네요. 비슷한지 여부를 판ㄹ별하는 것 유클리드 거리잖아요! 그렇다면 문서의 모든 단어를 3.3.2절 '카테고리 데이터 표준화'에서 설명한 원-핫 인코딩 방식을 적용해 수치 데이터로 바꾼 후 문서 같의 유클리드 거리를 계산하면 되겠군요. 그런데 문제가 있습니다. 일반적으로 문서에는 사용된 단어가 됭장히 많고, 춫ㄹ현 빈도가 다르며, 같은 단어라도 다른의미로 쓰일 수 있습니다.

이 문제를 해결하려면 문서 내의 모든 단어를 사용하는 대신 5.1.1절 '문서 분류에 많이 사용하는 피처'에서 배운 대로 문서에 나오는 중요단어를 피처로 추출하여 비교합니다. 그리고 문사 간 유사도를 계산하기 위해서는 6.2절 '유사도 계산'에서 설명한 유사도 계산법을 이용합니다.

이런한 내용 기반 추천 시스템은 다른 사용자의 정보가 없어도추천이 가능하고, 독특한 취향을 가진 사용자(즉, 다른 사용자와 겹쳐지 않는 상품만 구매하는 사용자)에게도 상품을 추천할 수 있으며, 상품을 추천하는 이유를 설명하기도 쉽습니다. 반면 특이한 상품을 추천하는 ㅔㄷ 제한적이며, 과거 구매 이력이 없는 신규 사용자에게 추천하기 어렵다는 단점이 있습니다.

6.4 협업 필터링
협업 필터링은 다른 사용자의 구매 이력을 이용해서 영화를 추천하는 방법입니다. 한 사용자의 구매 이력만 생각하는 내용 기반 추천 시스템과 달리 협업 필터링은 여러 사용자 혹은 여러 아이템 정보를 동시에 사용하여 추천합니다. 그림으로 나타내면 다음과 같습니다.

그림 6.2 사용자 기반 필터링

사용자 1이 영화1, 2, 3를 보고, 사용자 2가 영화 1,4를 보았을 때 , 사용자 2에게 영화2를 추천하는 것이 사용자 기반 협업 필터링의 아이디어 입니다. 반면 상품 기반 협업 필터링은 사용자으 상품 평가 유사성을 이용하여 상품을 추천합니다. 예를 들어 영화1과 영화2에 사용자 1과 사용자3이 좋은 별점을 줬을 경우, 사용자 2도 좋은 별점을 줄 거라고 생각하는 겁니다.

두 필터링 방법 모두 상품, 사용자, 별점의 괄계를 이용합니다. 이런 관계를 [표6-4]와 같이 행별로 표시한 것을 유틸리티 행렬(utlity matrix)이라고 합니다. 유틸리티 행렬은 '사용자 수 * 상품수(혹은 사품 수 * 사용자 수)' 크기 행렬입니다. 행렬의 각 원소는 사용자가 상품에 준 점수를 나타냅니다. ?는 사용자가 상품에 아직 점수를 주지 않은 항입니다.

표 6-4 유틸리티 행렬
                  영화1        영화2         영화3       영화4
사용자1           1            5               2              4
사용자2           2            2               5              1
사용자3           2            4               ?               ?

[표 6-4]에서 사용자 1은 영화 1에 별점 1을 줬습니다. 사용자 3은 아직 영화 3과 영화 4에 별점을 주지 않았습니다. 그럼 영화 3과 4를 사용자 3에게 추천할 지 여부를 정하려면 (사용자 3, 영화 3), (사용자3, 영화4) 별점을 예측할 필요가 있습니다. 별점 예측 기법으로는 사용자/상품 기반 협업 필터링과 잠재성 요인 모델이 있으며, 성능 평가에는 평균 제곱근 편차를 사용합니다.

6.4.1 평균 제곱근 편차
사용자가 입력할 별점을 되도록 실제 값에 가깝게 예측하는 것(근사)이 추천 시스템의 목표입니다. 예를 들어 사용자 1이 '어메이징 스파이더맨'에 줄 실제 별점이 5라고 할때 별점 3으로 예측하는  것보다 별점 4로 예측하는 것이 더 정확한 예측이고 더 정확한 추천입니다. 즉 실제 별점과 근사 별점의 차가 적을수록 좋은 예측이 됩니다. 이를 평가하는 것이 평균 제곱근 편차(Root Mean Square Error:RMSE)입니다.

실제 별점이 들어 있는 행렬 M, 예측한 별점이 들어 있는 행렬을 M', 행렬의 각각 mij, m'ij로 나타내고, 유틸리티 행렬의 원소 수를 N이라 할 때, 평균 제곱근 편차는 다음과 같이 계산합니다.

6-3 평균 제곱근 편차

루트(함(mij - m'ij)**/N)

mij: 실제 별점 행렬의 (i,j) 항
m'ij:예측 별점 행렬(i,j) 항
N: 유틸리티 행렬의 원소 수:

즉, 평균 제곱근 편차는 예측값과 실제 값의 차이를 제곱한 값의 평균의 제곱근입니다. 예측값과 실제값의 차이가 적을수록, 또 예측값과 실제값의 차이가 적은 항이 많을 수록 이 값은 작아집니다. 그러므로 값이 적을수록 좋은 예측입니다.

[표 6-4]의 유틸리티 행렬을 이용해 평균 제곱근 편차를 계산했습니다.

실제 별점 행렬M
              영화1                  영화2                 영화3                 영화4
사용자1      1                       5                        2                       4
사용자2      2                       2                        5                       1
사용자3      2                       4                       1                         4

예측 별점 행렬 M1
                   영화1           영화2            영화3         영화4
사용자1       1                  5                      2                 4
사용자2       2                 2                       5                 1
사용자3       2                 4                       1                  3

예측 벌점 행렬 M2
                   영화1           영화2            영화3         영화4
사용자1       1                  5                      2                 4
사용자2       2                 2                       5                 1
사용자3       2                 4                      4                  2

여기서 평균 제곱근 편차는 유틸리티 행렬(표6-4)에서 ?로 표시된 미지항에 대새서만 계산합니다. 즉, 예측한(사용자 3, 영화3)과 (사용자3, 영화4)의 항만 고려하여 값을 구합니다.  유틸리티 행렬의 원소 수는 12개이므로 N은 12가 됩니다. 따라서 예측 별점 행렬 1과 예측 별점 행렬 2의 평균 제곱근 편차는 다음과 같습니다.

RMSE(M1) = 루트(((1-1)** + (4-3)**/12)) = 0.29
RMSE(M2) = 루트(((1-4)**+(4-2)**/12)) = 1.04

예측 별점 행렬1이 더정확히 실제 별점을 예측했다는 것을 알수 있습니다.

6.4.2 사용자 기반, 상품 기반 협업 필터링
사용자 기반, 혹은 상품 기반 협업 필터링은 추천을 위해 사용자 혹은 상품의 유사도를 사용합니다.
사용자 간의 유사도를 계산할 때는 사용자가 본 영화와 별점을 이용합니다. 자카드 계수를 사용할 경우에는 두 사용자가 본 영화 중 공통된 영화가 많을수록 두 사용자가 비슷하다고 보는데, 이 경우 영화의 별점 정보를 무시하게 되므로 적절하지 않습니다. 예를 들어 두 사용자가 완전히 같은 영화를 봤더라도 상반되게 별점을 줬다면 두 사용자의 영화 취향이 비슷하다고는 할 수 없겠죠. 따라서 상품에 별점과 같은 선호도 정보가 있을때는 코사인 유사도를 계산하는 것이 좋습니다. 계산 절차는 다음과 같습니다.

1.  열마다 별점 평균값 구하기
2. 각 별점에서 평균값 빼기
3. 미지항을 0으로 채우기

[표 6-4]의 유틸리티 행렬에 이 방법을 적용해서 사용자1, 사용자2, 사용잦3의 유사도를 계산해 볼까요?

사용자1의 별점 평균: (1+5+2+4)/4 = 3
사용자2의 별점 평균:(2+2+5+1)/4 = 2.5
사용자3의 별점 평균:(2+4)/2 = 3

[표6-4]의 각 열에서 위에 계산한 별점 평균을 뺀 것이 [표 6-5]입니다. 사용자 3의 미지항은 0으로 채웠습니다.

표 6-5 수정된 사용자 별점

                     영화1           영화2            영화3         영화4
사용자1       -2                  2                      -1                 1
사용자2        -0.5                -0.5                      2.5                -1.5
사용자3       -1               1                     0                  0

[표6-5]의 값을 이용해서 계산한 사용자의 코사인 유사도는 다음과 같습니다.

sim(사용자1, 사용자3) = 0.89
sim(사용자2, 사용자3) = 0.0

사용자 1이 사용자 3과 비슷하므로, 사용자 3에게는 사용자1이 좋은 점수를 준 영화 4를 추천하면 될 것 같습니다.

상품 기반 추천 방식으로 영화를 추천할 경우 영화 정보 등을 이용하여 유사도를 계산하므로 기본적으로는 내용 기반 추천 시스템에서 사용하는 방식과 같습니다. 카테고리나 가격 같이 피처가 정해져 있는 상품은 유사도 계산이 더쉬우므로 실전에서는 사용자 기반 협업 필터링보다 상품 기반 협업 필터링을 더 자주 습니다. 상품 기반 협업 필터링을 이용한 사용자의 상품 별점 계산은 일반적으로 다음과 같습니다.

rxi = bxi  + (합(Sij*(rxj  - bxj))/합(Sij))

bxi = u  + bx + bi
rxi = 사용자 x의 상품 i에 대한 별점
i = 사용자 x의 별점 정보가 존재하지 않는 상품
Sij = 상품 i와 사품 j의 유사도
j = Sij가 높고 사용자 x 의 별점 정보가 존재하는 상품
bxi = 사용자 x의 상품 i에 대한 별점 편향
u = 전체 상품의 별점 평균
bxi = 사용자 x의 상품i에 대한 별점 편향
u = 전체 상품의 별점 평균
bx = 사용자 x의 별점 편향
bi = 상품 i의 별점 편향

미지의 별점을 구하려면 영화(상품) 전체의 평균 별점에 사용자 및 영화의 별점 편향(치우침)을 고려합니다. 별점 계산에서 편향을 다루는 표준화에 대해서는 6.5절 '표준화'에서 자세히 살펴보겠습니다.

6.4.3 잠재성 요인 모델
사용자/상품 기반 협업 필터링은 상품이나 사용자의 유사도를 계산해서 별점을 예측하지만 잠재성 요인 모델(latent factor model)은 유사도 계산하지 않고 유틸리티 행렬로 별점을 직접 예측합니다. 잠재성 요인 모델은 유틸리티 행렬이 두 행렬(사용자 요인 행렬, 별점 요인 행렬)의 곱으로 이루어져 있다고 가정합니다.

6.4.3.1 특잇값 분해
행렬 분해는 행렬 하나를 여러 행렬의 곱으로 분해하는 방법입니다. 이 방법에는 여러가지가 있지만, 그 중에서 가장 널리 사용되는 방법은 특잇값 분해(Singular Value Decomposition:SVC)와 7.3.2절 '코너'에서 공부할 고유벡터 분해 (eigen vector decomposition) 입니다.
행렬 A가  m*n 행렬일 때, A를 특잇값 분해하면 크기 m*m의 행렬  U, 크기 m * n행렬  합, 크기  m * n의 행렬 V로 분해할 수 있습니다. 그림으로 나타내면 [그림6-3]과 같습니다.

그림 6-3 특잇값 분해


특잇값 분해는 계산에 시간이 많이 걸리기 때문에 일반적으로 고윳값이 큰 고유벡터 k개만으로 U와 V를 만듭니다. 이를 절단 특잇값 분해(truncated SVD)라고 합니다. 적은 수의 고유벡터를 사용하여 만들어진 U와 V의 곱은 워래의 행렬에 가까운 행렬(근사 행렬)을 만들어낼 수 있습니다. 따라서 전단 특잇값 분해는 차원 축소에 이용되기도합니다.

절단행렬 분해를 크기라 '사용자 수 * 영화 수'인 유틸리티 행렬에 적용하면 유틸리티행렬을 크기가 '사용자수 * k'인 상요자 요인 행렬 X와 크기가 '영화 수 * k'인 영화 요인 행렬 Y로 나눌 수 있습니다. 여기서 K는 원래 사용자 수 및 영화 수보다 작습니다. 그리고 이 행렬의 곱을 구하는 것으로 원래 행렬을 예측하게 됩니다.

특잇값 분해를 적용하려면 행렬의 모든 값을 알아야 합니다. 하지만 지금 행렬에는 미지항(사용자의 별점이 없는 영화)이 있습니다.  따라서 미지항을 임의의 값으로 초기화 하고 가중치 행렬을 적용해서 무시하게 만들거나, 아애 손실함수를 존재하는 별점 값에 대해서만 계산합니다. 그리고 이미 값이 존재하는 항에 의한 과학습을 막기 위해 정규화를 적용합니다. 행렬의 전 항의 별점을 이용한 정규화된 손실함수는 [식 6-4]와 같습니다.



[식 6-4]의 값을 구하는 방법은 다양합니다. 여기서는 자주 쓰이는 교대 최소제곱법과 경사하강법에 대해 설명하겠습니다.

교대 최소제곱법
미지 행렬 X,  Y를 하나씩 구해나가는 방법입니다. X, Y를 임의의 행렬로 초기화한 후, 임의의 Y를 사용하여 X를 구하고, 그렇게 구해진 X를 업데이트 합니다. 이 과정을 각 단계마다 XY로  근사한 행렬 Q와 실제 점수 행렬 R을 이용하여 [식 6-4]의 손실을 계산하고,  이 손실값을 전 단계로 부터 변하지 않을  때 갱신을 멈춥니다. 일반적으로 반복횟수를 제한하거나, 이전 단계의 손실값과 비교하여 사용자가 지정한 차이보다 작을 경우 갱신을 머춥니다.

X와 Y로 행렬을 근사할때 이미 알고 있는 별점에 의한 근사 결과에 가중치를 더 주면 결과가 더 정확할 것 같습니다. 이를 위해 가중치 행렬을 정의합니다. 이  행렬은 점수 행렬 R과 같은 크기(m * n)인데, Rij 에 유저가 준 점수값이 있으면 1, 없으면 0입니다. 수식으로 표현하면 다음과 같습니다.

식 6-5 가중치 행렬
Wui = 0, rui = 0이면
Wui = 1 그렇지 않으면
wui = 가중치 행렬의 (i, j)의 값

가중치 행렬이 들어간 손실 함수는 다음과 같이 바뀝니다.

이와 같이 사용자와 상품 행렬을 더 이상 값이 바뀌지 않을 때까지 번갈아가며 갱신합니다. 그 후 두 행렬의 곱으로최종 근사 행렬을 계산합니다.

경사하강법
행렬 X,Y는 2.3.1절 '경사하강법'에서 공부한 경사하강법으로  풀 수 있습니다. 초기 X, Y를 임의로 정한 후 이를 이용하여 근사 행렬 Q를 구합니다. 그 후 R과  Q를 구합니다. 그 후 R과 Q를 잉요하여 손실을 구하고 그 값울 경사하강법에 적용합니다.


경사하강법을 전체 행렬에 적용하기 보다는 관측된 일부 값에 대해서만 SGD를 적용하면 빠른 속도를 얻을 수 있습니다. SGD에 대해서는 ㄹ제 구현은 12장에 살펴보겠습니다 2.3.3절 '활률적 경사하강법'에서 자세히 설명했으니 그곳을 참조하세요.