機械学習ライブラリ SHOGUN入門

shogun_logo

The machine learning toolbox’s focus is on large scale kernel methods and especially on Support Vector Machines (SVM)

* The SHOGUN Machine Learning Toolbox

サイトのデザインどうにかしたらいいのにとか将軍ってなんだよとかいろいろあるかと思いますけども、プロダクトとしては素晴らしいという噂を聞くので今回このSHOGUNという機械学習ライブラリを試してみました。目的は一般物体認識における分類タスクでMultiple Kernel Learning(MKL)やLatent SVMの実装を試すことなのですが、まずはインストール方法と簡単な使い方を調べるところから始めます。

また、この記事の内容はQiitaにも投稿しています。
* 機械学習ライブラリ SHOGUN入門 – Qiita

環境

* CentOS 6.4 (x86_64/Intel Xeon 2.9GHz 32コア/96GB RAM)
* gcc 4.4.7
* cmake 2.8.11
* swig 2.0.11
* Python 2.7.5 (+ NumPy 1.7.1)
* SHOGUN (development branch / libshogun.so.14)


  • インストール
    • 補足: 依存関係ライブラリのインストール
      • SWIG
      • BLAS (ATLAS) / LAPACK / GLPK / Eigen3
      • NumPy
    • コンパイル時の注意点
  • hello, world (libshogun)
    • メモリ管理の注意点
  • Python Modular

インストール

公式サイトではdebian系OSを前提にセットアップ手順等が書かれていますが、redhat系でも特に苦労なくインストールすることはできます。debian系ならdebパッケージで古いバージョンが配布されていますが、ここではCentOSなのでソースからコンパイル/インストールします。機械学習関連のタスクは長時間に及ぶことが多いため、SHOGUNに限らずこういったソフトウェアは実際に動作させる環境上でビルドして最適な状態で利用することをオススメします。

以前はAutotools(./configure && make)でビルドしていたらしいのですが、最新版パッケージはCMakeに対応していました。ここ数年でOpenCVやMySQLなどCMakeユーザーが増えてきましたね。
公式の SHOGUN: Installation ページには2013/11現在、CMakeによるビルド手順は記載されていません。注意!!

C++11の機能をサポートしているコンパイラならいくつかの機能(std::atomicなど)を利用してくれるようです。redhat6.x系のシステムGCC(v4.4.x)だとC++11のほとんどの機能はサポートされません。

僕の環境ではライブラリ本体の libshogun の他にコマンドラインとPython用のインタフェースをインストールしました。スクリプト言語のインタフェースを多く揃えたい場合はSWIGを別途インストールしておく必要があります。

補足: 依存関係ライブラリのインストール

SWIG

SWIGはC/C++で書かれたモジュール(共有ライブラリ)をスクリプト言語などの高級言語から利用するためのバインディングを作成してくれるツールです。僕もたまに業務でWebインタフェース向けにPHPバインディングをSWIGを使って作ることがあります。2013/11現在、yumでインストールできるパッケージはSHOGUNのバージョン要求を満たしていないので、これもソースからコンパイル/インストールしておきます。debian系の場合は $ apt-get install swig2.0 でOKです。

SWIGとバインディングを作りたい言語の処理系を揃えたら再度SHOGUNをビルドしましょう。

BLAS (ATLAS) / LAPACK / GLPK / Eigen3

線形代数関連のライブラリ群。yumでインストールできるパッケージでOKです。ATLASは最適化されたBLAS実装の一つで、簡単にインストールできるので入れておくと良いです(BLASはリファレンス実装)。また、SHOGUNはGLPKの他にCPLEXにも対応しているようなので、業務用に利用する場合はCPLEXを導入するとさらに性能が上がると思われます。稟議書がんばって書きましょう(アカデミック用途であれば無償で利用できるそうです)。Eigen3については2013/11現在、yumでインストールできるパッケージはSHOGUNのバージョン要求を満たしていませんが、もしEigen3が手元になければソースコード(テンプレートライブラリなのでヘッダファイル群)をダウンロードしてくるようCMakeに指示できるようです。CMakeのオプションに -DBUNDLE_EIGEN=ON を付ければOKです。

NumPy

Pythonインタフェースをインストールする場合はNumPyが必須になっています。NumPyについては以前このブログでも紹介しているので参考までに。ちなみに、OpenCV(コンピュータビジョンライブラリ)のPythonインタフェースもNumPyを利用しています。

* Pythonの数値計算ライブラリ NumPy入門

インストールはpip(A tool for installing and managing Python packages.)を使えば簡単です。

SHOGUNライブラリの全体像は以下の図の通りで、いまいちよくわかりません。
shogun_overview
スクリプト言語用のインタフェースはこの図に載っているもの以外にもJavaやRuby, Luaなどもサポートされています。前述の通り、SWIGをインストールして使いたい言語のバインディングを作っておきましょう。

コンパイル時の注意点

物理メモリ/仮想メモリ容量の少ない安物のVPS環境などでSHOGUNをリリースビルドすると、OOM Killer様にcc1plusプロセスを強制的にkillされる可能性が高いです。試しに1GB RAM/2GB Swapの仮想環境で試してみましたが案の定ひどいスコアで殺されてしまいました。。

その場合はswap容量を増やすことを検討しましょう。仮に物理メモリが1GBしかない場合はおそらく実メモリ容量の2倍程度では足りないので、一時的に4倍程度確保しておくと安全かと思います。OpenVZの仮想環境だとちょっと諦めた方がいいかもしれません。。

