관련글: Word2Vec 개념
Python을 이용해 한국어 Word2Vec을 만들어 보자. 대략적인 과정은 아래와 같다.
- 한국어로 된 글 모으기
- 형태소 분석 등 전처리하기
- gensim을 통해 Word2Vec 만들기
아래 튜토리얼을 따라하려면 아래와 같은 것이 설치되어 있어야 한다.
- Python 2.7, 3.3 이상
- python의 pip으로 필요한 라이브러리 설치
python -m pip install gensim konlpy
한국어로 된 글 모으기
웹 상에서 손쉽게 구할 수 있는 한국어로 된 글은 아래와 같다.
Wikipedia
Wikiepdia 덤프는 MediaWiki 포맷으로 되어 있다. 이 포맷을 plain text로 바꾸는 Tool은 많이 있지만, 여기서는 wikiextractor를 이용하겠다. 이 Tool을 이용하면 json/xml 형태로 제목, 링크와 본문을 저장한다. 여기서는 json 포맷으로 저장한다.
- attardi/wikiextractor로 이동해서, WikiExtractor.py를 다운로드한다.
- 위 파일을 임의의 디렉토리에 저장한다. 그 디렉토리에 output이라는 디렉토리를 만든다.
- 아래와 같은 명령어를 입력한다.
python WikiExtractor.py [덤프 파일 이름] -o step1 --json -b 50M -q
위 명령어의 의미는 아래와 같다.
- -o step1: step1 디렉토리에 plain text로 변환된 파일을 저장한다.
- --json: 출력 파일은 JSON 포맷이다.
- -b 50M: 파일 한 개의 크기를 50MB로 제한한다. 출력이 50MB를 초과한다면 새 파일을 만든다.
- -q: 덤프에 있는 문서 목록을 출력하지 않는다.
{"id": "", "revid": "", "url":"", "title": "", "text": "..."}
위와 같이 파싱이 되게 되는데, 이 json 파일을 한번 더 읽어서 plain text로 만들 수 있다.
전처리
이 예제에서 사용하는 전처리는 아래와 같다.
- Konlpy의 Hannanum 라이브러리를 이용해서 문장을 품사별로 분리
- 관계언(조사 등)과 특수문자 제거
전처리에 따라 Word2Vec의 품질이 달라질 수 있으므로 다양한 시도를 해 보는 것도 좋다.
- Hannanum에서 사용하는 품사 정보: link
아래 코드는 step1 디렉토리에 저장된 plain text를 읽어서 품사별로 분리한 뒤, 관계언과 특수문자를 제거하고 그 결과를 step2 디렉토리에 저장하는 예제이다.
# -*- coding: utf-8 -*-
import os
import re
import multiprocessing
from konlpy.tag import Hannanum
# tag reference: http://semanticweb.kaist.ac.kr/research/morph/
def extract_keywords(han, sentence):
"""
품사 분석을 진행한 뒤 관계언(조사 등)이나 기호를 제거한다.
"""
tagged = han.pos(sentence)
result = []
# 관계언 제거 (조사 등)
for word, tag in tagged:
if tag in ['F', 'N', 'P', 'M', 'I', 'X']: # 관계언 or 기호 제외
result.append(word)
return result
def worker(data):
han = Hannanum()
remove_special_char = re.compile(r'[^가-힣^A-z^0-9^.^,^?^!^ ]') # 한글, 영어, 기본 기호를 제외한 문자들
path, file_name = data
print("process file: {}".format(file_name))
with open(os.path.join(path, file_name), 'rt', encoding='utf-8') as input:
with open(os.path.join(os.getcwd(), 'step2', file_name), 'wt', encoding='utf-8') as output:
# step1에 있는, plain text를 읽어는다
i = 0
for input_line in input:
# 진행률을 출력하기 위한 부분
i += 1
if i % 100 == 0:
print("{}] {} finished".format(file_name, i))
# 특수 문자 제거 후 품사 분석 진행, 파일에 기록
text = remove_special_char.sub(' ', input_line)
keyword = extract_keywords(han, text)
output.write(' '.join(keyword))
output.write('\n')
if __name__ == '__main__':
pool = multiprocessing.Pool(processes=4)
print('loading multiprocessing pool...')
data = []
for path, dirs, files in os.walk('step1/'):
for file_name in files:
data.append( (path, file_name) )
pool.map(worker, data)
pool.close()
pool.join()
Word2Vec 만들기
같은 디렉토리에서 아래 script를 실행시키면 word2vec이 만들어진다.
아래 script는 한국어 Word2Vec 을 참고하여 만들었다.
# -*- coding: utf-8 -*-
import multiprocessing
import os
import gensim
class SentenceLoader(object):
def __init__(self, source_dir):
self.source_dir = source_dir
def __iter__(self):
for path, dirs, files in os.walk(self.source_dir):
for file in files:
with open(os.path.join(path, file), 'rt', encoding='utf-8') as f:
for line in f:
yield line.replace('\\n', '').replace(',', '').split(' ')
sentences_vocab = SentenceLoader('step2/')
sentences_train = SentenceLoader('step2/')
print("sentence loader loaded.")
config = {
'min_count': 5, # 등장 횟수가 5 이하인 단어는 무시
'size': 350, # 300차원짜리 벡터스페이스에 embedding
'sg': 1, # 0이면 CBOW, 1이면 skip-gram을 사용한다
'batch_words': 10000, # 사전을 구축할때 한번에 읽을 단어 수
'iter': 10, # 보통 딥러닝에서 말하는 epoch과 비슷한, 반복 횟수
'workers': multiprocessing.cpu_count(),
}
model = gensim.models.Word2Vec(**config) # Word2vec 모델 생성
model.build_vocab(sentences_vocab) # corpus 개수를 셈
print('model.corpus_count: {}'.format(model.corpus_count))
model.train(sentences_train, total_examples=model.corpus_count, epochs=config['iter']) # Word2Vec training
model.save('model') # 모델을 'model' 파일에 저장
gensim을 이용해서 word2vec을 만들었다. gensim이 자체적으로 처리해 주는 일은 아래와 같다.
- 문서를 자동으로 로딩한다.
- 단어들을 자동으로 One-hot encoding으로 바꿔준다.
- CBOW 기법을 이용해서 Word2Vec을 학습한다. (옵션 지정시 Skip-gram 가능)
- CBOW는 주변의 맥락(중심 단어 양옆에 있는 단어)을 보고 타깃 단어(중심 단어)를 학습하는 방법이다.
- 학습 방법은 Word2Vec 문서에서 확인이 가능하다.
- 단어들을 One-hot encoding된 index로, index를 원래 단어로 상호 변환한다.
- Word2Vec 벡터값을 출력하고, 벡터 간의 연산을 수행하고, 특정 단어와 가장 가까운 벡터를 출력한다.
이와 같이, Word2Vec을 학습하고 사용하는 데 있어서 필요한 대부분의 기능을 코드 몇 줄만으로 처리할 수 있다.
Word2Vec 사용하기
from gensim.models import Word2Vec
# 모델 로딩
model = Word2Vec.load('model')
print(model.vw['컴퓨터']) # 컴퓨터의 word vector 출력
print(model.most_similar(positive=['서울', '일본'], negative=['한국']))
# "서울 - 한국 + 일본" vector와 가장 가까운 단어 출력
'활용 > NLP' 카테고리의 다른 글
TextCNN (0) | 2020.04.12 |
---|---|
Natural Language Processing (0) | 2020.04.12 |
Word2vec (0) | 2020.04.12 |
Text Embedding (0) | 2020.04.12 |