こちらのコンテンツは最新の情報ではない可能性があります。無料で学べる最新のコンテンツは Python&機械学習入門コース 脱ブラックボックスコース をぜひご利用ください。

ニューラルネットワークの数学(逆伝播)

本章では、前章で学んだ順伝播の計算、目的関数の知識から、どのようにニューラルネットワークではパラメータの更新を行うのかについて学びます。次章からの実装に移る前にニューラルネットワークの学習の一連の流れを理解することをゴールとします。

本章の構成

  • 勾配降下法
  • ミニバッチ学習
  • 誤差逆伝播法

勾配降下法

それでは前章でお伝えした、ニューラルネットワークの計算の流れをアニメーションで確認しましょう。

20_1_gif

  1. パラメータの初期値をランダムに決定
  2. 順伝播の計算 : 予測値 yy の算出
  3. 損失の計算 : 損失 L\mathcal L の算出
  4. 勾配の計算 : 勾配の算出
  5. パラメータの更新 : 勾配を用いて重みを更新
  6. 2 ~ 5 を繰り返し、最適なパラメータに調整を行う

前章では 1 ~ 3 までの順伝播、そして、損失の計算方法について確認しました。4 ステップ目の勾配の計算方法は誤差逆伝播法とも呼ばれます。その計算方法は少し複雑であり、次章から始まるディープラーニングフレームワークを用いてニューラルネットワークを実装する際にはフレームワーク側で中身がラップされているため特に意識する必要がありません。そのため本章では誤差逆伝播法の計算方法について詳しくは取り扱いませんが、最低限イメージが湧くレベルまで数値例を用いながら解説します。

5 ステップ目のパラメータの更新方法についてまず解説します。

ニューラルネットワークのパラメータの最適化

改めて前章の復習ですが、重回帰分析のパラメータの最適化では、目的関数をパラメータで微分して勾配ベクトルを求め、そしてその勾配ベクトルがゼロベクトルとなるように、各パラメータの値を求めることによって行っていました。

ニューラルネットワークのパラメータの最適化に対し、この方法を採用した場合に 1 つ問題があります。それは、今回の目的関数を計算する中で ReLU 関数を採用する場合に max(0,x)\max(0,x) が含まれていることです。この関数は実際に値を入れていなければ関数の値を決定することができません。つまり、重回帰分析のように全体を見通して目的関数の微分を行うことができません。微分を行うことができなければ、パラメータの最適化を行うことが出来ません。

そのため、ニューラルネットワークでは、パラメータの初期値をランダムにとり、順伝播を通して実際に計算を行い、損失を計算することで、微分を可能にしています。そして、求まった傾きを用いて、パラメータを更新してくという流れとなっています。

勾配降下法

ニューラルネットワークのパラメータの更新に用いられる最適化のアルゴリズムの 1 つに勾配降下法があります。本節では、勾配降下法のアルゴリズムの理解を通して、ニューラルネットワークのパラメータの最適化方法について学びます。

まず、以下の図をご覧ください。図中の点線は、パラメータ ww を変化させた際の目的関数 L\mathcal L の値を表しています。この例では簡単のため二次関数の形になっていますが、ニューラルネットワークの目的関数は実際には多次元で、かつもっと複雑な形をしていることがほとんどです。 しかし、ここでは説明のためこのようにシンプルな形を考えます。 さて、この目的関数が最小値を与えるような ww は、どのようにして発見できるでしょうか。

20_13

ニューラルネットワークではパラメータはまず乱数で初期化されます。ここでは、例として w=8w=8 と初期化されたと想定します。そうすると、w=8w=8 における L\mathcal L の勾配 Lw\frac{\partial \mathcal L}{\partial w} が求まります。ニューラルネットワークの目的関数は、全てのパラメータについて微分可能であるように設計されます。

ここで仮に w=8w=8 における Lw\frac{\partial \mathcal L}{\partial w}55 であったとします。そのとき下記の図のように、この 55 という値は w=8w=8 における L(w)\mathcal L(w) という関数の接戦の傾き、勾配を表しています。

20_14