あと、VPSのような仮想環境だとinodeが少ないはずなので、学習データを大量に置くことはできないと思います。素直に物理サーバ上に構築した方が懸命です。ここでは32コア/96GB RAMの環境でビルドしましたが、リソース的には十分でスムーズにビルドすることができました。

ちなみに僕の環境におけるGCCの最適化オプションは以下のようになりました。

hello, world

まずはlibshogunを使って簡単なタスクを実行してみます。SVM(Support Vector Machine)を用いてデータを分類(Classification)するサンプルです。

* コンパイルと実行
比較的新しいコンパイラならC++11を有効にしてコンパイルすると良いです。

行列から特徴ベクトル(CDenseFeatures)を抽出、正解ラベル(CBinalyLabels)を設定、ガウシアンカーネル(CGaussianKernel)を使ってSVM(CLibSVM)で学習します。以下、いくつか特徴を。

* 行列のレイアウトはColumn-Major (Fortran Order)で扱われる。
* SVMの学習には内部的に LibSVM や SVMLight などの外部ライブラリを利用している。
* スレッドセーフな独自の参照カウント機構によるオブジェクト管理

特徴ベクトルは OpenGL や CUBLAS などと同様にColumn-Majorで行列から読み出されます(1つの列が1つの特徴ベクトルとなる)。SVMの学習には内部的に LibSVM や SVMLight などの外部ライブラリをSHOGUNのインタフェースから利用できます(shogun/classifier/svm/以下を参照)。

メモリ管理の注意点

上記のコードは明らかにメモリリークしてるように見えますが、valgrindでチェックしてみたところ内部で適切にメモリ管理されているようです。SHOGUNは内部で参照カウントによるオブジェクト管理を行っています。この参照カウントをインクリメント/デクリメントするマクロ(SG_REF/SG_UNREF)が定義されているのでこれを使うのですが、全てのインスタンスに対して手動でカウントを操作する必要はありません。SHOGUNのメモリ管理周りの実装を読んでみたのですが、参照先のインスタンスの参照カウントを参照元のインスタンスが解放されるときに(つまりデストラクタ内)デクリメントしています。参照カウントが0以下になった時にインスタンスは解放されるようになっているため、上記のコードにおいてはSVMのインスタンスを解放すれば連鎖的に他のインスタンスも解放されるようになっています。

注意点としてはスコープが外れた時はなにもしないという点で、インスタンスを解放するかどうかの判定は参照カウントの変化があった時のみとなります。小さな親切大きなお世話といった感じですけど、仕方がないので上手くこの仕組みと付き合っていく必要がありそうです。いくつか方針を書いてみます。

* 完全手動参照カウント管理
SHOGUNの参照カウントの支配下に置かれている時に、うかつに自分で delete すると二重解放(double free)の危険が出てきます。そこで、クラスのインスタンスを作ると同時に手動で参照カウントをインクリメント(SG_REF)し、インスタンスが必要なくなったら手動でデクリメント(SG_UNREF)するようにします。ARC offのObjective-C方式ですね。ただし、例外安全なコードを書くのは難しくなります。

* スマートポインタ + 半手動参照カウント管理
比較的新しいC++コンパイラなら std::unique_ptr/std::shared_ptr などが利用できるのでこれを使う方法です。注意点としては前述のようにSHOGUNの参照カウントの支配下においてはインスタンスの参照カウントが0以下になると内部で delete するため、スマートポインタで包んでいるだけだとこれも二重解放の危険があります。そこで、インスタンスを作ったら参照カウントを手動でインクリメントし、デクリメントは行わないことでSHOGUN内部で delete を実行させないようにします。つまり参照カウントを常に1以上にしてSHOGUNによるオブジェクト管理を実質的に意味のないものにします。これなら SG_UNREF 忘れに怯える必要もなく例外安全なコードを書きやすいというメリットがあります。

次は未知のデータを入力にしてみます。訓練データ/テストデータは以下のようにPythonで適当に生成してファイルに書き出したものを利用します。

注意) 以下のコードは libshogun.so.14 未満では動作しないことを確認済み

* 実行結果

SHOGUNはクラス設計の粒度もちょうど良く、APIも十分抽象化されているのですが、参照カウントの操作が入るとコードが汚くなりますね。。また、学習データは CCSVFile クラスを使ってファイルから読み込ませています。CSVと名前がついてますが、CSV形式ではなくスペース区切りで二次元データが書かれたファイルも読み込むことができます。

SHOGUNとOpenCVと仲良くさせるには、shogun::SGMatrix と cv::Mat を相互変換できるようなアダプタを作ると便利かもしれません。あと、OpenCVはCUDA対応も進んでいるのでSHOGUNもぜひ対応して欲しいところです。

Python Modular

次はSHOGUNのPythonバインディングを使ってみます。python_static と python_modular の2つが提供されていますが、python_modular の方がインタフェースがスマートなのでこちらを使います。

* 実行結果

C++(libshogun)版と同じ結果が得られました。分類結果をmatplotlibを使って可視化してみます。

shogun_svm

とりあえず、C++とPythonでの簡単な使い方を整理しました。SHOGUNにはSVMだけでなく様々な機械学習アルゴリズムが実装されているので、より実践的なタスクを使って検証を進めていきたいと思います。

あわせて読む:

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です