for textmining

Glove, 실전 사용하기

|

이번 글에서는 미국 스탠포드대 NLP랩에서 개발한 GloVe를 실전에서 사용하는 방법에 대해 살펴보도록 하겠습니다. GloVe와 관련 자세한 내용은 이곳을 참고하시면 좋을 것 같습니다. 그럼 시작하겠습니다.

함수 설치

본 포스팅은 스탠포드 NLP랩의 원코드(C)를 파이썬으로 옮겨놓은 이곳을 기본으로 참고하였습니다. 파이썬 환경이 구축돼 있는 분들의 경우 설치 방법은 간단합니다. 다음 한 줄이면 됩니다.

pip install glove

공기행렬 구축

GloVe의 입력 데이터는 다음과 같은 dict 구조의 공기행렬(Cooccurrence Matrix)입니다.

cooccur = {
	0: {
		0: 1.0,
		2: 3.5
	},
	1: {
		2: 0.5
	},
	2: {
		0: 3.5,
		1: 0.5,
		2: 1.2
	}
}

GloVe 코드엔 별도로 공기행렬을 만드는 과정이 있지는 않아서 ScikitLearn 패키지의 CountVectorizer 함수를 이용해 공기행렬을 구축하는 코드를 만들었습니다. 다음과 같은데요. GloVe 함수엔 공기정보가 들어있는 dic을 넣게 됩니다.

# co-occurrence matrix 만들기
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(min_df=10, ngram_range=(1,1))
X = vectorizer.fit_transform(corpus)
Xc = X.T * X             # co-occurrence matrix
Xc.setdiag(0)			 # 대각성분을 0으로
result = Xc.toarray()    # array로 변환
dic = {}
for idx1, word1 in enumerate(result):
	tmpdic = {}
	for idx2, word2 in enumerate(word1):
		if word2 > 0:
			tmpdic[idx2] = word2
	dic[idx1] = tmpdic

위 코드에서 raw data에 해당하는 corpus는 다음과 같이 원 텍스트들로 구성된 리스트입니다. 리스트의 각 요소는 개별 문서가 됩니다. 예컨대 다음과 같습니다.

corpus = [‘이건 무조건 n차각’, ​ ‘미친놈을 동경하는 이유’, ​ …

​ ‘울었다 웃었다 종 잡을 수 없지만 끝나고 나면 2편을 찾게 되는 영화’]

dic은 단어 ID들로만 구성된 dict이므로 단어 리스트들도 별도로 빼서 가지고 있는게 좋을 겁니다. 그 코드는 다음과 같습니다.

# 단어 리스트 작성
import operator
vocab = sorted(vectorizer.vocabulary_.items(), key=operator.itemgetter(1))
vocab = [word[0] for word in vocab]

단어벡터 학습

입력값을 만들었으니 GloVe 함수에 넣어 학습을 시킬 차례입니다. 학습 코드는 다음과 같습니다.

# training
import glove
model = glove.Glove(dic, d=100, alpha=0.75, x_max=100.0)
for epoch in range(25):
    err = model.train(batch_size=200, workers=4)
    print("epoch %d, error %.3f" % (epoch, err), flush=True)

각 파라메터에 대한 설명은 다음과 같습니다.

Glove.init()

  • cooccurence dict<int, dict<int, float» : the co-occurence matrix
  • alpha float : (default 0.75) hyperparameter for controlling the exponent for normalized co-occurence counts.
  • x_max float : (default 100.0) hyperparameter for controlling smoothing for common items in co-occurence matrix.
  • d int : (default 50) how many embedding dimensions for learnt vectors
  • seed int : (default 1234) the random seed

Glove.train

  • step_size float : the learning rate for the model
  • workers int : number of worker threads used for training
  • batch_size int : how many examples should each thread receive (controls the size of the job queue)

단어벡터 추출 및 저장

GloVe를 학습시키는 근본 이유는 임베딩된 단어벡터를 얻는 데 있으므로 학습 종료 뒤 단어벡터를 추출하는 것도 중요할 겁니다. 벡터 추출과 피클 저장 관련 코드는 다음과 같습니다.

# 단어벡터 추출
wordvectors = model.W

# 저장
import pickle
with open('glove', 'wb') as f:
	pickle.dump([vocab,wordvectors],f)

유사도 함수

파이썬 gensim 라이브러리에 포함된 Word2Vec 함수엔 ‘most_similar’라는 기능이 포함돼 있어 매우 편리합니다. 예컨대 ‘영화’라는 단어를 입력하면 가장 유사한 단어벡터를 뽑아주는 건데요. GloVe엔 이게 없어서 제가 간단히 아래와 같이 만들어봤습니다.

# 유사도 계산 함수
from scipy.spatial.distance import cosine
def most_similar(word, vocab, vecs, topn=10):
	query = vecs[vocab.index(word)]
	result = []
	for idx, vec in enumerate(vecs):
		if idx is not vocab.index(word):
			result.append((vocab[idx],1-cosine(query,vec)))
	result = sorted(result,key=lambda x: x[1],reverse=True)
	return result[:topn]

사용법은 다음과 같습니다. word는 코사인 유사도 계산 기준이 되는 쿼리 단어, vocab은 GloVe 학습 결과로 나온 전체 단어, vecs는 임베딩된 전체 단어벡터, topn은 상위 몇 개를 출력할지 결정해주는 파라메터입니다.

most_similar(word='영화', vocab=vocab, 
             vecs=wordvectors, topn=5)

파일럿 실험

한국어 영화 리뷰 50만여개를 학습시켜 봤습니다. ‘영화’와 가장 유사한 단어는 다음과 같습니다.

영화였다, 영화다, 스토리, 최고의, 하나, 한국, 영화에, 느낌, 마지막, 만든 ,보는, 같은…

‘쓰레기’와 가장 유사한 단어는 다음과 같습니다.

이딴, 하긴, 제발, 아깝다, 벗고, 거지, 진심, 성격, 수준, 만들지, 시나리오, 카리스마…

Comments