ガウス過程の実装②(動径基底関数カーネルを用いたガウス過程からのサンプリング_後編)|スクラッチ実装で理解する機械学習アルゴリズム #7

f:id:lib-arts:20190604133235p:plain

 

連載の経緯の詳細は#1でまとめましたが、本シリーズではあえてスクラッチ実装を元に機械学習アルゴリズムを実装していくことで、アルゴリズムの概要を掴んだり理論の流れを掴んだりできるようにできればと思います。

実装のほとんどが車輪の再発明に近くなりますが、ベーシックなアルゴリズムをあえて一から自分で追ってみるというのは引き出しを増やすという意味で非常に有意義です。
#2、#3、#4、#5では一般化線形モデル(GLM; Generalized Linear Model)の具体例としてロジスティック回帰やポアソン回帰に対しニュートンラプソン法や勾配法、MCMC法での実装を通して理解を深める手助けとしました。

一般化線形モデル(GLM)の理論と実装①【ロジスティック回帰_前編】|スクラッチ実装で理解する機械学習アルゴリズム #2 - lib-arts’s diary

一般化線形モデル(GLM)の理論と実装②【ロジスティック回帰_後編】|スクラッチ実装で理解する機械学習アルゴリズム #3 - lib-arts’s diary

一般化線形モデル(GLM)の理論と実装③【ポアソン回帰編】|スクラッチ実装で理解する機械学習アルゴリズム #4 - lib-arts’s diary

MCMC法(メトロポリス・ヘイスティングス法)による一般化モデルの最適化と実装|スクラッチ実装で理解する機械学習アルゴリズム #5 - lib-arts’s diary
#6以降では下記の本を最近読んでいて面白かったのでガウス過程について取り扱っていきます。

ガウス過程と機械学習 | 書籍情報 | 株式会社 講談社サイエンティフィク
#6では「動径基底関数カーネルを用いたガウス過程からのサンプリング」について行いました。
https://lib-arts.hatenablog.com/entry/ml_scratch6
#7では、#6の内容を元にサンプリングの区間や幅を変更するなどで考察を行っていきます。
以下目次になります。
 
1. サンプリングコードの書き換え
2. サンプリング区間の変更
3. サンプリングの幅の変更
4. まとめ

 

1. サンプリングコードの書き換え
まずは#6で実装したサンプリングコードの中で、共分散行列の計算の実装が実行にあたってのパラメータ変更の手間が効率的ではなかったので書き換えます。下記を実行してみてください。

import numpy as np
import matplotlib.pyplot as plt

theta = np.array([1,1])

def make_kernel(start_pos,end_pos,delta):

    x_ = np.arange(start_pos,end_pos,delta)
    res, _ = np.array(np.meshgrid(x_, x_))
    for i in range(res.shape[0]):
        res[:,i] = theta[0]*np.exp(-(res[:,i]-x_)**2/theta[1])
    return x_, res

x, K = make_kernel(1,5,1.)
print(K.shape)

plt.pcolor(K)
plt.show()

上記のように書くことで、共分散行列の計算をモジュール化することができました。また、共分散行列の値の確認も兼ねてヒートマップによる可視化も追加を行っています。こちらにより、Kの次元を増やしても視覚的に共分散行列の値を把握できるようになりました。実行結果は下記になります。

f:id:lib-arts:20190604133344p:plain
モジュール化は極力行わない方がサンプルコードとしては可読性が高くて良いので、この部分以外の実装は基本的にそのまま残しました。

 

2. サンプリング区間の変更
2節ではサンプリング区間の変更を行い、確認を行なっていければと思います。取り扱う間隔としては(1,2,3,4)(0,1,2,3,4,5,6,7,8,9)(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29)でサンプリングしてみます。それぞれサンプリング結果は以下のようになりました。
・1〜4

f:id:lib-arts:20190605163425p:plain
・0〜9

f:id:lib-arts:20190605163445p:plain

・0〜29

f:id:lib-arts:20190605163559p:plain
左側の図を確認することで元々のカーネル関数が距離に依存する数式となっていたため、違う区間に対しても同様の共分散行列となっているのがわかります。例えば1〜4の間も11〜14の間はどちらもそこだけ切り出せば同一の共分散行列となっています。
また、右側の図を確認することで、生成される確率過程について確認することができます。区間が1刻みでもなんとなく近くの値が相関しあって滑らかな直線になっていることが読み取れます。幅を変えたらより滑らかになるのではないかということで、3節では区間の幅を変えて結果を見比べてみたいと思います。

 

3. サンプリングの幅の変更
2節ではサンプリングの区間を変更して結果を比較しましたが、3節ではサンプリングの幅を変更して結果を比較していければと思います。間隔としては、0.5刻みの(1,1.5,2,2.5,3,3.5,4,4.5)と、0.2刻みの1,1.2,1.4,1.6,1.8,2,2.2,2.4,2.6,2.8,3,3.2,3.4,3.6,3.8,4,4.2,4.4,4.6,4.8)でサンプリングを行ってみました。(共分散行列の目盛りには誤りがあるので注意です)
・0.5刻み

f:id:lib-arts:20190605163925p:plain
・0.2刻み

f:id:lib-arts:20190605163944p:plain
上記を確認することで、刻み幅を小さくすることで関数がだんだん滑らかになっているというのがわかります。0.2刻みだとかなり関数が滑らかに見えたので、少々区間を広げて-1〜6の区間で関数をサンプリングしてみました。

f:id:lib-arts:20190605164002p:plain
ちなみにここで基本的に同じサンプルが得られている理由としては、結果の再現性を担保するためにnp.random.seedを用いて乱数の固定を行っているためです。np.random.seed(10)で固定を行っています。そのため、乱数のseed変えることで全く違ったサンプリングを得ることができます。

 

4. まとめ
#7では#6のコードを元に共分散行列の可視化、サンプリングの区間や幅の変更を通して考察を行いました。
#8ではカーネルのパラメータを変えたり違うカーネルを使ったりをすることでもう少しガウス過程について考察できればと思います。