by Yngie

GloVe & Fasttext

|

본 포스트의 내용은 고려대학교 강필성 교수님의 강의한국어 임베딩과 책의 저자인 Ratsgo님의 블로그를 참고하였습니다.

GloVe

Word2Vec에게도 단점이 있습니다. 시퀀스 내에 자주 사용되는 단어가 있으면 그 단어에 대해서 너무 많이 계산한다는 것입니다. 특히 아래는 위키피디아 - 대한민국의 첫 문단을 약간의 전처리 후에 형태소 분석한 것입니다.

“대한민국 은 동아시아 의 한반도 남부 에 있 는 민주 공화국 이 다 서쪽 으로 는 황해 를 사이 에 두 고 중화 인민공화국 이 동쪽 으로 는 동해 를 사이 에 두 고 일본 이 있 으며 북쪽 으로 는 조선 민주주의 인민공화국 과 맞닿 아 있 다 대한민국 의 수도 는 서울 특별시 이 고 실질 적 행정 수도 는 세종 특별자치시 이 다 국기 는 대한민국 국기법 에 따라 태극기 국가 는 관습 상 애국가 이 다 대한민국 내 에서 는 대한민국 을 간단히 한국 또는 남한 등 으로 도 부른다 조선 민주주의 인민공화국 에서 는 남조선 으로 불린다 대한민국 은 과거 엔 구한국 대한제국 과 구별 하 여 신 한국 이 라고 불리 기 도 하 였 다 연호 는 년 월 일 부터 서력기원 을 사용 한다”

위 문단에서 조사와 보조사인 “은”, “는”, “이”, “가”, “을”, “를” 등은 등장 횟수가 많기 때문에 학습 과정에서 해당 단어 시퀀스를 중복하여 계산하게 됩니다. 위 문단은 길이가 길지 않지만, 문단에서 ‘는’을 타겟 단어로 하는 시퀀스의 확률을 계산한다면 $P(\text{민주}\vert\text{는}), P(\text{황해}\vert\text{는}), P(\text{동해}\vert\text{는}), P(\text{조선}\vert\text{는}), P(\text{서울}\vert\text{는})$ 등 굉장히 많이 계산하게 될 것입니다.

서브샘플링(Sub-sampling)과 같은 기법을 활용하면 자주 등장하는 단어를 고의로 누락시켜 계산량을 보정해 줄 수는 있습니다만 완벽하게 문제를 해결하는 방법은 아닙니다. 이를 원천적으로 해결하기 위해서 등장한 방법이 GloVe(Global Vectors for word representation)입니다.

Glove는 행렬 분해법(Matrix factorization)에 기반하고 있습니다. 가장 먼저 동시 발생 행렬(Co-occurence)인 $X$를 만듭니다. $X$의 행과 열에는 말뭉치 내에 있는 모든 단어가 배치됩니다. 전체 단어의 개수가 $\vert V \vert$라면 $X$의 크기는 $\vert V \vert \times \vert V \vert$ 가 되겠습니다. 동시 발생 행렬 $X$의 성분인 $X_{ij}$ 는 $i$ 번째 행에 있는 단어가 $j$ 번째 열에 있는 단어와 함께 사용된 횟수를 나타냅니다. 즉 한 행의 성분인 $X_i$는 이를 전부 합친 것이므로 $i$ 번째 행에 있는 단어가 말뭉치 내에 등장한 횟수가 됩니다.

논문에서 사용한 예시를 통해서 Glove가 중복되는 시퀀스에 대한 계산을 보정하는 지를 알아보겠습니다. 아래 표는 특정 단어에 대하여 “ice”, “steam”이 각각 등장한 확률을 나타낸 것입니다. 표에 등장하는 조건부확률 $P(j\vert i)$, 즉 $i$ 단어가 주어졌을 때 $j$ 단어가 등장하는 확률을 구하는 식은 아래와 같습니다.

\[P(j|i) = \frac{X_{ij}}{X_i}\]
Prob. and Ratio. k = solid k = gas k = water k = fashion
$P(k \vert \text{ice})$ $1.9 \times 10^{-4}$ $6.6 \times 10^{-5}$ $3.0 \times 10^{-3}$ $1.7 \times 10^{-5}$
$P(k \vert \text{steam})$ $2.2 \times 10^{-5}$ $7.8 \times 10^{-4}$ $2.2 \times 10^{-3}$ $1.8 \times 10^{-5}$
$\frac{P(k \vert \text{ice})}{P(k \vert \text{steam})}$ 8.9 $8.5 \times 10^{-2}$ 1.36 0.96

