様々な場面で目にするようになったAI、あるいは機械学習は世界的にも注目されている技術のひとつです。
今回はその中でも時系列データに特化したRNN(Recurrent Neural Network)というネットワークを紹介します。
また時系列データに関する長期的な記憶を実現したRNNの改良版であるLSTMについても説明します。

RNNやLSTMを自然言語処理に応用すると、単語だけではなく文章全体の流れから意味を推測できるようになります。

機械学習ではプログラミング言語のPythonがよく利用されています。
こちらの無料講座でPythonの基礎を学び、未経験からでもプログラミングの基礎を身につけましょう!
過去にプログラミング学習に挫折した方でも続けやすい学習プログラムになっています。
ゼロから始めるPython入門講座(オンライン・無料)+【テックジム】

時系列データ

時系列データとは、ある情報を時系列ごとに並べたデータのことです。
例えば、ある会社の毎年の売り上げや毎日の天気予報をまとめたものなどがあります。

時系列データは、通常のデータのようにそれぞれを独立した情報とするのではなく、前のデータが次のデータに対して影響を与えていることを前提に扱います。

時系列データとして扱われるものの中には文章・音声・映像など様々なものがあります。
文章は単語区切りで見たときに、この単語の後にはこういう単語が来るかもしれない、というように時系列で見ていきます。

RNNの構成

RNNの概要

RNNとは、時系列データを扱うためのニューラルネットワークを派生させた手法のひとつです。
このネットワークでは、入力に前回の出力を加えて新たな出力を算出します。
言い換えると、中間層(隠れ層)の出力を再度中間層の入力として用いるということになります。

このようにして再帰的に前回の状態を次に継承していく様子から、日本語では再帰型ネットワークと呼ばれています。
またこの時に渡す状態のことを隠れ状態といいます。

通常のニューラルネットワークは上図のように、入力層・隠れ層・出力層からなります。

RNNでは、ニューラルネットワークの中間層部分に前回の中間層の出力を隠れ状態として入力します。
より分かりやすく各時間ごとのモデルを横に展開したものを下に示します。

以前の隠れ状態と現在の入力を元に次の隠れ状態を生成し、それを次の処理に渡しています
このように過去の情報を利用した学習ができるのは、通常のフィードフォワードニューラルネットワークにはない強みです。

RNNでは入力データに対する出力を元に誤差逆伝搬法(バックプロパゲーション)による学習を行います。
誤差逆伝搬法では出力に近い側、つまり最後の出力側から重みを更新していきます。
また、誤差を最小化するために使われる主な最適化アルゴリズムは、勾配降下法である確率的勾配降下法やミニバッチ学習SGDです。

ニューラルネットワークの基礎知識については以下の記事でまとめています。

RNNレイヤの中身

RNNレイヤでは、$t-1$時点での隠れ状態$\boldsymbol{h_{t-1}}$と$t$時点の入力$\boldsymbol{x_{t}}$を受け取ります。
それらに重み$\boldsymbol{w_{h}}, \boldsymbol{w_{x}}$を掛け合わせたものを加えます。
さらにバイアス項$\boldsymbol{b}$を加えたものをtanh関数で活性化します(活性化関数は他のものでも構いませんが、後ほど紹介する勾配消失問題の軽減のためにtanh関数を使用することが多いです)。
これが$t$時点での隠れ状態であり出力でもある$\boldsymbol{h_{t}}$となります。

RNNレイヤの中身は以下の図の通りで、MatMulは行列積、+は行列の和を表しています。

RNNレイヤの出力$\boldsymbol{h_{t}}$は以下の式で求められます。
ここで、$\phi$は活性化関数を表しています。

\begin{equation}
\boldsymbol{h}_{t} = \phi(A\boldsymbol{x}_{t}+B\boldsymbol{h}_{t-1}+\boldsymbol{b})
\end{equation}

文章の前方から隠れ状態を引き継いで学習を進めて行くものを順方向RNN、文章の後方から学習を進めて行くものを逆方向RNNといいます。
また、RNNレイヤを複数層積み上げたものを多層RNNといいます。

