Skip to content

RNNで言語モデルを作る – 理論編

この記事では、近年注目を集めるニューラルネットワークの拡張型RNNを用いて、ある文が与えられたらその次に来る単語の確率を与える言語モデルを作る過程を紹介する。この記事は、言語モデルに関わらずRNNの一般的な構造を取り扱うので、言語モデル以外にも応用することができる。(間違いなどがあればコメントでお知らせください)

 

言語モデルとは

言語モデルとは、ある文章が(学習元となったデータにおいて)生起する確率を与えるモデルで、例えば、以下の様な関係を知ることができる。

P(the cat slept peacefully) > P(slept the peacefully cat)

言語モデルがあることで、どの文章がより起こりやすいか=どの文章がより自然か を知ることができるので、機械翻訳や音声認識など応用範囲は様々だ。

これは一般には

    \begin{eqnarray*} P(x_{t+1} =v_j |x_t, \cdots ,x_1) \end{eqnarray*}

と表せる。つまり、言語モデルは ある単語の列x_t, \cdots , x_1が与えられた時の次の単語(あるいは単語の列)x_{t+1}v_jである確率を与える。(条件を付さなければ上のように、純粋に文章が生起する確率が得られる。)

 

RNNとは

RNN(Recurrent Neural Network)とは、通常のフィードフォワード型のニューラルネットワークの拡張で、時系列データ(各時間でのスナップショットのシーケンス)や文(単語のシーケンス)のようなシーケンスを扱うことができるようにした物。 各時刻tでの隠れ層は、時刻 t でのインプットに加え、時刻 t-1 の隠れ層を受け取る(両者の和をとる)。基本的な構造は以下のようになる。(画像は[1]より引用)

スクリーンショット 2016-03-25 0.35.02

言語モデルを作る場合、\bm{x(t)} は 文中 t 番目の単語のone-hotベクトル(次元数=全単語数で、そのベクトルの表現する単語の成分だけ1,他が0になっているベクトル)になる。そして、予測すべきは\bm{x}(t) の次に来る単語で、これを \bm{y}(t) として吐き出させるのがRNNで言語モデルを作る場合の主な手口だ。
実際、\bm{s}(t-1)の先にも同じように \bm{y}(t-1) の出力がついていて、これは \bm{x}(t-1) の次に来る単語、つまり \bm{x}(t) を予測するという構造になっている。

学習するのは通常のNNと同じように重み行列となるが、通常と違うのは3種類の異なる重みを学ぶという点だ。ノーテーションはソースによって異なるが、ここでは[1]に従って、\bm{U}を隠れ層→隠れ層の重み、\bm{V}をインプット→隠れ層の重み、\bm{W}を隠れ層→出力 の重みと定義する。 図中同じ\bm{U}がたくさん現れているが、これはすべて同じ行列を表している(ある単語の次にどの単語が来るかは、単語の絶対的な位置に依存しないので、重み行列は同じであって当然である)。

 

基本構造:もう少し詳しく

入力\bm{x}^{(t)}を受け、出力\bm{y}^{(t)}を計算するForward Propagationは次のようになる。(ノーテーションは上[1]とやや異なるが、以後こちらのノーテーションに従う)

    \begin{eqnarray*} \bm{net}^{(t)}_{in} &=& \bm{Vx}^{(t)} + \bm{Us}^{(t-1)}\\ \bm{s}^{(t)} &=& \mathrm{sigmoid}(\bm{net}^{(t)}_{in})\\ \bm{net}_{out}^{(t)} &=& \bm{W}\bm{s}^{(t)} \\ \bm{y}^{(t)} &=& \mathrm{softmax}(\bm{net}^{(t)}_{out}) \end{eqnarray*}

これをt=0からt=n-1まで順繰りに計算してやればよい。

\bm{y}^{(t)}ベクトルはt番目の単語の次にくる予測単語の確率を表している。つまり、

    \begin{eqnarray*} P(\bm{x}^{(t+1)}=\bm{w}_j|\bm{x}^{(t)}, \cdots, \bm{x}^{(1)}) = y^{(t+1)}_{j} \end{eqnarray*}

\bm{x}^{(t)}t番目の単語のone-hotベクトルであるように、 \bm{y}^{(t)}は次元数が全単語数のベクトルで、softmax関数を使っているので全要素の和が1になる。(\bm{w}_jj番目の要素が1,他が0の単語ベクトル)

各重みマトリックスは次の次元をとる。|V|はボキャブラリーサイズ(全単語数)、D_hは隠れ層\bm{s}のサイズで、D_hは自由に決められるハイパーパラメータの一つだ。

    \begin{eqnarray*} \bm{U} \in \mathbb{R}^{D_h \times D_h}, \ \bm{V} \in \mathbb{R}^{D_h \times |V|}, \ \bm{W} \in \mathbb{R}^{|V| \times D_h}, \ \end{eqnarray*}

 

学習アルゴリズム:BPTT

