AI/Basic NLP

NLTK를 활용한 N-GRAM 언어 모델

칼쵸쵸 2025. 3. 1. 15:29
반응형

N-gram 언어 모델이란?

자연어 처리에서 많이 사용되는 N-gram 언어 모델은 문장에서 앞에 나온 단어들을 활용해 다음에 올 단어를 예측하는 방법입니다. 쉽게 말해, "앞 단어들을 보고 다음 단어가 무엇일지 맞히는 모델"입니다.

N-gram에서 N은 단어의 개수를 의미합니다. 즉, 문장에서 N개의 연속된 단어 묶음(그램, gram)을 의미합니다.

  • 2-gram (Bigram): 앞 단어 1개를 보고 다음 단어를 예측 (예: "오늘 날씨" → "좋다")
  • 3-gram (Trigram): 앞 단어 2개를 보고 다음 단어를 예측 (예: "오늘 날씨가" → "좋다")
  • 4-gram (4-그램): 앞 단어 3개를 보고 다음 단어를 예측

즉, N이 커질수록 더 많은 앞 단어를 참고해서 예측하는 모델이 됩니다.

예제: 7-gram

예제 문장: "나는 오늘 맛있는 점심을 먹었다."

이 문장에서 7-gram을 만든다고 하면 다음과 같이 나뉠 수 있습니다.

  • "나는 오늘 맛있는 점심을 먹었다"
  • "오늘 맛있는 점심을 먹었다 ."

이런 식으로 7개의 단어를 묶어 모델이 학습하게 됩니다. 그러면 이후 문장에서 "나는 오늘 맛있는 점심을"까지 나왔을 때, 모델이 다음 단어로 "먹었다"를 예측할 수 있습니다.

Count에 기반한 방법

N-gram 모델을 이용하면 다음 단어가 나올 확률은 해당 단어 조합이 등장한 횟수(Count)에 기반해서 계산됩니다.

예를 들어, "its water is so transparent that" 이라는 단어 조합이 데이터에서 10,000번 등장했고, "its water is so transparent that the"라는 단어 조합이 500번 등장했다면, "its water is so transparent that" 다음에 "the"가 올 확률은 다음과 같이 계산됩니다.

이처럼 N-gram 모델은 등장 횟수를 바탕으로 확률을 계산하여 다음 단어를 예측합니다.

N-gram 언어 모델의 문제점

N-gram 언어 모델은 몇 가지 한계를 갖고 있습니다.

  1. 데이터 부족 문제: 단어의 조합 경우의 수가 너무 많아, 아무리 많은 데이터를 수집하더라도 특정 단어 조합이 한 번도 등장하지 않을 수 있습니다. 이 경우 확률 계산에서 분모나 분자가 0이 되는 문제가 발생할 수 있습니다.
  2. 긴 문맥을 반영하기 어려움: N이 너무 작으면 문맥을 충분히 반영하지 못하고, 너무 크면 데이터가 부족해집니다.

N-Gram 모델 실습

자연어 처리에서 N-Gram 모델은 주어진 단어 시퀀스를 기반으로 다음 단어를 예측하는 방법입니다. 이번 실습에서는 NLTK(Natural Language Toolkit) 라이브러리를 활용하여 3-gram 모델을 학습하고, 이를 이용해 새로운 문장을 생성하는 방법을 알아보겠습니다.

1. NLTK 라이브러리 설치 및 다운로드

N-Gram 모델을 구현하기 위해 필요한 라이브러리를 설치하고, 데이터를 다운로드합니다.

import nltk
from nltk.util import bigrams, ngrams, pad_sequence, everygrams
from nltk.lm.preprocessing import pad_both_ends, flatten, padded_everygram_pipeline
from nltk.lm import MLE
from nltk.tokenize import word_tokenize, sent_tokenize
import requests
import io
import os

