이 포스트는 책 '한국어 임베딩(자연어 처리 모델의 성능을 높이는 핵심 비결 Word2Vec에서 ELMo, BERT까지, 이기창 저)'을 기반으로 작성되었습니다.
자연어처리 쪽에 관심이 있는 사람이라면 한번쯤 들어봤을 Word2Vec은 2013년 구글에서 발표한, 가장 보편적인 단어 임베딩 모델이다.
CBOW와 Skip-Gram 모델이 제안된 Efficient Estimation of Word Representations in Vector Space 논문과, negative sampling 등의 최적화 기법을 제시한 Distributed Representations of Words and Phrase and their Compositionality 논문을 통해 발표되었다.
Word2Vec의 종류를 나누자면 다음과 같으며, 서로 학습되는 과정이 반대된다.
- CBOW : 주변 문맥 단어(context word)로 타깃 단어(target word)를 맞추는 과정 학습
- Skip-gram : 타깃 단어(target word)로 주변 문맥 단어(context word) 맞추는 과정 학습
같은 corpus가 주어졌을 때 Skip-gram이 CBOW보다 더 많은 학습 데이터를 얻을 수 있기 때문에 더욱 성능이 좋으므로, Skip-gram에 대해 더욱 깊이 알아보고자 한다.
학습 데이터 생성
학습 데이터를 구축하는 과정은 아래와 같이 2가지로 나눠지며, 전체 corpus를 단어별로 슬라이딩하면서 생성한다.
- Positive sample : (target 단어, 주변에 등장하는 context 단어) 쌍
- Negative sample : (target 단어, 주변에 등장하지 않은 단어) 쌍
모델링 과정
Skip-gram 모델의 input은 (target 단어, context 단어)이며, output은 해당 쌍의 Positive sample 여부(Positive sample 또는 Negative sample)이다.
모델 학습은 아래 로그확률 평균 식을 최대화하는 방향으로 진행되며, c는 학습시킬 단어 개수를 의미한다.
여기에서의 p(w_t+j | w_t)는 아래와 같이 softmax 함수를 이용하여 표현된다.
(v_w : input, v'_w : output, W : 단어 개수)
위의 softmax를 효율적으로 계산하기 위한 접근법은 이진 트리 기법을 이용하는 hierarchical softmax이다. 수식은 다음과 같다.
(n(w,j) : root부터 w까지의 경로 중 j번째 node, L(w) : 경로 길이, ch(n(w,j)) : 임의의 고정된 child node, [[x]] : x가 참이면 1, 거짓이면 -1, σ(x)=1/(1+exp(-x)) )
[[ ]]와 v의 내적은 코사인 유사도와 비례한다.
따라서 Positive sample일 경우 단어 간 코사인 유사도를 높여야 하며, Negative sample일 경우 단어 간 코사인 유사도를 낮춰야 한다.
모델링 보완 방식
처음 모델이 나왔을 때는 target 단어가 주어지면 context 단어가 무엇인지 맞추는 방향으로 모델링되었다. 그러나 이와 같은 방식으로 하게 되면 한 corpus에 속한 단어 수가 과도하게 많으므로 모두 계산하려면 과도하게 계산량이 필요했다.
따라서 이런 단점을 보완하기 위해 (target 단어, context 단어) 쌍이 Positive sample인지 Negative sample인지 분류하는 Negative sampling 방식이 제안되었다.
이 방식으로는 Positive sample 1개와 Negative sample k개만 계산하면 되어 계산량이 줄어들게 되었다.
(작은 corpus : k=5~20 / 큰 corpus : k=2~5로 하는 것이 좋은 성능을 낸다.)
Negative sample을 뽑을 때는 unigram 확률(=단어 등장 빈도 수 / 전체 단어 수)을 이용하여 corpus에 자주 나타나지 않는 단어가 더 많이 뽑힐 수 있도록 하였다. 아래와 같은 목적 함수를 통해 계산되며,
또한 subsampling 기법을 통해 자주 등장하지 않는 단어는 학습 데이터에서 제외하여 효율적으로 계산되도록 설계되었다.
python 코드
from gensim.models import Word2Vec
corpus = ["문장이","토큰별로","split","되어","있도록"]
model = word2Vec(corpus, size=100, workers=4, sg=1)
# size : 임베딩 크기
# workers : CPU 사용 개수
# sg : 0(CBOW) / 1(Skip-gram)
model.most_similar("찾아볼 단어", topn=5)
'DATA SCIENCE > NLP' 카테고리의 다른 글
[NLP] 잠재 의미 분석 (LSA) (0) | 2020.05.18 |
---|---|
[NLP] FastText (0) | 2020.05.17 |
[NLP] NPLM(Neural Probabilistic Language Model) (0) | 2020.05.02 |
[NLP] 한국어 형태소 분석 (0) | 2020.05.01 |
[NLP] 임베딩(Embedding) 방식의 종류 (0) | 2020.05.01 |