Codong's Development Diary RSS 태그 관리 글쓰기 방명록
2021-04-13 21:11:45

개요


오늘도 딥 러닝을 이용한 자연어 처리 입문 교재를 가지고 공부를 한다.
텍스트 전처리 다음으로 두번째로 공부할 내용은 언어모델이다. 언제 20 챕터까지...

느려도 좋으니 끝까지 할 수 있었으면 좋겠다.. 😂


1. 언어모델


언어 모델(Languagel Model)이란 단어 시퀀스(문장)에 확률을 할당하는 모델을 말한다. 어떤 문장들이 있을 때, 적절한지 사람처럼 판단할 수 있다면, 기계가 자연어 처리를 정말 잘 한다고 볼 수 있다. 이게 바로 언어 모델이 하는 일이다.


1.1 주어진 이전 단어들로부터 다음 단어 예측하기

확률을 할당하게 하기 위해서 가장 보편적으로 사용되는 방법은 언어 모델이 이전 단어들이 주어졌을 때 다음 단어를 예측하도록 하는 것이다.

1.1.1 단어 시퀀스의 확률

하나의 단어를 w, 단어 시퀀스을 대문자 W라고 한다면, n개의 단어가 등장하는 단어 시퀀스 W의 확률은 다음과 같다. P는 확률

$P(W)=P(w_1,w_2,w_3,w_4,w_5,...,w_n)$

1.1.2 다음 단어 등장 확률

n-1개의 단어가 나열된 상태에서 n번째 단어의 확률은 다음과 같다.

$P(w_n|w_1,...,w_{n−1})$

|의 기호는 조건부 확률(conditional probability)을 의미한다. * 참고 : $P(B|A) = \frac{P(A\cap B)}{P(A)}$

전체 단어 시퀀스 W의 확률은 모든 단어가 예측되고 나서야 알 수 있으므로 단어 시퀀스의 확률은 다음과 같다.

$P(W)=P(w_1,w_2,w_3,w_4,w_5,...w_n)=\prod_{i=1}^n P(w_n|w_1,...,w_{n−1})$

$\prod_{i=1}^n$ 는 곱기호로 요소들을 전부 곱한다는 뜻이다.

1.2 언어 모델 직관적으로 이해해보기

비행기를 타려고 공항에 갔는데 지각을 하는 바람에 비행기를 [ ] 라는 문장이 있다. 빈 괄호 안에 올 단어가 사람은 쉽게 '놓쳤다'라고 예상할 수 있다. 우리 지식에 기반하여 나올 수 있는 여러 단어들을 후보에 놓고 놓쳤다는 단어가 나올 확률이 가장 높다고 판단하였기 때문이다.

그렇다면 기계에게 위 문장을 주고, '비행기를' 다음에 나올 단어를 예측해보라고 한다면 과연 어떻게 최대한 정확히 예측할 수 있을까? 기계도 비슷하다. 앞에 어떤 단어들이 나왔는지 고려하여 후보가 될 수 있는 여러 단어들에 대해서 등장 확률을 추정하고 가장 높은 확률을 가진 단어를 선택한다.

ex. 검색엔진 같은경우 검색시 다음 단어를 예측해서 추천해준다.


2. 통계적 언어 모델(Statistical Language Model, SLM)


언어 모델의 전통적인 접근 방법인 통계적 언어 모델이다.

2.1 문장에 대한 확률

위에서 잠깐 언급 됐던, 조건부 확률의 연쇄 법칙을 이용해 문장의 확률을 구해보자.

➕ 연쇄 법칙(chain rule)

$P(x_1,x_2,x_3...x_n)=P(x_1)P(x_2|x_1)P(x_3|x_1,x_2)...P(x_n|x_1...x_{n−1})$

이 조건부확률을 이용하여 '안녕하세요 저는 딥러닝을 공부하고 있습니다.' 라는 문장의 확률을 구해보자.

이것을 수식으로 표현 한다면 다음과 같다.

P(안녕하세요 저는 딥러닝을 공부하고 있습니다.) = P(안녕하세요) x P(저는|안녕하세요) x
P(딥러닝을|안녕하세요 저는) x ... x P(있습니다.|안녕하세요 저는 딥러닝을 공부하고)