# NLTK 라이브러리 설치 및 다운로드
nltk.download("punkt", quiet=True)
nltk.download("all", quiet=True)

2. 데이터 준비 및 전처리

실습을 위해 샘플 텍스트 데이터를 다운로드하고, 문장 및 단어 단위로 토큰화합니다.

# 샘플 텍스트 데이터 다운로드
if os.path.isfile('language-never-random.txt'):
    with io.open('language-never-random.txt', encoding='utf8') as fin:
        text = fin.read()
else:
    url = "https://gist.githubusercontent.com/alvations/53b01e4076573fea47c6057120bb017a/raw/b01ff96a5f76848450e648f35da6497ca9454e4a/language-never-random.txt"
    text = requests.get(url).content.decode('utf8')
    with io.open('language-never-random.txt', 'w', encoding='utf8') as fout:
        fout.write(text)

text 예시

                      Language is never, ever, ever, random

                                                               ADAM KILGARRIFF




Abstract
Language users never choose words randomly, and language is essentially
non-random. Statistical hypothesis testing uses a null hypothesis, which
posits randomness. Hence, when we look at linguistic phenomena in cor-
pora, the null hypothesis will never be true. Moreover, where there is enough
data, we shall (almost) always be able to establish that it is not true. In

텍스트 토큰화

NLTK의 word_tokenizesent_tokenize를 사용하여 문장을 단어 단위로 토큰화합니다.

# 문장 및 단어 토큰화
tokenized_text = [list(map(str.lower, word_tokenize(sent))) for sent in sent_tokenize(text)]

tokenized_text

[['language', 'is', 'never', ',', 'ever', ',', 'ever', ',', 'random', 'adam', 'kilgarriff', 'abstract', 'language', ...

3. N-Gram 모델 생성

N-Gram 모델을 생성하기 위해 N(여기서는 3)을 설정하고, 데이터를 학습용으로 전처리합니다.

# N-gram 모델 생성
n = 3  # 3-gram 모델 사용
train_data, padded_sents = padded_everygram_pipeline(n, tokenized_text)

4. MLE(Maximum Likelihood Estimation) 모델 학습

MLE는 최대 우도 추정 기법을 사용하여 N-Gram 모델을 학습합니다.

# MLE (Maximum Likelihood Estimation) 모델 학습
model = MLE(n)
model.fit(train_data, padded_sents)

5. 단어 확률 계산

학습된 모델에서 특정 단어 시퀀스의 확률을 확인할 수 있습니다. 예를 들어, "language is" 다음에 "never"가 나올 확률을 계산해 보겠습니다.

# 단어 확률 확인
print(model.score('never', ['language', 'is']))  # P('never' | 'language is')

result

0.6363636363636364

6. N-Gram 기반 텍스트 생성

학습된 모델을 이용해 새로운 문장을 생성합니다.

from nltk.tokenize.treebank import TreebankWordDetokenizer

detokenize = TreebankWordDetokenizer().detokenize

def generate_sent(model, num_words, random_seed=42):
    """
    N-gram 모델을 이용하여 문장을 생성하는 함수
    :param model: NLTK의 ngram 언어 모델
    :param num_words: 생성할 최대 단어 수
    :param random_seed: 랜덤 시드 값
    """
    content = []
    for token in model.generate(num_words, random_seed=random_seed):
        if token == '<s>':
            continue
        if token == '</s>':
            break
        content.append(token)
    return detokenize(content)

7. 문장 생성 결과

위에서 만든 generate_sent 함수를 이용해 20개의 단어로 구성된 문장을 생성해 보겠습니다.

# 생성된 문장 출력
print(generate_sent(model, 20, random_seed=7))

result

and carroll used hypothesis testing has been used, and a half.
반응형

'AI > Basic NLP' 카테고리의 다른 글

scikit-learn을 활용한 One-hot Encoding  (0) 2025.02.27
NLTK를 활용한 Tokenizing  (0) 2025.02.27