🦥

誤差逆伝搬法の理論を計算してみる

2023/07/31に公開

今回は誤差逆伝搬法について学習します。
非常に面白い手法で、私が機械学習に興味を持った一つの要因でもあります。
※ニューラルネットワークをまだ学んでいない人は、先にそちらを学ぶと良いかもしれません。

誤差逆伝播法とは

誤差逆伝搬法は、ニューラルネットの重み(パラメータ)を自動で更新するために使用されます。

簡単に言うと、予測値と正解の誤差を元に重みを更新する手法です。
機械学習モデルの損失関数Eを減少させることを目的として、重みの調整を自動で行います。

記号の説明

記号 備考
入力 x 個数の増加につれてx_1,x_2,x_3...となる
各層の出力 z 層が深くなるにつれてz^1,z^2,z^3...となり、
各層の出力個数によりz^{1}_{1},z^{1}_{2},z^{1}_{3}...となる
最終層の出力 z^L または y 個数の増加につれてz^L_1,z^L_2,z^L_3...となる
同様にy_1,y_2,y_3...となる
教師データ d 個数の増加につれてd_1,d_2,d_3...となる
重み w z^l_1からz^{l+1}_2に移動する際の重みをw^{l+1}_{12}とする
重み付き線形和 u 各層の出力zに1:1で対応。u^l_j=w^l_{0j}z^{l-1}_0+w^l_{1j}z^{l-1}_1+w^l_{2j}z^{l-1}_2+w^l_{3j}z^{l-1}_3...と定義。
lj番目の一つのノードに向かう、前層の出力×重みの総和。
※先頭の値はバイアス
バイアス w^l_{0j} 存在しない0番目のノードから次のノードへ向かう際の重み(定数)。
出力z^{l-1}_0は常に1。
活性化関数 f z=f(u)で表される。
損失(誤差)関数 E(z(w,x),d) 出力(予測)データと教師データの差。
この関数Eの値が小さくなるような重みwを探すことが目的。
x(入力),d(教師データ)は変えられないため
学習率 η 重みを更新する割合を決める

前置き

・ニューラルネットの特性
ニューラルネットの重みが与える影響範囲についてはじめに考えます。

全結合の場合、重み付き線形和

u^l_j=w^l_{0j}z^{l-1}_0+w^l_{1j}z^{l-1}_1+w^l_{2j}z^{l-1}_2+w^l_{3j}z^{l-1}_3...
は、前の層の出力z^{l-1}×重みw^{l-1}を全て足したものになっています。そしてu^l_jが活性化関数fを通り出力z^l_jとなります。
つまり、各層の出力z^lは、前の層の出力z^{l-1}と重みw^{l-1}全てを引数に持つ関数と言えます。
逆に言えば、前半の層の重みは、その後の層の出力全てに影響を与えていることになります。
(前半の層の重みが変わるとその後の層の出力が全て変化する)

・重みの更新
次に重みの更新をどうやって行うか考えます。誤差逆伝播法の目的は、損失関数Eを減らす方向に重みwを変化させることです。

wの更新量Δwとすると、重みの更新式は
w=w+Δw・・・①となります。
ここで
Δw^l_{ij}=-η\dfrac{∂E}{∂w^l_{ij}}と定義できます。これは以下で説明します。

ここでは、損失関数Eを任意のwで偏微分して得られる傾きの、逆方向にwを動かすという動作を行います。これにより、Eの値が小さくなる方向にwが更新されます。
※微分すると傾きが導かれます。これは二次関数の傾きと同じでwを動かした時にEがどの程度動くかの係数に値するため、傾きが正ならwが増えるとEも増加し、負ならばwが増えるとEは減少します。よって、傾きと逆方向にwを更新することでEが小さくなります。
偏微分についてはこちらでも解説しています。

上記の公式①に従ってwを更新することで、損失関数が最小となる点を探すことができます。
Δwを求めることで、損失関数の改善→モデルの改善を行うことができるのです。

・重みの更新が与える影響
上記「ニューラルネットの特性」にあるように、各層の出力はそれ以前の層の重みを全て引数として持っています。これはつまり浅めの層の重みはその後の層の出力全てに影響を与え、結果的にEに非常に複雑な影響を与えることを意味します。
この特性上、ニューラルネット前半の重みの偏微分計算(wが変化した時にEがどれだけ変化するか求めること)が非常に難しいため、層の後半から巻き戻るようにして計算を行っていきます。
これが逆伝搬と呼ばれる所以です。