위 표에서 $P(\text{solid} \vert \text{ice}) = 1.9 \times 10^{-4}$라는 것은 “solid”“ice”가 동시에 등장한 횟수를 전체 말뭉치에 ice 라는 단어가 등장한 횟수로 나눈 것입니다. 이를 기억하며 표의 마지막 행에 집중해보겠습니다. $\frac{P(\text{solid} \vert \text{ice})}{P(\text{solid} \vert \text{steam})} = 8.9$ 는 무엇을 의미할까요?

(기준이 되는 단어가 다르기 때문에 횟수로는 비교할 수 없지만) 특정 문서에서 “solid”라는 단어가 등장하는 빈도는 “steam”보다 “ice”가 등장했을 때 더 높음을 나타냅니다. 즉 “solid”“ice”와 더 깊은 관련이 있다는 것이지요. 반대로 “gas”는 마지막 행의 수치가 $\ll 1$ 이므로 “ice”보다 “steam”과 함께 더 자주 등장하는 것으로 보아 “steam”과 더 깊은 관련이 있음을 알 수 있습니다. “water”“fashion”는 마지막 행의 수치가 $\approx 1$이므로 “ice”“steam”이든 등장하는 빈도에 별 차이가 없다는 것을 알 수 있습니다.

Objective Function

Glove의 목적 함수(Objective function)가 어떻게 구해지는지 알아보겠습니다. 위 3번째 행을 일반화한 $\frac{P(k \vert i)}{P(k \vert j)}$를 각각의 단어 $w_i, w_j, \tilde{w_k}$ 를 파라미터로 하는 함수 $F$로 나타내보겠습니다. $\tilde{w}$ 는 주변 단어에 대한 벡터, 즉 문맥(Context) 벡터를 나타냅니다.

\[F(w_i, w_j, \tilde{w}_k) = \frac{P_{ik}}{P_{jk}} = \frac{P(k|i)}{P(k|j)}\]

기준이 되는 두 단어의 관계는 두 단어의 차인 $w_i - w_j$로 표현합니다. 또한 기준이 되는 두 단어와 타깃 단어 $w_k$ 에 대한 관계는 내적으로서 나타내기로 합니다. 이를 적용하면 $F$의 인자를 세 단어 벡터가 결합된 하나의 항으로 변형시킬 수 있습니다.

\[F(w_i, w_j, \tilde{w}_k) = F(w_i - w_j, \tilde{w}_k) = F((w_i -w_j)^T \cdot \tilde{w}_k)\]

이 $F$ 를 이용하여 표 3행 2열에 있는 성분, $\frac{P(\text{solid} \vert \text{ice})}{P(\text{solid} \vert \text{steam})}$ 와 역수를 나타내면 아래와 같이 나타낼 수 있습니다.

\[\begin{aligned} \frac{P(\text{solid} \vert \text{ice})}{P(\text{solid} \vert \text{steam})} &= F((\text{ice} - \text{steam})^T\text{solid}) \\ \frac{P(\text{solid} \vert \text{steam})}{P(\text{solid} \vert \text{ice})} &= F((\text{steam} - \text{ice})^T\text{solid}) \\ \therefore F((\text{ice} - \text{steam})^T\text{solid}) &= \frac{1}{F((\text{steam} - \text{ice})^T\text{solid})} \end{aligned}\]

준동형 사상(Homomorphism)이라는 방법을 사용하여 함수 $F$의 형태를 유추해볼 수 있습니다. 아래 수식을 통해서 함수 내의 변수는 덧셈에 대한 역원 관계에 있고, 함숫값은 곱셈에 대한 역원관계가 있음을 알 수 있습니다.

\[\begin{aligned} (\text{ice} - \text{steam})^T\text{solid} &= - (\text{steam} - \text{ice})^T\text{solid} \\ F((\text{ice} - \text{steam})^T\text{solid}) &= \frac{1}{F((\text{steam} - \text{ice})^T\text{solid})} \\ \therefore F(a+b) &= F(a)F(b) \end{aligned}\]

