第5週:ニューラルネットワーク:学習【Coursera Machine Learningコース】
Cost Function and Backpropagation
Cost Function
シンボル定義:
L ... ネットワーク内のレイヤー数
... レイヤー にあるユニット数 (バイアスユニットは除く)
K ... 分類問題のクラス数
2クラス分類なら , ,
多クラス分類なら , (K ≧ 3)
ロジスティック回帰のときのコスト関数は以下。
ニューラルネットワークでは以下のようになる。
はユニットがK個あるうちの何番目かを表す添字。
ロジスティック回帰のコスト関数との違いは、ユニットK個分の和をとっていること。
正則化項はぱっと見複雑に見えるが、そんなに難しくない。
, , はそれぞれ、 層目の 番目のユニットの
番目の特徴量の重みを取り出すために使われている。
つまり、ネットワーク全体の重みの二乗和をとっているということ。
Backpropagation Algorithm
ニューラルネットワークでも、これまで同様、コスト関数とその微分が必要。
つまり、 の他に、 が必要。
この微分計算のために誤差逆伝搬法(Backpropagation)を使う。
誤差逆伝搬法は、レイヤ にあるノード 番目の誤差 を求めるイメージ。
ニューラルネットワークでは各レイヤにアクティベーション が存在するが、
このアクティベーションが、期待される値からどれだけずれているかを求めていく。
具体的には以下のような計算をする。
レイヤ で、トレーニングセットx, yがそれぞれ1つずつしかない場合を考えると
出力層 :
隠れ層 :
隠れ層 :
上式の , , , , はそれぞれベクトル。
という演算子は、要素ごとの積を表している。
というのは、アクティベーション関数の を入力値が のところで微分した値。
これを計算すると、 になる。
なお、レイヤ1(入力層)にはアクティベーションがない(入力値)ので、 も存在しない。
このように、誤差 を出力層から始めてレイヤを遡りながら
計算していくので、誤差逆伝搬法と呼ばれている。
正規化項を無視すると、これらの誤差 を使って、 は以下のように計算できる。
以上の計算を、トレーニングセットが複数ある場合({(, ), ..., (, )})で考える。
まず、 とおく。これは後ほど偏微分項を累積するために使う。
次に から までのループの中で(つまり各トレーニングセットに対して)以下の計算をする。
・(入力層)
・フォワードプロパゲーションにより を算出 ()
・出力層の誤差 を計算
・バックプロパゲーションにより を計算
・ で偏微分項を累積する
最後に、ループを抜けたのち、以下のように正規化項の計算をする。
・( の場合)
・( , つまりバイアス項の場合)
以上で、ニューラルネットワークのコスト関数の偏微分は次のように計算できる。
Backpropagation Intuition
逆伝搬は線形回帰やロジスティック回帰に比べると、数学的にクリーンでもシンプルでもない。
なので直感的には理解しにくいかもしれない。
直感的に理解できなくても、使い方さえ覚えれば問題ない。
課題をこなすことで、逆伝搬の実装方法は分かるようになる。ひとまずそれでいい。
下図のようなニューラルネットワークがあるとする。
順伝搬において、あるノードへの入力は、ひとつ前のレイヤーの各ノードの出力に重みをかけたものの和になっている。
逆伝搬の計算も、これと似たプロセスになっている。
違いは、計算が左から右に流れるか、右から左に流れるか。
逆伝搬のコスト関数について、データセットのうち と だけに着目し、出力ユニットはひとつだけとして、正規化項を無視すると、以下のようになる。
このコスト関数がやっているのは、誤差の2乗と似たような役割。
そのため、感覚的な理解としては、
のように近似して考えてもよい。
では、これを前提として、逆伝搬が何をやっているか。
逆伝搬は、 を計算している。
これは、 番目のレイヤーにある 番目のユニットのアクティベーション の値の「誤差」と捉えることができる。
正式には、 を計算している。
直感的には以下のように理解すればよい。
の求め方は順伝搬とよく似ていて、前のレイヤーの各ユニットの誤差の重みつき和になっている。
例えば下図のように、出力層の誤差 は、正解データと出力値の差をとる。
レイヤー2のユニット2の誤差 なら、下図のようになる。
バイアスユニットについては誤差がないので無視してよい。
Backpropagation in Practice
Implementation Note: Unrolling Parameters
行列からベクトルへのパラメータのアンロールについて。
高度な最適化アルゴリズムを利用する際、これが必要になる。
Octaveで学習を走らせる際、以下のようなコードを書いてた。
function [jVal, gradient] = costFunction(theta) ... optTheta = fminunc(@costFunction, initialTheta, options)
ここで、thetaやgradientはベクトルを期待している。
しかしニューラルネットワークにおいてこれらは行列になる。
そのため、行列からベクトルへのアンロールが必要になる。
例として、下図のようなネットワークを考える。
このとき、行列ΘやDをベクトルにアンロールするには、(Octaveの場合)以下のようなコードを書けばよい。
反対に、ベクトルを行列に戻す場合は以下のようなコードを書く。
Gradient Checking
逆伝搬の実装は複雑でバグが混入しやすい。
そして一見すると正しく動いているように見えてしまう。
この問題は、Gradient Checkingと呼ばれるアイデアで対処可能。
これは、別の方法で勾配(あるいはその近似値)を計算して、両者を比較することで正しさを検証するというもの。
勾配の近似値は下図のような式で求めることができる。
ある程度小さなεを設定し、これを使ってΘを両側微分したものを近似値として利用する。
Octaveで実装すると以下のようなコードになる。
Θをベクトルに拡張すると次のようになる。
Octaveで実装した場合こうなる。
得られたgradApproxと逆伝搬の計算で得られたDVecを比較し、差がある範囲に収まれば、逆伝搬の計算は正しい可能性が高くなる。
なお、Gradient Checkingは逆伝搬の実装を検証する際にのみ使用し、実際に学習する際にはいちいち計算しないように注意する。
逆伝搬の計算と比較して計算に時間がかかるので、この方法を使って学習することはしない。
Random Initialization
Random Initializationと呼ばれるアイデアについて。
学習のために最適化アルゴリズムを走らせる際、パラメータΘの初期値を選ぶ必要がある。
ロジスティック回帰の場合は、ゼロ初期化でうまくいった。
しかしニューラルネットワークの場合、Θをゼロ初期化するとうまく動かない。
そのため、Θをランダムに初期化する必要がある。
Θを の範囲の値で初期化するために、Octaveでは以下のように記述すればよい。
Theta1 = rand(10, 11) * (2 * INIT_EPSILON) - INIT_EPSILON; Theta2 = rand(1, 11) * (2 * INIT_EPSILON) - INIT_EPSILON;
rand(10, 11)は10x11の0から1の間の値をとる行列を生成する。
Putting It Together
ニューラルネットワークの利用手順について。
● モデル形状の決定
- 入力層のユニット数 ... 扱う特徴量の数できまる
- 出力層のユニット数 ... 分類に必要なクラスの数できまる
- 隠れ層の数 ... 通常は1層でいい
- 隠れ層のユニット数 ... だいたい入力層のユニット数と同程度 ~ 4倍程度にする 隠れ層が複数あるなら各層のユニット数は同じにする
● 学習の実装
- パラメータΘをランダムに初期化する (Θは0付近の値)
- フォワードプロパゲーションを実装して に対する を計算可能にする
- コスト関数 の実装
- バックプロパゲーションを実装して偏微分 を計算可能にする
- バックプロパゲーションの実装の正しさを検証するためにGradient Checkingを行う (検証が済んだらこの処理はOFFにしておく)
- 勾配降下法、またはより高度な最適化アルゴリズムによって を最小化する処理を実装する
Application of Neural Networks
Autonomous Driving
ニューラルネットワークで自動運転する研究結果の映像。