Re:ゼロから始めるML生活

どちらかといえばエミリア派です

自然言語処理について勉強してみた(その2:word2vec)

この前は自然言語処理の基本を勉強していました。

tsunotsuno.hatenablog.com

今回は、今どきの自然言語処理で普通に使われているword2vecについて勉強していきます。

今回もこちらの本を使って勉強しました。

ゼロから作るDeep Learning ? ―自然言語処理編

ゼロから作るDeep Learning ? ―自然言語処理編

細かい数式や概念については、上の本をぜひご参照ください。めちゃくちゃ分かりやすいので。

word2vec

元論文

word2vecの本家の論文はこちら。あんまりよくわかんないですが。

arxiv.org

解説論文はこちら。

arxiv.org

シソーラス/カウントベースの問題点

シソーラスやカウントベースでは下記のような問題がありました。

  • シソーラス
    • 手作業が多い
    • 新しく単語を追加する手間が多い
  • カウントベース
    • コーパスのサイズに応じて共起行列のサイズも大きくなる

このように、どちらもうまく使えるとは言い難いものでした。

推論ベースのイメージ

シソーラス/カウントベースの単語の意味の取得とは異なり、word2vecは推論ベースの手法です。 word2vecでの単語の推定は、CBOWモデルかskip-gramモデルの2種類あり、それぞれ微妙に違いますが大体こんな感じです。

CBOWモデル

f:id:nogawanogawa:20190204220656j:plain:w180

skip-gramモデル

f:id:nogawanogawa:20190204220707j:plain:w180

ある単語の隣になんの単語が来るかを推論することで、単語のベクトル表現を得るというやり方です。

単語2つから近傍の単語を推論するか、単語1つから両側の単語を推論するかの違いですね。 詳しいことはあんまりわからなかったですが、skip-gramモデルの方が良いらしいです。

Word2Vecひとめぐり

ネットワーク

word2vecでは、CBOWでは下記のような2層NNを使用します。(あとでいろいろ修正します)

f:id:nogawanogawa:20190204224721j:plain:w400

入力層は、着目する位置の前後にある暫定単語ベクトル(One-hot ベクトル)を表していて、出力層が着目する単語ベクトルになっています。 このNNを学習させるとW_{in}, W_{out}がそのうち収束します。

ここで行列W_{in}について確認するとこんな感じになっています。

f:id:nogawanogawa:20190204225529j:plain:w250

この行列において、横ベクトルが各単語のベクトル表記(ベクトルは中間層でのベクトルと同じ長さ)になっています。

学習させたネットワークを単語のベクトルとして扱うところがトリッキーですね。

改良

上のやり方でも間違いではないんですが、コーパスのサイズが大きくなるとNNで使用するデータ量が大きくメモリに乗り切らなくなる問題があります。

そこで改良を加えていきます。

Embedding レイヤ

まず、コーパスの単語をone-hotベクトルで表現していたのを、インデックスで表現するように変換します。 これを行うのがEmbedding レイヤです。

変換のイメージはこんな感じです。

f:id:nogawanogawa:20190205183037j:plain:w400

ワンクッションかますので、W_{in}はこんな感じに小さくなります。

f:id:nogawanogawa:20190205183051j:plain:w500

二値推定とNegative Sampling

embedding レイヤだけだとW_{in}は小さくなりますが、W_{out}は依然として大きいままです。 そのため、こちらの行列を小さくすることを考えます。

まず多値推定(one-hotベクトルを推論)を2値推定(yes/no問題)にすり替えます。

f:id:nogawanogawa:20190205183106j:plain:w500

これだけだと、コーパスに登場する単語全てに2値推定することになってしまうので、コーパスから不正解データ(Negative)をいくつかサンプリングして使用することを考えます。

コーパスから単語の登場回数を予め計算しておき、その分布に基づいてサンプリングしてやることで登場頻度に応じた単語のサンプリングが可能になります。

このようにして、2値推定する母集団自体を圧縮し、メモリ使用量を削減します。

最終的にはこんな感じになっているかと思います。

f:id:nogawanogawa:20190205183118j:plain:w600

word2vecの特徴

word2vecを含めた単語の分散表現の特徴として、概念の加減算ができることが挙げられます。 イメージとしてはこんな感じです。

f:id:nogawanogawa:20190413072846p:plain:w500

この例だとKINGに複数形の概念を加えたらKINGSだし、女性の概念を加えたらqueenになるといいます。

このように、単語それぞれが持つベクトルの加算結果が指し示すベクトルを、概念の足し算引き算にすり替えることが可能のようです。

実装

省略します。詳しくは本買っていただければと。

そのうちなんかやるんで、コードについてはその時まとめて勉強します。 まずは概念だけお勉強します。

感想

記事を書くにあたり、こちらも参考にさせていただきました。

qiita.com

ありがとうございます。非常にわかりやすかったです。

理解はなんとかできますが、やはりまだまだ難しいですね。 次回、RNNを勉強して基本的な部分については終了したいと思います。