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의 단점을 보완하기 위해 나옴
Word2vec의 단점
- 단어의 유사도를 측정하기는 좋지만 사용자가 지정한 윈도우 내에서만 학습/분석이 이뤄지기 때문에 말뭉치 전체의 co-occurrence는 반영되기 어려움
LSA의 단점
- 말뭉치 전체의 통계 정보는 이용하지만 단어/문서 간 유사도 측정이 어려움
Glove의 목적 함수
- 임베딩 된 두 단어벡터의 내적이 말뭉치 전체에서의 동시 등장확률 로그값이 되도록 설정 함
- 임베딩 된 단어 벡터 간 유사도 측정을 수월하게 하면서도 말뭉치 전체의 통계 정보를 더 잘 반영할 수 있음
- 학습 말뭉치를 대상으로 symmetric한 행렬 X를 만들고 아래 목적함수를 최소화 할 수 있는 matrix factorization을 수행
- 지나치게 빈도가 높은 단어 때문에 목적함수 값이 튀는 것을 방지하기 위해 Xmax 이상인 경우에는 f(Xij)값이 1로 수렴하게 설정
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/
댓글남기기