LIBLINEAR用のスケーリングスクリプトとグリッド探索スクリプト
LIBLINEARとは線形分類に特化した分類器である.
簡単な説明とか,使い方は検索すればすぐ出てくると思うが,
LIBLINEARを用いた機械学習入門(単語分割)
あたりはわかりやすいと思う.
一応,公式ページも載せておく.
LIBLINEAR -- A Library for Large Linear Classification
で,LIBLINEARに限ったことではないのだが,分類器を学習させるには,一般にハイパーパラメータのチューニングが必要になる.SVMの場合はCパラメータのチューニングが必要になるのだが,まあ理論的なことは黄色い本でも読んでもらいたい.
このCパラメータのチューニングには,ふつうはグリッド探索というやり方が使われる.
やってることはとっても単純で,
「ある範囲のCパラメータでどんどん学習とテストを繰り返して,一番いい精度が出ている時のCパラメータがベスト.」
要はこれだけである.
残念ながら,LIBLINEARにはグリッド探索のスクリプトがないようだ.
それくらい,自分で実装しろよ.って言われそうだが,せっかくならば,あるものを活用したいところ.
LIBLINEARのFAQを見ると,「LIBSVMのgrid.pyを次のコマンドで実行してね.python grid.py -log2c -3,0,1 -log2g null -svmtrain ./train heart_scale」みたいなことが書いてある.
LIBLINEAR FAQ
LIBSVMとは,非線形の分類に特化した分類器で,単純に線形に分離できないデータにはLIBSVMの方が良いことが多い.
しかし,線形分離ならば,明らかにLIBLINEARの方が早い.(LIBLINEARの公式ページにも書いてある)
これは,LIBSVMは,一度,カーネル空間に飛ばして分離しているからである.(LIBSVMでも線形分離は可能だけど,それでもカーネル空間に飛ばしているからやっぱり遅い)
ついでにLIBSVMとLIBLINEARは同じ大学が作っているので,こういう芸当ができるんだろう.
それは良いとして,例えばLIBLINEARをpythonスクリプトから呼び出して,スケーリングして(スケーリングもLIBSVMのものを使えと書いてある),グリッド探索して...ベストなハイパーパラメータを返す...ってことを全自動でやりたかったので,そんなスクリプトを書いた.
感覚的にはLIBSVMのeasy.pyに似ている.と,いうより easy.pyをコピペして作った.
#! /usr/bin/python # -*- coding:utf-8 -*- __date__='2013/12/02'; __author__='Kensuke Mitsuzawa'; import re, subprocess, os, sys; sys.path.append('/home/kensuke-mi/opt/liblinear-1.94/python/'); import liblinear, liblinearutil; #下の3つのパスを自分の環境に合わせて書き換える svmscale_exe='/home/kensuke-mi/opt/libsvm-3.17/svm-scale'; liblinear_exe='/home/kensuke-mi/opt/liblinear-1.94/train'; grid_py='/home/kensuke-mi/opt/libsvm-3.17/tools/grid.py'; def scalling_value(train_pathname, devset_pathname): assert os.path.exists(train_pathname),"training file not found" file_name=os.path.basename(train_pathname); scaled_file = file_name + ".scale" model_file = file_name + ".model" range_file = file_name + ".range" file_name = os.path.split(test_pathname)[1] assert os.path.exists(test_pathname),"testing file not found" scaled_test_file = file_name + ".scale" predict_test_file = file_name + ".predict" cmd = '{0} -s "{1}" "{2}" > "{3}"'.format(svmscale_exe, range_file, train_pathname, scaled_file) print('Scaling training data...') p = subprocess.Popen(cmd, shell = True, stdout = subprocess.PIPE).communicate() cmd = '{0} -r "{1}" "{2}" > "{3}"'.format(svmscale_exe, range_file, test_pathname, scaled_test_file) print('Scaling testing data...') p = subprocess.Popen(cmd, shell = True, stdout = subprocess.PIPE).communicate() return scaled_file, scaled_test_file; def grid_search(target_file): #To check the C parameter for LIBLINEAR, use following command. "python grid.py -log2c -3,0,1 -log2g null -svmtrain ./train heart_scale" # from LIBLINEAR FAQ page: http://www.csie.ntu.edu.tw/~cjlin/liblinear/FAQ.html cmd = 'python {0} -log2c -3,0,1 -log2g null -svmtrain "{1}" "{2}"'.format(grid_py, liblinear_exe, target_file) print 'command for grid search is following:\n{}'.format(cmd); print('Cross validation...') f = subprocess.Popen(cmd, shell = True, stdout=subprocess.PIPE).stdout line='' while True: last_line=line line=f.readline() if not line: break #outline format is [local] 0.0 92.7184 (best c=0.125, rate=94.0543) processed_line=re.sub(ur'\[local\]\s\.+\(best\sc=(.+),\srate=(.+)\)', ur'\1 \2', last_line); c,rate=map(float, processed_line.split()); print('The result of grid search is Best c={0}, rate={1}'.format(c,rate)); return c,rate; def main(train_pathname, devset_pathname, scale): if scale==True: scaled_filepath, scaled_test_filepath=scalling_value(train_pathname, devset_pathname); c,rate=grid_search(scaled_filepath); return c, rate, scaled_filepath, scaled_test_filepath; else: c,rate=grid_search(train_pathname); return c, rate, None, None; if __name__=='__main__': train_pathname=sys.argv[1]; test_pathname=sys.argv[2]; main(train_pathname, test_pathname, False);