洋食の日記

「た・である」調ではなく「です・ます」調で書きはじめれば良かったなと後悔してる人のブログです

Rumaleにカーネルリッジ回帰を追加した

はじめに

Rumaleのversion 0.13系では、固有値分解や逆行列計算といった、Numo::Linalgにある線形代数のテクニックを利用する機械学習アルゴリズムの実装を進めている。version 0.13.3では、カーネルリッジ回帰とカーネル主成分分析を追加した。

rumale | RubyGems.org | your community gem host

使い方

Rumaleは、gemコマンドでインストールできる。データセットの読み込みでred-datasetsを使用したいので、あわせてインストールする。

$ gem install rumale red-datasets-numo-narray

そして、Numo::Linalgをインストールする。Numo::LinalgはBLAS/LAPACK系のライブラリに依存する。別途OpenBLASなどをインストールする必要がある。

$ gem install numo-linalg

Boston Housingデータセットを利用して、カーネルリッジ回帰を試してみる。Boston Housingデータセットは、地域の住宅価格を、犯罪発生率や平均部屋数などから推定するタスクである。リッジ回帰・カーネルリッジ回帰で住宅価格を推定し、決定係数により評価を行う。ハイパーパラメータはそれらしい値をいれた(※カーネルリッジ回帰は正則化パラメータを調整したほうがよい)。

require 'rumale'
require 'numo/linalg/autoloader'
require 'datasets-numo-narray'

# データセットを読み込む.
datasets = Datasets::LIBSVM.new('housing').to_narray
values = Numo::DFloat.cast(datasets[true, 0])
samples = Numo::DFloat.cast(datasets[true, 1..-1])

# 訓練とテストに分割する.
ss = Rumale::ModelSelection::ShuffleSplit.new(n_splits: 1, test_size: 0.2, random_seed: 1)
train_ids, test_ids = ss.split(samples, values).first
train_s = samples[train_ids, true]
train_v = values[train_ids]
test_s = samples[test_ids, true]
test_v = values[test_ids]

# 特徴量を正規化する.
t = Rumale::Preprocessing::MinMaxScaler.new
train_s = t.fit_transform(train_s)
test_s = t.transform(test_s)

# リッジ回帰を学習し決定係数で評価する.
ridge = Rumale::LinearModel::Ridge.new(reg_param: 0.1, solver: 'svd')
ridge.fit(train_s, train_v)
score = ridge.score(test_s, test_v)
puts "linear ridge: #{score.round(4)}"

# カーネルリッジ回帰を学習し決定係数で評価する.
kridge = Rumale::KernelMachine::KernelRidge.new(reg_param: 0.1)
## 訓練データ間のRBFカーネル関数の値をもとめ訓練を行う.
gamma = 2.0
train_kernel_mat = Rumale::PairwiseMetric::rbf_kernel(train_s, nil, gamma)
kridge.fit(train_kernel_mat, train_v)
## テストデータと訓練データ間のRBFカーネル関数の値をもとめ決定係数を計算する.
test_kernel_mat = Rumale::PairwiseMetric.rbf_kernel(test_s, train_s, gamma)
score = kridge.score(test_kernel_mat, test_v)
puts "kernel ridge: #{score.round(4)}"

これを実行すると次のようになる。

linear ridge: 0.6443
kernel ridge: 0.8655

決定係数の値が大きいほどよい。カーネルリッジ回帰のほうが、Boston Housingデータセットに関しては、回帰の推定性能がリッジ回帰よりも優れていると思われる(上記スクリプトは、シンプルなホールドアウト検証になってるので、本当は交差検証をちゃんとしたほうが良い)。

おわりに

Rumaleにカーネルリッジ回帰を実装した。カーネル法は、データ数が十分にない場合などでは、まだまだ有効であると思われる。また、ニューラルネットワークがReLUやDropoutなどの学習方法を発見して復活したように、とんでもないカーネル関数やすごいマルチカーネル手法などが発見されると、復活の可能性はあるかもしれない??

Rumaleでは、その他、カーネル主成分分析やissueでリクエストのあったShared Nearest Neighborクラスタリングなどを追加している。しばらくは、Numo::Linalgありきのアルゴリズムを追加していく。そろそろRumaleのユーザーガイドやチュートリアル的な文書が必要だな〜とかも考えている。

github.com