즉, $F$는 임의의 $a,b$에 대하여 $F(a+b) = F(a)F(b)$를 만족합니다. 이 조건을 만족하는 함수 중 가장 간단한 형태는 $e^x$ 형태의 지수함수(Exponential function)입니다. $F(x) = \exp(x)$로 두고 식을 변형시킬 수 있습니다.

\[\begin{aligned} F\bigg((w_i-w_j)^T \cdot \tilde{w_k}\bigg) &= \frac{F(w_i^T\tilde{w_k})}{F(w_j^T\tilde{w_k})} \\ \exp(w_i^T\tilde{w_k}-w_j^T\tilde{w_k}) &= \frac{\exp(w_i^T\tilde{w_k})}{\exp(w_j^T\tilde{w_k})} \end{aligned}\]

$P_{ik} = \exp(w_i^T\tilde{w}_k)$ 이므로 식을 다음과 같이 변형할 수 있습니다.

\[\begin{aligned} w_i^T\tilde{w}_k = \log P_{ik} &= \log X_{ik} - \log X_i \\ \because P_{ik} &= \frac{X_{ik}}{X_i}\\ \end{aligned}\]

$\log X_i$ 는 상수이므로 2개의 상수의 합 $b_i+ \tilde{b_k}$ 로 치환하여 나타낼 수 있습니다. 치환 후에는 다음과 같이 식이 변하게 됩니다.

\[\begin{aligned} w_i^T\tilde{w}_k &= \log X_{ik} - b_i - \tilde{b_k} \\ w_i^T\tilde{w}_k + b_i + \tilde{b_k} &= \log X_{ik} \end{aligned}\]

위 식을 이용하여 GloVe의 목적 함수(Objective function)를 다음과 같이 쓸 수 있습니다. 여기서 마지막 항에 해당하는 $\log X_{ij}$는 데이터셋을 통해서 이미 알고있는 것이고 나머지 $w_i, \tilde{w_j}, b_i, \tilde{b_j}$는 학습이 되는 미지수입니다.

\[J = \sum_{i,j=1}^V (w_i^T\tilde{w}_j + b_i + \tilde{b_j} - \log X_{ij})^2\]

목표는 이 오차를 최소화 시키는 것이므로 $\text{argmin}_{w,b} J(w,b)$ 가 됩니다. 논문에서는 알고리즘의 성능을 높이기 위해서 목적 함수에 동시 발생 행렬의 원소를 인자로 가지는 하나의 함수 $f$ 를 더 적용했습니다.

논문에서 함수 $f$가 만족해야 하는 조건으로 제시한 것은 3가지 입니다. 첫 번째로 $f(0) = 0$ 이어야 합니다. 두 번째로는 동시 발생 횟수가 적은 단어에 과한 가중치를 부여하지 않기 위해서 증가 함수여야 합니다. 세 번째는 동시 발생 횟수가 높은 단어에도 과한 가중치를 부여하지 않기 위해 상대적으로 적은 값을 적용하는 함수여야 합니다. 이 모든 조건을 만족하는 함수로 논문에서 제시한 함수는 다음과 같습니다.

\[f(x) = \begin{cases} \big(\frac{x}{x_\text{max}}\big)^\alpha \quad \text{ if} \quad x < x_\text{max}\\ 1 \qquad \qquad \text{otherwise}\end{cases}\]

$\alpha = 0.75$일 때, 위 함수의 그래프는 아래와 같습니다. 이 함수를 적용한 목적함수 $J$ 는 그 아래 수식과 같이 변하게 되어, 최종적인 $J$ 를 줄이는 것을 목표로 학습하게 됩니다.

glove

이미지 출처 : lovit.github.io

\[\Rightarrow J = \sum_{i,j=1}^V f(X_{ij})(w_i^T\tilde{w}_j + b_i + \tilde{b_j} - \log X_{ij})^2\]

Fasttext

지금까지 등장했던 확률기반 신경망 모델(NPLM), Word2Vec, GloVe는 단어가 가진 형태적 특성을 무시하고 있다는 한계점을 가지고 있습니다. 이런 문제 때문에 형태소 변화가 다양한 언어인 터키어나 핀란드어에는 잘 작동하지 않는다는 단점을 가지고 있습니다. 예를 들면, 다음과 같은 것입니다.

