본문 바로가기

Data Analysis

기계학습 - Spark(5) - Word2Vec, 학습하는 부분 코드 분석

이런 저런 주변의 일을 처리하고, 다시 Word2Vec.scala 소스코드중에서 학습을 하는 부분을 분석해봤다. 기반 지식에 대한 이해도 부족한 상황에서 직관에 상당히 의존하며 분석했다. 따라서 이 글은 틀린 내용을 담고 있을 수 있다.


학습은 전체에서 사용되는 상당히 큰 배열 (단어수 x 벡터차원수)과 부분적으로 사용되는 배열(벡터차원수)가 사용된다. 하나의 문장단위로 순서대로 학습을 하는데, 문장마다 첫 단어부터 마지막 단어까지 순서대로 학습한다. 일단 이 것만으로도 2중 반복문이다. 그리고 각각의 단어마다 앞, 뒤로 위치한 단어들을 추려서 학습하는데, 추리는 단어의 수는 정해져 있고, 다만 앞으로 몇번째 단어부터 처리할 것인지를 랜덤하게 선택한다.



위의 그림속의 문장을 보면, federal이라는 단어의 앞뒤에 놓여진 단어들을 선택하는데 선택된 단어의 범위를 "window"라 하고 이 크기는 일정하게 미리 정해져 있다. 그리고 같은 문장이어도 몇번째 앞의 단어를 랜덤하게 선택하기 때문에 처리되는 단어들은 달라지게 된다. 여기서 묘미는 가까이 있는 단어들은 같이 처리될 확률이 높고, 멀어질 수록 처리되지 않을 확률이 높아진다. 어쨌든 여기까지 하면 3중 반복문이다.


지금 단락에 쓰는 내용은 아직까지 직관적으로도 이해되지는 않는다. spark에서 구현한 word2vec을 보면, 이 블로그 spark(4)에서 언급했던 이진 트리에서 학습할 단어에 해당하는 노드를 찾고 그 노드부터 Root노드까지 부모노드들을 차례대로 학습에 이용한다. 이 노드들에 해당하는 단어가 마지막 반복문이 된다.


다시 코드를 풀이해보도록 한다. 


1. 앞서 설명한 2개의 커다란 배열을 초기화 한다. 하나는 랜덤값에서 0.5를 빼고 다시 벡터의 크기로 나눈 값을 채우고, 다른 하나는 0으로 채운다. 앞의 것을 syn0, 뒤의 것을 syn1이라고 하자. syn0 값은 각 행=단어를 벡터상 공간에  흩뿌리기 위한 것인데, 앞으로 퍼져나갈 것을 대비해서 작은 지점안에 흩뿌렸다고 본다.


2. 문장에서 순서대로 "학습단어"를 선택하고, 그 단어의 위치상 "근접단어"를 선택한다. 학습단어의 부모노드의 단어, 즉 보모단어를 선택한다. 부모단어의 시작은 자기자신=학습단어부터이다. 


3. 부모단어와 근접단어의 벡터를 스칼라곱 연산값을 구한다. 그리고 이 값이 일정한 범위안이면 스칼라곱 연산값을 기반으로 계산된 보정값을 기울기값으로 갖는 선형함수를 이용해서 부모단어의 syn1벡터를 이동시킨다. 이때 임시벡터도 이동시킨다.


4. 마지막으로 syn0를 이동시킨다. 이 때도 선형함수를 이용하는데, 기울기 값은 1이고 x값들은 임시벡터를 사용한다.


1~4를 계속한다.


풀이한 코드를 다시 이해해본다. N-차원의 공간은 이해하기 힘들기 때문에 우선 2차원에서 이해해보자.


3항에서 스칼라곱이 무엇을 의미하는 것일까? 소스코드는 아래와 같다.

var f = blas.sdot(vectorSize, syn0, l1, 1, syn1, l2, 1)


sdot함수는 syn0배열 l1위치부터 1씩증가하고, syn1배열 l2위치부터 1식 증가하면 vectorSize 갯수만큼 서로 곱해서 그 값들을 모두 더한값이다. 식으로 하면...

와 같이 된다.


스칼라곱의 값은 벡터의 크기와 방향에 따라 값이 커지기도하고 작아지기도 한다. 두 벡터의 내각이 90도에 가까워질수록 벡터의 크기와 상관없이 0에 수렴한다. 두벡터의 방향이 일치하거나 반대일 때 두벡터의 크기에 비례한 값에 수렴하며 방향이 반대이면 음수가 된다. 즉 스칼라 곱이 일정한 범위를 넘어서려면 벡터의 크기가 클수록 그리고 방향이 일치 할수록 아니면 반대방향에 일치 할수록 가능성이 커진다.


그렇다면 벡터의 크기가 크다는 것은 어떤 의미이고 방향이 같다는 것은 어떤 의미일까?