これから実際の計算に入りますが、その前に偏微分で使用する連鎖律という手法を紹介しておきます。
-連鎖律
重みを更新する際、連鎖律と呼ばれる微分の手法を使用します。
これはE(x(y))の時、Eの偏微分が
\dfrac{∂E}{∂y}=\dfrac{∂E}{∂x}\dfrac{∂x}{∂y}と変形できる性質のことです。

これを多変数に展開すると、E(u,v)かつu(x,y),v(x,y)の時、
\dfrac{∂E}{∂x}=\dfrac{∂E}{∂u}\dfrac{∂u}{∂x}+\dfrac{∂E}{∂v}\dfrac{∂v}{∂x}

となります。これはつまり多変数関数で連鎖律を使用する際には、変数xが影響を及ぼしている全ての関数の連鎖律の総和が必要であるということです。これにより特定の変数がEへ与える影響を考えることができるのです。

-関数選定
そして、実際に誤差逆伝播を考えるにあたり、その値は損失関数Eと活性化関数fによって異なります。そこで今回は誤差関数Eに二乗誤差関数、出力層の活性化関数fに恒等関数を使用することにします。
これは回帰問題で一般的に使用されている設定になります。
・二乗誤差関数 E=\dfrac{1}{2}\sum\limits_{i}(y_i-d_i)^2
・恒等関数 f(u)=u
※恒等関数は値を変更しない、便宜上の関数。3を入れると3が出力される

誤差逆伝搬法の計算

前置きが長くなりましたが、ここから実際の計算に入っていきます。

0.目的
重要なので確認して下さい。

誤差伝播法の目的は、損失関数Eを減少させる方向に、重みwを更新することです。

重みww=w+Δwで更新されます。
以下の計算の目的は重みの更新に必要な
Δw^l_{ij}=-η\dfrac{∂E}{∂w^l_{ij}}の変数である 「\dfrac{∂E}{∂w^l_{ij}}を求めること」 です。

1.まずは出力層^L(最終層)について考えましょう。
任意の重みに対するEの傾き\dfrac{∂E}{∂w^L_{ij}}を求めます。

はじめに連鎖律を使用して重み付き線形和{u^L_j}を登場させます。
\dfrac{∂E}{∂w^L_{ij}}=\dfrac{∂E}{∂u^L_j}\dfrac{∂u^L_j}{∂w^L_{ij}}・・・(a)
これはニューラルネットがE(u^L(w^L))となっており、Eは重み付き線形和uの関数、uは重みwの関数であるため可能です。
そして右辺の各成分について、
\dfrac{∂E}{∂u^L_j}=δ^L_j・・・①と仮に置き(飛ばして下さい)、
\dfrac{∂u^L_j}{∂w^L_{ij}} = z^{L-1}_i・・・②と計算します。これは以下※で説明します
※②はuの定義u^l_j=w^l_{0j}z^{l-1}_0+w^l_{1j}z^{l-1}_1+w^l_{2j}z^{l-1}_2+w^l_{3j}z^{l-1}_3...+w^l_{ij}z^{l-1}_iより、偏微分で他の項が落ち、=\dfrac{∂w^L_{ij}z^{L-1}_i}{∂w^L_{ij}}となるため。

一度整理して、①,②より
\dfrac{∂E}{∂w^L_{ij}}=δ^{L}_{j}z^{L-1}_i・・・(b)となります。

次にδ^L_jzについて連鎖律を用いて
δ^L_j=\dfrac{∂E}{∂u^L_j}=\dfrac{∂E}{∂z^L_j}\dfrac{∂z^L_j}{∂u^L_j}・・・③とできます。(E(z^L(u^L))より。uに活性化関数を通したものがzなので、zuの関数)
右辺の各成分について
\dfrac{∂E}{∂z^L_j}=\dfrac{∂E}{∂y_j}=(y_j-d_j)・・・④ 以下※で説明します
\dfrac{∂z^L_j}{∂u^L_j}=\dfrac{∂u^L_j}{∂u^L_j}=1z=f(u)であり、fは恒等関数なのでz=u
※④は損失関数E=\dfrac{1}{2}\sum\limits_{i}(y_i-d_i)^2について、y_jで偏微分するとy_j以外の項が落ちてE=\dfrac{1}{2}(y_j-d_j)^2の微分となり、=(y_j-d_j)となります。

