洋食の日記

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

Numo::NArrayでLIBLINEARを使うGemを作成した

はじめに

Numo::Libsvmと同様に、特徴ベクトルやラベルをNumo::NArray形式で扱えるLIBLINEARのbinding gemを作成した。LIBLINEARは、SVMやロジスティック回帰による線形の分類器や回帰が実装されている。

numo-liblinear | RubyGems.org | your community gem host

使い方

準備

Numo::Liblinearでは、LIBLINEAR自体を同梱していないので、別途LIBLINEARをインストールする必要がある(必要になるのはliblinear.soとlinear.hである)。

例えば、macOSであれば、

$ brew install liblinear

Ubuntuであれば、

$ sudo apt-get install liblinear-dev

となる。

インストール

numo-liblinearは、gemコマンドでインストールできる。

$ gem install numo-liblinear

L2正則化ロジスティック回帰による分類

LIBSVM DataにあるPendigitsデータセットを使って、ロジスティック回帰による分類を行う。データの取得にはred-datasetsを用いる。

$ gem install red-datasets-numo-narray 

まず、ロジスティック回帰による分類器を訓練する。

require 'numo/liblinear'
require 'datasets-numo-narray'

# Pendigitsデータの訓練データセットをダウンロードする.
puts 'Download dataset.'
pendigits = Datasets::LIBSVM.new('pendigits').to_narray
x = pendigits[true, 1..-1]
y = pendigits[true, 0]

# LIBLINEARのパラメータを定義する.
# solver_typeでL2正則化ロジスティック回帰を示す.
param = {
  solver_type: Numo::Liblinear::SolverType::L2R_LR_DUAL
}

# L2正則化ロジスティック回帰を訓練する.
puts 'Train logistic regression.'
model = Numo::Liblinear.train(x, y, param)

# パラメータと訓練したモデルをMarshalでファイルに保存する.
puts 'Save parameters and model with Marshal'
File.open('pendigits.dat', 'wb') { |f| f.write(Marshal.dump([param, model])) }

これを実行すると、以下のようになる。

$ ruby train.rb
Download dataset.
Train logistic regression.
Save parameters and model with Marshal

次に、訓練したモデルで、テストデータの分類を行う。

require 'numo/liblinear'
require 'datasets-numo-narray'

# Pendigitsデータのテストデータセットをダウンロードする.
puts 'Download dataset.'
pendigits_test = Datasets::LIBSVM.new('pendigits', note: 'testing').to_narray
x = pendigits_test[true, 1..-1]
y = pendigits_test[true, 0]

# パラメータと訓練したモデルをMarshalで読み込む.
puts 'Load parameter and model.'
param, model = Marshal.load(File.binread('pendigits.dat'))

# テストデータのラベルを推定する.
puts 'Predict labels.'
predicted = Numo::Liblinear.predict(x, param, model)

# 推定結果を正確度で評価する.
mean_accuracy = y.eq(predicted).count.fdiv(y.size)
puts "Accuracy: %.1f %%" % (100 * mean_accuracy)

これを実行すると、以下のようになる。正確度(Accuracy)が87.9%となり、線形分類としてはまずまずこんなモノかなといった感じ。

$ ruby test.rb
Download dataset.
Load parameter and model.
Predict labels.
Accuracy: 87.9 %

おわりに

Numo::Libsvmと同様、ひとまず、最低限の動きができるようになったので公開した。また、これもNumo::Libsvmと同様で、LIBLINEAR自体を同梱していないので、RubyInstallerによるWindows環境では動作しないかもしれない(liblinearライブラリとlinear.hがあればWindowsでも動くと思われる)。ひとまず、広く使われている機械学習関連ライブラリの薄いラッパーを用意して、リッチなインターフェースをRumaleかなにかで提供できれば、と考えている。次は、なにか近似最近傍探索ライブリかな〜。

github.com