通常のNNではBack Propagation(誤差逆伝播法)が学習アルゴリズムに用いられるが、RNNではBack Propagation Through Time (BPTT)というアルゴリズムが用いられる。基本アイディアは同じで、出力層の誤差を重みを通じて伝播させていくのであるが、BPTTは出力層\bm{y}^{(t)}での誤差のみならず、一つの前の時刻t-1の誤差を加算する。もちろん、一つだけとは言わず任意のタイムステップ \tauだけ遡った誤差を加味してよい。ただし、\tauを大きくすれば計算量は増える。単純に、例えば10ステップ前の誤差まで加味するRNNはレイヤー数のFeedFoward NNの計算量に匹敵するので、適当な\tauを決めなければいけない(これもまたハイパーパラメータである)。遡るタイムステップ数\tauを限定したBPTTをTruncated BPTTという。また、多層NNと同じ理由でVanishing Gradient Problem も発生する。(その解決策がいわゆるLSTMである。)

以下が、各重みの更新式となる。添字pは、データ内から取ってきたセンテンスpを表す。\bm{x}_p^{(t)}p内のt番目の単語である。\bm{d}_p^{(t)}は教師データ(desired vector)、つまり、\bm{x}_p^{(t)}の次に実際に来る単語である。通常、\bm{d}_p^{(t)} = \bm{x}_p^{(t+1)}となる。

    \begin{eqnarray*} \bm{\delta}_{out,p}^{(t)} &=& (\bm{d}_p^{(t)} - \bm{y}_p^{(t)})g'(\bm{net}_{out,p}^{(t)})\\ \Delta\bm{W}_p^{(t)} &=& \bm{\delta}_{out,p}^{(t)} \bm{s}_p^{(t)} \\ \end{eqnarray*}

\bm{W}は純粋にアウトプットのエラー(\bm{d}_p^{(t)}\bm{y}_p^{(t)}の差)だけに影響を受けるので、タイムステップを遡る必要はない。

    \begin{eqnarray*} \bm{\delta}_{in,p}^{(t-k)} &=& \begin{cases} \bm{W}^T\bm{\delta}_{out,p}^{(t)} f'(\bm{net}_{in,p}^{(t)}) & (k=0) \\ \bm{U}^T\bm{\delta}_{in,p}^{(t-k+1)} f'(\bm{net}_{in,p}^{(t-k)}) & (k>0) \end{cases}\\ \Delta\bm{V}_p^{(t-k)} &=& \bm{\delta}_{in,p}^{(t-k)}\otimes \bm{x}_p^{(t-k)} \\ \Delta\bm{U}_p^{(t-k)} &=& \bm{\delta}_{in,p}^{(t-k)}\otimes \bm{s}_p^{(t-k-1)} \\ \end{eqnarray*}

なお、\otimesは直積(outer product)を表す。
今回は損失関数にCross Entropy Loss(次回記事参照)を使用し、活性化関数にsigmoidとsoftmaxを利用しているので、それらの微分は次のようになる。

    \begin{eqnarray*} g'(\bm{net}_{out,p}^{(t)}) &=& \bm{I}\\ f'(\bm{net}_{in,p}^{(t)})&=&  \bm{s}_p^{(t)} ( \bm{I} - \bm{s}_p^{(t)}) \end{eqnarray*}

\bm{I}は適当な長さの成分がすべて1のベクトルである。なお、断りがない限りベクトルどうしの積は対応要素ごとの積である(結果はベクトル)。

これを遡るタイムステップ\tauぶんと、全データNについて足し合わせればよい。つまり、重みの更新式は

    \begin{eqnarray*} \bm{W} & \leftarrow & \bm{W} + \eta \sum_{p}^{N} \sum_{t=1}^{n} \Delta\bm{W}_p^{(t)} \\ \bm{V} & \leftarrow & \bm{V} + \eta \sum_{p}^{N} \sum_{t=1}^{n} \sum_{k=0}^{\tau}\Delta\bm{V}_p^{(t-k)} \\ \bm{U} & \leftarrow & \bm{U} + \eta \sum_{p}^{N} \sum_{t=1}^{n} \sum_{k=0}^{\tau}\Delta\bm{U}_p^{(t-k)} \\ \end{eqnarray*}

となる。

 

ネットワークの形は異なるが、学習や順伝播など、基本的なアイディアはほとんど通常のニューラルネットワークと同じである。次回記事では、これを用いて実際にトレーニングを行って文章生成を行うプログラムを作ってみる。

 

参考文献

[1] Jiang Guo , BackPropagation Through Time , Unpubl. ms., Harbin Institute of Technol- ogy, 2013.
[2] Frank Keller, Natural Language Understanding – Lecture 11 Recurrent Neural Network, University of Edinburgh, 2016

Pocket

Published inDeep Learning人工知能自然言語処理

3 Comments

  1. NLP NLP

    BPTTに関して色々情報を漁っていましたが一番明確に書かれている資料だと思います。
    大変助かりました。

    多分打ち間違いだと思いますが、基本構造のところは
    net_in(t) = Vx(t) + Us(t-1)
    ではないかと思います。
    あと学習アルゴリズムのUの更新式のところはΔV_p(t-k)ではなくてΔU_p(t-k)だと思います。

    • functionp functionp

      初コメントありがとうございます。励みになります。
      ご指摘の通り、式が間違っておりお詫び申し上げます。
      修正致しました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です