Glove

최근 참가한 Kaggle “Quora Classification”에서는 추가 데이터 업로드를 허용하지 않고 이미 제공된 pre-trained word embedding만 사용해야 하는 제약 사항이 있다. word2vec과 fastText와 달리 glove는 실무에서 사용해 본 적이 없어서 관련 내용을 정리하게 되었다.

같이 보면 좋을 자료 : word2vec / fastText 내용 바로가기

Glove

  • 미국 스탠포드대학에서 2014년 개발한 워드 임베딩 방법론
  • 논문 : Jeffrey Pennington, Richard Socher, and Christopher D. Manning. 2014. GloVe: Global Vectors for Word Representation
  • 기존의 word2vec과 LSA의 단점을 보완하기 위해 나옴

word_emb
Word2vec의 단점

  • 단어의 유사도를 측정하기는 좋지만 사용자가 지정한 윈도우 내에서만 학습/분석이 이뤄지기 때문에 말뭉치 전체의 co-occurrence는 반영되기 어려움

LSA의 단점

  • 말뭉치 전체의 통계 정보는 이용하지만 단어/문서 간 유사도 측정이 어려움

Glove의 목적 함수

  • 임베딩 된 두 단어벡터의 내적이 말뭉치 전체에서의 동시 등장확률 로그값이 되도록 설정 함
  • 임베딩 된 단어 벡터 간 유사도 측정을 수월하게 하면서도 말뭉치 전체의 통계 정보를 더 잘 반영할 수 있음
  • 학습 말뭉치를 대상으로 symmetric한 행렬 X를 만들고 아래 목적함수를 최소화 할 수 있는 matrix factorization을 수행
  • 지나치게 빈도가 높은 단어 때문에 목적함수 값이 튀는 것을 방지하기 위해 Xmax 이상인 경우에는 f(Xij)값이 1로 수렴하게 설정
    glove_func

Gensim에서 pre-trained된 Glove 모델 불러오기

아래 링크에서 pre-trained된 Glove 모델을 다운받을 수 있음

  • https://nlp.stanford.edu/projects/glove/

glove.6B.100d.txt training data : Wikipedia data with 6 billion tokens and a 400,000 word vocabulary

Gensim의 glove2word2vec function을 사용하면 glove를 word2vec format으로 변경할 수 있다. 이후 변경된 format을 이용하여 기존 word2vec의 function을 사용할 수 있다.

from gensim.scripts.glove2word2vec import glove2word2vec
glove_input_file = './input/glove.6B.100d.txt'
word2vec_output_file = 'glove.6B.100d.txt.word2vec'
glove2word2vec(glove_input_file, word2vec_output_file)
(400000, 100)
from gensim.models import KeyedVectors
# load the Stanford GloVe model
filename = 'glove.6B.100d.txt.word2vec'
model = KeyedVectors.load_word2vec_format(filename, binary=False)
# calculate: (king - man) + woman = ?
result = model.most_similar(positive=['woman', 'king'], negative=['man'], topn=1)
print(result)
[('queen', 0.7698541283607483)]

word2vec과 같이 Glove model에 포함된 데이터로 similarity 계산이 가능하다

Keras에서 pre-trained된 Glove 모델 사용하기

from numpy import array
from numpy import asarray
from numpy import zeros
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Flatten
from keras.layers import Embedding
Using TensorFlow backend.

keras에서 text data를 사용하기 위해서는 text를 컴퓨터가 이해할 수 있는 숫자 데이터로 바꿔줘야 한다. 이를 위해 keras에서는 tokenizer API를 제공한다.

  • Tokenizer.fit_on_texts : 입력에 맞게 내부의 word_index를 생성
  • Tokenizer.texts_to_sequences : 문장을 index의 sequence로 변환
  • pad_sequences : 길이가 각기 다른 문장을 maxlen에 따라 동등하게 맞춰줌

keras tokenizer API 정보 : https://keras.io/preprocessing/text/#tokenizer

# define documents
docs = ['Well done!',
		'Good work',
		'Great effort',
		'nice work',
		'Excellent!',
		'Weak',
		'Poor effort!',
		'not good',
		'poor work',
		'Could have done better.']
