サポートベクターマシン(SVM

ここでは、“使い方”という立場から、排他的論理和(XOR)例を使って説明する。

SVMネットワークの構成は次のようになっている。

 

 

 

 

 

 

 

 

 


ネットワークは、入力(図のxは一寸曲者でベクトル、m入力なら(x1,x2,…,xm))が中間ユニットに送られる。各中間ユニットは各教師データに対応して作成するもので、当然中間ユニット数は教師データの数と同じである。各中間ユニットの出力はK(x,xs)はスカラーである(ss番目の中間ユニットを表す)。中間ユニットの出力には重みwsが掛けられ出力ユニットで加算されて、最終出力yが得られる。

式で書くと、 となる。

SVMの課題は中間ユニットの出力Kの求め方とw(上の式のα*y)の求め方である。

(理論的には線形分離できない空間をK(中間ユニット)で別の超平面に写像し、写像後の空間をwで分離している)

Kはカーネル(核)関数と呼ばれ、いくつかの関数が提案されている。例えば、p次の多項式カーネルK(x,x’)=(xTx’+1)P、やガウシアンカーネルである。以下では2次多項式カーネルを用いた例を示す。

wを求めるにはαを求めて、yを掛ければよい。αを求めるにはニューラルネットの学習のような反復法と、固有値問題を解くような方法がある。以下では簡単な繰り返し法を示す。

 

排他的論理和(XOR)の実現

学習データはである。

2次多項式カーネルの式は次の通りである。

この式でii番目の中間ユニット、すなわちi番目の学習パターンに対応したユニットを示している。

 

XORのネットの図は以下の通りである。

 

 

 

 

 

 

 

 

 

 


この図では入力をxa,xbとした。各中間ユニットの出力は、教師データ(は教師データ1の1番目の要素(−1)を示す)を代入すると次のようになる。

KとYをまとめると次のようになる。

 

ここで、とは、教師データiが入力された時のj番目のユニットの出力、は教師データの出力ijの積を表す。

次に、中間層と出力層間の重みを反復計算で求める方法を示す。

wを求めるにはαを求めyを掛ければよい。αを反復計算で求める際は次の手順を行う。

Step1: i=1~4)に初期値0を入れる。また、次の行列Dijを用意する。

Step2:各教師データ(i=1,..,4)に対して次の処理を行う。

Step2をαが収束するまで繰り返す

ここで、γは学習率、Cはαの上限を決める正の数。

 

これをプログラムで実行した結果は、α1~α40.125(全て同じ)であった。wは次の通りである。w1=0.125*-1=-0.25, w2=0.125, w3=0.125, w4=-0.125

学習済みのネットでは出力yの正負で入力パターンを2つのクラスに分類する。

 

上の例はカーネル関数に多項式を用いた、多項式ではKのイメージがつかみにくいが、カーネルをガウシアンにするとRBFというモデルになりイメージがつかみやすくなる。RBFでは、教師データを正規分布で表すので、入力が2つの場合、平面におわんを逆さに置いていくイメージになる。排他的論理和では以下のイメージとなる。

 

 

 

 

 

 

 

 

 

 

 

 

 


//プログラム

#include <stdio.h>

 

double x[4][2]={{-1,-1},{-1,1},{1,-1},{1,1}};  //教師入力データ

double y[4]={-1, 1, 1,-1};  //教師出力データ

double K[4][4], Y[4][4], D[4][4], u[4], xa, xb; int i,j,k, count;

double E[4];

double C=10.0, gamma=0.01, dalpha, mi, ma, uk;

double alpha[4]= {0,0,0,0};

 

   double kk(int ii, int jo){        //教師データiが入力された時ユニットjの出力

       return (1+x[ii][0]*x[ii][0]*x[jo][0]*x[jo][0]+2*x[ii][0]*x[ii][1]*x[jo][0]*x[jo][1]

                +x[ii][1]*x[ii][1]*x[jo][1]*x[jo][1]+2*x[ii][0]*x[jo][0]+2*x[ii][1]*x[jo][1]);     

   } 

   

   double yy(int ii, int jj){

       return (y[ii]* y[jj]);

    }     

 

   void main() {

       int i,j;

       printf("K\n");

           for(i=0; i<4; i++){

                for( j= 0; j<4; j++) {

                   K[i][j]= kk(i,j);

                    printf("%f, ",K[i][j]);

                  }

                  printf("\n");

               }

       printf("Y\n");

               for(i=0; i<4; i++){

                for( j= 0; j<4; j++) {

                   Y[i][j]= yy(i,j);

                    printf("%f, ",Y[i][j]);

                  }

                  printf("\n");

               }

       printf("D\n");

          for(i=0; i<4; i++){

                for( j= 0; j<4; j++) {

                   D[i][j]= Y[i][j]*K[i][j];

                    printf("%f, ",D[i][j]);

                  }

                  printf("\n");

               }

               

              for(count=0; count<1000; count++) {

                 for(i=0; i<4; i++){

                    E[i]=alpha[0]*D[i][0]+alpha[1]*D[i][1]+alpha[2]*D[i][2]+alpha[3]*D[i][3];

                    if ((gamma*(1.0-E[i]))> -alpha[i]) ma=gamma*(1.0-E[i]);

                    else ma= -alpha[i];

                    if( ma< (C-alpha[i])) dalpha= ma;

                    else dalpha= C- alpha[i];

//                dalpha= min{ max{ gamma*(1.0-E[i]), alpha[i]}, C-alpha[i]};

                alpha[i]+= dalpha;

              }

              }

             

              printf("alpha\n");            

              for(i=0; i<4; i++)

                 printf("%f,",alpha[i]);

           printf("\n");

                     

               

//report1

       printf("report1\n");

       for(i=0; i<4; i++){

          for(j=0; j<4; j++){

              xa=x[i][0]; xb=x[i][1];

              u[j]= (1+xa*xa*x[j][0]*x[j][0]+2*xa*xb*x[j][0]*x[j][1]

                +xb*xb*x[j][1]*x[j][1]+2*xa*x[j][0]+2*xb*x[j][1]);     

              printf("%f,",u[j]);

          }

          printf("\n");

        }

//report2

       printf("report2\n");

       for(i=0; i<10; i++){

          for(j=0; j<10; j++){

              xa=(double)i -5.0; xb=(double)j -5.0;

              uk=0.0;

              for(k=0;k<4;k++){

                 uk= uk+ (1+xa*xa*x[k][0]*x[k][0]+2*xa*xb*x[k][0]*x[k][1]

                +xb*xb*x[k][1]*x[k][1]+2*xa*x[k][0]+2*xb*x[k][1])*alpha[k]*y[k];

              }    

              if(uk>0) printf("+");

              else printf("-");

          }

          printf("\n");

        }     

    }