SVMは、オーバーフィッティングを避けて効率よく識別関数を求めることができる 手法です。
「集合知」の9章で紹介されているSVMをSageを使ってまとめてみます。
いきなりSVMに進む前にクラス分けを簡単な例を使って解いてみます。
下図は、赤(-1)のグループと青(1)のグループの分布です。
|
青点の値に1、赤点の値に-1をセットし、$w_1 x_1 + w_2 x_2 + b$の線形モデルを find_fit関数を使って解いて、$w_1, w2, b$の値を求めます。
find_fitのデータは、$x_1, x_2, 値$の順にセットします。
[[1, 2, -1], [1, 4, -1], [2, 4, -1], [2, 1, 1], [5, 1, 1], [4, 2, 1]] [[1, 2, -1], [1, 4, -1], [2, 4, -1], [2, 1, 1], [5, 1, 1], [4, 2, 1]] |
{b: 0.1962962962945436, w2: -0.4333333333364595, w1: 0.32592592592445524} {b: 0.1962962962945436, w2: -0.4333333333364595, w1: 0.32592592592445524} |
implicit_plot関数を使ってデータ(赤、青)と判別式が0となる線を表示します。 上手く赤と青の点を分離しているのが分かります。
|
求まった判別式がどのような形なのかplot3dを使って表示してみます。 データ(赤、青)の判別式の値も合わせて表示してみます。
一つの平面上として表されています。
|
SVM(サポートベクターマシン)は、クラスの境界線と分離平面(超平面) の距離(マージン)を最大になるようにクラスを分類します。
先ほどの例では、下図のように境界線(半線)の中間に$y = x$の分離平面が、 あります。(線形分類の境界線とずれていることに注意して下さい)
境界線を求めるとき使った学習データのことを「サポートベクター」と呼びます。
|
sageを使ってSVMを計算したいところですが、sageにはSVMを計算する関数がありません。 そこで、LIBSVMをインストールします。
LIBSVMの ホームページ のDownload LIBSVMから最新のtar.gzファイルをダウンロードします。
ダウンロードしたファイル(libsvm-2.9.tar.gz)を適当な場所(~/local)で解凍します。
$ tar xzvf libsvm-2.9.tar.gz $ cd libsvm-2.9/python
MacOSXの場合、Makefileの一部を変更します。
#LDFLAGS = -shared # Mac OS LDFLAGS = -framework Python -bundle
また、そのままではsageで動かなかったので、svm.pyの以下の2点にfloatのキャストを 追加するように修正してください。
126c126 < svmc.svm_node_array_set(data,j,k,x[k]) --- > svmc.svm_node_array_set(data,j,k,float(x[k])) 138c138 < svmc.double_setitem(y_array,i,y[i]) --- > svmc.double_setitem(y_array,i,float(y[i]))
sage内部のpythonにLIBSVMをインストールするには、sageのpythonで seup.pyを実行します。私は、sageを~/localにインストールしているので
$ ~/local/sage/local/bin/python setup.py installと実行しました。
正しく動くか、集合知の9.9.2の例題で確認します。 無事、同じ結果がでたので、次に進みます。
* optimization finished, #iter = 1 nu = 0.025000 obj = -0.250000, rho = 0.000000 nSV = 2, nBSV = 0 Total nSV = 2 * optimization finished, #iter = 1 nu = 0.025000 obj = -0.250000, rho = 0.000000 nSV = 2, nBSV = 0 Total nSV = 2 |
1.0 1.0 |
LIBSVMへの入力は、各データどのクラスに属するかを示すclsと データのベクトル値datを引数に取ります。
[-1, -1, -1, 1, 1, 1] [[1, 2], [1, 4], [2, 4], [2, 1], [5, 1], [4, 2]] [-1, -1, -1, 1, 1, 1] [[1, 2], [1, 4], [2, 4], [2, 1], [5, 1], [4, 2]] |
* optimization finished, #iter = 4 nu = 0.033333 obj = -1.000000, rho = 0.000000 nSV = 2, nBSV = 0 Total nSV = 2 * optimization finished, #iter = 4 nu = 0.033333 obj = -1.000000, rho = 0.000000 nSV = 2, nBSV = 0 Total nSV = 2 |
データが正しく分類されているか赤(1,4)の座標を入力すると、-1.0が返され、 正しい結果が返ってきます。
-1.0 -1.0 |
contour_plotを使って、SVMの予想をコンタマップで表示すると、$y = x$ の線でうまく、分類されているのが、分かります。
|
さらに、各点(赤、青)の予想値と境界線の形状をlist_plot3で表示します。
|
SVMのカーネルメソッドのすごさを確かめるために点の値がチェスボードのように 格子状に部分布する点を分析することにします。
まずは、チェスボードのマスの値を返すchessBox関数を作成します。 ただしく、値がセットされるか、conour_plotでみてみましょう。
|
0から5の範囲にランダムに点を生成し、chessBox関数で赤(red)と青(blue) に振り分けます。
|
kernel_type=LINEAR(線形を意味する)を使って分類すると、 うまく格子状のデータを分類することができません。
|
........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ .................................*......................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ...........................................*............................\ ........................................................................\ ........................................................................\ ........................................................................\ ............................................................*...........\ ........................................................................\ ....................*...................................................\ .................*......................................................\ ........................................................................\ .......................*................................................\ ...................................................................*....\ ......................................................*.................\ ........................................................................\ ........................................................................\ ........................................................................\ ...............................*........................................\ ........................................................................\ ........................................................................\ ............................................*...........................\ ........................................................................\ ........................................................................\ ........................................................................\ ........................................................................\ ..................................................* optimization finished, #iter = 3348299 nu = 0.974402 obj = -974232.337534, rho = -0.857296 nSV = 976, nBSV = 973 Total nSV = 976 .........................................................................................................................................................................................................................................................................................................................................................................................................*.........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................*................................................................................................................................................................................................................................................................................................................*.......................................................................................................*....................................................................*.....................................................................................................................................................*...................................................................................................................*..........................................................*........................................................................................................................................................................................................................................................................*....................................................................................................................................................................................................................................*.............................................................................................................................................................................................................................................................................................................................................................................* optimization finished, #iter = 3348299 nu = 0.974402 obj = -974232.337534, rho = -0.857296 nSV = 976, nBSV = 973 Total nSV = 976 |
次に、kernel_type=RBF(ガウシアンカーネル関数)を使って分類すると、 なんとなく格子状に分類しているように見えます。
ガウシアンカーネル関数は、 $$ K(x, x') = e ^{\left( - \frac{| x - x' |^2}{\sigma^2} \right)} $$
...............................................*.......................*\ ....................* optimization finished, #iter = 90313 nu = 0.213203 obj = -161853.152563, rho = 9.646479 nSV = 238, nBSV = 187 Total nSV = 238 ...............................................*.......................*....................* optimization finished, #iter = 90313 nu = 0.213203 obj = -161853.152563, rho = 9.646479 nSV = 238, nBSV = 187 Total nSV = 238 |
最後に簡単な画像認識をLIBSVMを使って確かめてみます。
5x5のマス目に数字の0から4までを書いた画像5個(本当に少ないです!) をテストデータとして使用します。
|
作成したデータをcontour_plotを使って表示して、確認します。 なんとなくそれらしく見えるでしょう。(笑)
|
いよいよ画像認識の準備が整いました。 えいや〜で、モデルを作成します。
* optimization finished, #iter = 1 nu = 0.246622 obj = -2.466216, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.280928 obj = -2.809276, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.676333 obj = -6.763327, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.262318 obj = -2.623181, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.262318 obj = -2.623181, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.280928 obj = -2.809276, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.280928 obj = -2.809276, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.330771 obj = -3.307713, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.202682 obj = -2.026823, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.262318 obj = -2.623181, rho = 0.000000 nSV = 2, nBSV = 0 Total nSV = 5 * optimization finished, #iter = 1 nu = 0.246622 obj = -2.466216, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.280928 obj = -2.809276, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.676333 obj = -6.763327, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.262318 obj = -2.623181, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.262318 obj = -2.623181, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.280928 obj = -2.809276, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.280928 obj = -2.809276, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.330771 obj = -3.307713, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.202682 obj = -2.026823, rho = 0.000000 nSV = 2, nBSV = 0 * optimization finished, #iter = 1 nu = 0.262318 obj = -2.623181, rho = 0.000000 nSV = 2, nBSV = 0 Total nSV = 5 |
テストに使う画像は、以下の3個です。 判別結果は、ただしく0, 1, 1となっています。(めでたし、めでたし)
|
|
0.0 1.0 1.0 0.0 1.0 1.0 |
念のため、学習に使ったデータが正しく識別されるかもみてみました。
こんなに少ないデータでよく認識できるものだと感心しました。これがSVMのすごさなのでしょうか?
0.0 1.0 2.0 3.0 4.0 0.0 1.0 2.0 3.0 4.0 |
|