HELLO CYBERNETICS

深層学習、機械学習、強化学習、信号処理、制御工学、量子計算などをテーマに扱っていきます

入力データの構造に着目した畳み込みニューラルネットとリカレントニューラルネット

 

 

follow us in feedly

f:id:s0sem0y:20170704115917p:plain

 

リカレントと畳み込みの共通点

リカレントと畳み込みの共通点は入力データを2階のテンソルとして受け取ることです。

 

例えばリカレントであれば、D次元のベクトル{\bf x_t}=(x_1,...,x_D)^Tを1つのデータ点としてこれらを並べた時系列データ\bf {X = (x_1,x_2,...,x_T)}=x_{d,t}を入力に持ちます。

 

一方で畳み込みならば、M×Nピクセル(多くの場合はM=N)の2階テンソルX=x_{m,n}を直接受け取ります(カラー画像なら、X_r,X_g,X_bの3階テンソルを受け取るが今回は割愛)。

 

このことを出発点にリカレントと畳み込みについて見ていきます。

 

リカレントネットワークのデータについて

入力データ(2階テンソル)

時刻tの入力データを{\bf x_t} = (x_1,...,x_D)^T \in \mathcal R ^Dとして、系列長をTとすると、時系列データは\bf X = (x_1,x_2,...,x_T)の形をしており、具体的に成分を書き出すと以下のような形をしています。

 

{\bf X} = \left(\begin{array}{c} x_{1,1} \cdots x_{1,T}\\  \\ x_{D,1} \cdots x_{D,T}\end{array}\right) = x_{d,t}

 

最右辺は、成分を具体的に表示しているだけであって、今後2階のテンソルをこの表記で表します(楽だから)。当然d = 1,...,Dt = 1,...,Tです。

 

出力データ

出力データは問題に依存します(問題に応じて設計者が決める)。

 

1階のテンソルを出力するケース

このケースについて考えてみましょう。

具体的にはこのときX = x{d,t} \in \mathcal R^{D \times T}を受け取って、適当な次元のベクトル\bf y \in \mathcal R ^Kを出力するということになります。ここでは簡単のため\bf y \in \mathcal R^Dだと考えて1時刻のデータ点と同じサイズベクトルを想定しましょう。

 

これはT個の時系列データから1つの出力をしているということであり、時間幅Tの中に何らかの情報を1つ見出すという操作に値します。

 

f:id:s0sem0y:20170704082839p:plain

監視対象からセンサーでデータを読み取ったとしましょう。今、監視対象に異常が生じている時には1秒間に渡って変な波形が現れるという仮説があるとします。

 

そうならば、センサーが1秒間に100回データを読み取るとしたら、系列長T=100として、1秒間(100個のデータ点)をひとかたまりのデータだと考え、そこから異常であるかどうかを見出す情報を取り出したいと考えるはずです。ここではセンサーの個数がDに相当し、仮定した時間幅が系列長Tとなりました。

 

言わばこのケースでは時間方向に情報を圧縮して取り出しているという見方をすることができます。そしてリカレントネットワークではその情報の圧縮の仕方とは、時刻tのデータがt-1のデータに依存するという仮定の元、時間発展を上手く考慮した方式になっています。

 

今、出力されるベクトルの方も、入力データの次元Dに合わせていますが、これはもっと大きくしても小さくしてもいいです。ただし、本質的に重要なのは時間方向での操作です。

 

2階のテンソルを出力するケース

こちらのケースでも次元Dの方を固定して話します。そうすると話は単純で、出力は入力と全く同じ形をしています。すなわちx_{d,t}を受け取り、y_{d,t}を返してくるのです。

 

f:id:s0sem0y:20170704084226p:plain

 

しかし、この時出力に関して

 

y_{d,t} = f(x_{d,t},y_{d,t-1})

 

の形をしており、出力はいつもすぐ左隣のデータに依存した何らかとして出てきています。当然、その左隣のデータは、更に左隣のデータを反映したものであるはずで、あわよくば右の方の成分は左の方の成分の情報も上手く取り入れていることが期待できます。

 

実をいうと、先ほどの1階のテンソルを返してくる例では、今回のケースで得られるy_{d,t}t = Tの成分のみを出力しているということになります。最後(一番右)の成分はそれより前の(左側)の成分を反映していることを期待しているため、不要だと判断するわけです。

 

もちろん本来は此方でも出力のDは自由に決めて良いです。

 

未来予測に使う場合(若干脱線)

リカレントネットワークを未来の予測に使う場合は入力x_{d,t}に対して、出力をy_{d,t} x_{d,t+1}に近づくように学習させます。

 

y_{d,t} = f(x_{d,t},y_{d,t-1})

 

の式において

 

x_{d,t+1} = f(x_{d,t},x_{d,t}) = f(x_{d,t})

 

