u++の備忘録

RBFカーネルのハイパーパラメータは何物か?

はじめに

今回の記事は、下記の質問に答えるものです。

f:id:upura:20180121220647p:plain

RBFカーネルとは?

RBFカーネル(Radial basis function kernel)は下記のように定義される関数のことです。

 K(x, x')=\exp(-\gamma||x-x'||^2)
ただし ||x-x'||^2ユークリッド空間上の距離の2乗、 \gamma=-\frac{1}{2\sigma^2}です。

RBFカーネルカーネル関数の一つで、機械学習の文脈では、サポートベクターマシン(SVM)など内積のみを扱う線形のアルゴリズム非線形化する際に登場します*1

RBFカーネルを用いたSVM

RBFカーネルのハイパーパラメータが何物かを知るには、実際にRBFカーネルを用いたSVMが(RBFカーネルの)ハイパーパラメータの違いでどのような挙動を示すかを見るのが分かりやすいかと思います。

そしてscikit-learnの公式ページに、ズバリそのものの項目があるので、該当部分を引用します。

RBF SVM parameters — scikit-learn 0.19.1 documentation

Intuitively, the gamma parameter defines how far the influence of a single training example reaches, with low values meaning ‘far’ and high values meaning ‘close’. The gamma parameters can be seen as the inverse of the radius of influence of samples selected by the model as support vectors.

日本語訳:
直感的には、ハイパーパラメータ \gammaは「一つの訓練データが与える影響の範囲」を意味します。小さいほど「遠く」、大きいほど「近く」まで影響します。ハイパーパラメータ \gammaはサポートベクトルモデルとして選ばれた訓練データの影響範囲の半径の逆数(インバース)としても見なすことができます。

つまり、ハイパーパラメータ \gammaが小さいほど個々の訓練データが「存在を主張」し、大きいほど「おとなしく」なります。そのためハイパーパラメータ \gammaが小さい場合には青・赤の訓練データがお互いに存在を大きく主張するので、互いの境界で識別曲線が引かれます。一方で大きい場合には青・赤の訓練データがお互いに自分の周りしか存在を主張しないため、歪な形の識別曲線が引かれるといった具合です。

f:id:upura:20180121230034p:plain

上の画像を生成したPythonコード

SVM(RBFカーネル)のハイパーパラメータを変えると何が起こるの?を参考に作成しました。

# -*- coding: utf-8 -*-
import numpy as np
from sklearn import svm, datasets
import matplotlib.pyplot as plt
from itertools import product

if __name__ == '__main__':
    iris = datasets.load_iris()
    #特徴量は最初の2つ, クラスラベルも最初の2つを使う
    X = iris.data[:100, :2]
    #特徴量にノイズを加える
    E = np.random.uniform(0, 1.0, size=np.shape(X))
    X += E
    y = iris.target[:100]
    #meshのステップサイズ
    h = 0.02
    #コストパラメータ
    Cs = [2 ** -5, 2 ** 15]
    #RBFカーネルのパラメータ
    gammas = [2 ** -9, 2 ** -6, 2** -3, 
              2 ** 3, 2 ** 6, 2 ** 9]

    svms = [svm.SVC(C=C, gamma=gamma).fit(X, y) for C, gamma in product(Cs, gammas)]
    titles = ["C: small, gamma: 2**-3", "C: small, gamma: 2**-2",
              "C: small, gamma: 2**-1", "C: small, gamma: 2**1",
              "C: small, gamma: 2**2", "C: small, gamma: 2**3",
              "C: large, gamma: 2**-3", "C: large, gamma: 2**-2",
              "C: large, gamma: 2**-1", "C: large, gamma: 2**1",
              "C: large, gamma: 2**2", "C: large, gamma: 2**3"]
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))

    for i, clf in enumerate(svms):
        plt.subplot(4, 3, i + 1)
        plt.subplots_adjust(wspace=0.4, hspace=1)
        Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
        Z = Z.reshape(xx.shape)
        plt.contourf(xx, yy, Z, cmap=plt.cm.Paired, alpha=0.8)
        plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired)
        plt.xlabel("Sepal length", fontsize=8)
        plt.ylabel("Sepal width", fontsize=8)
        plt.xlim(xx.min(), xx.max())
        plt.ylim(yy.min(), yy.max())
        plt.xticks(())
        plt.yticks(())
        plt.title(titles[i], fontsize=8)
    plt.show()

おわりに

質問に立ち返ると、RBFカーネルのハイパーパラメータ \gammaは「個々の訓練データをどれだけ重要視するか」の設定と捉えられそうです。訓練データからRBFカーネルを用いて分布を推定するという文脈では「(RBFカーネル)関数の広がり(やすさ)を制御する」というような解釈で間違っていないかと思います。

この辺りは大学/大学院できちんと習ったわけではなく独学なので、ビシバシご指摘いただけますと幸いです。

(技術的なことに限らず)質問募集

upura.sarahah.com