ここで傾きとは、ww を増加させたときに L\mathcal L が増加する方向を意味しています。いま、目的関数 L\mathcal L の値を最小化することを目的としているので、算出した傾きの逆方向へ ww を変化させる、すなわち ww から Lw\frac{\partial \mathcal L}{\partial w} を引けばより小さい値になることになります。

式で表すと下記になります。

wwLw\begin{array}{c} w \leftarrow w - \frac{\partial \mathcal L}{\partial w} \end{array}

左側の ww はパラメータ更新後の ww です。そして、矢印の右側はパラメータの更新方法を表しています。前述のとおり、最初のパラメータ ww から勾配を引いています。今回の数値例に当てはめると、

385\begin{array}{c} 3 \leftarrow 8 - 5 \end{array}

となります。この流れがニューラルネットワークのパラメータを更新していく基本的な考え方です。

下記のアニメーションではパラメータ更新の一連の流れを繰り返していますので、具体的なイメージを掴んでください。

20_2

徐々に目的関数 L\mathcal L が最小値をとるときの ww の値に近づいていることが見てとれます。

学習率

ニューラルネットワークのパラメータの最適化について理解するためには学習率 (Learning rate) について理解しておく必要があります。パラメータの更新量を決定する際に、パラメータから勾配を引くという計算を行いましたが、実際には勾配に対して学習率と呼ばれる値を乗じるのが一般的です。下記は学習率を η\eta とした場合の式になります。

wwηLw\begin{array}{c} w \leftarrow w - \eta \frac{\partial \mathcal L}{\partial w} \end{array}

実際の学習時には勾配をそのままパラメータを更新量とすると値が大きすぎる場合が一般的です。そのため、0.001 などの学習率を乗じることでパラメータの更新量を調整します。そのため学習率は一種のハイパーパラメータと呼ぶことができ、モデルの学習結果を確認しながら調整を行います。学習率が大きすぎる場合、小さすぎる場合のデメリットを確認しましょう。

20_15

  • 学習率が大きすぎる場合 : パラメータの調整が収束せず学習がうまく進まない
  • 学習率が小さすぎる場合 : パラメータの更新量が小さくなりすぎ、学習の収束までに時間を要する

実装を行う際にはこの学習率の調整も必要なことを覚えておいてください。こちらはこの値にしておけば間違いない、という値はなく経験的に調整していく必要があるので、実装で感覚を掴んでいきましょう。

ミニバッチ学習

通常ニューラルネットワークを勾配降下法で最適化する場合は、データを一つ一つ用いてパラメータを更新するのではなく、いくつかのデータをまとめて入力し、それぞれの勾配を計算したあと、その勾配の平均値を用いてパラメータの更新を行う方法がよく行われます。 これをミニバッチ学習と呼びます。

下記のアニメーションを見てミニバッチ学習を理解しましょう。

20_3_gif

