単語分散表現のひとつGloVeを使ってみました。
この記事では理論については詳しく書きません、numpyを使って実装されているGloVeの使い方について書いていきます。
関連リンク
GitHub - hans/glove.py: Python implementation of GloVe word embedding algorithm (Pennington et al., 2014) for educational purposes
GloVe
単語分散表現のひとつGloVe(Global Vectors for Word Representation)を使ってみました。numpyを使って実装されているものを見つけたので、それの使い方を書いていきます。
こちらのRepositoryがオリジナルです。こちらはpython 2で書かれているのでpython 3に書き換えたものをGithubにあげときました。この記事ではpython 3に書き換えたものを使ってGloVeの使い方を書いていきます。
github.com
使い方
MeCabが必要なのでインストールしていない方はこちら、
https://www.pytry3g.com/entry/2018/04/24/143934#Windows
1. ライブラリとかの準備
はじめに、ライブラリとloggingの設定をする。
import MeCab
import argparse
import codecs
import evaluate
import glove
import logging
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
parser = argparse.ArgumentParser(
description="Build a GloVe vector-space model from the provided corpus."
)
parser.add_argument(
'--window_size',
default=10,
type=int,
help="Number of context words to track to left and right of each word."
)
parser.add_argument(
'--min_count',
default=10,
type=int,
help=("Discard cooccurrence pairs where at "
"least one of the words occurs fewer "
"than this many times in the training corpus")
)
parser.add_argument(
'--embedding_size',
default=100,
type=int,
help="Dimensionality of output word vectors"
)
parser.add_argument(
'--iterations',
default=25,
type=int,
help="Number of training iterations."
)
args = parser.parse_args()
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s\t%(message)s")
logger = logging.getLogger("glove")
2. データの用意
次にデータを用意します。今回使うデータはロシアワールドカップの期間中に集めたツイートを使ってみます。
www.pytry3g.com
集めたツイートはpositive.txt
というファイルに入っています。
logger.info("Building a corpus..")
tagger = MeCab.Tagger('-Owakati')
corpus = codecs.open('positive.txt', 'r', 'utf-8').read().splitlines()
corpus = [tagger.parse(sentence).strip().split() for sentence in corpus]
print(corpus[:3])
"""
[['原口', 'と', '槙野', 'も', '先発', 'だ', 'と', '期待', 'し', 'て', 'ます', '。'],
['槙野', 'は', '出る', 'と', '思う', 'ん', 'です', 'が', '、', '原口', 'は', 'もしか', 'する', 'と', '乾', 'の', ' サブ', 'かも', 'ねー', '。', 'どちら', 'に', 'し', 'て', 'も', '頑張っ', 'て', 'ー', '!'],
['今日日', '本戦', '!', '!', '!', 'たのしみ', '!', '頑張れ', '!', 'コロンビア', '!']]
"""
最初データを読み込んだcorpus
の中身は改行区切りで以下のようになっています。
このメンツなら原口だな。
コロンビアってサッカーつよいんですか
そうなんか今日日本と試合するんしょ?
これをMeCabを使って形態素解析し形態素が入ったリストにしています。
3. 単語辞書と共起ペアの作成
データを用意したら単語辞書と共起ペアを作成します。
vocab = glove.build_vocab(corpus)
logger.info("Vocab has %i elements.\n", len(vocab))
logger.info("Fetching cooccurrence list..")
cooccur = glove.build_cooccur(
vocab,
corpus,
window_size=args.window_size,
min_count=args.min_count
)
logger.info("Cooccurrence list fetch complete (%i pairs).\n", len(cooccur))
id2word = evaluate.make_id2word(vocab)
4. 学習
学習部分です。作成した単語辞書と共起ペアを渡して学習を開始します。
logger.info("Beginning GloVe training..")
W = glove.train_glove(
vocab,
cooccur,
vector_size=args.embedding_size,
iterations=args.iterations
)
W = evaluate.merge_main_context(W)
5. モデルの保存
学習したモデルを保存する。
glove.save_model(W, "glove.pkl")
6. 似ている単語を見つける
evaluate.pyにあるmost_similar()
を使って、与えた単語に類似している単語を見つけてみます。下の例では日本に似た単語を見つけています。
sample = "日本"
tokens = evaluate.most_similar(W, vocab, id2word, sample)
for n, token in enumerate(tokens):
print("Similar word to the {}: No.{} {}".format(sample, n+1, token))
結果
Similar word to the 日本: No.1 サッカー
Similar word to the 日本: No.2 乾
Similar word to the 日本: No.3 と
Similar word to the 日本: No.4 が
Similar word to the 日本: No.5 は
Similar word to the 日本: No.6 試合
Similar word to the 日本: No.7 ベルギー
Similar word to the 日本: No.8 今日
Similar word to the 日本: No.9 いい
Similar word to the 日本: No.10 か
Similar word to the 日本: No.11 で
Similar word to the 日本: No.12 セネガル
Similar word to the 日本: No.13 ポーランド
Similar word to the 日本: No.14 コロンビア
Similar word to the 日本: No.15 それ
7. 似ている文書を見つける
今回は本田半端ねぇと似ている文書を見つけたいと思います。
そのために本田半端ねぇを形態素解析し、学習モデルから文書ベクトルに変換します。
文書ベクトルの求め方は単語ベクトルを平均で表したものになっています。
sample = "本田半端ねぇ"
tokens = tagger.parse(sample).split()
docv_sample = evaluate.plain_glove_document_vector(W, vocab, tokens).reshape(1, -1)
次に学習に使った文書を文書ベクトルに変換します。
docv = np.zeros((len(corpus), args.embedding_size), dtype='float32')
for i, tokens in enumerate(corpus):
docv[i] = evaluate.plain_glove_document_vector(W, vocab, tokens)
本田半端ねぇの文書ベクトルと学習データの文書ベクトルをCosine Similarityに渡して類似度を計算します。
indices = cosine_similarity(docv_sample, docv)[0]
top_indices = np.argsort(indices)[::-1][:10].tolist()
print("Most similarity sentence: \n{}".format("".join(corpus[top_indices[0]])))
結果
Most similarity sentence:
大迫今日まじ半端ねぇ!
import MeCab
import argparse
import codecs
import evaluate
import glove
import logging
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
parser = argparse.ArgumentParser(
description="Build a GloVe vector-space model from the provided corpus."
)
parser.add_argument(
'--window_size',
default=10,
type=int,
help="Number of context words to track to left and right of each word."
)
parser.add_argument(
'--min_count',
default=10,
type=int,
help=("Discard cooccurrence pairs where at "
"least one of the words occurs fewer "
"than this many times in the training corpus")
)
parser.add_argument(
'--embedding_size',
default=100,
type=int,
help="Dimensionality of output word vectors"
)
parser.add_argument(
'--iterations',
default=25,
type=int,
help="Number of training iterations."
)
args = parser.parse_args()
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s\t%(message)s")
logger = logging.getLogger("glove")
logger.info("Building a corpus..")
tagger = MeCab.Tagger('-Owakati')
corpus = """このメンツなら原口だな。
コロンビアってサッカーつよいんですか
そうなんか今日日本と試合するんしょ?""".splitlines()
corpus = [tagger.parse(sentence).strip().split() for sentence in corpus]
vocab = glove.build_vocab(corpus)
logger.info("Vocab has %i elements.\n", len(vocab))
logger.info("Fetching cooccurrence list..")
cooccur = glove.build_cooccur(
vocab,
corpus,
window_size=args.window_size,
min_count=args.min_count
)
logger.info("Cooccurrence list fetch complete (%i pairs).\n", len(cooccur))
id2word = evaluate.make_id2word(vocab)
logger.info("Beginning GloVe training..")
W = glove.train_glove(
vocab,
cooccur,
vector_size=args.embedding_size,
iterations=args.iterations
)
W = evaluate.merge_main_context(W)
sample = "コロンビア"
tokens = evaluate.most_similar(W, vocab, id2word, sample)
for n, token in enumerate(tokens):
print("Similar word to the {}: No.{} {}".format(sample, n+1, token))
sample = "コロンビア半端ねぇ"
tokens = tagger.parse(sample).split()
docv_sample = evaluate.plain_glove_document_vector(W, vocab, tokens).reshape(1, -1)
docv = np.zeros((len(corpus), args.embedding_size), dtype='float32')
for i, tokens in enumerate(corpus):
docv[i] = evaluate.plain_glove_document_vector(W, vocab, tokens)
indices = cosine_similarity(docv_sample, docv)[0]
top_indices = np.argsort(indices)[::-1][:10].tolist()
print("Most similarity sentence: \n{}".format("".join(corpus[top_indices[0]])))
glove.save_model(W, "glove.pkl")