となっている(つまり過去のデータのみで未来のデータが決まる)ことを心の中で願うということです。実際にはy_{d,t}x_{d,t+1}の予測値x_{d,t+1}'であるので、システムが完全に上手く上記に当てはまることは無いですが、そのズレが小さければ、

 

y_{d,t} = f(x_{d,t},y_{d,t-1})

(心の中ではx_{d,t+1} = f(x_{d,t})

 

y_{d,t+1} = f(x_{d,t+1},y_{d,t})

(心の中ではx_{d,t+2} = f(x_{d,t+1})

 

と再帰的に学習済fを作用させていくことで未来の予測に使えることが期待できます。

 

過去の値にのみ依存するx_{d,t+1} = f(x_{d,t})の形式は自己回帰モデルと呼ばれます。一般的にはx_{d,t+1} = f(x_{d,t},x_{d,t-1},x_{d,t-2})みたいに、もっと直接的に過去のデータを引数に取ります。(ただし、リカレントネットワークでは、LSTMが上手く長期的に記憶を保てるとされているため、あくまで引数は1つ前の時刻)

 

リカレントネットを未来予測に使うのは、自己回帰モデルを構築して予測に使うということに相当します。

 

畳み込みニューラルネット

入力データ

通常、入力データはm×nピクセルの2階テンソルx_{m,n}となります。カラー画像の場合、x_{m,n,c}という3階のテンソルを引数に取りますが、m,nの添字に対する演算とcの添字に対する演算は明確に異なる上、cの方は単純な線形和を取るだけなので割愛します。

 

画像データを学習に使う場合、m=nとしたケースが多いですが、別にその必要は一切ないのでこのまま話を進めます。

 

出力データ

2階のテンソルを出力

出力はサイズの変更が行われることが多いですが、基本的にはy_{i,j}という2階のテンソルとなります。実際にはy_{i,j,l}という3階のテンソルが出力になってきますが、これは2階テンソルのフィルターをL個準備することで出てくる添字であり、フィルターをL=1個とすれば出力は2階のテンソルのままになります。

 

以下の図では、4×4の入力データに対して、2×2のフィルターを作用させた場合の出力を表示しています。この場合サイズが変更されるという結果になっています(入力データを適当にサイズ変更し、出力を調整することができるパディングという技術もある)。

 

f:id:s0sem0y:20161222222443p:plain

 

 

この際出力されたデータの成分の1つy{i,j}はフィルターサイズに応じて、入力データの一部の情報を集約したものとなっています。

 

このようなフィルターを10個準備しておけば、出力は2階のテンソルを10個並べた3階テンソルとなります(1つのフィルターはもしかしたらエッジ処理に相当することをしているかもしれない。複数準備しておけばボカシとかのフィルタも準備されて、複数の特徴を考えられる)。

 

出力を1階テンソルにしてしまう

フィルターh_{q,r} \in \mathcal R^{Q \times R}の大きさが、情報の集約度合いを決めます。フィルターサイズは何も正方形Q=Rになっている必要はありません。

 

ここでは仮に入力データx_{m,n} \in \mathcal R^{M \times N}として、h_{q,r} \in \mathcal R^{1 \times N}というフィルターを考えてみましょう。すると、出力されるデータは横方向の情報を一挙に集約し、1つの成分に納めたベクトルになります。

 

f:id:s0sem0y:20170704101654p:plain

 

もしも横方向の繋がりにこそ本質的な意味があると思うのであればこのようにフィルターを準備するのも大いに有りです(逆に縦も)。通常は画像においては縦と横を区別する必要はありません。どちらも対等に扱い、ある局所的なピクセルの集まりに対してフィルターを作用させてやりたいというのが画像処理に対する作戦になります。

 

 

リカレントと畳み込みの応用

リカレントネットの画像処理への応用

通常リカレントネットワークは時系列データに利用されますが、これまで見てきたとおり、入力が2階のテンソルx_{i,j}である場合において、2個めの添字j方向の情報を主に抽出してくれる演算処理であると考えれば、画像処理への応用も考えられます。

 

例えば下記の画像は明らかに猫が写っていますが、画像上にデカデカと写っているわけではありません。左から右へ画像を眺めて行って猫を探すような動作をする場合には、リカレントネットの働きが有効に使えるかもしれません。

f:id:s0sem0y:20170704103602j:plain

 

一方で左から右へ目線を流すのではなく、右から左へ目線を流すという方法も考えられます。

そのような場合はデータx_{i,j}を左右反転して入力していけばよく、既にこのような方法は具体的に考案されています(Bidrection:実際には時系列データをまとめて入れたとしたならば、未来から過去を振り返るという動作ができるということで考案されました)。

 

 

mnistデータに対するリカレントネット

BidirectionLSTMを用いてmnistを学習しました。

その際のlossを表示します。順調に降下していっているのが分かります。

f:id:s0sem0y:20170704104439p:plain

 

 

 

時系列データに対する畳み込みニューラルネット

LSTMでsin波の予測をする以下の記事

qiita.com

 

こちらのコードを借りまして、モデルをCNN(畳み込み層1つ)に変更し、学習した結果が以下となりました(100点入れて1点先を予測する比較的簡単なタスク)。

f:id:s0sem0y:20170704111615p:plain

f:id:s0sem0y:20170704111853p:plain

元記事のLSTMの結果がこうなっている。むしろこれくらい単純なタスクなら並列処理のできるCNNの方が有利だと言える。


 

コードでは1DConvを利用していますが、2DConvのカーネルを時間方向のみに幅を持たせても同じことができます(がめんどくさいだけ)。

 

モデルを詳しく見る

また、この際、畳み込み層は事実上、入力データの時刻を基準としてx_{t,d}

 

\displaystyle y_{t,d} = \sum_{i=0}^{99} h_{t - i,d}x_{t - i,d} (d=1) 

 

という出力を行うモデルになっており、これによりy_{t,d} = x_{t+1,d}を予測することは、

 

\displaystyle x_{t+1,d} = \sum_{i=0}^{99} h_{t - i,d}x_{t - i,d} (d=1)

 

という100点分の過去データを使った自己回帰モデルになっています(普通の自己回帰モデルでは過去100点も使わない)。

 

LSTMも予測において自己回帰モデルを構築しますが、LSTMは内部で非常に複雑な計算をしており、非線形な自己回帰モデルになります。従って、もはやパラメータに対する凸関数の形で損失関数は書けなくなり、学習は非常に難しくなります(一方で表現力はユタカ)。

 

今回の畳み込みニューラルネットは畳み込み層が1つとアフィン層が1つで、活性化関数はいずれも恒等写像を用いたため、線形自己回帰モデルを準備したフィルタの数だけ構築し、 複数の線形自己回帰モデルが出力する結果を線形結合した値を予測値に用いてることになります。

 

f:id:s0sem0y:20170704120028p:plain

 

この単純な問題では実は1つの自己回帰モデルだけで十分であり、すなわち以下のような処理にしてしまうだけで十分です。

 

f:id:s0sem0y:20170704120151p:plain

 

活性化関数も恒等変換であるため、こうなるともはや普通の線形回帰モデルと同じ働きをします(学習後はデータをずらしながらフィルタに入れていくだけ)。

二乗誤差関数は

 

\displaystyle L = (x_{t+1} - y_t)^2= (x_{t+1} - \sum_{i=0}^{99} h_{t - i,d}x_{t - i,d})^2

 

で、パラメータhに関して凸関数となり、必ず最適解が見つかります。すなわちモデルが正しい(あるいは妥当)ならば、最適解が保証されているため、結果も必ず良好なものになります。

このモデルでの予測結果は以下(まあまあイケてる)。

f:id:s0sem0y:20170704121927p:plain

ちなみに学習は1秒も掛かりません。 

 

 

学習スピードについて

2階のテンソルを引数にすると言っても、実際の計算モデルは全く異なっています。

 

畳み込みの方は、2階のテンソルを「まさに1つのデータ」として見ていますが、リカレントの方はあくまで「ベクトルを並べた2階のテンソル」であって、演算自体はベクトルに対して施されます。仮に系列長が10ならば、10回の繰り返し計算を必要とすることになります。

 

もちろん畳み込みの方も、フィルターサイズが小さければ、1つの入力を処理するために複数回計算処理をする必要がありますが、リカレントネットのように左側の計算結果を待つ(y_{d,t} = f(x_{d,t},y_{d,t-1})の形は1個左の計算結果y_{d,t-1}を待たねばならない)必要はないので、実際には複数の計算を同時に済ませてしまうことができます。

 

このような学習スピードの差があるため、時系列データに対してCNNを用いようと言う試みは結構盛んで、以下のような「QRNN」なるモデルも登場しています。

 

qiita.com

 

 

 

最後に

入力データの構造に着目して、ニューラルネットがどういうデータを引数とし、どのような処理を施す装置になっているのかを意識すれば、良いモデルを構築する手がかりになります。

 

実問題ではデータは大規模かつ解釈が困難なものが多いため、ニューラルネットワークの構造や学習方法に試行錯誤は必要となりますが、少しでも何らかの意図を持って構築できると良いのではないかと思います。

 

また今では、各ニューラルネットが得意とする分野が(例えばリカレントは時系列、畳込みは画像など)明確になっていますが、ニューラルネットは対象をただの数値の塊として見ているに過ぎません。それが時系列データであるのか画像であるのか、お金の単位なのか何なのかを全く意識しません。あくまでニューラルネットのモデルに意味を見出すのは人間です。

 

是非とも色々考察してみて、面白いニューラルネットの活用方法を考えてみましょう。私もがんばります。日本がんばりましょう。余談ですが、ソニーがニューラルネットのフレームワークを公開しました。なんか嬉しかった(一度も触ってないけど…)。

 

 

s0sem0y.hatenablog.com

s0sem0y.hatenablog.com

s0sem0y.hatenablog.com