Seq2Seq(エンコーダ・デコーダモデル)

Seq2Seq(Sequence To Sequence)エンコーダ・デコーダモデルで、文章から文章を生成することで学習を行う自然言語処理モデルです。
教師データとなる文章を入力し、入力した文章と同様のものを出力側で復元することを目的とします。
Seq2SeqにはRNNレイヤなどを組み込むことで、時系列データを用いた学習を行うことができます。

Seq2Seqはエンコーダとデコーダという2つの部品から構成されています。

エンコーダ側で時系列データを用いて隠れ状態を次の層に渡していき、最終的な隠れ状態をデコーダに渡します
デコーダ側で受け取った隠れ状態をもとに入力文章の復元を行います。

入力と出力の差を損失として、誤差逆伝搬法により時系列とは逆順に重みパラメータを更新していきます。

さらに詳しいSeq2Seqの構造については以下の記事で紹介しています。

機械学習エンジニアを目指したいなら、本格的にプログラミングを学べるスクールを利用してみてはいかがでしょうか?
データサイエンス・機械学習に特化したコースでプロのエンジニアにチャットで質問することもできます。
まずは、無料体験・無料カウンセリングから自分にあったコースを探してみましょう!
データサイエンスコース

RNNが持つ課題

RNNには、長期的な記憶がうまく行えないという課題があります。
これは時系列的に後半(下位)のレイヤでは普通に学習がおこなわれる反面、前半(上位)のレイヤについてはパラメータの更新がうまくいかない場合があるという欠点です。

この原因は勾配消失や勾配爆発が起きやすいことにあります。
RNNは時系列順にデータを処理していく都合上、学習方向に多層化するためディープラーニングで発生するような問題を持ちます。

勾配消失問題

勾配失問題は、上位のレイヤへ行くほど勾配が消失していき学習が進まなくなってしまうという問題です。
誤差逆伝搬法では損失が最小になるようにパラメータを更新していき、モデルを最適化していきます。
この時勾配降下法により、繰り返し活性化関数の微分を計算することになります。

例えば、tanh関数は次のような式で表されます。

\begin{equation}
f(x)=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}}
\end{equation}

この関数を微分すると、以下のようになります。

\begin{equation}
\begin{split}
f'(x)&=\frac{(e^{x}+e^{-x})^{2}-(e^{x}-e^{-x})^{2}}{(e^{x}+e^{-x})^{2}} \\
&=\frac{4}{(e^{x}+e^{-x})^{2}} \\
&=\frac{1}{(\frac{e^{x}+e^{-x}}{2})^{2}} \\
&=\frac{1}{cosh^{2}x} \\
&=\frac{cosh^{2}x-cosh^{2}x+1}{cosh^{2}x} \\
&=1-\frac{cosh^{2}x-1}{cosh^{2}x} \\
&=1-\frac{sinh^{2}x}{cosh^{2}x} \\
&=1-tanh^{2}x \\
&=1-f(x)^{2}
\end{split}
\end{equation}

次に、tanh関数のグラフを見てみます。
tanh関数のとりうる値は$-1\sim1$です。

tanh関数のとりうる値の範囲から、tanh関数の微分の値は$0\sim1$の範囲になります。
1より小さい数が次々に乗算されていくため、当然数値が小さくなっていく傾向が生まれます。

これが原因となり、微分を繰り返すたびに勾配が小さくなっていき消失していきます。
勾配が消失すると、上位のレイヤに関してはうまく更新できなくなってしまうのです。

勾配爆発問題

勾配消失問題は逆伝搬時にtanh関数の微分が繰り返し行われることで、勾配が徐々に失われていくというものでした。
勾配爆発問題は隠れ状態と重みの行列積を計算するMatMulにより繰り返し重み$\boldsymbol{w_{h}}$がかけられ、勾配がどんどん大きくなっていくという問題です。

行列積の逆伝搬の計算は簡単で、以下のように求めることができます。

\begin{equation}
\begin{split}
\boldsymbol{f(x)}&=\boldsymbol{h_{t-1}}\cdot \boldsymbol{w_{h}} \\
\boldsymbol{\frac{\partial f(x)}{\partial h_{t-1}}}&=\boldsymbol{w_{h}}
\end{split}
\end{equation}

