はじめに
ニューラルネットのフレームワークを使うと、誤差逆伝搬は既に実装されているため、ほとんど意識すること無く使えてしまいます。言わばブラックボックスという状態です。ここで誤差逆伝搬法について学んでおくことで、ニューラルネットがいかにして学習を行っているのかを理解しましょう。
数式が相応に難解なため、一番最後まで飛んでしまっても構いません。
最終的に得られる式を見れば、誤差逆伝搬法の由来を理解できるかと思います。
ニューラルネットの基礎
ニューラルネットの順伝搬
1つの層での処理
まずニューラルネットワークといえば入力
に対して以下のような処理を行います。
基本的にはたったコレだけです。
は
の行列で、
は
の行列(ベクトル)です。
結果は
次元の行列(ベクトル)になります。
は何らかの活性化関数で、成分毎に作用し、
は
次元の行列(ベクトル)です。
一括すれば
という処理になります。ここで、
と置き直せば
という処理に一括することができます。
は単に
でありこうしておくことで、バイアス
の計算を含んでしまうことができるというちょっとしたテクニックです。
以後、と
はこのような処理が施されていることとします。
多層での処理
前述までの
に関して、これを層目の処理と明記するために以下のよう表現にします。
こうしておくと、は
層目への入力であるとハッキリ分かります。
(単に見やすさの問題で、文字は実際は何でもいいのです)
すると層と
層間での処理については
と表すことができ、層が個あるならば、結局上記の式を
から
まで繰り返すという処理になります。これが順伝搬と呼ばれる処理です。
成分を明示的に書けば
となります。(この処理がわからない場合は下記の記事)
順伝搬のまとめ
層と
層での処理は以下で表され
これをから
まで繰り返す。
線形変換→活性化を小分けにすると
と表すことができます。
ニューラルネットワークの学習
勾配法
学習とは損失関数を減少させるようにを変更していく処理です。
損失関数を減少させるためには、これの勾配を計算し、勾配は関数を増加させる方向を示しているため
と更新をします。
は学習率と呼ばれ、どれだけ大きく更新を行うかを決めるパラメータです。
十分損失関数が小さくなるまで更新を繰り返すことで学習を行います。この方法を勾配法と言い、ニューラルネットの基礎的な手法となっています。
例えば回帰ではニューラルネットの出力とし、目標値(ラベル)を
として、損失関数は
のように設定されます。データが個あれば、それぞれのデータの損失
を考えて、全てのデータの損失の和
を損失関数の具体的な計算とします。
つまり出力がニューラルネットのパラメータ
に依存する値となっており、
を色々調整して
を減少させる(つまり
を
に近づける)というのがニューラルネットの学習です。
微分の難しさ
問題は、勾配を如何にして計算するかです。
行列でスカラー
の微分というのは、
と同じサイズの行列になり、
成分が
となります(単に各成分で微分していくだけ)。ベクトルも行列の一種(例えば
の行列)のように考えて、同じように成分毎に微分するだけです。
結局知りたいのは、での微分であって、これが計算できれば
の更新も上手く行えるという状況です。しかし、歴史上これの計算が非常に手間取ったため、ニューラルネットは一時期姿を消しました。
理由は
という処理を、例えば2回行えば、ニューラルネットの出力は
という計算になります。成分毎に書けば
となります。パラメータを更新するためにはと
すべての微分を計算しなければなりません。こいつはかなり厄介です。
これを解決したのが誤差逆伝搬法です。
誤差逆伝搬法
問題
ニューラルネットワークの出力は以下で表されます。
通常データは複数あるわけで個目のデータであることを明示すれば
であり、更に損失はベクトルの表現で以下ですから
これも成分を明示すると
となります。これでデータの個数と成分も明示した表現に書き換えることができました。
最後のニューラルネットの出力を誤差関数に代入すれば
となります。これを存在する全てので1つずつ微分をしていこうというわけですが、もうやりたくないですよね。
に関して非常に複雑な合成関数の形をしており、普通に1つ1つ微分していったんではとんでもない計算になってしまいそうなのが目に見えています。しかも層の数を2つとかなり制限していてコレです。もっと多層にすれば、入れ子がどんどん増えていき手におえません。
誤差逆伝搬法
まずは損失の和を計算する
まず以下の式に関して、データがつであるとしましょう。
複数あっても結局後で和を取ればいいだけなので問題ありません。データ点1つに対して計算ができるようになればそれでいいのです。
ちなみにデータ1つを適当に選んで学習するのが確率的勾配法、データを複数まとめるのがミニバッチ法、データをすべて使うのがバッチ法であり、単にいくつのデータに対して損失の和を取るかで区分けされているにすぎません。従って、データ1つに対する誤差逆伝搬が分かればそれで十分です。
ということで、以下の損失関数からは消し去ってしまいましょう。
特に本質的な話ではありませんが、とりあえず見やすくはなったと思います。
これの計算を複数のデータで行い、和を取ればいいということになります。
今回は回帰を想定していますが、分類ならば交差エントロピーを使うだけで話は一緒です。
微分の連鎖律
一般的な議論をするために損失関数は単にと記述することにします。
目標は以下の計算を効率化することです。
今は明示的には見えていませんが、はとてつもなく複雑なので簡単には計算できません。しかし、微分には連鎖率というものがあり以下のように(あたかも分数のごとく)計算することが許されています。
今は適当にを間に挟みましたが、もっと一杯挟んでも良いです。
ニューラルネットでは順伝搬の最後層で
という計算が行われていることに着目します。
(層目への入力が
であるように添字を付けたので
という添字が出てきてきますが、気持ち悪かったら、添字の付け方を
から開始したり
層目の出力を基準につけるなどすればいい)
という連鎖律を使います。ここでの計算は簡単であるということに注目してください。単に
になります。従って、に関する微分は
と求まりました。そうなると、知りたいのはという部分の計算になります。これで問題が楽になったのか、今は定かではありませんが、後に見るように驚異的なアルゴリズムの導出に繋がります。
出力での損失の微分
知りたい計算がにすり替わったので、これを一々書くのがめんどうということで、以下のように文字でおいてしまいます。
すると損失関数の微分は
で表され、見かけ上随分簡単になりました。
とにかくを計算する手立てさえ見つかれば、良いという状況ですが、これは非常に簡単な問題です。回帰の問題においては最後の層のことだけを考えれば、
となっているのです。これをで微分するのはたやすく
となります。回帰の問題では出力層の活性化関数は恒等変換なので
ととんでもなく簡単になります。しかも、分類の問題で損失関数が交差エントロピーで、活性化関数がソフトマックス関数となっていても、計算すると上記のように出力と目標値の差という単純な形に計算できます。
結局出力での損失の微分は
と非常に単純な形で求まりました。
中間層での損失の微分
ここまでは出力層のみに着目していたので、複雑な合成関数の形を意識すること無く解くことができていました。上記では損失関数の微分を具体的に計算するために、出力層に着目しましたが。しかし、下記のような連鎖規則はでなくとも良く、もっと一般的に
を間に挟んでも良いのです(問題はそのような連鎖規則をしたときに計算しやすくなるのかどうか)。
こうなったときにを計算する手立てさえあればいいのです。ここで再度連鎖規則を用います。
ここで最右辺の第一因子はになっています。
第二因子は、順伝搬において
であるので、
と微分が簡単に求まり、まとめると
と求まります。
この導出された式を整理してみましょう。
右辺に関して
という値は順伝搬の際に既に得られている値です。
活性化関数も既知ですから、その微分もすぐに求まります。
も現在の重みの値を使えばよく、既知となっています。
わからないのはの値だけです。
しかし上記の式によれば
という具合に層の添字を変更すれば値を求めることができ、かつ、出力層でのに至っては、
と値が簡単に求まります。
すなわち、出力層から始めて、順番にの値を求めればよいのです。
式を見直す
ニューラルネットの順伝搬法の式を見てみましょう。
による重み付け和を行った後に、活性化関数を作用させるという流れです。
一方で誤差逆伝搬法において、求めなければいけないのはだけであることが、連鎖規則により明らかになりました。そしてその
を求める式は以下で表されます。
による重み付け和を行った後に、活性化関数の値を掛けています。
活性化関数の使われ方は違えど、順伝搬においては「前の層の値の線型結合」を使い、逆伝搬では「次の層の値の線型結合」を使っています。
まるでニューラルネットは、データを与えたら前方向にデータを伝搬していき、出力層で誤差を計算したら、その誤差を今度は後ろ向きに流して返してくれるかのようです。
便宜的にのことを「誤差」と表現し、この手法を誤差逆伝搬法と呼びます。
は何のために求めたかというと、誤差関数
の
による微分を求めるためでした。実際には誤差逆伝搬法とは微分を求めるための高速計算手法であり、高い汎用性を有しています。
誤差逆伝搬法により微分を求めたら、勾配法により学習を行うというのがニューラルネットの学習手法となります。