Skip to content

Korean Morphological Analyzer using Hidden Markov Model (HMM)

Notifications You must be signed in to change notification settings

lovit/hmm_postagger

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hidden Markov Model (HMM) 기반 한국어 형태소 분석기

세종 말뭉치를 이용하여 학습한 HMM 기반 한국어 형태소 분석기입니다. HMM 을 이용하여 형태소 분석을 하는 과정을 설명하기 위한 코드로, 오로직 Python 코드로만 이뤄져 있습니다.

이 repository 에서는 HMM 모델을 학습하는 Trainer 와, 학습된 모델을 이용하여 품사 판별을 하는 TrainedHMMTagger 을 제공합니다.

models/ 에는 세종 말뭉치를 이용하여 학습한 HMM 의 emission, transition probability 가 JSON 형식으로 저장되어 있습니다. 구현 과정 및 원리에 대해서는 블로그 포스트를 참고하세요.

Usage

Training

학습을 위하여 Corpus 와 CorpusTrainer class 를 import 합니다.

from hmm_postagger import Corpus
from hmm_postagger import CorpusTrainer

data_path = '../data/sejong_corpus_lr_sepxsv.txt'
model_path = '../models/sejong_lr_sepxsv_hmm.json'

Corpus 는 nested list 형식의 문장을 yield 하는 class 입니다. 학습에 이용한 네 문장의 예시입니다. 각 문장은 list 로 표현되며, 문장은 [형태소, 품사] 의 list 로 구성되어 있습니다.

corpus = Corpus(sejong_path)
for i, sent in enumerate(corpus):
    if i > 3:
        break
    print(sent)
[['뭐', 'Noun'], ['타', 'Verb'], ['고', 'Eomi'], ['가', 'Verb'], ['ㅏ', 'Eomi']]
[['지하철', 'Noun']]
[['기차', 'Noun']]
[['아침', 'Noun'], ['에', 'Josa'], ['몇', 'Determiner'], ['시', 'Noun'], ['에', 'Josa'], ['타', 'Verb'], ['고', 'Eomi'], ['가', 'Verb'], ['는데', 'Eomi']]

CorpusTrainer 에 품사의 min count, 단어의 min count 를 설정한 뒤, corpus 와 model_path 를 train 함수에 입력합니다.

trainer = CorpusTrainer(min_count_tag=5, min_count_word=1, verbose=True)
trainer.train(corpus, model_path)

model_path 에 JSON 형식으로 모델이 저장되어 있습니다. 모델은 두 종류의 정보가 담겨 있습니다.

import json
with open(model_path, encoding='utf-8') as f:
    model = json.load(f)

print(model.keys())
# dict_keys(['emission', 'transition'])

emission 은 {tag:{word:prob}} 형식의 nested dict 이며 transition 은 {'Noun -> Josa': prob} 형식의 dict 입니다. 문장의 시작에 대한 transition (예: ('BOS', 'Noun')) 나 문장의 마지막에 대한 transition (예: ('Eomi', 'EOS')) 는 transition 에 저장되어 있습니다.

Tagging

학습된 형태소 분석기는 hmm model 파일을 입력해야 합니다.

from hmm_postagger import TrainedHMMTagger

model_path = '../models/sejong_lr_sepxsv_hmm.json'
tagger = TrainedHMMTagger(model_path)

예시로 네 문장에 대한 형태소 분석을 수행합니다.

from pprint import pprint

sents = [
    '주간아이돌에 아이오아이가 출연했다',
    '이번 경기에서는 누가 이겼을까',
    '아이고 작업이 쉽지 않구만',
    '샤샨 괜찮아'
]

for sent in sents:
    print('\n\n{}'.format(sent))
    pprint(tagger.tag(sent))

2, 3 번째 문장의 단어들은 세종말뭉치에 존재하였기 때문에 형태소 분석이 어느 정도 되지만, '주간아이돌'과 '아이오아이'는 미등록단어 문제가 발생하여 형태소 분석이 제대로 이뤄지지 않습니다.

