はじめに
この実験では、RBFSampler と Nystroem を使って RBF カーネルの特徴マップを近似することを示します。これにより、手書き数字データセットで SVM を使った分類において、RBF カーネルの特徴マップを近似します。元の空間での線形 SVM、近似マッピングを使った線形 SVM、およびカーネル化 SVM の結果を比較します。近似マッピングについて、さまざまな数のモンテカルロサンプリング(ランダムフーリエ特徴を使う RBFSampler の場合)と訓練セットの異なるサイズのサブセット(Nystroem の場合)に対する計測時間と精度を示します。
VM のヒント
VM の起動が完了したら、左上隅をクリックしてノートブックタブに切り替え、Jupyter Notebook を使って練習しましょう。
時々、Jupyter Notebook が読み込み終了するまで数秒待つ必要があります。Jupyter Notebook の制限により、操作の検証を自動化することはできません。
学習中に問題に遭遇した場合は、Labby にお問い合わせください。セッション終了後にフィードバックを提供してください。すぐに問題を解決いたします。
Python パッケージとデータセットのインポート、データセットの読み込み
## 標準的な科学的 Python のインポート
import matplotlib.pyplot as plt
import numpy as np
from time import time
## データセット、分類器、および性能指標をインポート
from sklearn import datasets, svm, pipeline
from sklearn.kernel_approximation import RBFSampler, Nystroem
from sklearn.decomposition import PCA
## 手書き数字データセット
digits = datasets.load_digits(n_class=9)
計測時間と精度のプロット
## このデータに分類器を適用するには、画像をフラット化して
## データを (サンプル数,特徴量) の行列に変換する必要があります。
n_samples = len(digits.data)
data = digits.data / 16.0
data -= data.mean(axis=0)
## 最初の半分の手書き数字で学習します
data_train, targets_train = (data[: n_samples // 2], digits.target[: n_samples // 2])
## 次に、後半の手書き数字の値を予測します:
data_test, targets_test = (data[n_samples // 2 :], digits.target[n_samples // 2 :])
## 分類器を作成します:サポートベクトル分類器
kernel_svm = svm.SVC(gamma=0.2)
linear_svm = svm.LinearSVC(dual="auto")
## カーネル近似と線形 SVM からパイプラインを作成します
feature_map_fourier = RBFSampler(gamma=0.2, random_state=1)
feature_map_nystroem = Nystroem(gamma=0.2, random_state=1)
fourier_approx_svm = pipeline.Pipeline([
("feature_map", feature_map_fourier),
("svm", svm.LinearSVC(dual="auto"))
])
nystroem_approx_svm = pipeline.Pipeline([
("feature_map", feature_map_nystroem),
("svm", svm.LinearSVC(dual="auto"))
])
## 線形およびカーネル SVM を使って学習と予測を行います:
kernel_svm_time = time()
kernel_svm.fit(data_train, targets_train)
kernel_svm_score = kernel_svm.score(data_test, targets_test)
kernel_svm_time = time() - kernel_svm_time
linear_svm_time = time()
linear_svm.fit(data_train, targets_train)
linear_svm_score = linear_svm.score(data_test, targets_test)
linear_svm_time = time() - linear_svm_time
sample_sizes = 30 * np.arange(1, 10)
fourier_scores = []
nystroem_scores = []
fourier_times = []
nystroem_times = []
for D in sample_sizes:
fourier_approx_svm.set_params(feature_map__n_components=D)
nystroem_approx_svm.set_params(feature_map__n_components=D)
start = time()
nystroem_approx_svm.fit(data_train, targets_train)
nystroem_times.append(time() - start)
start = time()
fourier_approx_svm.fit(data_train, targets_train)
fourier_times.append(time() - start)
fourier_score = fourier_approx_svm.score(data_test, targets_test)
nystroem_score = nystroem_approx_svm.score(data_test, targets_test)
nystroem_scores.append(nystroem_score)
fourier_scores.append(fourier_score)
## 結果をプロットします:
plt.figure(figsize=(16, 4))
accuracy = plt.subplot(121)
## 計測時間用の 2 番目の y 軸
timescale = plt.subplot(122)
accuracy.plot(sample_sizes, nystroem_scores, label="Nystroem 近似カーネル")
timescale.plot(sample_sizes, nystroem_times, "--", label="Nystroem 近似カーネル")
accuracy.plot(sample_sizes, fourier_scores, label="Fourier 近似カーネル")
timescale.plot(sample_sizes, fourier_times, "--", label="Fourier 近似カーネル")
## 正確な RBF と線形カーネル用の水平線:
accuracy.plot([sample_sizes[0], sample_sizes[-1]], [linear_svm_score, linear_svm_score], label="線形 SVM")
timescale.plot([sample_sizes[0], sample_sizes[-1]], [linear_svm_time, linear_svm_time], "--", label="線形 SVM")
accuracy.plot([sample_sizes[0], sample_sizes[-1]], [kernel_svm_score, kernel_svm_score], label="RBF SVM")
timescale.plot([sample_sizes[0], sample_sizes[-1]], [kernel_svm_time, kernel_svm_time], "--", label="RBF SVM")
## データセット次元 = 64 の垂直線
accuracy.plot([64, 64], [0.7, 1], label="n_features")
## 凡例とラベル
accuracy.set_title("分類精度")
timescale.set_title("学習時間")
accuracy.set_xlim(sample_sizes[0], sample_sizes[-1])
accuracy.set_xticks(())
accuracy.set_ylim(np.min(fourier_scores), 1)
timescale.set_xlabel("サンプリングステップ = 変換された特徴次元")
accuracy.set_ylabel("分類精度")
timescale.set_ylabel("秒単位の学習時間")
accuracy.legend(loc="best")
timescale.legend(loc="best")
plt.tight_layout()
plt.show()
RBF カーネル SVM と線形 SVM の決定面
## 決定面を可視化します。データセットの最初の 2 つの主成分に射影します
pca = PCA(n_components=8).fit(data_train)
X = pca.transform(data_train)
## 最初の 2 つの主成分に沿ってグリッドを生成します
multiples = np.arange(-2, 2, 0.1)
## 最初の成分に沿ったステップ
first = multiples[:, np.newaxis] * pca.components_[0, :]
## 2 番目の成分に沿ったステップ
second = multiples[:, np.newaxis] * pca.components_[1, :]
## 結合
grid = first[np.newaxis, :, :] + second[:, np.newaxis, :]
flat_grid = grid.reshape(-1, data.shape[1])
## プロットのタイトル
titles = [
"rbf カーネルを持つ SVC",
"Fourier rbf 特徴マップを持つ SVC(線形カーネル)\nn_components=100",
"Nystroem rbf 特徴マップを持つ SVC(線形カーネル)\nn_components=100",
]
plt.figure(figsize=(18, 7.5))
plt.rcParams.update({"font.size": 14})
## 予測とプロット
for i, clf in enumerate((kernel_svm, nystroem_approx_svm, fourier_approx_svm)):
## 決定境界をプロットします。そのために、メッシュ [x_min, x_max]x[y_min, y_max] 内の各点に色を割り当てます。
plt.subplot(1, 3, i + 1)
Z = clf.predict(flat_grid)
## 結果をカラープロットに入れます
Z = Z.reshape(grid.shape[:-1])
levels = np.arange(10)
lv_eps = 0.01 ## 計算された等高線レベルから色へのマッピングを調整します。
plt.contourf(
multiples,
multiples,
Z,
levels=levels - lv_eps,
cmap=plt.cm.tab10,
vmin=0,
vmax=10,
alpha=0.7,
)
plt.axis("off")
## 訓練ポイントもプロットします
plt.scatter(
X[:, 0],
X[:, 1],
c=targets_train,
cmap=plt.cm.tab10,
edgecolors=(0, 0, 0),
vmin=0,
vmax=10,
)
plt.title(titles[i])
plt.tight_layout()
plt.show()
まとめ
この実験では、RBFSampler と Nystroem を使って RBF カーネルの特徴マップを近似することを示しました。これにより、手書き数字データセットで SVM を使った分類において、RBF カーネルの特徴マップを近似します。元の空間での線形 SVM、近似マッピングを使った線形 SVM、およびカーネル化 SVM の結果を比較しました。近似マッピングについて、さまざまな数のモンテカルロサンプリング(ランダムフーリエ特徴を使う RBFSampler の場合)と訓練セットの異なるサイズのサブセット(Nystroem の場合)に対する計測時間と精度を示しました。最後に、分類器の決定面をデータの最初の 2 つの主成分に射影して可視化しました。