備忘録とか日常とか

学んだこととかを書きます。

Machine Learning: An Algorithmic Perspective 読んでいく(2)

前回に引き続いて、機械学習の本を読んでいく。
読んでいるのはこれです

Machine Learning: An Algorithmic Perspective, Second Edition (Chapman & Hall/Crc Machine Learning & Pattern Recognition)

Machine Learning: An Algorithmic Perspective, Second Edition (Chapman & Hall/Crc Machine Learning & Pattern Recognition)

例によってほぼ自分用なので参考にはならないかもです。

3.5 Linear Regression

回帰とは、連続値を持つデータに対して、それをうまくできる関数を求めることである。下の図のように、与えられた黒い点から関数(この場合は直線)を求め、未知のデータである白い点の値を推定することができる。

f:id:may46onez:20151221230909p:plain

クラス分類の問題は、各クラスにindicator variableという整数を割り当て、出力から適切な閾値を選択すれば回帰として扱うことができる。
線形関数の式は {y = \sum^M_{i=0}\beta_i x_i}と表せる。{\beta}は関数を決定するパラメータである。線形回帰で一般的な手法として、関数とデータの値の二乗誤差を最小化することを考える。式は式は以下で与えられる。

 { \displaystyle
\sum^N_{j=0} \left( t_j - \sum^M_{i=0}\beta_i x_{ij} \right)^2
}

これを行列の形で表すと

 { \displaystyle
(\mathbf{t}-\mathbf{X}\beta)^T(\mathbf{t}-\mathbf{X}\beta)
}

となる。{\mathbf{t}}は目標値のベクトル、{ \mathbf{X} } は入力とバイアスを合わせた行列である。
これを {\beta}について微分して最小値をとる {\beta}を求めると、

 { \displaystyle
\beta = (\mathbf{X}^T \mathbf{X})^{-1} \mathbf{X}^T \mathbf{t}
}

となるので、この値を使って回帰を行う。
実装するとこんな感じ↓

#### linreg.py ####

import numpy as np

def linreg(inputs,targets):

	inputs = np.concatenate((inputs,-np.ones((np.shape(inputs)[0],1))),axis=1)
	beta = np.dot(np.dot(np.linalg.inv(np.dot(np.transpose(inputs),inputs)),np.transpose(inputs)),targets)

	outputs = np.dot(inputs,beta)
	#print shape(beta)
	#print outputs
	return beta

inputの値から上の式通りに {\beta}を求め、パーセプトロンと同様な方法で出力を求める。


ANDとORとXORについて実際にやってみる。
コードは以下

#### linreg_logic_eg.py ####

import numpy as np
import linreg

inputs = np.array([[0,0],[0,1],[1,0],[1,1]])
testin = np.concatenate((inputs,-np.ones((np.shape(inputs)[0],1))),axis=1)

# AND data
ANDtargets = np.array([[0],[0],[0],[1]])
# OR data
ORtargets = np.array([[0],[1],[1],[1]])
# XOR data
XORtargets = np.array([[0],[1],[1],[0]])

print "AND data"
ANDbeta = linreg.linreg(inputs,ANDtargets)
ANDout = np.dot(testin,ANDbeta)
print ANDout

print "OR data"
ORbeta = linreg.linreg(inputs,ORtargets)
ORout = np.dot(testin,ORbeta)
print ORout

print "XOR data"
XORbeta = linreg.linreg(inputs,XORtargets)
XORout = np.dot(testin,XORbeta)
print XORout

実行結果↓

f:id:may46onez:20151221230921p:plain

図に書いてある通り、ANDとORは閾値を0.5として二値に直すと、うまく分離できていることがわかる。ただしXORについてはパーセプトロンの場合と同様に線形回帰でも解けない。
以下からは、理論的にはあらゆるモデルを表現できる多層パーセプトロン(Multi-layer Perceptron)を説明する。

chapter4 The Multi-layer Perceptron

f:id:may46onez:20151221233452p:plain

4.1 Going Forwards

Multi-layer Perceptron(以下MLP)では学習は2ステップに分けられる。初めの一つがこれ。
入力層から普通に順方向に伝搬していき、出力層で誤差関数を求める。
これを使って次のステップに移る。

4.2 Going Backwards

誤差を使って重みを更新していきたいが、パーセプトロンの時と違い、どの重みを更新すべきかわからない。そこで誤差を出力層から逆方向に伝搬していき、適切な重みを調節するのが誤差逆伝搬法である。

そのためにはまず、誤差関数を最小化することを考える。ただし誤差関数の大域的な最小値を見つけるのは不可能なので、ある初期値から勾配方向に少しずつ重みを更新し、極小値を求めることになる。イメージは以下。
f:id:may46onez:20151222002306p:plain

勾配を求めるには微分する必要があるが、パーセプトロンのような単純な閾値処理のような活性化関数では微分不可能なため、連続値をとるシグモイド関数を使うことにする。
シグモイド関数の式は
{\displaystyle
g(h) = \frac{1}{1+exp(-\beta h)}
}
多くの場合{\beta=1}とかだと思う。

誤差関数は以下で定義する。

{\displaystyle
E(t,y) = \frac{1}{2} \sum^N_{k=1}(y_k-t_k)^2
}

ネットワークと添え字が下図のようにあった時のアルゴリズムを書いてく
f:id:may46onez:20151222005905p:plain
・Forwards phase

{\displaystyle
h_\zeta = \sum^L_{i=0}x_iv_{i\zeta} \ \ \ \ \ , \ \ \ \ \ a_\zeta = g(h_\zeta)=\frac{1}{1+exp(-\beta h_\zeta)}
}

{\displaystyle
h_\kappa = \sum^M_{j=0}a_jw_{j\kappa} \ \ \ \ \ , \ \ \ \ \ y_\kappa = g(h_\kappa)=\frac{1}{1+exp(-\beta h_\kappa)}
}


・Backwards phase

{\displaystyle
E(t,y) = \frac{1}{2}\sum^N_{k=1}(y_k-t_k)^2
}

{\displaystyle
w_{\zeta \kappa} \leftarrow w_{\zeta \kappa} - \eta \frac{\partial E}{\partial w_{\zeta \kappa}}
}

{\displaystyle
v_\iota \leftarrow v_\iota - \eta \frac{\partial E}{\partial v_\iota}
}

ここでL, M, Nはそれぞれの層のユニット数である。


とりあえずここまで。
次は誤差逆伝搬法の計算とMLPの実装。