말로 풀어본다면, 해당 문장의 확률은
'안녕하세요'가 나올 확률 X
'안녕하세요'가 나오고 '저는'이 나올 확률 X
'안녕하세요 저는'이 나오고 '딥러닝을'이 나올확률 X ... X
'안녕하세요 저는 딥러닝을 공부하고 있습니다.'가 나오고 '있습니다'가 나올 확률 이다.

결론은 문장의 확률을 구하기 위해서 각 단어에 대한 예측 확률들을 곱한다.

2.2 카운트 기반의 접근

문장의 확률을 구하기 위해 각 단어에 대한 예측 확률을 모두 곱한다는 것은 알겠지만 이전 단어로부터 다음 단어에 대한 확률은 어떻게 구할까? 그것은 바로, 카운트에 기반하여 확률을 계산한다.

'안녕하세요 저는 딥러닝을 공부하고'가 나왔을 때 '있습니다'가 나올 확률을 구해보자

$P(있습니다|안녕하세요 저는 딥러닝을 공부하고) = \frac{count(안녕하세요 저는 딥러닝을 공부하고 있습니다)}{count(안녕하세요 저는 딥러닝을 공부하고)}$

단순히 학습한 코퍼스 데이터에서 '안녕하세요 저는 딥러닝을 공부하고'가 100번 등장하고, 그 다음에 '있습니다'가 등장한 경우가 30번이라고 한다면 $P(있습니다|안녕하세요 저는 딥러닝을 공부하고)$ 는 30%가 된다.

➕ 카운터 기반의 한계 - 희소 문제(Sparsity Problem)

기계에게 많은 코퍼스를 훈련시켜서 언어 모델을 통해 현실에서의 확률 분포를 근사하는 것이 언어 모델의 목표이다. 하지만, 카운트 기반으로 접근하려고 한다면 갖고있는 코퍼스(corpus). 즉, 다시 말해 기계가 훈련하는 데이터는 정말 방대한 양이 필요하다.

위의 카운트 기반 조건부 확률을 구하는 공식에서 분모에 해당하는 카운트 수가 0이면 확률이 정의될 수가 없다. 쉽게 말해 학습 데이터를 통해 카운트가 한 번도 되지 않거나 아주 적게 되는 경우 언어를 정확히 모델링하지 못하는 문제가 생긴다.

이러한 문제를 완화하기 위해 n-gram이나 스무딩 백오프와 같은 여러가지 일반화(generalization) 기법이 존재한다. 하지만 근본적 해결책은 되지 못하기에, 통계적 언어 모델에서 인공 신경망 언어 모델로 트렌드가 바뀌었다.


3. N-gram 언어 모델(N-gram Language Model)


n-gram 또한 카운트 기반 통계적 접근 언어 모델이므로 SLM의 일종이다. 하지만 모든 단어를 고려하는 것이 아니고, 일부 단어만 고려하는 접근 방법을 사용한다. 이 때 일부 단어를 몇 개 보느냐를 결정하는데 이것이 N-gram의 n 을 의미한다.

3.1 코퍼스에서 카운트하지 못하는 경우를 감소

SLM의 한계는 훈련 코퍼스에 확률을 계산하고 싶은 문장이나 단어가 없을 수 있다는 점이다. 또한 문장이 길어질수록 갖고있는 코퍼스에서 그 문장이 존재하지 않을(카운트할 수 없을) 가능성이 높다. 그런데 다음과 같이 참고하는 단어들을 줄이면 카운트를 할 수 있을 가능성이 높일 수 있다.

가령, An adorable little boy가 나왔을 때 is가 나올 확률을 그냥 boy가 나왔을 때 is가 나올 확률로 생각해보는 건 어떨까? 갖고있는 코퍼스에 An adorable little boy is가 있을 가능성 보다는 boy is라는 더 짧은 단어 시퀀스가 존재할 가능성이 더 높다.

즉, 앞에서는 An adorable little boy가 나왔을 때 is가 나올 확률을 구하기 위해서는 An adorable little boy가 나온 횟수와 An adorable little boy is가 나온 횟수를 카운트해야만 했지만, 이제는 단어의 확률을 구하고자 기준 단어의 앞 단어를 전부 포함해서 카운트하는 것이 아니라, 앞 단어 중 임의의 개수만 포함해서 카운트하여 근사하자는 것이다. 이렇게 하면 갖고 있는 코퍼스에서 해당 단어의 시퀀스를 카운트할 확률이 높아집니다.