ミニバッチ学習時のパラメータの更新の流れを確認します。先程の勾配降下法との違いについて着目して読み進めて下さい。

  1. 指定した数のサンプルを抽出(図内は 120 サンプルを 3 つずつにまとめる)
  2. 1.で抽出したサンプルごとの損失を計算(図内では x1\mathbf{x_1}~x3\mathbf{x_3}
  3. 損失の平均から勾配を計算
  4. パラメータの更新

※ 1. のサンプルの抽出は基本的にランダムに抽出されます。

上記のミニバッチ学習と異なり、データセット全体を一度に用いて一回の更新を行う(抽出を行わない)方法をバッチ学習と呼びます。

勾配降下法では、データを用いてパラメータを 1 度更新するまでのことを 1 イテレーション と呼び、データセット全体を使用することを 1 エポックと呼びます。バッチ学習では学習用データセットのデータ全体を 1 度の更新に一気に用いるため、1 エポック = 1 イテレーション となります。 一方、例えばデータセットを 10 個のグループに分割してグループごとに更新を行うミニバッチ学習の場合は、1 エポック = 10 イテレーション となります。

図内の例を上記の言葉に置き換えると次になります。

  • バッチサイズ (batch_size):3
  • イテレーション (iteration):40
  • エポック (epoch):1

プログラミングでは、英語で登場しますので英語でも覚えておきましょう。またバッチサイズとエポック数は実装する際にも調整が必要なものになりますので、それぞれがどのような意味を持つのかしっかり理解しておいてください。

このようなミニバッチ学習を用いた勾配降下法は特に、確率的勾配降下法 (stocastic gradient descent; SGD) と呼ばれます。 現在多くのニューラルネットワークの最適化手法はこの SGD をベースとした手法となっています。

誤差逆伝播法

前章の数値例で計算の節で紹介したとおり、パラメータの値を決めると順伝播により左側から右側へ値を計算していき、予測値を計算することができます。この予測値に対して目的関数を計算でき、どの程度正解と予測が離れているかを把握することができ、この情報に基づいて、より良い方向へパラメータを調整していきたいと考えます。本節では、どのように損失から勾配を算出するかの基礎的な考え方について理解します。

合成関数の微分

勾配降下法の節で、ニューラルネットワークではどのようにパラメータを更新していくかの大枠を把握することができました。しかし、実際に計算をするにはもう少し知識が必要です。もう一度今回の問題設定の全体像を図で確認しましょう。

20_2

上記の回帰でした。目的関数に対して、更新したいパラメータで偏微分を行うことで更新量を算出できるのですが、複数の層にまたがって複雑な計算が行われているため、そのままでは求めることが困難です。そこで、多層のニューラルネットワークでは、何層にも重ねた層の一つ一つの 1 つの関数をみなすことで、多層のニューラルネットワークは複数の関数(層)を合成した合成関数と見ることができます。

ここで、合成関数について復習します。関数 y=f(x)y = f(x)z=g(y)z = g(y)合成とは、ff を適用したあとに gg を適用する関数、z=g(f(x))z = g(f(x)) を指します。多層のニューラルネットワークでは、この合成関数を微分することを考えるため、連鎖律 (chain rule) と呼ばれる合成関数の微分公式を使用します。連鎖律は、合成関数の微分を簡単に計算するための公式だけではなく、ニューラルネットワークの学習方法である誤差逆伝播法を理解する上で本質的な役割を果たします。

今回は簡単な例として、

f(x)={(2x+4)2}\begin{array}{c} f(x) = \bigl\{(2x+4)^2 \bigr\} ^{'} \end{array}

を計算することにします。この式を計算しようとすると最初に思い浮かぶのは (4x2+16x+16)(4x^2 + 16x + 16)^{'} とカギ括弧の中身を展開してからそれぞれを微分することです。その方法でも計算できるのですが、さらに複雑な計算の場合 3 乗や 4 乗という風に式展開することが大変になります。ここで合成関数の微分が役に立ちます。合成関数の微分では、内側の部分である 2x+42x+4 と外側の部分である ()2(\cdot)^2 をそれぞれ微分を行い、その結果を掛け合わせることで求めます。

それでは、具体的に f(x)f(x) という関数の微分を考えてみます。内側の関数を u=2x+4u = 2x+4 とおくと、

f(u)=u2u=2x+4\begin{aligned} f(u) &= u^2 \\\\ u &= 2x+4 \end{aligned}

とできます。ここで合成関数の微分から求めたい式をまとめると、

ddxf(u)=df(u)dududx\begin{array}{c} \frac{d}{dx}f(u) = \frac{df(u)}{du}\frac{du}{dx} \end{array}

それでは順番に計算していきましょう。

dduf(u)=ddu(u2)=2u=2(2x+4)dudx=ddu(2x+4)=2\begin{aligned} \frac{d}{du} f(u) &= \frac{d}{du} (u^{2}) \\\\ &= 2u = 2(2x+4)\\\\ \frac{du}{dx} &= \frac{d}{du} (2x+4) \\\\ &=2 \end{aligned}

となり、

ddxf(u)=df(u)dududx=2(2x+4)2=8x+16\begin{aligned} \frac{d}{dx}f(u) &= \frac{df(u)}{du}\frac{du}{dx} \\\\ &= 2(2x+4) \cdot 2 \\\\ &= 8x+16 \end{aligned}

となります。(4x2+16x+16)(4x^2 + 16x + 16)^{'} と展開してから微分する方法と結果が一致しています。このような合成関数の微分公式を使用して、ニューラルネットワークではパラメータの更新量を求めます。

パラメータの更新量の算出

それでは実際に合成関数の微分公式を使用して、先程の例で実際にパラメータの更新量を計算していきましょう。

20_3

上の図の w7w_7 における勾配を計算します。同じ層にあるパラメータは同じ手順で求めることができます。

目的関数に対する w7w_7 の勾配 Lw7\frac{\partial \mathcal L}{\partial w_7} を求めます。u\mathbf{u}, z\mathbf{z}, y,y, L\mathcal L は事前に計算を行ってください。活性化関数には ReLU 関数を使用します。目的関数 L\mathcal L の式から微分したい w7w_7 の式までの流れを確認しておきましょう。まず、回帰の目的関数は、

L=1Nn=1N(tnyn)2\begin{array}{c} \mathcal L = \frac{1}{N} \sum_{n=1}^{N} (t_n - y_n)^{2} \end{array}

で表される平均ニ乗誤差でした。また、予測値 yny_n は、

yn=w7z11+w8z12+b\begin{array}{c} y_n = w_7z_{11} + w_8 z_{12} + b \end{array}

となります。

今回はわかりやすいようにサンプル数を 1 として、バイアスに関しては考慮しないとします。これより目的関数 L\mathcal L は、

L=(ty)2={t(w7z11+w8z12)}2\begin{aligned} \mathcal L &= (t - y)^{2} \\\\ &= \bigl\{t - (w_7z_{11} + w_8 z_{12})\bigr\}^{2} \end{aligned}

となります。それでは求めたい式を整理しておくと、

Lw7=Lyyw7\begin{array}{c} \frac{\partial \mathcal L}{\partial w_7} = \frac{\partial \mathcal L}{\partial y}\frac{\partial y}{\partial w_7} \end{array}

とそれぞれの式に対応する微分へと切り分けることができるので、前節で学んだ合成関数の微分を用いながら計算していくと、

Ly=2(tw7z11w8z12)yw7=z11\begin{aligned} \frac{\partial \mathcal L}{\partial y} &= -2(t - w_7z_{11} - w_8 z_{12}) \\\\ \frac{\partial y}{\partial w_7} &= z_{11} \end{aligned}

となり、求めたい勾配の値は

Lw7=Lyyw7=2(tw7z11w8z12)×z11=2×11(103×112×0)=506\begin{aligned} \frac{\partial \mathcal L}{\partial w_7} &= \frac{\partial \mathcal L}{\partial y}\frac{\partial y}{\partial w_7} \\\\ &= -2(t - w_7z_{11} - w_8 z_{12}) \times z_{11} \\\\ &= -2 \times 11 (10 - 3 \times 11 - 2 \times 0) \\\\ &= 506 \end{aligned}

となります。勾配降下法から、学習係数 η=0.01\eta = 0.01 の場合、更新後の w7w_7 の値は、

w7=w7ηLw7=30.01×506=2.06\begin{aligned} w_7 &= w_7 - \eta \frac{\partial \mathcal L}{\partial w_7} \\\\ &= 3 - 0.01 \times 506 \\\\ &= -2.06 \end{aligned}

となります。

いかがだったでしょうか。今回は出力層にもっとも近いパラメータの更新方法をお伝えしましたが、層がさらに深くなるとこの計算が更に長く複雑になっていくイメージです。入力層に近いパラメータになると、その前の層までの計算結果を流用できるようになり、計算量も削減することができます。このように、計算過程で共通する項目を逆方向から伝播していくと計算量の削減ができ、この方法が誤差逆伝播法と知られています。予測値の計算では左側から右側へ値を伝播していきましたが、この方向を順方向とし、パラメータ更新のために必要な勾配の計算が逆方向に値を伝播させるため、逆伝播と呼ばれています。

前章から続いたニューラルネットワークの数学は、これで完了です。次章から始まる実装やその他の種類のニューラルネットワークについて学ぶ際の基礎になりますので、何度も振り返り、次の章に進むようにしましょう。

shareアイコン