FreeStyleWiki

Coursera 機械学習 - Week5

このエントリーをはてなブックマークに追加

[機械学習]

Week5

この辺の計算は本当に難しい

  コースの理解のために見た記事

行列の計算を頭でイメージするための目安

バックプロパゲーションの数式

  目的関数と誤差逆伝播法 (Cost Function and Backpropagation)

目的関数

ここからはニューラルネットワークの独自の用語そのイメージとともに覚えていく必要がある。そうしないとOctaveの計算が通らない。

以下のような変数が数式の中で定義される:

  • L = ニューラルネットワークの中にあるレイヤーの総数
  • sl = レイヤーL内に存在するユニットの数(バイアスユニットは含まない)
  • K = 出力先のユニット/クラスの数

この図を例とすると、L = 3, K = 2 という感じ。

左から順に…

  • 入力層 (Input)
  • 隠れ層 (Hidden Layer)
  • 出力層 (Output)

目的関数は以下のようになる(ごちゃごちゃしすぎだろ…)

  • J(\Theta) = - \frac{1}{m} \sum_{i=1}^m \sum_{k=1}^K \left[ y_k^{(i)} log(( h_\theta(x^{(i)}) )_k) + (1 - y_k^{(i)}) log (1- ( h_\theta(x^{(i)}) )_k) \right] + \frac{\lambda}{2m} \sum_{l=1}^{L-1} \sum_{i=1}^{sl} \sum_{j=1}^{sl+1} ( \Theta_{j,i}^{(l)} )^2

式の意味をちょっとだけメモしておく

  • \sum_{i=1}^m
    • m は全てのデータセットの数になる
  • \sum_{k=1}^K
    • K は出力先のユニット/クラスの数
    • イメージがつきにくいかもしれない
    • あるデータに対して、それが0〜9の数字かどうか判定する場合;K = 10
    • あるデータに対して、それが食べ物か否か(true/false)で判別するなら;K=2
  • この2つのシグマについて、平易な日本語で説明を試みる
    • 1.行列の形でデータセットがm行与えられた時、まずは内部でK=1〜Kまでの仮説関数hθ(x)を計算する
    • 2.それをm回繰り返して出てきた行列をさらに合算する
    • 3.出てきた和を-mで割る、大きさはだいたい最初の1の和の平均値みたいになるはず
    • 4.出た和に、ラムダ式つきの「正規化パラメーター」を足す、これでオーバーフィッティングを防ぐ

誤差逆伝播法 (Backpropagation Algorithm)

何をしたいのだっけ?
さあ、Week5最大の難関がやってきました。まずこれの目的を再確認。

「誤差逆伝播法」は我々の目的関数を最小化するためのニューラルネットワークの用語です、それの対象は最急降下法を使ったロジスティクス回帰と線形回帰です。

我々の目標はただ、 minθ J(Θ) を計算することなのです。

そうそう、元々そういうことをやろうとしてたんだった。そして、目的関数を効率的に最小化するにはJ(θ)の傾き=Gradientを求めて各種アルゴリズムにぶち込んでやりたいのだった。

これでわかったと思わないでください、実際計算すると計算が合わないんすよ…

誤差逆伝播法(Backpropagation Algorithm)の疑似コード
以下はコースの中で紹介されている疑似コード
  • \Delta_{i j}^{(l)} = 0 \text{( for all l, i, j )}
    • Δという名前でデータセットの数(=i)×ノード数(=j)分の2次元配列(つまりは行列)を初期化する
    • lはレイヤーの数を表す、つまりl個分の行列
  • \text{For i = 1 to m} \\
    • データセットを1〜mまでループさせて取り出す
    • \text{Set } a^{(1)} = x^{(i)} \\ \text{Perform forward propagation to compute } a^{(l)} \text{for l = 2, 3, ... L}
      • 最初の活性ノードa(1)はデータセットの値Xそのまま、そのままの行列
      • そこからレイヤーの数Lに到達するまで、順番に活性ノードを計算する(= forward propagation)、計算方法は次の項に
    • \text{Using } y^{(i)} \text{ , compute } \delta^{(L)} = a^{(L)} - y^{(i)}
      • 実際のデータyと活性ノードa(L)の差分、これを小文字のデルタ(=δ)と呼ぶ
      • このδをどんどん計算していくことで各階層の傾きを求める
    • \text{Compute} \delta^{(L - 1)}, \delta^{(L - 2)}, \cdots, \delta^{(2)}
      • 最初の階層以外のδは同じようにforward propagationで求められる
      • そして最後のδ(1)は存在しない、それはデータセットの値Xそのままを表すからだ
    • \Delta_{i j}^{(l)} := \Delta_{i j}^{(l)} + a_j^{(l)} \cdot \delta_i^{(l + 1)}
      • 各階層のδを合計してΔを作る
      • 計算式が =ではなく、:=になっているのはプログラミングで言うところの +=
      • どうせ最後 m で割るので、Δは大きくなっても構わない
  • D_{i j}^{(l)} := \frac{1}{m} \Delta_{i j}^{(l)} + \lambda \Theta_{i j}^{(l)} \text{ ( if j != 0 ) } \\ D_{i j}^{(l)} := \frac{1}{m} \Delta_{i j}^{(l)} \text{ ( if j == 0 ) }
    • ノードがバイアスユニット(=1しか入ってないやつ)のときだけ正規化パラメーターを足さない
    • D を合算してから m で割る
    • これで各θに対する Gradient が求められる!
順方向伝播法(Forwardpropagation Algorithm)
あまりこの単語の和訳がないのだが、とりあえず語感を合わせてみた

ノードとa, zの関係は以下のようなものだ。

行列で出来たデータセットxに対して処理を行うものとする。

  • a^{(1)} = x
    • 1列目の活性ノードにデータセットの中身をそのまま渡す
  • z^{(2)} = \Theta^{(1)} \cdot a^{(1)}
    • 次の2列目のノードへの計算結果をz(2)として、パラメーターθとa(1)を計算する。
    • もちろんこれは行列の積で求められる計算である
  • a^{(2)} = g(z^{(2)}) ( add a_0^{(2)} )
    • 計算結果がそのままほしいわけではなく、2値化したいのでシグモイド関数にかける
    • その際、活性ノードの一番頭にバイアスノード(=1)を付加する

後は、ニューラルネットワークの層の数だけこれを繰り返す。一般化するとこんな感じだろうか。

  • z^{(l+1)} = \Theta^{(l)} \cdot a^{(l)}
  • a^{(l+1)} = g(z^{(l+1)}) ( add a_0^{(l+1)} )

要は、活性ノードaの計算ができればそれでいいのだ。

  まとめ

とりあえず、内容としてはほぼこれで全部だと思う。式が間違って無ければfor文でプログラミングの問題も正解できる。