どん底から這い上がるまでの記録

どん底から這い上がりたいけど這い上がれない人がいろいろ書くブログ(主にプログラミング)

GloVeを使ってみる。

 

単語分散表現のひとつ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に渡して類似度を計算します。

# 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')
# Toy dataset
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)
# 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]])))

# モデルの保存
glove.save_model(W, "glove.pkl")