SoNeO:Automata

機械学習、量子情報、サブカルチャーなどに興味がある大学生が読んだ本、論文、気になったことなどを雑にまとめていく。

「ゼロから作るDeep Learning ❷ ―自然言語処理編」のまとめ 前半

なんとなく自然言語処理に興味を持ったので読んでみた。

 


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

 

BERTが理解できるようになりたさ。

 

この本の構成は、スタンフォードCS224d: Deep Learning for Natural Language Processingを基にしているそう。

 

1章 ニューラルネットワークの復習

そのまま。NNの基本的なことについての復習。Softmaxとかクロスエントロピーとかアフィン変換とかBackpropとか。前巻読んだ人はスルーで大丈夫。

 


ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装

 

2章 自然言語と単語の分散表現

自然言語処理は、プログラミング言語とは違い、「柔らかい」言語を処理する。

 

コンピュータに単語の意味を理解させるためには

シソーラス

・カウントベース

・推論ベース(word2vec)

による手法がある。

 

まずシソーラス(thesaurus)とは、人手によって単語の意味を定義した辞書のこと。

辞書と言っても、一般的な広辞苑みたいなのではなく、同じ意味の単語がまとまった「類語辞書」らしい。

https://www.yoheim.net/image/s326.png

こんな感じ

 

WordNetという1985年に発表されたシソーラスがあり、それを使うと単語の意味やネットワークが求められる。付録に使用方法も記載されている。

 

しかし、シソーラスは、

・時代の変化に対応するのが難しい

・人の作業コストが高い

・単語の細かなニュアンスが表現できない

など問題が多い。

 

 

そこで、カウントベースの手法が出てくる。

これはコーパス(corpus)を用いて、単語の分散表現を獲得する手法。

分散表現とは、単語の意味をベクトルで表したもの。

それに当たって、分布仮説というのを仮定する。

分布仮説とは、「単語の意味は、周囲の単語によって形成される」というもの。

周囲の単語を「コンテキスト」、どれだけ周囲の単語を見るかの幅を「ウィンドウサイズ」という

 

"You say goodbye and I say hello"

 

という文(ビートルズの曲が流れてきそうw)のgoodbyeを見ると、ウインドウサイズを1にしたとき、say, andがコンテキスト。

sayだと2回出てきているので、You, goodbye, I, hello がコンテキスト。

 

ここから共起行列を作る。

これは単語ごとに、共起するかを0,1で表したものを行列にしたもの。

 

これで単語のベクトル化ができる。

このベクトルをコサイン類似度(ベクトルを内積して正規化する)を用いて、類似度を測れる。

 

これだけだと、例えばthe と car という単語の類似度が高くなってしまうが、それは直感に合わない。

そこで相互情報量(Pointwise Mutual Information)を使う。

 PMI(x, y) = \log_2\frac{P(x, y)}{P(x)P(y)}

これを使うと、文章中にその単語が出てくる頻度を考慮に入れて、単語同士の関連性が見られる。

共起する回数をC(・)で表すと

 PMI(x, y) = \log_2\frac{P(x, y)}{P(x)P(y)} = \log_2\frac{\frac{C(x, y)}{N}}{\frac{C(x)}{N} \cdot \frac{C(y)}{N}} = \log_2\frac{C(x, y) \cdot N}{C(x)C(y)}

で求められる。

扱うときは正にしたいので、

PPMI(x,y)=max( 0, PMI(x,y) )

にする。

 

このPPMI行列のままだと疎な行列なので、次元削減をすることが多い。

 

特異値分解(Singular Value Decomposition:SVD)を用いるとUに単語の意味を表わせる。Dの特異値が小さいものは重要度が低いので、Uの先頭数列を取り出すと、次元削減した表現として利用できる。

これで密なベクトルになる。

https://i.stack.imgur.com/D25Ya.png

 

以上がカウントベースの手法。

 

3章 word2vec

 カウントベースの手法だと、SVDの計算にO(n^3)かかるので、巨大なデータを扱うのに現実的でない。

そこで推論ベースでは、データの一部を使って逐次的に学習していく。

 

ここでword2vecが出てくる。

例えば

"You ? goodbye and I say hello"

の?をコンテキストから推論できるような学習をする。

この?をターゲットという。

つまり、コンテキストを入力してターゲットの?を推論する隠れ層1層のNNを作る。

その学習結果として、NNの重み行列が単語の意味を表現している、という寸法。

 

入力には単語のone-hotベクトル([1,0,0, ... 0,0])を用いる。

重みは入力のときと出力のときのものがあるが、入力側のほうが単語の意味が良く表現されているらしい。

 

word2vecにはCBOWモデルとskip-gramモデルがある。

 

CBOWは上記のような推論をする。

 

skip-gramは

"? say ? and I say hello"

のように、sayから2つの?を推論する。

skip-gramの方が難易度が高い処理をしているためか、こちらの方が精度が高いらしい。

 

カウントベースと推論ベースのどちらが良いか、は一概に言えない。

単語の分散表現を更新したい場合は、カウントベースだとSVDを一から計算しないといけないので面倒。推論ベースなら、それまでの重みを利用して再学習ができるので楽。

カウントベースだと単語の類似性が表現できる。

推論ベースだと、単語の類似性の上、「king - man +woman = queen」などのような類推問題も解ける。

skip-gramとNegative Samplingモデルは、共起行列にある特殊な行列分解をしたものと同じらしく、関連性が有る。

また、2つを融合させたGloVeという手法もある。

 

4章 word2vecの高速化

 単語のone-hotベクトルを中間表現にする際に行列積を行うが、実際は重み行列の行成分を取り出しているだけ。

この計算はもったいないので、Embeddingレイヤを作り、置き換えることで計算量を減らせる。

このレイヤの逆伝播は、前の勾配をそのまま伝える(行が重複する場合は加算する)。

 

次に計算が重いのは

・出力の重みをかけるとき

・Softmax層

 

ここでNegative samplingという手法を用いる。

これは、多クラス分類を二値分類で近似できないか?(できる)という手法。

 

上記のCBOWの場合だと、「youとgoodbyeからsayを正答できるかどうか?」を二値で扱う。

 

これでは負例も二値分類するから結局計算量は変わらないのでは?

となるが、負例に対しては、corpus中の出現回数に応じた確率分布を用いて5個とか10個をサンプリングする。

これがNegative samplingということ。

 

こうすることで、出力層のニューロンは1つになり、計算量が減る。

このニューロンは、Embeddingで抜き出した行と、重み行列の列の内積となる。

これにSigmoidとクロスエントロピー誤差を使ってLossが求まる。

 

 

 

結果、得られた単語の分散表現では、ベクトルの加算で類推問題が解ける。

また、分散表現が有用なのは、Wikipediaなどで学習したものを使った、転移学習がしやすい、という面がある。

 

 

 

キリがいい(次からRNN)のでいったんここまで。

 

ここまで読んで、まぁSVDが使えたり、word2vecの仕組み頭いいなーとか思ったりとかもあるんですが、一番気になったのが、分布仮説の「単語の意味は、周囲の単語によって形成される」ってこと(え)。

 

よく言えないけど、再帰的な感じがして気になる。

 

某SF作家の博士論文が「 自己参照関数方程式 : 自然言語の理解へ向けて 」ってタイトルなのは知ってたんですけど、そこらへん少し関係してるのかな、と思ったり(s○i-hub使ってもwebで読めない)。

 

あとは、単語を分散表現で表すのって、ソシュールの「差異の体系」が基になってそうですよね、たぶん(読んだこと無いけど)。

 

このあたり詳しい人がいたら、ぜひ本とか教えてください。