관리 메뉴

TEAM EDA

Chapter 3 : 단어 임베딩을 사용하여 텍스트 유사성 계산하기 본문

책 내용 정리/딥러닝 쿡북

Chapter 3 : 단어 임베딩을 사용하여 텍스트 유사성 계산하기

김현우 2019. 3. 10. 08:28

Note : 이 포스터는 (주)느린생각의 지원을 받아 딥러닝 쿡북이라는 교재로 스터디를 하고 작성하는 포스터입니다. 이론은 딥러닝을 이용한 자연여 처리 입문(https://wikidocs.net/22660) 교재를 사용하였고 코드는 딥러닝 쿡북이라는 교재를 사용하였습니다. 


단어 임베딩이란?


이 장에서는 단어 임베딩을 사용해 텍스트 간 유사도를 계산하는 방법을 설명합니다. 단어 임베딩은 원-핫 인코딩과는 다른방식으로 단어를 공간상의 벡터로 표현하는 기술 입니다. 단어 임베딩을 사용할 경우 비슷한 의미가 있는 단어들이 서로 가까운 곳에 나타나게 됨으로써 벡터 상에 단어의 의미를 포함시킬 수 있습니다. 


이번 챕터에서는 단어 임베딩의 방법으로 구글의 Word2Vec을 사용할 것입니다. Word2Vec은 '비슷한 위치에서 등장하는 단어들은 비슷한 의미를 가진다'(분산가정) 라는 가정을 가진다라는 '분산표현' 방법을 사용합니다. 예를 들어, 강아지는 귀엽다. 강아지는 예쁘다. 강아지는 사랑스럽다. 라는 문장 3개가 오면 귀엽다, 예쁘다, 사랑스럽다를 비슷한 의미를 가진다고 판단하는 방법입니다. 


추가적으로 이를 활용해서 아래의 그림과 같은 임베딩 된 벡터들간의 연산도 가능합니다. 

한국 - 서울 + 도쿄 = 일본 

킹 - 퀸 + 맨 = 워맨 

(다음의 링크에 들어가면 더 많은 것들을 시도 해 볼 수 있습니다. http://w.elnn.kr/search/ )


이미지 출처 : https://datascienceschool.net/view-notebook/6927b0906f884a67b0da9310d3a581ee/ 데이터사이언스스쿨 


Word2Vec의 유사도 계산


Word2Vec에서 유사도를 계산하는 방법으로는 1. CBOW와 2. Skip-Gram 두가지 방식이 있습니다. 

참고 : 아래 부분의 CBOW와 Skip-Gram방식은 https://wikidocs.net/22660의 예문을 그대로 사용하였고 부족한 내용은 다른 블로그의 글을 참고하여 만들었습니다. 


1. CBOW (Continuous Bag of Words)

CBOW는 주변에 있는 단어들을 가지고, 중간에 있는 단어들을 예측하는 방법입니다.


예문 : "The fat cat sat on the mat"

예를 들어서 {"the", "fat", "cat", "on", "the", "mat"}으로부터 sat을 예측하는 것은 CBOW가 하는 일입니다. 한마디로 문맥으로 부터 빠진 단어를 예측하는 방법입니다. 예로, o잃고 외양간 고친다. 라는 속담을 보고 o에 들어갈 올바른 단어를 맞추는 것 또한 CBOW라고 생각하시면 됩니다. 참고로 예측해야하는 단어 sat을 중심 단어(center world)라고 하고, 예측에 사용되는 단어들을 주변 단어(context word)라고 합니다. 


중심 단어를 예측하기 위해서 앞, 뒤로 몇 개의 단어를 볼지를 결정했다면 이 범위를 윈도우(window)라고 합니다. 예를 들어서 윈도우 크기가 2이고, 예측하고자 하는 중심 단어가 sat이라고 한다면 앞의 두 단어인 the와 fat, 그리고 뒤의 두 단어인 on, the를 참고합니다. 이렇게 window를 설정한는 이유는 너무 많으면 계산량의 문제와 불필요한 부분까지 학습한다는 문제, 너무 적으면 언더피팅 되는 문제가 생기기 때문입니다. 이럴경우 window의 크기를 1부터 하나씩 증가시켜가면서 정확도를 비교해보면 좋을 것 같습니다. 


이미지 출처 : https://wikidocs.net/22660



윈도우 크기를 정했다면, 윈도우를 계속 움직여서 주변 단어와 중심 단어 선택을 바꿔가며 학습을 위한 데이터 셋을 만들 수 있는데, 이 방법을 슬라이딩 윈도우(Sliding window)라고 합니다.


위 그림에서 좌측의 중심 단어와 주변 단어의 변화는 윈도우 크기가 2일때, 슬라이딩 윈도우가 어떤 식으로 이루어지면서 데이터 셋을 만드는지 보여줍니다. 또한 Word2Vec에서 입력은 모두 원 핫 벡터가 되어야 하는데, 우측 그림은 중심 단어와 주변 단어를 어떻게 선택했을 때에 따라서 각각 어떤 원 핫 벡터가 되는지를 보여줍니다. 위 그림은 결국 CBOW를 위한 전체 데이터 셋을 보여주는 것입니다.


입력이 비슷하면 출력도 비슷해질 것이라는 직관적인 이해를 통하여 유사도를 계산하게 됩니다. 그리고 아래 그림처럼 [fat,cat,on,the]의 주변단어들이 들어오면 sat의 유사도를 계산하게 됩니다. 


이미지 출처 : https://wikidocs.net/22660



CBOW의 뉴럴 네트워크를 간단히 도식화하면 다음과 같습니다. input layer의 입력으로서 앞, 뒤로 사용자가 정한 윈도우 크기 범위 안에 있는 주변 단어들의 원 핫 벡터(중심 단어)가 들어가게 되고, output layer에서 예측하고자 하는 중간 단어의 원 핫 벡터가 필요합니다. 위에서 말한대로 Word2Vec의 학습을 위해서 이 중간 단어의 원 핫 벡터가 필요합니다.

- 입력 : fat, cat, on the의 원 핫 벡터 = 중간 단어의 원 핫 벡터

- 출력 : sat의 유사도 벡터 = 임베딩하고 난 벡터


CBOW의 뉴럴 네트워크를 좀 더 확대하여, 동작 메커니즘에 대해서 상세하게 알아보도록 하겠습니다. 이 그림에서 주목해야할 것은 두 가지 입니다. 하나는 hidden layer의 크기가 N이라는 점입니다. CBOW에서 hidden layer의 크기 N은 임베딩하고 난 벡터의 크기가 됩니다. 다시 말해, 위의 그림에서 hidden layer의 크기는 N=5이기 때문에 해당 CBOW를 수행하고나서 나오는 벡터의 크기는 5가 될 것입니다. ( 임베딩 차원수 + 단어가 속한 열 1 )


두번째는 입력층(input layer)과 은닉층(hidden layer)사이의 가중치 W는 V X N 행렬이며, 은닉층(hidden layer)에서 출력층(ouput layer)사이의 가중치 W'는 N X V 행렬이라는 점입니다. 여기서 V는 단어 집합의 크기를 의미합니다. 즉, 위의 그림처럼 원 핫 벡터의 차원이 7이고, N은 5라면 가중치 W는 7 X 5 행렬이고, W'는 5 X 7 행렬이 될 것입니다. 주의할 점은 이 두 행렬은 동일한 행렬을 Transpose한 것이 아니라, 서로 다른 행렬이라는 점입니다. 뉴럴 네트워크의 훈련 전에 이 가중치 행렬 W와 W'는 대게 굉장히 작은 랜덤 값을 가지게 됩니다. CBOW는 주변 단어로 중심 단어를 더 정확히 맞추기 위해 계속해서 이 W와 W'를 학습해가는 구조입니다. 조금 더 자세하게 설명하면 처음의 W와 W' 값은 작은 랜덤값을 가지지만 뉴럴네트워크의 Back propagation 과정을 거치면서 점점 유사도의 가중치로 변해갑니다. 그렇게 해서 만들어진 W는 아래와 같은 식을 가지고, 거리(의미가 유사한 정도)의 정규분포 값을 가지는 걸 알 수 있습니다. 






이미지 출처 : https://wikidocs.net/22660


입력으로 들어오는 주변 단어의 원 핫 벡터와 가중치 W 행렬의 곱이 어떻게 이루어지는지 보겠습니다. 위 그림에서는 각 주변 단어의 원 핫 벡터를 x로 표기하였습니다. 입력 벡터는 원 핫 벡터이기 때문에 i번째 인덱스에 1이라는 값을 가지고 그 외의 0의 값을 가지는 입력 벡터와 가중치 W 행렬의 곱은 사실 W행렬의 i번째 행을 그대로 읽어오는 것과(lookup) 동일합니다. 그래서 이 작업을 Table lookup이라고도 부릅니다. 앞서 CBOW의 목적은 W와 W'를 잘 훈련시키는 것이라고 언급한 적이 있는데, 사실 그 이유가 여기서 lookup해온 W의 각 행벡터가 사실 Word2Vec을 수행한 후의 각 단어의 N차원의 크기를 갖는 임베딩 벡터들이기 떄문입니다.



이미지 출처 : https://wikidocs.net/22660


이렇게 각 주변 단어의 원 핫 벡터에 대해서 가중치 W가 곱해서 생겨진 결과 벡터들은 은닉층에서 만나 이 벡터들의 평균인 벡터를 구하게 됩니다. 만약 윈도우 크기가 2라면, 입력 벡터의 총 갯수는 2m이기때문에 중간 단어를 예측하기 위해서는 총 4개가 입력 벡터로 들어가게 됩니다. 그렇기 때문에 평균을 구할 때는 4개의 결과 벡터에 대해서 평균을 구하게 됩니다. 은닉층에서 벡터의 평균을 구하는 부분은 CBOW가 Skip-Gram과 다른 차이점이기도 합니다. 뒤에서 보게되겠지만, Skip-Gram은 입력이 중심 단어 하나이기때문에 은닉층에서 벡터의 평균을 구하지 않습니다.


이미지 출처 : https://wikidocs.net/22660


이렇게 구해진 평균 벡터는 두번째 가중치 행렬인 W'와 곱해집니다. 이렇게 되면 크기가 V와 동일한 벡터. 즉, 인풋이었던 원 핫 벡터들과 차원이 동일한 벡터가 나오게 됩니다. 만약 입력 벡터의 차원이 7이었다면 여기서 나오는 벡터도 마찬가지입니다.


이 벡터에 CBOW는 softmax를 취하는데, softmax 함수로 인한 출력값은 0과 1사이의 실수로, 각 원소의 총 합은 1이 되는 상태로 바뀝니다. 이렇게 나온 벡터를 우리는 스코어 벡터(score vector)라고 합니다. 스코어 벡터의 각 차원 안에서의 값이 의미하는 것은 이와 같습니다.


스코어 벡터의 j번째 인덱스가 가진 0과 1사이의 값은 j번째 단어가 중심 단어일 확률을 나타냅니다. 그리고 이 스코어 벡터는 우리가 실제로 값을 알고있는 벡터인 중심 단어 원 핫 벡터의 값에 가까워져야 합니다. 스코어 벡터를 𝑦 ̂라고 하겠습니다. 중심 단어를 y로 했을 때, 이 두 벡터가 가까워지게 하기위해서 CBOW는 cross-entropy 함수를 사용합니다. 즉, 다른 말로 loss function으로 cross-entropy 함수를 사용하는 것입니다.



cross-entropy 함수에 실제 중심 단어인 원 핫 벡터와 스코어 벡터를 입력값으로 넣고, 이를 식으로 표현하면 위와 같습니다.



그런데 y가 원 핫 벡터라는 점을 고려하면, 이 식은 위와 같이 간소화시킬 수 있습니다. 이 식이 왜 loss function으로 적합한지 알아보겠습니다. c를 중심 단어에서 1을 가진 차원의 값의 인덱스라고 한다면, 는 y^가 y를 정확하게 예측한 경우가 됩니다. 이를 식에 대입해보면 -1 log(1) = 0이 되기 때문에, 결과적으로 y^가 y를 정확하게 예측한 경우의 cross-entropy의 값은 0이 됩니다. 즉, 우리는 



이 값을 최소화하는 방향으로 학습해야 합니다.


이제 Back Propagation을 수행하면 W와 W'가 학습이 되는데, 학습이 다 되었다면 N차원의 크기를 갖는 W의 행이나 W'의 열로부터 어떤 것을 임베딩 벡터로 사용할지를 결정하면 됩니다. 때로는 W와 W'의 평균치를 가지고 임베딩 벡터를 선택하기도 합니다.



2. Skip-Gram 

Skip-Gram은 중간에 있는 단어로 주변 단어들을 예측하는 방법입니다. Skip-gram은 CBOW를 이해했다면, 메커니즘 자체는 동일하기 때문에 쉽게 이해할 수 있습니다. 앞서 CBOW에서는 주변 단어를 통해 중심 단어를 예측했다면, Skip-gram은 중심 단어에서 주변 단어를 예측하려고 합니다. 


이미지 출처 : "word2vec Parameter Learning Explained", Xin Rong


이미지 출처 : https://ratsgo.github.io/from%20frequency%20to%20semantics/2017/03/30/word2vec/


위의 CBOW 방법과는 다르게 Skip-Gram은 주어진 단어로 근처에 올 단어들을 예측하는 방법입니다. 학습 샘플을 보면 CBOW에서는 주변단어들만을 가지고 학습을 진행했던 반면 Skip-Gram은 중심단어 + 주변단어의 조합으로 학습을 진행하게 됩니다. 그렇기 때문에 중심단어가 올 경우 주변에 어떤 주변단어가 오는지를 알 수 있게 됩니다. 


여러 논문에서 성능 비교를 진행했을 때, 전반적으로 Skip-gram이 CBOW보다 성능이 좋다고 알려져 있습니다.

두가지 방식의 보다 자세한 내용은 다음의 링크(https://arxiv.org/abs/1411.2738)에서 확인할 수 있습니다. 


코드 파일 : 



참고 

- https://datascienceschool.net/view-notebook/6927b0906f884a67b0da9310d3a581ee/

- https://wikidocs.net/22660 

- https://www.youtube.com/watch?v=sY4YyacSsLc

- https://ngio.co.kr/5324

https://ratsgo.github.io/natural%20language%20processing/2017/03/08/word2vec/

- https://ratsgo.github.io/from%20frequency%20to%20semantics/2017/03/30/word2vec/