よって③,④より
δ^L_j=(y_j-d_j)となり、この式と(b)式より
出力層の任意の重みに対するEの傾き\dfrac{∂E}{∂w^L_{ij}}=(y_j-d_j)z^{L-1}_iが導かれます。

これを見ると、出力層の重みの更新を行うには、誤差(y_j-d_j)と一つ前の層の出力(z^{L-1})だけが必要で、それ以前の出力は不要であることが分かります。

2.次に中間層^lについて考えましょう。
任意の重みに対するEの傾き\dfrac{∂E}{∂w^l_{ij}}を求めます。

1.と同様に連鎖律で書き換えます。
\dfrac{∂E}{∂w^l_{ij}}=\dfrac{∂E}{∂u^l_j}\dfrac{∂u^l_j}{∂w^l_{ij}}
次も同様の計算を行い、整理した後の
\dfrac{∂E}{∂w^l_{ij}}=δ^{l}_{j}z^{l-1}_iが得られます。
z^{l-1}_iは前層出力なので、あとはδ^{l}_{j}を計算します。

計算は、連鎖律を用いて以下のようになります。
δ^{l}_{j}=\dfrac{∂E}{∂u^{l}_{j}}=\sum\limits_{k}\dfrac{∂E}{∂u^{l+1}_{k}}\dfrac{∂u^{l+1}_{k}}{∂u^{l}_{j}}・・・⑤ 以下で説明します。
※⑤では、1.と同様に連鎖律を用いて\dfrac{∂E}{∂u^{l}_{j}}を変形しました。1.では連鎖率で∂z^Lを代入しましたが、今回は次の層の重み付き線形和∂u^{l+1}を代入します(こうするとうまくいくため)。ここで、u^{l}_{j}は全結合により次の層^{l+1}全てに影響を与えているので、u^{l+1}_{j}は全てu^{l}_{j}の関数となります。よって連鎖律の説明でも記載しましたが、Eへの影響を考えるにはu^{l+1}_{j}の総和を用いる必要があるため、\sumを利用しています。

次に⑤の右辺の成分に仮定\dfrac{∂E}{∂u^{l+1}_k}=δ^{l+1}_{k}を利用して
δ^{l}_{j}=\sum\limits_{k}\dfrac{∂E}{∂u^{l+1}_{k}}\dfrac{∂u^{l+1}_{k}}{∂u^{l}_{j}}=\sum\limits_{k}δ^{l+1}_{k}\dfrac{∂u^{l+1}_{k}}{∂u^{l}_{j}}

右辺成分に連鎖律で∂z^{l}_{j}を登場させて
=\sum\limits_{k}δ^{l+1}_{k}\dfrac{∂u^{l+1}_{k}}{∂z^{l}_{j}}\dfrac{∂z^{l}_{j}}{∂u^{l}_{j}}

これを計算すると、
=\sum\limits_{k}δ^{l+1}_{k} w^{l+1}_{jk} \dfrac{∂z^{l}_{j}}{∂u^{l}_{j}}・・・⑥ 以下※で説明します

=\sum\limits_{k}δ^{l+1}_{k} w^{l+1}_{jk} \dfrac{∂f^l(u^l_j)}{∂u^{l}_{j}}・・・⑦ 以下※で説明します

※⑥:uの定義u^{l+1}_j=w^{l+1}_{0j}z^{l}_0+w^{l+1}_{1j}z^{l}_1+w^{l+1}_{2j}z^{l}_2+w^{l+1}_{3j}z^{l}_3...+w^{l+1}_{ij}z^{l}_iより、偏微分で他の項が落ち、\dfrac{∂w^{l+1}_{jk}z^{l}_j}{∂z^l_{j}}となるため。
※⑦:z^{l}_{j}u^{l}_{j}に活性化関数f^lを通したものであるため。z^{l}_{j}=f(u^{l}_{j})(活性化関数はuごとに指定でき、恒等関数の場合\dfrac{∂f^l(u^l_j)}{∂u^{l}_{j}}=1)

よって
δ^{l}_{j}=\sum\limits_{k}δ^{l+1}_{k} w^{l+1}_{jk} \dfrac{∂f^l(u^l_j)}{∂u^{l}_{j}}・・・⑧