주간아이돌에 아이오아이가 출연했다
[('주간', 'Noun'),
 ('아이돌', 'Noun'),
 ('에', 'Josa'),
 ('아이오아', 'Noun'),
 ('이가', 'Noun'),
 ('출연', 'Noun'),
 ('하', 'Verb'),
 ('았다', 'Eomi')]


이번 경기에서는 누가 이겼을까
[('이번', 'Noun'),
 ('경기', 'Noun'),
 ('에서는', 'Josa'),
 ('누가', 'Noun'),
 ('이기', 'Verb'),
 ('었을까', 'Eomi')]


아이고 작업이 쉽지 않구만
[('아이고', 'Noun'),
 ('작업', 'Noun'),
 ('이', 'Josa'),
 ('쉽', 'Adjective'),
 ('지', 'Eomi'),
 ('않', 'Verb'),
 ('구만', 'Eomi')]


샤샨 괜찮아
[('샤샤', 'Noun'),
 ('ㄴ', 'Josa'),
 ('괜찮', 'Adjective'),
 ('아', 'Eomi')]

사용자 사전을 추가할 수 있는 기능을 넣었습니다. 사용자 사전이 입력되면 해당 단어들은 각 품사에서 가장 큰 emission probability 를 지닙니다. 즉, 다른 어떤 단어보다도 우선적으로 추가한 단어를 선호합니다.

tagger.add_user_dictionary('Noun', ['아이오아이', '주간아이돌'])
pprint(tagger.tag('주간아이돌에 아이오아이가 출연했다'))
[('주간아이돌', 'Noun'),
 ('에', 'Josa'),
 ('아이오아이', 'Noun'),
 ('가', 'Josa'),
 ('출연', 'Noun'),
 ('하', 'Adjective'),
 ('았', 'Eomi'),
 ('다', 'Eomi')]

Inferring unknown word

형태소 분석을 하여도 전혀 보지 못한 string 이 존재할 수 있습니다. '갹갹' 이라는 단어는 등록된 형태소로도 분해하지 못합니다.

sent = '갹갹은 어디있어'
tagger.tag(sent, inference_unknown=False)
[('갹갹', 'Unk'),
 ('은', 'Josa'),
 ('어디', 'Noun'),
 ('있', 'Verb'),
 ('어', 'Eomi')]

위와 같은 경우에 '갹갹'의 앞 단어 (BOS) 에서의 state transition probability 와 '갹갹'의 뒤 단어 '은/josa'으로의 state transition probability 를 고려하여 '갹갹'의 품사를 추정합니다. inference_unknown 의 기본값은 True 입니다.

sent = '갹갹은 어디있어'
tagger.tag(sent, inference_unknown=True)
[('갹갹', 'Noun'),
 ('은', 'Josa'),
 ('어디', 'Noun'),
 ('있', 'Verb'),
 ('어', 'Eomi')]

품사 추정의 기능을 이용하면 아래와 같이 영문과 한글이 혼용된 경우, 영어 단어의 품사도 추정할 수 있습니다.

tt는 좋은 노래야tt
[('tt', 'Noun'),
 ('는', 'Josa'),
 ('좋', 'Adjective'),
 ('은', 'Eomi'),
 ('노래', 'Noun'),
 ('야', 'Josa'),
 ('tt', 'Noun')]

TODO

기호 처리

마침표나 물음표와 같은 기호가 입력되지 않음을 가정하였습니다. 오로직 완전한 한글이 입력된 경우만을 가정하여 세종 말뭉치 데이터에서도 기호는 제거한 뒤 학습하였습니다.

실제 문제에 적용가능하도록 모델을 변형하려면 외래어, 기호에 대한 처리륻 더해야 합니다.

shortest path 최적화

HMM 의 decoding 과정은 shortest path 문제와 같습니다. 현재 구현된 코드에서는 shortest path 의 최적화가 이뤄져 있지 않습니다.

Releases

No releases published

Packages

No packages published

Languages