今回はニューラルネットワークの話をします。
僕のブログに行き着く人の多くは「ニューラルネットワーク」とか「ディープラーニング」とかで検索している人が多いみたいなので、きっと最も需要がある項目なのでしょう。
ディープラーニングをやるにしても、元々の出発点になっているニューラルネットワークについての勉強は欠かせません。なぜなら、積層自己符号化器のようなディープラーニングには、最終的に普通のニューラルネットワークを学習させるためのバックプロパゲーションを用いることが多いからです。
ニューラルネットワークの基本
ニューラルネットワークは様々な種類がありますが、最も単純なフィードフォワードニューラルネットについて解説します。フィードフォワードニューラルネットは、データの流れが一方向であって、データが行ったり来たり、あるいはループしたりしないような構造になっています。以後ニューラルネットと行ったらフィードフォワードニューラルネットのことになります。
基本と用語
取り敢えず具体例があった方がいいと思うので、3入力1出力のニューラルネットで説明します。一番左側は入力層と言います。例えば3次元データの回帰問題を解かせたい場合は、3次元の各成分が一番左側の入力層に与えられます。入力層は、入力されたデータをそのまま出力するだけです。
真ん中が中間層と言います。中間層には、入力されたデータの各成分に適当な重みを付けて和を取ったものが入力されます。中間層は、入力されたデータに対して何らかの変換を行ったあとに、その値を出力します。
一番右が出力層です。ここは、中間層の値を受け取って何らかの変換を行い値を出力します。応用上はその値が上手い回帰曲線になっていれば嬉しいといった具合です。
次に図の各青い丸は、ノードと言います。この図では、入力層のノード数が3、中間層のノード数が3、出力層のノード数が1といった具合です。ノードのことをユニットという場合もあります(Bishop本ではユニットになっています)。
ノード同士を繋いでる辺のことをエッジと言います。しかしこれはニューラルネットではあまり使わないです。「ノード同士の接続を〜」などと言い回されることのほうが多いです。
層から層へ値が渡されるときには、値に対してとある重みが付加されます。
図の入力層と中間層を例に取れば、中間層の一番上のノードに対しては入力層の値が
であれば、
が入力されます。このときのを重みと言います。
通常は、入力層の第iノードから中間層の第jノードへの重みをと書きます(こうやって書いておかないと、中間層の一番上のノードと真ん中のノードと一番下のノードそれぞれに対して違う文字を使わなければいけなくて大変!)。
改めて、中間層の一番上へのノードへの入力を書きなおせば
となります。
次に中間層のノードは、入力層から受け取った値と、とある値を比較します。
つまり中間層の一番上のノードは
という値について検討をするのです。このときのを閾値とかバイアスとか言います。
次に中間層は、入力された値に対して何らかの変換を施します。
例えば中間層の一番上のノードは
を計算します。このときの変換を活性化関数と言います。
中間層はこのようして変換を行った値を、出力層に渡します。
出力層は中間層から受け取る値に対して重み付き和を得て、その値からバイアスを引き、活性化関数によって変換をして何らかの値を得ます(要するに中間層と一緒)。
今回の図のケースの場合は、層が3つあるので、3層ニューラルネットと言います。
場合によっては中間層が1つのニューラルネットと言います。
しかし、Bishop本は、今回の図のニューラルネットを2層ニューラルネットと呼ぶことを推奨しています。なぜなら、実際にニューラルネットが仕事をしているのは中間層と出力層のみだからです。入力層は一切何もしておらず、ただただデータの値を表しています。つまり下図のように見ることもできるからです。
まあ勉強する上では自分が分かればそれでいいです。
今何を計算しているのかというのが理解できていれば大丈夫でしょう。他の人とニューラルネットについて会話するときにはこのへんには注意してください。
今回はこの図以上に多層のニューラルネットを扱いませんので、あまり気にしないことにします。
ニューラルネットでは活性関数を問題に応じて予め設定しておき、学習によって重みとバイアス
を獲得します。
ニューラルネットワークの数式的表現
以上でニューラルネットの基本的なことを知ったものとして話します。
まず中間層のj番目のノードに対して
という値が入り、これを活性化関数で変換するというのを見てきました。
もっと一般的に入力層が個のノード、中間層が
個のノード、出力層が
個のノードで構成されている場合を見ていきます。
中間層番目のノードへの入力は
となります。の中に
を含んでしまいたいので、コレを
と置いて
としてしまいます。こんなことして良いのかと思うかもしれませんが、結局のところ重みもバイアス
も学習によって獲得するもので、区別する必要がないので構いません。
だからもうバイアスのことは忘れてください。
これをベクトルを使って表現すれば、
と出来て非常に見やすいですね。ベクトルを使って表記された教科書も多いので、どちらでも読めるようにしておいてください。
中間層の番目のノードは活性化関数によって変換した
を出力層に渡します。出力層も中間層と同様な計算をします。出力層
番目のノードは重み
を使って
を計算し、を出力することになります。
重み(weight)にって文字使うのは気持ち悪いので、入力層から中間層への重みを
、中間層から出力層への重みを
と表現することにします。
まとめると、ニューラルネットワークは以下の計算をします。
・中間層番目のノード
が入力され
を出力する。
・出力層番目のノード
が入力され
を出力する。
こうしてネットワーク全体では、
入力ベクトルに対して出力ベクトル
の
番目の成分は
場合によっては、中間層と出力層の活性関数に異なったものを用いる場合もあります。
それぞれの活性化関数をと置くと、より一般的には
となります。
まとめ:ニューラルネットワークという合成関数
普通の回帰問題では、データに対して回帰曲線
を
として獲得すべく、都合の良い関数を探します。
例えば最も単純な最小二乗直線を得る場合には、
となるようなを探すわけです。より一般の回帰問題では
という係数と基底関数
の組を探します。
もしも入力データが1次元でと置けば、この回帰問題は多項式フィッティングということになります。
ともかく、一般的な回帰問題に対して複数個の基底関数なるものを準備し、それに対する係数を探すという手続きを行います。一方で、ニューラルネットの場合は、多次元入力データの各成分を適当な重み付け和として扱い、ある1つの活性化関数によってまとめて変換してしまいます。
データの扱いがずいぶん乱暴に見えますが、代わりにこれを複数回行うことによって全体では、活性化関数の出力の和を更に活性化関数によって変換するという合成関数になっています。
十分にたくさんのノードを準備することで、任意の関数が表現されることが知られており、たくさんの基底関数を準備しなくても良いということです。
しかし、合成関数によって表現力を得たことにより困難も生じてきます。
通常、回帰問題は評価関数の最適化を行いますが、このときに頻繁に使われるのが勾配法です。評価関数を微分して0となる点が極値を与えますから、とにかく微分を計算したくなります。
ニューラルネットで回帰をするならば、真の曲線に対して出力
がどれだけ近いかを評価したいところですが、合成関数の微分はかなり厄介ですね。しかもパラメータの数が膨大なので、全てのパラメータにより偏微分が0になる場所を求めるのはかなり困難を極めそうです。
そこで登場したのがバックプロパゲーションになります。
今回はこの辺で閉じます。またいずれ復習のためにバックプロパゲーションについての記事を書くかもしれません。(でもこれは計算だけで、とくに解釈を説明する部分もないのでやらないかも…)