学習済みの分散表現をLSTMの埋め込み層に利用する

## 概要

自然言語処理におけるディープラーニングでニューラルネットを構成する際には、RNNやLSTMなどの層の前に、単語ごとに任意の次元のベクトルを用意した埋め込み層(embedding layer)を利用することがあります。この層はニューラルネットの学習の際に同時に重みを学習することもできますが、既に単語の分散表現(word embedding)を別の手法やデータセットで学習しておき、学習済みの分散表現を重みとして利用することができます。

今回は、Kerasにおいて埋め込み層に学習済みの分散表現を利用する方法を紹介します。今回は、word2vec等の機能を提供しているパッケージgensimでの読み込み機能を用いることにします。

## 方法
### 日本語の単語分散表現

今回は東北大の乾/岡崎研究室が公開している「日本語 Wikipedia エンティティベクトル」を利用します。

[日本語 Wikipedia エンティティベクトル](http://www.cl.ecei.tohoku.ac.jp/~m-suzuki/jawiki_vector/)


上記ウェブサイトから`20170201.tar.bz2`をダウンロードして展開します。中にはbinファイルとtxtファイルの2つがあり、今回はbinファイルをgensimから読み込みます。なお、txtファイルの中には単語とそのベクトルがスペース区切りで入っているので、これを手動でパースして利用することも可能です。

```py
from gensim.models import KeyedVectors

embeddings_model = KeyedVectors.load_word2vec_format('/path/to/entity_vector.model.bin', binary=True)
```

### 埋め込み行列の作成

gensimで読み込んだ単語とその分散表現を、LSTMの埋め込み層に組み込むための前処理として、埋め込み行列を作成します。

前提として、単語とそのIDの変換は以下のようにKerasのTokenizerを利用しているものとします。

```py
tokenizer = Tokenizer()
tokenizer.fit_on_texts(tokenized_text_list)
```

埋め込み層に組み込むための埋め込み行列として、numpyのarrayを作成します。今回利用する「日本語 Wikipedia エンティティベクトル」は200次元のため、(単語数,200)次元のゼロ行列をあらかじめ作成しておき、対応するIDの行に読み込んだ分散表現を置き換えていく形で作成していきます。


```py
word_index = tokenizer.word_index
num_words = len(word_index)

embedding_matrix = np.zeros((num_words+1, 200))
for word, i in word_index.items():
    if word in embeddings_model.index2word:
        embedding_matrix[i] = embeddings_model[word]
```


### 埋め込み層への組み込み

最後に、Kerasのモデルの中の`Embedding`の`weights`パラメータに先ほど作成した埋め込み行列`embedding_matrix`を指定し、`trainable`パラメータをFalseにします。

```py
model.add(Embedding(num_words+1,
                    embedding_dim,
                    weights=[embedding_matrix],
                    trainable=False))
```

また、Functional APIの場合は、以下のようにレイヤーを定義します。

```py
embedding_layer = Embedding(num_words+1,
                            embedding_dim,
                            weights=[embedding_matrix],
                            input_length=max_sequence_length,
                            trainable=False)

input = Input(shape=(max_sequence_length, ))
x = embedding_layer(input)
```

これで、埋め込み層には学習済みの単語の分散表現を利用することができます。

## その他のリソース

今回は「日本語 Wikipedia エンティティベクトル」を利用しましたが、他にも日本語の学習済み分散表現がいくつか公開されています。中にはfasttextで学習したモデルなどもあります。選定する観点としては、


- 形態素解析の辞書
	- 学習済み分散表現は、単語に対して任意の次元のベクトルが割り当てられている
	- その分散表現の単語が、自分が作成しているニューラルネットの単語分割と一致していないと、学習済み分散表現を利用できない
	- なるべくカバレッジを増やすためにも、辞書はある程度揃えておいたほうがいい（特にneologdなど単語の種類数を増やしている場合）
- 学習データ
	- Wikipedia、GoogleNewsなど
	- 上記の形態素解析の辞書と関連して、なるべく自分が対象とするデータに使われている単語が入っているようなデータセットが望ましい
- 分散表現のロジック
	- Skip-gram、CBow、GloVe、fastTextなど
	

などあると思うので、色々と試してみると面白いと思います。学習コードも同時に公開されているものもありますので、自分で分散表現を学習させるのも良いでしょう。

- [word2vecの学習済み日本語モデルを公開します | カメリオ開発者ブログ](http://aial.shiroyagi.co.jp/2017/02/japanese-word2vec-model-builder/)
- [日本語 Wikipedia エンティティベクトル](http://www.cl.ecei.tohoku.ac.jp/~m-suzuki/jawiki_vector/)
- [fastText/pretrained-vectors.md at master · facebookresearch/fastText](https://github.com/facebookresearch/fastText/blob/master/pretrained-vectors.md)
- [Polyglot - Rami Al-Rfou](https://sites.google.com/site/rmyeid/projects/polyglot)
- [Kyubyong/wordvectors: Pre-trained word vectors of 30+ languages](https://github.com/Kyubyong/wordvectors)


## 参考

- [Using pre-trained word embeddings in a Keras model](https://blog.keras.io/using-pre-trained-word-embeddings-in-a-keras-model.html)