が導かれます。⑧右辺のw^{l+1}_{jk}・・・⑨_1は重みで既出の値であり、\dfrac{∂f^l(u^l_j)}{∂u^{l}_{j}}(=\dfrac{∂z^{l}_{j}}{∂u^{l}_{j}})・・・⑨_2は出力の微分なので、既出の値の微分計算で求める事ができます。
しかしδ^{l+1}_{k}(=\frac{∂E}{∂u^{l+1}_k})は通常、非常に複雑な計算となり求められないのですが、先程の出力層ではδ^L_j=(y_j-d_j)と定数として求めることができました。
これを利用することにしましょう。⑧式を使用します。
まず「出力層の(y_j-d_j)(=δ^L_k)の総和=\sum\limits_{k}δ^L_k」を求めます(1. でδ^L_j=(y_j-d_j)が定数として求められいるので、全て足す)。そして⑨_1,⑨_2と併せて⑧式に代入することで、⑧式を計算により直接求める事ができ、出力層の一つ前のδ^{L-1}_{j}を得ることができます。そうしたら次は「出力層の一つ前の層のδ^{L-1}_{j}の総和=\sum\limits_{k}δ^{L-1}_k」を利用して同様にδ^{L-2}_{j}を求め...
とすることで、出力層から逆算して全てのδを求めることができます。

これで⑧式の全ての値が求められたので、最初の(a)式から計算してみましょう。
求めたい「中間層の任意の重みに対するEの傾き\dfrac{∂E}{∂w^l_{ij}}」は連鎖律より
\dfrac{∂E}{∂w^l_{ij}}=\dfrac{∂E}{∂u^l_j}\dfrac{∂u^l_j}{∂w^l_{ij}}
=δ^{l}_{j}z^{l-1}_i
⑧より
=\sum\limits_{k}δ^{l+1}_{k} w^{l+1}_{jk} \dfrac{∂f^l(u^l_j)}{∂u^{l}_{j}}z^{l-1}_i

仮置きしたδを元の形(\dfrac{∂E}{∂u})に戻して
=\sum\limits_{k} \dfrac{∂E}{∂u^{l+1}_k} w^{l+1}_{jk} \dfrac{∂f^l(u^l_j)}{∂u^{l}_{j}}z^{l-1}_i

よって
\dfrac{∂E}{∂w^l_{ij}}=\sum\limits_{k} (\dfrac{∂E}{∂u^{l+1}_k} w^{l+1}_{jk}) \dfrac{∂f^l(u^l_j)}{∂u^{l}_{j}}z^{l-1}_i

として、任意の重みWに対する損失関数Eの傾き\dfrac{∂E}{∂w^l_{ij}}を解析的に求めることができました。
これをプログラム上で行うことで、自動で重みを更新する事ができるのです。

まとめ

今回は、誤差逆伝播法がどのように重みの更新を行なっているのか、実際に計算してみました。

また上式から、重みの更新量Δw
Δw^l_{ij}=-η\sum\limits_{k} (\dfrac{∂E}{∂u^{l+1}_k} w^{l+1}_{jk}) \dfrac{∂f^l(u^l_j)}{∂u^{l}_{j}}z^{l-1}_iとなります。

つまり重みw^l_{ij}の更新には

\dfrac{∂E}{∂u^{l+1}_k}(=δ^{l+1}_{k}):次の層の全ての重み付き線形和u^{l+1}_kが損失関数Eに与える影響(=予測値と正解の誤差(y_j-d_j)が伝搬してきたもの)

w^{l+1}_{jk}:重みw^l_{ij}が入るニューロンから出る、次の層の全ての出力z^{l+1}_{jk}に対する重み

\dfrac{∂f^l(u^l_j)}{∂u^{l}_{j}}(=\dfrac{∂z^{l}_{j}}{∂u^{l}_{j}}):重みw^l_{ij}が入るニューロンの活性化関数成分

z^{l-1}_i:重みw^l_{ij}が出てきたニューロンの出力

が関係していることが分かります。

最後に

誤差逆伝播法では、今回紹介したような手法を用いて、任意の重み{w^l_{ij}}に対するEの傾き\dfrac{∂E}{∂w^l_{ij}}を求め、これを反転してwの移動量とすることで、損失関数Eを最小にするための調整を行なっていました。

このように重みの調整を自動で行えることが誤差逆伝播法の強みと言えるでしょう。

Discussion