3.2 N-gram

예를 들어 '안녕하세요 저는 딥러닝을 공부하고 있습니다.' 라는 문장에 대해 n-gram을 전부 구해보면 아래와 같다.

unigrams : 안녕하세요 / 저는 / 딥러닝을 / 공부하고 / 있습니다.
bigrams : 안녕하세요 저는 / 저는 딥러닝을 / 딥러닝을 공부하고 / 공부하고 있습니다.
trigrams : 안녕하세요 저는 딥러닝을 / 저는 딥러닝을 공부하고 / 딥러닝을 공부하고 있습니다.
4-grams : 안녕하세요 저는 딥러닝을 공부하고 / 저는 딥러닝을 공부하고 있습니다.

n-gram을 통한 언어 모델에서는 다음에 나올 단어의 예측은 오직 n-1개의 단어에만 의존한다. 예를 들어 '안녕하세요 저는 딥러닝을 공부하고' 다음에 나올 단어를 예측하고 싶다고 할 때, n=3 라고 한 3-gram을 이용한 언어 모델을 사용한다고 합시다. 이 경우, 공부하고 다음에 올 단어를 예측하는 것은 다른 부분은 제외한 n-1에 해당되는 앞의 2개의 단어(예제에서 '딥러닝을 공부하고')만을 고려합니다.

3.3 N-gram의 한계

예를 들어서 '골목에서 담배를 피던 소녀가 나를 쳐다봐서 [ ].' 라는 문장의 마지막에 들어갈 단어를 정하는데, 4-gram 이라 가정한다면 소녀가 나를 쳐다봐서 '설레였다' 라는 문장이 카운트가 많이 되서 결정 될 수 있다는 점이다. 근처 단어 몇 개만 고려하니, 문장 앞쪽의 '골목에서 담배를 피던'이란 수식어가 반영이 되지 않아 '무서웠다'와 같이 의도하고 싶은 대로 문장을 끝맺음하지 못하는 경우가 생긴다는 점이다. 뿐만아니라 여전히 카운트를 기반으로 하기때문에 희소 문제가 존재한다.

➕ n 을 선택하는 것은 trade-off 문제

trade-off 란, 질과 량 가운데 어느 한편을 늘리면 다른 한편은 그 만큼 줄어드는 것을 이르는 말이다.
혹시나 나처럼 trade-off의 뜻을 모르는 분들을 위해 적어둔다.

n을 크게하면 실제 훈련 코퍼스에서 해당 n-gram을 카운트할 수 있는 확률은 적어지므로 희소 문제는 점점 심각해지고, 모델 사이즈가 커진다는 문제점도 있다. 기본적으로 코퍼스의 모든 n-gram에 대해서 카운트를 해야 하기 때문이다.

n을 작게 선택하면 훈련 코퍼스에서 카운트는 잘 되겠지만 근사의 정확도는 현실의 확률분포와 멀어진다. 그렇기 때문에 적절한 n을 선택해야 합니다. 앞서 언급한 trade-off 문제로 인해 정확도를 높이려면 n은 최대 5를 넘게 잡아서는 안 된다고 권장되고 있다.

그래도 n을 1보다는 2로 선택하는 것은 거의 대부분의 경우에서 언어 모델의 성능을 높일 수 있다.


4. 한국어에서의 언어 모델


영어나 기타 언어에 비해 한국어는 정말 까다롭다. 대표적인 이유를 살펴보자.

4.1 한국어는 어순이 중요하지 않다.

ex) 떡볶이 진짜 맛있지 않냐? = 진짜 맛있지 않냐 떡볶이?
어순이 중요하지 않다는 것은, 어떤 단어든 나타나도 된다는 의미이다. 언어 모델이 얼마나 헷갈릴까..

4.2 한국어는 교착어다.

한국어는 조사와 같은 것이 있어 발생가능한 단어 수를 굉장히 늘린다.
ex) '그녀' => 그녀가, 그녀를, 그녀의, 그녀로, 그녀에게, 그녀처럼 등 다양한 경우 존재.

