처음부터 시작하는 자연어처리(3)

June
None
Published in
6 min readFeb 7, 2023

안녕하세요. 휴먼스케이프 june입니다.

저번 시간에 이어 또 다른 word embedding 방식인 word2vec에 대해 알아보도록 하겠습니다.

Word2vec

word2vec은 Distributional Hypothesis을 기반으로 합니다.

Distributional Hypothesis(분산가설)

비슷한 문맥에서 발생하는 단어들은 비슷한 의미를 가지는 경향이 있다. 라는 이론입니다.

예를들어 안경은 _이 안 좋으면 쓰는 것입니다. 라는 문장이 있습니다.

해당 문장에서 _ 에 들어갈 단어는 시력, 등 비슷한 의미를 가진 단어로 제한되어 있습니다.

Word2vec의 학습방식은 2가지가 있습니다.

  1. CBOW: 주변에 있는 단어들을 입력으로 중간에 있는 단어들을 예측하는 방법입니다.
  2. skip-gram: 중간에 있는 단어를 입력으로 주변의 단어들을 예측하는 방법입니다.
출처: https://www.researchgate.net/publication/339921386_Learning_supervised_embeddings_for_large_scale_sequence_comparisons

CBOW

cbow의 학습과정은 다음과 같습니다.

먼저 학습시킬 모든 단어들을 원-핫 인코딩으로 벡터화 합니다.

  • 원-핫 인코딩은 단어를 벡터화 시키는 가장 간단한 방식 중 하나입니다.

예로, this is test code for test me 라는 문장을 원-핫 인코딩으로 벡터화해보겠습니다.

this = [1, 0, 0, 0, 0, 0]
is = [0, 1, 0, 0, 0, 0]
test = [0, 0, 1, 0, 0, 0]
code = [0, 0, 0, 1, 0, 0]
for = [0, 0, 0, 0, 1, 0]
test = [0, 0, 1, 0, 0, 0]
me = [0, 0, 0, 0, 0, 1]
  • 위와 같이 각 단어의 인덱스에만 1이 들어가고, 나머지엔 0이 들어가는 방식을 원-핫 인코딩이라고 합니다.

하나의 target 단어에 대해, One-hot encoding을 거친 총 2m개의 문맥 단어(context-word) 벡터를 Input으로 집어넣어 줍니다.

  • target 단어 왼쪽으로 m개, 오른쪽으로 m개의 문맥 단어를 벡터화 한 후 input으로 넣어 줍니다.
  • m은 임의의 수이며, 파라미터로 지정합니다.

One-hot encoding 방식의 단어 벡터들은 신경망 첫 번째 층의 가중치(W1)와 연산 되어 (파라미터 W와 곱해져서) embedded word vector가 됩니다.

  • 가중치 행렬의 크기는 사용자가 지정한 크기 * 단어 수로 정해집니다.
  • one-hot vector의 특성(하나의 요소만 1이고 나머지는 0으로 채워짐)때문에 1로 채워진 인덱스(i)에 해당하는 가중치행렬의 행(W[i])을 가져오는 것과 동일합니다.

n번째 단어 하나를 가져와 가중치 행렬과 연산하는 과정을 간단히 그려보면 다음과 같습니다.


| 1, 2, 3 |
| 5, 8, 1 |
[0, 0, 0, 0, 1] * | 9, 1, 5 | = [2, 7, 4]
| 8, 2, 3 |
| 2, 7, 4 |

위에서 구한 embedded word vector 2*m개의 평균을 계산한 벡터가 Hidden layer가 됩니다.

h1 = ([2, 7, 4] + [1, 2, 3] + [3, 4, 2] + [2, 3, 3])/4 = [2, 4, 3]

Hidden layer에 가중치행렬(W2)을 곱해 각 단어의 score를 만들고, 마지막으로 각 score값들에 softmax 함수를 씌워 최종적으로 Output layer를 도출합니다.

  • 위에서 나온 가중치 행렬(W1)과는 다른 별개의 가중치 행렬입니다.
  • 가중치 행렬의 크기는 (위에서 구한 Hidden layer 배열의 크기, 3)*(one-hot vector의 크기, 6)이 됩니다.
  • softmax는 score가 너무 커지는 것을 방지하기 위해 결과 값을 정규화하는 함수입니다. (요소의 총합이 1이 되도록 정규화합니다.)
  • output layer에서 n번째 요소의 값이 주변 단어가 주어졌을 때 해당 단어가 중심 단어일 확률을 의미합니다.
  • 실제 출현 단어(정답)과 비교해 역전파를 수행하게 됩니다.

Hidden layer의 n번째 행(n번째 단어)를 가져와 연산하는 과정을 그려보면 다음과 같습니다.


| 1 2 3 4 5 6 | | 2*1 + 4*5 + 3*1 | | 25 |
[2, 4, 3] * | 5 9 2 1 2 9 | = | 2*2 + 2*9 + 3*3 | = | 31 | = [25, 31, 35 ... ]
| 1 3 7 3 9 2 | | 2*3 + 4*2 + 3*7 | = | 35 |
... ...
softmax([25, 31, 35 ...]) = [0.15, 0.20, 0.22 ... ]

Skip-Gram

skip-gram은 cbow와 거의 같은 방식으로 진행됩니다.

따라서 차이점만 서술하도록 하겠습니다.

먼저 학습시킬 모든 단어들을 원-핫 인코딩으로 벡터화 합니다.

하나의 target 단어에 대해, One-hot encoding을 거친 총 2m개의 문맥 단어(context-word) 벡터를 Input으로 집어넣어 줍니다.

  • Skip-Gram은 하나의 단어 벡터를 Input으로 집어넣고, 여러 target단어 벡터를 얻어냅니다.

One-hot encoding 방식의 단어 벡터들은 신경망 첫 번째 층의 가중치(W1)와 연산 되어 (파라미터 W와 곱해져서) embedded word vector가 됩니다.

  • Input 단어 벡터가 하나뿐이니 embedded word vector도 하나만 존재하며, 평균을 구할 필요가 없어집니다.

위에서 구한 embedded word vector 2*m개의 평균을 계산한 벡터가 Hidden layer가 됩니다.

  • 위에서 서술한대로, Hidden layer를 구하는 과정은 생략됩니다.

Hidden layer에 가중치행렬(W2)을 곱해 각 단어의 score를 만들고, 마지막으로 각 score값들에 softmax 함수를 씌워 최종적으로 Output layer를 도출합니다.

  • 각 단어에 해당하는 인덱스의 값이 해당 단어가 출현할 확률이 됩니다.

gensim이라는 파이썬 패키지를 활용해 word2vec을 간단하게 사용해볼 수 있습니다.

from gensim.test.utils import common_texts
from gensim.models import Word2Vec
>>>
model = Word2Vec(sentences=common_texts, vector_size=100, window=5, min_count=1, workers=4)
model.save("word2vec.model")

각 파라미터의 의미는 다음과 같습니다.

vector_size = 임베딩 벡터의 차원.
window = 컨텍스트 윈도우 크기, 문맥단어를 몇개 가져올지 지정
min_count = 단어 최소 빈도 수 제한 (빈도가 적은 단어들은 학습하지 않는다.)
workers = 학습을 위한 프로세스 수
sg = 0은 CBOW, 1은 Skip-gram

--

--