こんにちは!ぼりたそです!
今回はガウス過程回帰で登場する「カーネル」について初心者の方にもわかりやすく説明していきたいと思います。
ざっくりとした説明ですので、あまり身構えずにご覧になっていただければと思います。
この記事は以下のポイントでまとめています。
それでは詳しく説明していきます。
カーネルとは
それでは早速カーネルとは何なのか?について説明していきます。
ガウス過程回帰やサポートベクターなどで登場するカーネルとはデータポイント間がどれだけ似ているかを評価する指標です。
もう少しわかりやすく例を使って説明していきます。
例えば上のように丸、三角、四角の図形が並んでいたとします。
この図形の中で似たもの同士をまとめていくつかのグループに分けてくださいと言われたら、あなたはどのようにグルーピングするでしょうか?
恐らく、多くの方は下の2パターンの分け方をするのではないでしょうか?
一つは色が同じであるグループとして黒と赤の図形で分けるパターン
二つ目は形が同じであるグループとして丸、三角、四角で分けるパターン
どちらも妥当なグルーピングですよね。違うのは「色」か「形」どちらの指標を使ったかと言うことだけです。
このグルーピングする際に使った「色」や「形」といった指標こそがカーネルなのです。
ガウス過程回帰を実行する際にもデータ間の類似度を評価するためにカーネルを使用しますが、どの指標で似ていると判断するかはカーネルによって異なります。
例えば、データ間のユークリッド距離の近さで判断するカーネルもあれば、周期性や内積の大きさで判断するカーネルもあります。
カーネルの種類と特徴
カーネルとは何なのか?と言うことはなんとなく理解いただけたのではないでしょうか?
ここからはカーネルの種類とその特徴について説明していきます。
今回は広く知られているカーネルとして以下の6つを紹介します。
- ガウスカーネル(RBF kernel)
- Matern カーネル(Matern kernel)
- 周期カーネル(Periodic kernel)
- 線形カーネル(Linear kernel)
- 多項式カーネル(Polynomial kernel)
- 指数カーネル()
ガウシアンカーネル(RBF kernel)
$$K(x, x’) = \exp\left(-\frac{|x – x’|^2}{2\sigma^2}\right) $$
ガウスカーネルは上の数式で表されるカーネルです。
連続的な関数に使用され、無限次元の特徴空間に写像できます。データ間の類似性はガウス分布で評価し、滑らかな関数をモデル化します。
ハイパーパラメータは $\sigma$ であり、データ間の類似性を評価する際に、どれだけ遠いデータを類似とみなすかを調整します。
$\sigma$ が大きい場合、広い範囲のデータポイントを類似とみなします。$\sigma$ が小さい場合、近いデータポイントのみを類似とみなします。
ガウシアンカーネルを使用するメリット、デメリットは以下の通りです。
メリット
デメリット
実際にPythonにより二次元座標間についてガウシアンカーネルで計算してみましょう。
使用するコードは以下の通りです。
import numpy as np
from sklearn.metrics.pairwise import rbf_kernel
# 二次元座標の例
coords = np.array([[0, 0], [1, 1], [2, 2], [3, 3]])
# ガウシアンカーネルのパラメータ(例)
gamma = 1.0
# ガウシアンカーネルを計算する関数
def gaussian_kernel(coord1, coord2):
return np.exp(-gamma * np.linalg.norm(coord1 - coord2) ** 2)
# 二次元座標のペアの距離を計算
distances = np.zeros((len(coords), len(coords)))
for i in range(len(coords)):
for j in range(len(coords)):
distances[i, j] = np.linalg.norm(coords[i] - coords[j])
# ガウシアンカーネルを計算
gaussian_kernel_matrix = rbf_kernel(coords, gamma=gamma)
# 計算結果を出力
print("Distance Matrix:")
print(distances)
print("\nGaussian Kernel Matrix:")
print(gaussian_kernel_matrix)
'''
Distance Matrix:
[[0. 1.41421356 2.82842712 4.24264069]
[1.41421356 0. 1.41421356 2.82842712]
[2.82842712 1.41421356 0. 1.41421356]
[4.24264069 2.82842712 1.41421356 0. ]]
Gaussian Kernel Matrix:
[[1.00000000e+00 1.35335283e-01 3.35462628e-04 1.52299797e-08]
[1.35335283e-01 1.00000000e+00 1.35335283e-01 3.35462628e-04]
[3.35462628e-04 1.35335283e-01 1.00000000e+00 1.35335283e-01]
[1.52299797e-08 3.35462628e-04 1.35335283e-01 1.00000000e+00]]
'''
今回、[[0, 0], [1, 1], [2, 2], [3, 3]]の四つの座標についてガウシアンカーネルを計算しました。ハイパーパラメータ $\sigma$ は1.0で設定しています。
計算した結果はGaussian Kernel Matrixとして4×4のマトリクスとして出力されています。1列目に注目すると[0,0]に対して[1, 1], [2, 2], [3, 3]となるにつれて値が小さくなっていることが分かります。
この結果から遠くの座標になるほど値が小さくなりデータは類似していないということになりますね。
Matern カーネル(Matern kernel)
$$K(x, x’) = \frac{2^{1-\nu}}{\Gamma(\nu)} \left(\frac{\sqrt{2\nu}|x – x’|}{\rho}\right)^\nu K_\nu\left(\frac{\sqrt{2\nu}|x – x’|}{\rho}\right)$$
Maternカーネルはガウスカーネルを一般化したもので、平滑度を調整するハイパーパラメータ ν を持っています。そのため、高次元の特徴空間での使用に適しています。
ハイパーパラメータは $\nu$ , $\rho$ です。
$\nu$ はカーネルの滑らかさを調整しており、小さい値ではよりギザギザした関数を生成し、大きい値ではより滑らかな関数を生成します。
$\rho$ は特徴のスケールを調整し、データポイント間の距離の尺度を調整しており、ガウシアンカーネルと同じようなパラメータとなります。
Maternカーネルを使用するメリットとデメリットは以下の通りです。
メリット
デメリット
MaternカーネルについてもPythonにて二次元座標間の計算を実行してみました。
実行したコードは以下の通りです。
import numpy as np
from sklearn.metrics.pairwise import pairwise_kernels
# 二次元座標の例
coords = np.array([[0, 0], [1, 1], [2, 2], [3, 3]])
# Matérnカーネルのパラメータ(νは平滑化パラメータ)
nu = 1.5
length_scale = 1.0
# Matérnカーネルを計算する関数
def matern_kernel(coord1, coord2):
distance = np.linalg.norm(coord1 - coord2)
sqrt_3_nu_distance = np.sqrt(3 * nu) * distance / length_scale
return (1. + sqrt_3_nu_distance) * np.exp(-sqrt_3_nu_distance)
# 二次元座標のペアの距離を計算
distances = np.zeros((len(coords), len(coords)))
for i in range(len(coords)):
for j in range(len(coords)):
distances[i, j] = np.linalg.norm(coords[i] - coords[j])
# Matérnカーネルを計算
matern_kernel_matrix = pairwise_kernels(coords, metric=matern_kernel)
# 計算結果を出力
print("Distance Matrix:")
print(distances)
print("\nMatérn Kernel Matrix:")
print(matern_kernel_matrix)
'''
Distance Matrix:
[[0. 1.41421356 2.82842712 4.24264069]
[1.41421356 0. 1.41421356 2.82842712]
[2.82842712 1.41421356 0. 1.41421356]
[4.24264069 2.82842712 1.41421356 0. ]]
Matérn Kernel Matrix:
[[1. 0.19914827 0.01735127 0.0012341 ]
[0.19914827 1. 0.19914827 0.01735127]
[0.01735127 0.19914827 1. 0.19914827]
[0.0012341 0.01735127 0.19914827 1. ]]
'''
ハイパーパラメータである $\nu$ と $\rho$ はそれぞれ1.5, 1.0にて設定しています。
結果はMatérn Kernel Matrixとして4×4のマトリクスで出力されています。
一列目に注目すると[0,0]に対して[1, 1], [2, 2], [3, 3]となるにつれて値が小さくなっていることが分かります。ガウシアンカーネルと同様に座標が遠くなることでデータ間の類似度が低下することを意味します。
周期カーネル(Periodic kernel)
$$ K(x, x’) = \exp\left(-\frac{2\sin^2(\pi|x – x’|/p)}{\lambda^2}\right) $$
周期カーネルは周期的なデータパターンをモデル化するために使用されます。サイン関数を使用してデータポイント間の周期的な類似性を評価します。
ハイパーパラメータは $p$ , $\lambda$ です。
$p$ は周期性の周期を表し、どのくらいの間隔でデータが繰り返されるかを調整します。
$\lambda$ は周期性のスケールを調整し、周期的な変動の広がりを調整します。
周期カーネルを使用するメリット、デメリットは以下の通りです。
メリット
デメリット
周期カーネルについてもPtyhonにて計算を実行してみました。
計算に使用したのは以下のように周期性のある座標データ10点を使用しています。
実際に使用したコードは以下の通りです。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics.pairwise import pairwise_kernels
# 周期性を持つデータを生成する関数
def generate_periodic_data(num_points, period=10, amplitude=1, noise=0.1):
x = np.linspace(0, period, num_points)
y = amplitude * np.sin(2 * np.pi * x / period) + np.random.normal(0, noise, num_points)
return x, y
# 周期性を持つデータの生成
num_points = 10
period = 10
amplitude = 1
noise = 0.1
x, y = generate_periodic_data(num_points, period, amplitude, noise)
# データをプロット
plt.figure(figsize=(10, 6))
plt.scatter(x, y, color='blue', label='Data')
plt.title('Periodic Data')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.grid(True)
plt.show()
# 周期カーネルの計算
def periodic_kernel(x, y, period=10, gamma=1.0):
return np.exp(-2 * (np.sin(np.pi * np.abs(x - y) / period) ** 2) / gamma ** 2)
# 周期カーネルを計算
periodic_kernel_matrix = pairwise_kernels(x.reshape(-1, 1), metric=periodic_kernel)
# 計算結果を出力
print("Periodic Kernel Matrix:")
print(periodic_kernel_matrix)
'''
Periodic Kernel Matrix:
[[1. 0.79139699 0.43764298 0.22313016 0.14374813 0.14374813
0.22313016 0.43764298 0.79139699 1. ]
[0.79139699 1. 0.79139699 0.43764298 0.22313016 0.14374813
0.14374813 0.22313016 0.43764298 0.79139699]
[0.43764298 0.79139699 1. 0.79139699 0.43764298 0.22313016
0.14374813 0.14374813 0.22313016 0.43764298]
[0.22313016 0.43764298 0.79139699 1. 0.79139699 0.43764298
0.22313016 0.14374813 0.14374813 0.22313016]
[0.14374813 0.22313016 0.43764298 0.79139699 1. 0.79139699
0.43764298 0.22313016 0.14374813 0.14374813]
[0.14374813 0.14374813 0.22313016 0.43764298 0.79139699 1.
0.79139699 0.43764298 0.22313016 0.14374813]
[0.22313016 0.14374813 0.14374813 0.22313016 0.43764298 0.79139699
1. 0.79139699 0.43764298 0.22313016]
[0.43764298 0.22313016 0.14374813 0.14374813 0.22313016 0.43764298
0.79139699 1. 0.79139699 0.43764298]
[0.79139699 0.43764298 0.22313016 0.14374813 0.14374813 0.22313016
0.43764298 0.79139699 1. 0.79139699]
[1. 0.79139699 0.43764298 0.22313016 0.14374813 0.14374813
0.22313016 0.43764298 0.79139699 1. ]]
'''
周期カーネルの結果はPeriodic Kernel Matrixとして10×10のマトリクスとして出力されています。
分かりにくくて申し訳ないのですが、マトリクスの1行目に注目すると最初の座標データから最終的に1周期に当たる座標が1.0となっており、周期性によるデータの類似度を反映できていることがわかると思います。
線形カーネル(Linear kernel)
$$ K(x, x’) = x \cdot x’ $$
線形カーネルは内積に基づいて類似性を評価し、直線的な関係をモデル化します。特徴間の関係性を単純に評価します。
内積に基づく単純なカーネルであり、ハイパーパラメータは必要ありません。
線形カーネルを使用するメリット、デメリットは以下の通りです。
メリット
デメリット
実際に線形カーネルについてPythonにより二次元座標間の計算を実行してみました。
使用したコードは以下の通りです。
import numpy as np
from sklearn.metrics.pairwise import linear_kernel
# 二次元座標の例
coords = np.array([[1, 1], [2, 2], [3, 3], [4, 4]])
# 線形カーネルを計算する関数
def linear_kernel_custom(coord1, coord2):
return np.dot(coord1, coord2)
# 二次元座標のペアの内積を計算
dot_products = np.zeros((len(coords), len(coords)))
for i in range(len(coords)):
for j in range(len(coords)):
dot_products[i, j] = np.dot(coords[i], coords[j])
# 線形カーネルを計算
linear_kernel_matrix = linear_kernel(coords)
# 計算結果を出力
print("Dot Product Matrix:")
print(dot_products)
print("\nLinear Kernel Matrix:")
print(linear_kernel_matrix)
'''
Dot Product Matrix:
[[ 2. 4. 6. 8.]
[ 4. 8. 12. 16.]
[ 6. 12. 18. 24.]
[ 8. 16. 24. 32.]]
Linear Kernel Matrix:
[[ 2. 4. 6. 8.]
[ 4. 8. 12. 16.]
[ 6. 12. 18. 24.]
[ 8. 16. 24. 32.]]
'''
線形カーネルの計算結果はLinear Kernel Matrixとして4×4のマトリクスとして出力しています。
線形カーネルは単純な内積を計算しているので必ずしも座標が遠くなることで値が小さくなることはありません。
座標間のベクトルがなす角度が小さいほど値が大きくなり、データが類似していることになります。
多項式カーネル(Polynomial kernel)
$$ K(x, x’) = (x \cdot x’ + c)^d $$
多項式カーネルは内積の多項式によって類似性を評価し、高次元の非線形関係をモデル化します。
また、特定の次数の多項式関数を表現します。
ハイパーパラメータは $d$ , $c$ です。
$d$ は多項式の次数を制御し、どれだけ複雑な多項式を使用するかを調整します。
$c$ はオフセットを表し、内積にオフセットを加えて非対称性を持たせることができます。
多項式カーネルを使用するメリット、デメリットは以下の通りです。
メリット
デメリット
多項式カーネルについてもPythonにより二次元座標間の計算を実行しました。
使用したコードは以下の通りです。
import numpy as np
from sklearn.metrics.pairwise import polynomial_kernel
# 二次元座標の例
coords = np.array([[1, 1], [2, 2], [3, 3], [4, 4]])
# 多項式カーネルのパラメータ(degreeは次数、coef0は定数項)
degree = 2
coef0 = 1.0
# 多項式カーネルを計算する関数
def polynomial_kernel_custom(coord1, coord2):
return (np.dot(coord1, coord2) + coef0) ** degree
# 二次元座標のペアの内積を計算
dot_products = np.zeros((len(coords), len(coords)))
for i in range(len(coords)):
for j in range(len(coords)):
dot_products[i, j] = np.dot(coords[i], coords[j])
# 多項式カーネルを計算
polynomial_kernel_matrix = polynomial_kernel(coords, degree=degree, coef0=coef0)
# 計算結果を出力
print("Dot Product Matrix:")
print(dot_products)
print("\nPolynomial Kernel Matrix:")
print(polynomial_kernel_matrix)
'''
Dot Product Matrix:
[[ 2. 4. 6. 8.]
[ 4. 8. 12. 16.]
[ 6. 12. 18. 24.]
[ 8. 16. 24. 32.]]
Polynomial Kernel Matrix:
[[ 4. 9. 16. 25.]
[ 9. 25. 49. 81.]
[ 16. 49. 100. 169.]
[ 25. 81. 169. 289.]]
'''
ハイパーパラメータである$d$ と $c$はそれぞれ2, 1.0となっています。
結果はPolynomial Kernel Matrixとして4×4のマトリクスとして出力しています。
多項式カーネルについても線形カーネルと同様に内積を計算しているので必ずしも座標が遠くなることで値が小さくなることはありません。
座標間のベクトルがなす角度が小さいほど値が大きくなり、データが類似していることになります。
指数カーネル(Exponential kernel)
$$ K(x, x’) = \exp\left(-\frac{|x – x’|}{2\sigma^2}\right) $$
指数カーネルはデータ間のユークリッド距離を単純な指数関数に適用して評価します。
ガウシアンカーネルといていますがユークリッド距離の項が二乗されていません。
ハイパーパラメータは$\sigma$ です。
$\sigma$ が大きい場合、広い範囲のデータポイントを類似とみなします。$\sigma$ が小さい場合、近いデータポイントのみを類似とみなします。
指数カーネルを使用するメリット、デメリットは以下の通りです。
メリット
デメリット
指数カーネルについても実際にPythonにより二次元座標間の計算を実行しました。
使用したコードは以下の通りです。
import numpy as np
from sklearn.metrics.pairwise import pairwise_kernels
# 二次元座標の例
coords = np.array([[0, 0], [1, 1], [2, 2], [3, 3]])
# 指数カーネルのパラメータ(gammaはバンド幅)
gamma = 0.1
# 指数カーネルを計算する関数
def exponential_kernel(coord1, coord2):
return np.exp(-gamma * np.linalg.norm(coord1 - coord2))
# 指数カーネルを計算
exponential_kernel_matrix = pairwise_kernels(coords, metric=exponential_kernel)
# 計算結果を出力
print("Exponential Kernel Matrix:")
print(exponential_kernel_matrix)
'''
Exponential Kernel Matrix:
[[1. 0.86812345 0.75363832 0.65425109]
[0.86812345 1. 0.86812345 0.75363832]
[0.75363832 0.86812345 1. 0.86812345]
[0.65425109 0.75363832 0.86812345 1. ]]
'''
ハイパーパラメータである$\sigma$ は0.1で設定しています。
結果はExponential Kernel Matrixとして4×4のマトリクスとして出力しています。
指数カーネルについては座標間の距離をベースとしているので、座標が遠くなれば値は小さくなり、データ間の類似度が低下することを意味しています。
オススメの書籍
最後にガウス過程回帰やカーネルついてもっと知りたい方に向けてオススメの書籍をご紹介します。
以下に紹介する「Pythonで学ぶ実験計画法入門 ベイズ最適化によるデータ解析」では初心者にも非常にわかりやすいようにベイズ最適化について説明されています。
もちろん、ガウス過程回帰やカーネルについても書かれており、実際にGithubからPythonコードとデータセットを取得できるので、自分で実践しながらベイズ最適化について勉強することができます。
記載されているコードの中にはカーネルごとに予測精度を計算し、最適なカーネルを用いてベイズ最適化できるようなものも収載されています。
また、ベイズ最適化以外についても機械学習の手法が記載されているので、ご興味のある方はぜひ購入いただければと思います。
ベイズ最適化のオススメ参考書については以下の記事でもまとめていますので、興味のある方はご参照いただければと思います。
終わりに
以上がカーネルについてとそれぞれのカーネルの特徴に関する説明になります。色々なカーネルの種類があるので、交差検証などでそのモデルに適したカーネルを選択する必要がありそうですね。
カーネルの数式まで詳細に理解するかはさておき、カーネルがどの指標で類似度を評価しているかはしっかりと把握する必要がありますね。