워드 임베딩(Word Embedding)
자연어처리를 수행하는 시스템들은 입력을 텍스트로 받는다. (출력의 경우에는 다를 수 있다.)
그러나, 우리가 자연어처리를 하기 위해 사용하는 여러 모델들은 수치화된 입력을 받고, 수치화된 출력을 내보낸다.
따라서, 우리는 텍스트 정보를 모델에 넣고, 모델에서 나온 결과를 텍스트로 이해하기 위해 텍스트-숫자 간의 변환 방법이 필요하다.
이때, 텍스트를 숫자 벡터로 바꾸는 과정을 워드 임베딩(Word Embedding)이라고 한다.
원핫 인코딩(One-hot Encoding)
텍스트를 벡터롤 바꾸는 방법으로는 원핫 인코딩이 있다.
원핫 인코딩이란, 0과 1로 구성된 벡터로 변환하는 과정이며, 훈련 데이터에 존재하는 단어들로 단어장을 만든 후 나열한 다음, 각 단어가 단어장의 해당 위치에 해당되면 1, 아니면 0을 부여하는 과정이다.
아래의 예시와 함께 살펴보자.
특정한 텍스트에서 다음과 같은 단어장이 생성되었다고 가정해보자.
"자동차, 배, 기차, 비행기"
그리고 나서, 위의 단어들을 원핫 인코딩으로 변환하면 다음과 같은 형태로 변환된다.
자동차 : [1, 0, 0, 0]
배 : [0, 1, 0, 0]
기차 : [0, 0, 1, 0]
비행기 : [0, 0, 0, 1]
각 단어가 해당하는 단어장의 순서에는 1이 부여되고, 나머지 부분에는 0이 들어감을 확인할 수 있다.
이렇게 원핫 인코딩을 통해 텍스트를 숫자 벡터로 변환할 수 있다. 그러나, 이러한 방법에는 한계점이 있다.
먼저, 단어 사이의 유사도나 모호성을 표현할 수 없다.
다음의 예시를 살펴보자
파랑, 빨강, 핑크를 one-hot vector로 표현했을 때, 빨강과 핑크는 분명히 비슷한 단어이다. 그러나, 위와 같은 방법으로는 빨강과 핑크의 유사성이 높고, 파랑과 빨강의 유사성이 낮다는 것을 표현하지 못한다.
따라서 우리는 단어의 특징을 추출하여 dense한 vector로 표현하여, 이러한 문제를 해결하는 것이다.
다음과 같이 dense한 vector로 위의 세 단어를 표현해보았다(값은 임의로 설정했기에 실제 값과 차이가 있습니다.)
이런 형태로 표현이 된다면, Cosine-Similarity, L1 Distance, L2 distance와 같은 지표들로 단어 사이의 유사성을 구할 수 있게 된다.
또한, 단어의 수가 너무 많아지면 차원도 덩달아 너무 커져버리는 문제점이 있다.
따라서, 이러한 문제점들을 해결하기 위해 텍스트를 dense한 vector로 변환하는 과정들이 고안되었다.
Word2Vec
Word2Vec은 주변에 같은 단어가 나타나는 단어일수록 비슷한 벡터 값을 가지게끔 한다.
이를 가능하게 하기 위해, 주변의 단어들이 주어졌을 때, 현재의 단어를 예측하도록 하는 C-BOW 방식과 현재 단어가 주어지면 주변 단어를 학습하게 하는 Skip-gram의 방법을 이용한다. 여기서는 두 모델 중 Skip-gram 위주로 살펴보겠다.
Word2Vec - Skip-gram
Skip-gram의 기본 전략은, 주변 단어를 예측하도록 하는 과정에서 적절한 단어의 임베딩을 할 수 있다는 것이다.
여기서 짚고 넘어가야할 점은, 단어의 임베딩 과정은 일종의 정보의 압축이라고 볼 수 있다.
위에서 언급했던 One-hot vector는 매우 sparse한 vector로 구성되어져 있는데, 이를 dense한 layer로 바꾸는 과정이 word embedding이기에, sparse한 정보를 dense하게 압축하는 과정과 일맥상통하는 것이다.
이를 염두에 두고 아래의 Skip-gram 모델 예시를 봐보자.
왼쪽이 input text라고 하면, 왼쪽의 vector에서 중심 단어가 주어지게 되면(여기서는 회색 칸) 주변 단어를 예측하도록 위의 모델을 학습시키는 과정에서 가운데의 회색 vector가 학습되게 되고, 이를 embedding vector로 사용한다.
(위와 같은 형태는 오토인코더(Autoencoder)와 매우 비슷한데, 오토인코더에 대해서는 나중에 따로 다뤄보도록 하겠다.)
Skip-gram의 작동 원리를 조금 더 살펴보기 위해 수식과 함께 살펴보도록 하겠다.
우선, Skip-gram은 다음과 같은 수식을 최대화하는 방향으로 학습한다.
$$ \sum_{t=1}^{T}\sum_{c\in{C_t}}\log{p(w_c|w_t)} $$
이는 $w_t$가 주어졌을 때, $w_c$의 확률이며, $w_t$는 문장 내의 단어, 즉 현재 timestep에서 주어지는 중심 단어이다.
$w_c$는 현재 timestep에서 주어진 중심 단어의 주변 단어이다.
따라서 $w_t$가 주어졌을 때, $w_c$의 확률이란 중심 단어가 주어졌을 때 해당 단어의 주변 단어가 출현할 확률인 셈이다.
Skip-gram은 중심 단어가 주어졌을 때 해당 단어의 주변 단어가 출현할 확률을 최대화하는 방향으로 학습하는 것이다.
그렇다면, $p(w_c|w_t)$는 어떻게 구할까? 다음 수식을 통해 구할 수 있다.
$$p(w_c|w_t)= \frac{e^{s(w_t,w_c)}}{\sum_{j=1}^{|V|}e^{s(w_t,w_c)}}$$
일단 $s(w,w')$가 어떻게 나오는지 그림과 함께 살펴보겠다.
다음과 같은(1, V)의 형태의 one-hot vector가 존재한다고 가정해보자.
이를 위의 그림에서 Encoder 부분인 $W$에 곱해주면 다음과 같은 결과가 나온다.
(행렬곱을 하는 이유는 Linear layer이기 때문에..!)
one-hot vector는 하나의 값만 1이고 나머지는 0이기에, 행렬곱을 진행하면 1을 가진 부분만 남고 나머지는 모두 없어진다.
그리하여, 위와 같은 (1,D) 형태의 Embedding vector가 생성된다. 이는 Skip-gram 예시 그림에서 가운데 회색 부분이다.
이제, Decoder 부분인 $W'$와 해당 벡터를 행렬곱을 해보자
그러면 다음과 같은 벡터가 나온다
이를 일반화하면 다음과 같은 값이 나온다
특정 단어에 대해 $s(w,w')$를 위와 같은 절차로 구할 수 있다. 이렇게 나온 값들을 다시 위의 수식에 대입하여
$p(w_c|w_t)$, 즉, 중심 단어가 주어졌을 때 해당 단어의 주변 단어가 출현할 확률을 구할 수 있는 것이다.
그러나, 이러한 방법에는 문제가 있다. 만약 단어의 수가 엄청 많다면, 그 모든 단어에 대하 하나하나 score($s(w,w')$)를 구해야 한다.
이는 매우 비효율적인 방법이다.
따라서 이러한 방법을 해결하기 위한 방법으로 Negative sampling을 소개하고자 한다.
Negative Sampling
단어의 수가 많아지면 모든 단어에 대한 계산을 해야해 비효율적이라는 문제를 해결하기 위해,
정답이 아닌 negative들을 일부만 sampling하여 Negative set(아래 수식에서의 $N$)을 만들고,
반대되는 방향으로 score를 학습하는 방법이다.
즉, -positive score도 minimize하고 (positive score를 maximize), negative score도 minimize하는 것이다.
수식은 다음과 같다.
$$\log(1+e^{-s(w_t,w_c)}) + \sum_{n\in N}\log(1+e^{s(w_t,w_n)})$$
'NLP' 카테고리의 다른 글
[논문 리뷰] Neural Machine Translation by Jointly Learning to Align and Translate - Bahdanau Attention (0) | 2022.12.04 |
---|---|
Attention이란?-원리부터 masking까지 (General Luong Attention을 기반으로) (0) | 2022.11.25 |
시퀀스-투-시퀀스(Sequence-to-Sequence, seq2seq)란? - 기본 구조편 (0) | 2022.11.22 |
[NLP] 언어 모델(Language Model) 이란? (0) | 2022.11.05 |
Tokenization(토큰화)란 무엇일까? (0) | 2022.08.20 |
댓글