1. N-gram 모델
N-gram 모델은 총 N개의 단어의 그룹 내에서 N번째 단어 이전의 (N-1)개의 단어에 기반해 다음에 올 단어를 예측하는 모델입니다. 단어들의 집합에 확률을 부여하는 방식으로 다음에 올 단어를 맞추게 되는데, 기본적으로 조건부확률을 기반으로 추정하게 됩니다. 이에 대한 수학식은 다음과 같습니다.
N-gram 모델은 몇 가지 문제점을 가지고 있습니다.
- 데이터셋에 존재하지 않은 단어의 조합은 추정이 어렵다
- N 개수를 증가시키는 것은 모델의 성능을 높일 수 있지만, 모델 사이즈 증가에 따른 비용 문제가 된다
그래서 최근에는 이런 문제들을 해결하기 위해 딥러닝에 기반한 언어모델들이 주로 사용되고 있습니다. 이는 추후 미래의 글에서 다루도록 하겠습니다.
2. N-gram 모델 구현
N-gram 모델은 NLTK(Natural Language Toolkit) 라이브러리를 대표로 하여 구현할 수 있습니다다. (아래 링크 참조)
NLTK Libarary
다음은 바이그램(2글자)을 구현한 코드입니다. bigrams 함수는 입력은 시퀀스(문자열, 리스트, 튜플)을 받아 바이그램을 리스트를 반환합니다. 바이(bi)그램은 2개의 글자를 뜻하므로, 아래 출력값처럼 2개의 글자씩 묶여있는 것을 확인할 수 있습니다.
from nltk.util import bigrams
text = 'abc'
list(bigrams(text))
같은 방식으로 nltk에서 제공하는 ngrams 함수를 이용해 구현할 수 있습니다.
from nltk.util import ngrams
list(ngrams(text, n=2))
문장의 끝을 표시하는 것은 문장단위 해석을 위해서 필요할텐데, 이를 위한 기능이 nltk에서 제공됩니다. 문장의 시작과 끝을 나타내는 것을 추가해주는 것입니다. 사용하기 위한 예제코드는 다음과 같습니다.
from nltk.util import pad_sequence
list(pad_sequence(text,
pad_left=True, left_pad_symbol="<s>",
pad_right=True, right_pad_symbol="</s>",
n=2))
또는 pad_both_ends를 통해 같은 기능을 수행할 수도 있습니다.
from nltk.lm.preprocessing import pad_both_ends
list(pad_both_ends(text, n=2))
우리가 원하는 모델은 이상치에도 영향을 덜 받기 원합니다. 그래서 단일 단어를 기준으로도 훈련을 할 수 있는데, nltk에서는 이를 everygrams라는 함수를 통해서 가능합니다.
from nltk.util import everygrams
padded_bigrams = list(pad_both_ends(text, n=2))
list(everygrams(padded_bigrams, max_len=2))
여기서 문자를 하나의 흐름으로 펼치기 위해 사용하는 것은 flatten 함수입니다. 사용방법은 다음과 같습니다.
from nltk.lm.preprocessing import flatten
list(flatten(pad_both_ends(sent, n=2) for sent in text))
위 작업들을 한꺼번에 수행할 수 있습니다.
from nltk.lm.preprocessing import padded_everygram_pipeline
train, vocab = padded_everygram_pipeline(2, text)
3. 훈련
MLE(Maximum Likelihood Estimation)는 한글로 최대우도추정이라고 하는데, 이는 원하는 값이 나올 가능성(우도)을 최대로 만드는 모수를 추정하는 기법입니다. 위에서 준비된 데이터를 바탕으로 MLE를 통해 훈련을 진행합니다.
from nltk.lm import MLE
lm = MLE(2) # bigram
lm.fit(train, vocab)
또한, 아래는 nltk 언어모델의 몇 가지 메서드를 정리한 것 입니다.
# 'a' 개수 세기
lm.counts['a']
# 'a'가 들어간 것 중 'b' 개수 세기. 즉, Count('b'| 'a')
lm.counts[['a']]['b']
# 'a'가 있을 확률
lm.score('a')
# 'b'가 'a'보다 앞에 올 확률
lm.score('b', ['a'])
4. 생성
이렇게 만들어진 n-gram 모델을 통해서 새로운 텍스트를 생성 가능합니다.
print(lm.generate(20, random_seed=123))
'Python > Data Analysis' 카테고리의 다른 글
[NLP] 임베딩과 Word2Vec 실습해보기 (0) | 2022.09.07 |
---|---|
[NLP] Char-RNN 을 활용하여 언어 모델링 실습 | 텍스트 생성 (0) | 2022.06.06 |
TensorFlow로 딥러닝 모델 구현하기 | 시퀀셜, 함수형, 서브클래싱 API (0) | 2022.05.17 |
[NLP] Python으로 영어 가독성 테스트하기 | Flesch, Gunning fog (0) | 2020.09.28 |
[Modeling] 파이썬으로 선형계획법 최적화하기 | SciPy (0) | 2020.07.20 |