ゼロから作るRNN2

機械学習 Python R

PTBコーパスを使って、 言語モデルを作ります。つまり、単語の列を与えたときに、次に来る単語を予測するモデルを作ります。その為に必要な関数を実装して、モデルの学習を行います。また、このモデルが意味のあるものになっているか、コサイン類似度を用いて評価してみます。
前回の記事はこちら。

ゼロから作るRNN1
RNNをnumpy だけで実装していきます。ゼロから作るDeep Learning 2に載っているコードを解説しながら作っていきます。

Embedding 層

パソコンに言葉を理解させるには、単語をベクトルや行列で表す必要があります。単語をベクトルで表現することを分散表現と呼びます。単語をベクトルで表すと、単語の意味の近さを測れたり、単語同士の足し算が出来たりと、便利な事があります。
分散表現を得る事に相当する層は、Embedding 層と呼ばれます。ニューラルネットワークでいう所の中間層ですが、入力から中間層への行列\( W \)が、分散表現になります。

Embedding
Embedding 層

単語がone hot encoding されている時は、単語に相当する番号の行を抜き出すだけの操作になります。そのようになっていると仮定して、実装します。 python で実装すると以下のようになります。

モデルの概略図と関数の実装

作るモデルの概略を書いておきます。

モデル
モデルの図

単語のベクトルが入ってきたら分散表現に変換し、RNNと全結合層で学習します。損失関数はsoftmaxにします。RNNは簡単に勾配消失が起きてしまうので、例えば10個とかで、誤差逆伝搬を断ち切りたい1のでした。
Embedding, Affine, softmax関数を、 TimeEmbedding, TimeAffine, TimeSoftmaxWithLossという名前で、 実装します。RNNについては、前回TimeRNNという形で実装しました。softmax関数は、ベクトルに\(x\) に対して以下を対応させる関数です。
$$\begin{eqnarray}
{\rm softmax } (x) = \frac{\exp (x)}{\sum_{i} \exp (x_i)}
\end{eqnarray}$$
TimeEmbeddingについては、Embedding 層をT個用意して、それぞれ計算するだけです。
TimeAffine も同様ですが、2次元の行列を作って一度に計算してから3次元にバラします。
TimeSoftmaxWithLoss は、 損失関数を\(t \)方向に平均を取って一つの値とします。 ラベルが-1となっている部分は無視するようにしておきます。
softmax関数は定義せずに使っていますが、以下の記事で定義しています。

Pythonによるニューラルネットワークの実装➂
python でニューラルネットモデルを1から実装する記事の最終回です。前回までで、正解の予測と勾配の計算が出来るようになりました。今回はパラメーターを更新する為の関数を作成し、実fashon mnist の分類問題を解かせます。

softmax関数に適当な数字とラベルを放り込んでみます。

動いたのでよしとしましょう。次に、初めに貼った図のようにモデルを作ります。

モデルの作成

モデルを作ります。クラスで必要な層は揃えているので、次元に気を付けて組み立てるだけです。SimpleRnnlmという名前のクラスで実装します。embed_W というパラメーターがptbコーパスの分散表現になります。
forward で損失関数を計算し、 backward で微分を計算します。

モデルの学習

ニューラルネットワークのように、損失関数を頼りに、モデルを訓練します。実装が一番簡単な、SGD(確率的勾配降下法)でパラメーターを更新します。また、初期値としてXavier の初期値を使います。SGDと相性が良いとされる初期値2です。
今回は、コーパスから最初の1000個までの単語を対象に学習を行います。また、分散表現は何次元のベクトルで作るか、という問題がありますが、本に載っていた数字\(D = 100\) をそのまま使います。全結合層も特に意味はなく、\(H=100\) 次元にしています。時間のサイズは\( T=5\) 3 です。
学習に必要なコード 4 と、実行結果のグラフを描きます。

モデルのトレーニング
モデルの学習の様子

一度学習が止まっていますが、何回か繰り返す間にデータを学習していることが分かります。412個の単語を100次元のベクトルで表し、文を入力すればその次に来る単語を予測するモデルが出来ました。
勿論このモデルでは、学習に使った単語以外が載っている文は扱えませんし、単語をベクトルにすることも出来ません。
とは言え、412単語の中でなら好きに遊べるので、このモデルで遊んでみましょう。1000エポック回しましたが、lossの値が0.6くらいで止まってしまったので精度は期待できません。

1000エポック
1000エポック学習した結果

単語同士の近さを測る

ベクトル同士が似ているかどうか測りたい時は、内積を取ってそれぞれのベクトルの絶対値で割ってみると良いです。0に近ければ似ていなくて、±1に近ければ似ています。5この類似度を、この記事内ではコサイン類似度と呼び、単語a, b のコサイン類似度を\( \cos ({\rm a, b} ) \)で表します。
$$\begin{eqnarray}
\cos({\rm a,b} )= \frac{ a\cdot b}{\|a \| \|b \| }
\end{eqnarray}$$
意味が似てるような単語でコサイン類似度を計算させてみます。
$$\begin{eqnarray}
\cos({\rm join , group} )&=& 0.04 \\
\cos({\rm old , once} )&=& 0.36 \\
\cos({\rm researchers , university} )&=& 0.23 \\
\cos({\rm but , although } )&=& 0.16
\end{eqnarray}$$
とても人様にお見せできるような結果ではありません。お遊びのシンプルなモデルならこんなもんです。
次回はLSTMを実装し、大きなコーパスで計算してみます。

まとめ

  • モデル構築のための関数を定義した。
  • 単純なモデルを作成した
  • モデルを訓練した。
  • シンプルなRNNだとパソコンに言葉を理解させることは叶わなかった。
  1. Truncated BPTT と呼んでいました。
  2. アルゴリズムと初期値の関係は別の記事でまとめたいと思っています。
  3. 微分の情報が単語5つ分しか伝わらないので、言葉の意味をモデルが理解するのは難しいかもしれません。
  4. ptbコーパスは、 https://github.com/oreilly-japan/deep-learning-from-scratch-2 のdataset からimport して使用しています。
  5. 統計で出てくる相関係数とか、コサインの事です。
タイトルとURLをコピーしました