覚え書きブログ

Pythonによる機械学習10(3/4)

<< Pythonによる機械学習10(2/4)

Pythonによる機械学習10(3/4)の目次】

非線形な関数の回帰

これまでは、入力 xと出力 yの関係が線形な場合の回帰の例を見てきまし。しかしながら、現実のデータがこのように都合よく線形な関数になっているとは限りません。そこで、ここからは入力と出力の関係が非線形な場合の回帰を考えていきます。まず、以下のようにregressionData.artificialメソッドを実行する際に「isNonlinear=True」を指定し、非線形なデータを生成してみましょう。

import regressionData as rg
myData = rg.artificial(200,100, dataType="1D", isNonlinear=True)
myData.plot()

f:id:hirotaka_hachiya:20180116210631p:plain

さて、これに対して線形モデルで回帰した結果は以下のような直線(赤)となるため、非線形な曲線を表現できていないことがわかります。
f:id:hirotaka_hachiya:20180116205229p:plain

カーネルモデルの導入

線形モデルを非線形な曲線でも回帰できるようにするために、非線形な表現力を持つカーネルモデルを導入します。
まず、任意の入力ベクトル \textbf{x}および N個の学習データ \textbf{x}^i非線形関数 \phi(\cdot)を用いて高次元空間 H写像します。
f:id:hirotaka_hachiya:20180110111319p:plain
そして、高次元ベクトル \phi(\textbf{x}) \phi(\textbf{x}^i)との内積 <\phi(\textbf{x}),\phi(\textbf{x}^i)>を計算し、モデルパラメータ w_iとの線形和を求めます。つまり、カーネルモデルでは、モデルパラメータ \textbf{W} N次元のベクトルとなっています。
f:id:hirotaka_hachiya:20180116234734p:plain

分類におけるカーネルモデルのイメージ

f:id:hirotaka_hachiya:20180110111345p:plain

カーネルトリックカーネル関数の例

超高次元(無限次元の場合もあり)空間 \mathcal{H}上での内積を計算するカーネル関数の実装は容易ではありません。カーネル関数を効率よく計算するために、以下の特性を持つ正定値カーネル関数 k_{+}(\textbf{x},\textbf{x}')を導入ます。
f:id:hirotaka_hachiya:20180110093930p:plain

正定値カーネル関数には以下のようなものがあります。
f:id:hirotaka_hachiya:20180110100624p:plain
これらの正定値カーネルにより、高次元空間上での内積の計算を、例えばガウスカーネル関数の計算に置き換えることができるため、非常に効率よく計算することができます。ただし、正定値カーネルを有効的に利用するためには、ハイパーパラメータをデータに合わせて調整する必要があるので注意しましょう。

演習4

ガウスカーネル関数の対称性と正定値性を、式の上で確認しましょう。
また、ガウスカーネル関数が、どのような写像関数 \phi(\textbf{x})内積に対応しているのか式の上で確認しましょう。

カーネルモデルの線形性

カーネルモデルは、入力 \textbf{x}に対しては非線形な関数になっていますが、モデルパラメータ \textbf{w}\textbf{b}に対しては線形性を維持しています。そのため、線形モデルと同様に最小二乗法を用いて解析的にモデルパラメータを最適化できるのが特徴となっています。
f:id:hirotaka_hachiya:20180110111410p:plain

演習5

2つのデータ集合間の全ての組み合わせのユークリッド距離の計算する関数calcDistを実装しましょう。

#------------------------------------
# 6) 2つのデータ集合間の全ての組み合わせの距離の計算
# x: 行列(次元 x データ数)
# z: 行列(次元 x データ数)
def calcDist(self,x,z):
	#【行列xのデータ点x1, x2, ..., xNと、行列zのデータ点z1, z2, ..., zMとの間のMxN個の距離を計算】
	return dist
#------------------------------------

※for文を用いずに行列演算のみで実装しましょう。
※ヒント:「次元xデータ数」の行列xとzとをそれぞれ、「xのデータ数 x zのデータ数 x 次元」の行列に変形することにより行列演算で実装できます。

演習6

ガウスカーネル関数を題材に、カーネル行列(グラム行列)を計算するメソッドlinearRegression.kernelを実装しましょう。

#------------------------------------
# 5) カーネルの計算
# x: カーネルを計算する対象の行列(次元 x データ数)
def kernel(self,x):
	#【self.xの各データ点xiと行列xの各データ点xjと間のカーネル値k(xi,xj)を各要素に持つグラム行列を計算】
	return K	
#------------------------------------
<span style="color: #ff0000">※コンストラクタ「__init__(self, x, y, kernelType="linear", kernelParam=1.0)」にて設定している2つのインスタンス変数self.kernelType(カーネルの種類)とself.kernelParam(ハイパーパラメータ)を利用して、カーネルの切り替えおよび計算を行うように実装しましょう。</span>

演習7

カーネルモデルのパラメータ \textbf{w}'を最適化するメソッドlinearRegression.trainMatKernelを実装しましょう。
※行列のランク落ちにより逆行列の計算が不安定になる場合があります。その場合は、以下のように行列の対角成分に小さな正の値\lambdaを加算してから、逆行列を計算しましょう。

 \Big(\mathbf{X}\mathbf{X}^\top + \lambda \mathbf{I}\Big)^{-1}
ここで、 \lambda \ge 0および I単位行列です。

ガウスカーネル回帰の結果例

 \lambda=0.01\sigma=1の場合】
f:id:hirotaka_hachiya:20180117011126p:plain
予測(赤い点)が、テストデータ(黄の点)に近く非線形な曲線をスムーズに近似できていることがわかります。

 \lambda=0.01\sigma=0.1の場合】
今度はガウスの幅を\sigma=0.1に設定して狭くしてみます。
f:id:hirotaka_hachiya:20180117011247p:plain
\sigma=1の時とくらべ、予測(赤い点)がガタガタになっていて、ところどころテストデータ(黄の点)から外れているのがわかります。

 \lambda=0.01\sigma=5の場合】
今度はガウスの幅を\sigma=05に設定して、広くしてみます。
f:id:hirotaka_hachiya:20180117011017p:plain
\sigma=1の時とくらべ、今度は予測(赤い点)がスムーズになりすぎて、テストデータ(黄の点)をよく近似できていないがわかります。

このように、カーネルモデルを用いた線形回帰により非線形な関数を回帰するためには、カーネルのハイパーパラメータをデータに合わせて調整する必要があることがわかります。

Pythonによる機械学習10(4/4) >>