그래서 한국어에서는 토큰화를 통해 접사나 조사 등을 분리하는 것이 중요한 작업이 되기도 한다.

4.3 한국어는 띄어쓰기가 제대로 지켜지지 않는다.

한국어는 띄어쓰기를 제대로 하지 않아도 의미가 전달되며, 띄어쓰기 규칙 또한 상대적으로 까다로운 언어이기 때문에 한국어 코퍼스는 띄어쓰기가 제대로 지켜지지 않는 경우가 많다. 토큰이 제대로 분리 되지 않는채 훈련 데이터로 사용된다면 언어 모델은 제대로 동작하지 않습니다.


5. 펄플렉서티(Perplexity)


두 개의 모델 A, B가 있을 때 이 모델의 성능은 어떻게 비교할 수 있을까? 일일히 모델들에 대해서 실제 작업을 시켜보고 정확도를 비교하는 작업은 공수가 너무 많이 드는 작업이다.

이러한 평가를 외부 평가(extrinsic evaluation)라고 하는데, 이러한 평가보다는 어쩌면 조금은 부정확할 수는 있어도 테스트 데이터에 대해서 빠르게 식으로 계산되는 더 간단한 평가 방법이 있다. 바로 모델 내에서 자신의 성능을 수치화하여 결과를 내놓는 내부 평가(Intrinsic evaluation)에 해당되는 펄플렉서티(perplexity)이다.

5.1 언어 모델의 평가 방법(Evaluation metric) : PPL

펄플렉서티(perplexity)는 언어 모델을 평가하기 위한 내부 평가 지표이고, 보통 줄여서 PPL이 라고 표현한다. 'perplexed'라는 '헷갈리는'과 유사한 의미가져서 그런가 PPL은 수치가 높으면 좋은 성능을 의미하는 것이 아니라, '낮을수록' 언어 모델의 성능이 좋다는 것을 의미한다.

PPL은 단어의 수로 정규화(normalization) 된 테스트 데이터에 대한 확률의 역수이다.PPL을 최소화한다는 것은 문장의 확률을 최대화하는 것과 같다. 문장 W의 길이가 N이라고 할 때 다음과 같다.

$PPL(W) = P(w_1,w_2,w_3, ... ,w_N)^{-\frac{1}{N}} = \sqrt[N]{\frac{1}{P(w_1,w_2,w_3, ... ,w_N)}}$

문장의 확률에 연쇄 법칙을 적용 하면,

$PPL(W) = \sqrt[N]{\frac{1}{P(w_1,w_2,w_3, ... ,w_N)}} = \sqrt[N]{\frac{1}{\prod_{i=1}^N P(w_i|w_1,...,w_{i−1})}}$

n-gram까지 적용이 되면, ex. bigram

$PPL(W) = \sqrt[N]{\frac{1}{\prod_{i=1}^N P(w_i|w_{i−1})}}$

5.2 분기 계수 (Branching factor)

PPL은 선택할 수 있는 가능한 경우의 수를 의미하는 분기계수(branching factor)이다. PPL은 이 언어 모델이 특정 시점에서 평균적으로 몇 개의 선택지를 가지고 고민하고 있는지를 의미한다. 어떤 테스트 데이터을 주고 측정했더니 PPL이 10이 나왔다고 해보자.

$PPL(W) = P(w_1,w_2,w_3, ... ,w_N)^{-\frac{1}{N}} = (\frac{1}{10}^{N})^{-\frac{1}{N}} = \frac{1}{10}^{-1} = 10$

같은 테스트 데이터에 대해서 두 언어 모델의 PPL을 각각 계산 후에 PPL의 값을 비교하면, 두 언어 모델 중 어떤 것이 성능이 좋은지도 판단이 가능합니다.

주의할 점은 PPL의 값이 낮다는 것은 테스트 데이터 상에서 높은 정확도를 보인다는 것이지, 사람이 직접 느끼기에 좋은 언어 모델이라는 것을 반드시 의미하진 않는다는 점이다. 또한 언어 모델의 PPL은 테스트 데이터에 의존하므로 두 개 이상의 언어 모델을 비교할 때는 정량적으로 양이 많고, 또한 도메인에 알맞은 동일한 테스트 데이터를 사용해야 신뢰도가 높다는 것이다.