このように勾配爆発は重み$w_{h}$が繰り返しかけられることによって発生します。
勾配消失とは反対に、上位のレイヤに行くほど更新量が大きくなっていってしまいオーバーシュートが発生してしまいます。

LSTM

RNNの問題点として、長期的な時系列データに対してはうまく対応できないということを確認してきました。
時系列的に離れたデータ同士はRNNではうまく関連付けて学習することができないのです。

LSTM(Long Short Term Memory)はこういった問題を解決するために生まれた、改良版RNNとなっています。

$σ$はシグモイド関数、×は行列のアダマール積になります。
アダマール積は行列同士の掛け算ではなく、行列の要素ごとの掛け算になります。

前の情報を保持する手段として、RNNの隠れ状態$h$に加えて新しく$c$というものが増えました。
これは記憶セルと呼ばれ、LSTMが長期的な記憶を実現するための重要な要素です。

LSTMを理解する上で最も大切なのは、図中に$f_{t}, i_{t}, o_{t}$として示したゲートと呼ばれるものの働きです。
ゲートはLSTM上を流れている情報をどれだけ伝達するかを決定する、その名の通り門のような役割があります。
$0\sim1$の範囲を持ち、1に近いときはほぼすべての情報を通し、0に近いときはほぼすべての情報を遮断します。

各ゲートのより詳細な役割について、それぞれ順番に確認していきます。

Forget Gate

まずは$f_{t}$で示した忘却ゲートです。
記憶セルの内容を忘れることを学習する目的のゲートになっています。

LSTMは過去の経験を積み上げて次の出力を予測していきますが、あるデータを境に入力されるデータの傾向が大幅に変化した場合には記憶セル全体を一気に更新する必要があります。
この役割を果たすのがForget Gateです。

今までの経験を保持した記憶セルに対して現在のデータとのアダマール積をとることで、記憶セル中の不必要な情報を一気に削除することができます。

Input Gate

次に$i_{t}$で示した入力ゲートについて見ていきます。
$h_{t-1}$と$x_{t}$を加え合わせたものをtanh関数により活性化したものが現在のセルの状態となり、これが長期的に記憶したい情報になります。
しかし、これらすべてを保持するわけではなく必要な部分だけを長期的に記憶にとどめたいので、これに記憶率をかけます
記憶率は $h_{t-1}$と$x_{t}$を加え合わせたものをシグモイド関数により活性化したもので、入力ゲートそのものを意味します。

こうして算出した現在のデータの中でも記憶にとどめたい情報を記憶セルに対して加え、内容を更新します。
これが$t$時点での記憶セルとなります。

Output Gate

最後に$o_{t}$で示した出力ゲートです。
$t$時点での隠れ状態$h_{t}$は、現在の記憶セル$c_{t}$を元に生成されます。
この時に適用するのが、前の隠れ状態と現在の入力を元にした出力ゲートです。

これにより、長期的な記憶は記憶セル$c_{t}$により、短期的な記憶は隠れ状態$h_{t}$によって保持することができます。

まとめ

時系列データを扱うためのニューラルネットワークのレイヤであるRNN、LSTMについて見てきました。
文章や音声、動画などの時系列データに対して、過去の状態を隠れ状態として引き継いで学習を行います。

これらのレイヤを利用した学習モデルとしては、Seq2Seqがあります。
さらにLSTMにも学習の計算が並列化できないという欠点があり、これを改良したモデルもあります。

しかし、そういった比較的新しいモデルも、もともとの考え方はこのRNNやLSTMを用いたSeq2Seqです。
しっかりと身につけておきましょう!

AIエンジニアやデータサイエンティストへのキャリアチェンジを目指すなら、3カ月間の集中プログラムで徹底的に学習しましょう!
業務課題をAIを用いて解決したい方、教養としてAIを学習したい方にもおすすめです。
オンラインでPythonの基礎知識からしっかり学べるコンテンツを利用できます。
AIを学ぶならアイデミープレミアムプラン

関連記事

この記事のタグ