# define class labels
labels = array([1,1,1,1,1,0,0,0,0,0])
# prepare tokenizer
t = Tokenizer()
t.fit_on_texts(docs)
vocab_size = len(t.word_index) + 1
# integer encode the documents
encoded_docs = t.texts_to_sequences(docs)
print(encoded_docs)
# pad documents to a max length of 4 words
max_length = 4
padded_docs = pad_sequences(encoded_docs, maxlen=max_length, padding='post')
print(padded_docs)
[[6, 2], [3, 1], [7, 4], [8, 1], [9], [10], [5, 4], [11, 3], [5, 1], [12, 13, 2, 14]]
[[ 6  2  0  0]
 [ 3  1  0  0]
 [ 7  4  0  0]
 [ 8  1  0  0]
 [ 9  0  0  0]
 [10  0  0  0]
 [ 5  4  0  0]
 [11  3  0  0]
 [ 5  1  0  0]
 [12 13  2 14]]

pre-trained된 glove.6B.100d 파일은 각 줄마다 101개의 값이 존재함
1개는 word, 100개는 word에 대한 vector 값 (100차원)
이를 단어 / 벡터값으로 python dict 타입으로 읽어옴

# load the whole embedding into memory
embeddings_index = dict()
f = open('./input/glove.6B.100d.txt')
for line in f:
	values = line.split()
	word = values[0]
	coefs = asarray(values[1:], dtype='float32')
	embeddings_index[word] = coefs
f.close()
print('Loaded %s word vectors.' % len(embeddings_index))
Loaded 400000 word vectors.

단어의 index 부분에 해당 vector 값을 꺼내어 넣어주는 부분

# create a weight matrix for words in training docs
embedding_matrix = zeros((vocab_size, 100))
for word, i in t.word_index.items():
	embedding_vector = embeddings_index.get(word)
	if embedding_vector is not None:
		embedding_matrix[i] = embedding_vector
  • vocab_size, dimension(100) 명시
  • input_length는 최대 문장 길이가 4이기 때문에 4로 설정
  • trainable false인 경우에는 pre-trained된 vector값이 변하지 않음
e = Embedding(vocab_size, 100, weights=[embedding_matrix], input_length=4, trainable=False)

keras model 생성 및 binary classification 수행

# define model
model = Sequential()
#e = Embedding(vocab_size, 100, weights=[embedding_matrix], input_length=4, trainable=False)
model.add(e)
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
# compile the model
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])
# summarize the model
print(model.summary())
# fit the model
model.fit(padded_docs, labels, epochs=50, verbose=0)
# evaluate the model
loss, accuracy = model.evaluate(padded_docs, labels, verbose=0)
print('Accuracy: %f' % (accuracy*100))
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_1 (Embedding)      (None, 4, 100)            1500      
_________________________________________________________________
flatten_1 (Flatten)          (None, 400)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 1)                 401       
=================================================================
Total params: 1,901
Trainable params: 401
Non-trainable params: 1,500
_________________________________________________________________
None
Accuracy: 100.000000

단상

  • Glove의 경우 문서 전체의 co-occurance를 반영하기 때문에 key words가 서로 멀리 떨어져있는 경우에는 효과가 있을 것 같음.
    (word2vec의 경우 windows 사이즈 내에서만 확률 값이 계산되기 때문)
  • Glove도 training 과정을 살펴보면 0으로 초기값이 셋팅되기 때문에 word2vec과 같이 out of vocabulary 문제가 있을 수 있음
  • 오타, 줄임말 등이 많은 한글 댓글 데이터 같은 경우에는 glove, word2vec 보다 fastText가 더 효과 있을 것으로 생각됨
  • word embedding의 경우 어느 것이 좋다라고 확신할 수 없고, text의 속성, 전처리에 따라 성능이 좌우될 것임

Reference

  • https://www.youtube.com/watch?v=uZ2GtEe-50E&index=28&list=PLlMkM4tgfjnJhhd4wn5aj8fVTYJwIpWkS
  • https://ratsgo.github.io/from%20frequency%20to%20semantics/2017/04/09/glove/
  • https://machinelearningmastery.com/use-word-embedding-layers-deep-learning-keras/

댓글남기기