word2vec を青空文庫で試してみる
word2vec は単語のベクトル表現をえるための手法の一つで、ニューラルネットワークを利用して行われているものです。 登場した当時の他の単語ベクトル生成手法に比べ高速に、そして単語関係の表現能力が高い獲得できる点がポイントです。 CBOWとskip−gramの2つのアルゴリズムが提案されていて、今回はCBOWを使ってみました。
CBOWは、注目する単語の周辺 N 語を入力すると、注目する単語にカテゴライズするように学習します。 ニューラルネットワークの形としては、やや変則的ですが、入力層がNxV(Vは単語数)、出力層がVの2層のニューラルネットワークになります。 入力層から隠れ層への重み行列は単語ごとに共通で、単語表現を合計した後、V次元の入力層に入力するのと同じになります。 入力層や出力層での単語表現は、IDの割り当てになります。その単語を表現する次元は1、それ以外は0になっているベクトルです。 一方、学習の結果得ることができる単語ベクトルは、入力層から隠れ層への重み行列を用います。 このことにより、学習器が獲得した内部表現を利用することができるようになります。
ちなみに今回は、chainer のword2vecサンプルではなく、C言語実装のword2vecを利用しました。 理由としては、単純にこっちの方が非常に高速だからです。こちらのブロク記事で一目瞭然ですが、C言語実装のword2vecはCPUだけで非常に高速に動作します。 C言語で実装されているということと、頻出語の学習を極力行わないようにするサブサンプリングという処理を行っているのが大きいのだろうと思います。
データには、青空文庫のテキストデータを使用しました。特定の作家の作品を全て落としてきて、青空文庫用の特殊記法やヘッダー、フッターを以下のようなコードで削って利用しました。 また、テキストを分かち書き形式にしておく必要がありますが、それにはmecabを利用しています。
import re import argparse # 文中の特殊記号の正規表現 replace_regex = [ re.compile("《.+?》"), re.compile("|"), re.compile("[#.+?]"), re.compile("〔.+?〕") ] def aozora2txt(input, output): f_in = open(input, 'r', encoding='shift_jis') f_out = open(output, 'a', encoding='utf-8') # 本文推定用 start_line = "-------------------------------------------------------" end_word = "底本:" start_line_count = 0 for line in f_in: # 終了と開始を判定する if line.find(end_word) > -1: break if line.find(start_line) > -1: start_line_count += 1 continue if start_line_count < 2: continue for regex in replace_regex: line = regex.sub('', line) # 本文中の特殊記号を除去 f_out.write(line) f_in.close() f_out.close()
作家は、夏目漱石と太宰治。類似単語を検索する単語には、人生、愛。 パラメーターによる結果比較のため、出力するベクトルの次元数と、サブサンプリングに利用する値を変えてみています。ベクトルの次元数を変えることで獲得される内部表現の形が、サブサンプリングに利用する値を変えることで頻出語の扱われ方がそれぞれ影響を受けます。
- 人生
ランク | ベクトル100 サンプリング1e-2 |
ベクトル200 サンプリング1e-2 |
ベクトル100 サンプリング1e-4 |
ベクトル200 サンプリング1e-4 |
---|---|---|---|---|
1 | 人世 | 人世 | 触れろ | 意義 |
2 | 自己 | 宇宙 | 意義 | 人世 |
3 | 宇宙 | 人格 | 美的 | 触れろ |
ランク | ベクトル100 サンプリング1e-2 |
ベクトル200 サンプリング1e-2 |
ベクトル100 サンプリング1e-4 |
ベクトル200 サンプリング1e-4 |
---|---|---|---|---|
1 | 人間 | 奇蹟 | ドラマ | ドラマ |
2 | 愛 | 青春 | 做 | 做 |
3 | 行為 | 行為 | 現実 | 青春 |
- 愛
ランク | ベクトル100 サンプリング1e-2 |
ベクトル200 サンプリング1e-2 |
ベクトル100 サンプリング1e-4 |
ベクトル200 サンプリング1e-4 |
---|---|---|---|---|
1 | 恋 | 恋 | 弄ぶ | 対象 |
2 | 情 | 個々 | 純潔 | 深刻 |
3 | 宇宙 | 宇宙 | 信念 | 恋 |
ランク | ベクトル100 サンプリング1e-2 |
ベクトル200 サンプリング1e-2 |
ベクトル100 サンプリング1e-4 |
ベクトル200 サンプリング1e-4 |
---|---|---|---|---|
1 | 美 | 美 | 遂行 | 遂行 |
2 | 正義 | 愛情 | 異性 | 異性 |
3 | 愛情 | 信実 | 愛情 | 表現 |
結果としては、作家と頻出語の扱いの違いが、類似語の探索結果に大きく影響を与えているようです。思ったより出力次元数には影響がないようですね。一作家の文章だけなので全体として語彙が少なめ(一万五千語くらい)だからかもしれません。