터키어 단어 : “çevrenizdekilere” = “çevreniz + de + ki + ler + e” (5개 형태소의 합)

핀란드 단어 : “sanoinhan” = “sano + i + n + han” (4개 형태소의 합)

이렇게 하나의 단어가 여러 가지 형태소의 합으로 되어있는 경우에는 형태소 분석을 제대로 해주지 않는다면 제대로 된 임베딩을 하기가 어렵습니다. Fasttext는 이런 한계점을 극복하기 위해서 고안된 방법입니다. Fasttext는 단어 혹은 형태소 단위가 아니라 캐릭터(Character,철자) 단위로 접근합니다. 이를 서브워드(Subword) 모델이라고도 합니다.

Fasttext는 그럼 하나의 단어를 어떻게 표현하는 것일까요? 각 캐릭터의 N-gram 표현을 벡터로 나타내며 이 벡터들의 합을 단어로 표현합니다. $N = 3, 4, 5, 6$ 일 때의 캐릭터 시퀀스를 만들어 각각에 임베딩 벡터를 부여한 뒤 원래 단어를 포함한 벡터까지의 합을 한 단어의 임베딩 벡터로 계산합니다. 위에서 예를 들었던 “sanoinhan”이라는 단어가 Fasttext에서는 어떻게 임베딩 되는 지를 보겠습니다. Fasttext에서는 양 옆에 ”<”,”>“을 붙여 단어를 구분합니다.

<sanoinhan>을 $N = 3$ 으로 나눈 캐릭터 시퀀스는 ”<sa”, “san”, “ano”, … ,”an>“으로 총 11개가 있습니다. 원래 단어는 sanoinhan 입니다.

총 12개의 벡터를 더하여 단어의 최종 임베딩 벡터로 사용합니다. (물론 4, 5, 6-gram 캐릭터 시퀀스까지 적용하면 갯수가 더 많아집니다.) 아래 그림에서도 “eating”이라는 단어를 3-gram의 캐릭터로 자른 뒤에 원래 단어와의 합을 통해 단어 임베딩 벡터를 나타내고 있습니다.

to3-gram

3-gram

word_embedding

이미지 출처 : amitness.com

Fasttext에 서브워드 모델을 적용할 수 있는 바탕에는 Word2Vec의 목적 함수가 있습니다. 네거티브 샘플링을 사용한 Word2Vec의 목적 함수는 다음과 같았습니다.

\[J_t(\theta) = \log \sigma(u_o^Tv_c) + \sum^k_{i=1}E_{i \sim P(w)}[\log \sigma(-u_i^Tv_c)]\]

위 식을 보면 각 시그모이드 함수에 들어가는 파라미터, 즉 Score는 임베딩 벡터와 가중치 벡터의 내적으로 이루어져 있는 것을 알 수 있습니다. 그래서 서브워드 모델에서도 Score를 다음과 같이 두 벡터의 내적 값을 모든 시퀀스에 대해 더하여 도출합니다. $G_w (\subset {1, \cdots , G})$는 단어 내에 등장하는 모든 캐릭터 시퀀스입니다.

\[\text{score}(w,c) = \sum_{g \in G_w} \mathbf{z}_g^T\mathbf{v}_c\]

Fasttext는 Score를 계산하는 방법만 다를 뿐이지 나머지 목적 함수에 대해서는 네거티브 샘플링을 적용한 Word2Vec 모델과 동일합니다.

위에서도 설명한 것처럼 Fasttext는 단어의 형태 변화에 대해 강건(Robust)합니다. 아래처럼 단어의 원형에 다른 접미사 등이 붙더라도 서브워드로 분리하기 때문에 좋은 성능을 보여줍니다.

character

이미지 출처 : amitness.com

이런 특징 덕분에 교착어1인 한국어에 적용하여도 꽤 높은 임베딩 성능을 보인다는 장점을 가지고 있습니다.

  1. 교착어는 언어의 유형론적 분류의 하나인 형태론적 관점에서의 분류에 따른 언어의 한 유형이다. 교착어는 고립어와 굴절어의 중간적 성격을 띠는 것으로 어근과 접사에 의해 단어의 기능이 결정되는 언어의 형태이다. ‘교착’은 아교와 같이 단단히 달라붙음을 뜻한다. - 위키피디아 : 교착어 



Comments