『サポートベクターマシン入門』とか

購入したのはいいんだが、
どうにも数式ばかりで、
なかなか読む気にならない。



ってか、
理屈はもう諦めて、
libsvmに逃げてしまったほうがいい気がする。
phpでLIBSVM

で、
ところでサポートベクターマシンって何なの?
実はここにSVMのサンプルがJavaのソースで公開されていて、
殆ど変更するところはなかったのですが、
なんとなくロジカルなところをPHPで書き直してみたのだけど、
(インデントがしっちゃかめっちゃか)
どうも速度がね。。。

[php] <?php $patterns = array(); $lambda = array(); $b = 0; $w = array(); $e_cache = array(); $c = 10; $tol = 0.7; $z = 0;

function kernel($p1, $p2) { $n = ($p1['x'] - $p2['x']) ^ 2 + ($p1['y'] - $p2['y']) ^ 2; return exp(-1 * $n / 1500); }

function learn() {

   global $patterns, $lambda, $b, $w, $c, $z, $tol, $e_cache;

   $w = array();
   $b = 0;

   $lambda = array();

   for ($i=0;$i<count($patterns);$i++) {
   $lambda[$i] = 0;
   }

   $alldata = true;
   $changed = false;

   $e_cache = array();

   for($lp=0;$lp < 500000 && ($alldata || $changed); $lp++) {
   $changed = false;
   $z = 0;
           $lastchange = true;
           for ($j=0;$j<count($patterns);$j++) {
                   $alpha2 = $lambda[$j];
                   if (!$alldata && ($alpha2 <=0 || $alpha2 >= $c)) {
                           continue;
                   }
                   if ($lastchange) {
                           $e_cache = array();
                   }
       $lastchange = false;

                   $t2 = $patterns[$j]['k'];
                   $fx2 = calc_e($j);

                   $r2 = $fx2 * $t2;
       if(!(($alpha2 < $c && $r2 < (-1 * $tol)) || ($alpha2 > 0 && $r2 > $tol))){
                           continue;
                   }
                   $i = 0;
                   $offset = mt_rand(0, count($patterns) - 1);
       $max = -1;

                   for ($ll=0;$ll<count($patterns);$ll++) {
                           $l = ($ll + $offset) % count($patterns);
                           if (0 >= $lambda[$l] || $c <= $lambda[$l]) {
                                   continue;
                           }
                           $dif = abs(calc_e($l) - $fx2);
           if ($dif > $max) {
                                   $max = $dif;
                                   $i = $l;
           }
                   }
       if($max >= 0){
                           if(step($i, $j)){
                                   $changed = true;
                                   $lastchange = true;
               continue 2;
                           }
                   }

                   $offset = mt_rand(0, count($patterns) - 1);
                   for($l=0;$l<count($patterns);$l++) {
                           $i = ($l + $offset) % count($patterns);
           if(0 >= $lambda[$i] || $c <= $lambda[$i]) {
                                   continue;
                           }
           if(step($i, $j)){
               $changed = true;
               $lastchange = true;
               continue 2;
           }
       }

       $offset = mt_rand(0, count($patterns) - 1);
       for($l=0;$l<count($patterns);$l++) {
                           $i = ($l + $offset) % count($patterns);
           if(step($i, $j)){
               $changed = true;
               $lastchange = true;
               continue 2;
           }
       }
   }

   if($z < 0.01) {
                   $changed = false;
   }
           if($alldata){
       $alldata = false;
   } else {
       if($changed){
                           $alldata = true;
                   }
           }

}

for($i=0;$i<count($patterns);$i++) { $w[$i] = $lambda[$i] * $patterns[$i]['k']; }

   $b = 0;

$count = 0; for ($i=0;$i<count($patterns);$i++) { if (abs($w[$i]) <= 0.05) { continue; } for ($l=0;$l<count($patterns);$l++) { $b -= $w[$l] * kernel($patterns[$i], $patterns[$l]); } $count++; }

$b /= $count;

   return;

}

function trial($p) { global $patterns, $lambda, $b, $w, $c, $tol, $e_cache;

   $s = $b;
   for ($i=0;$i<count($patterns);$i++) {
           $s += $w[$i] * kernel($p, $patterns[$i]);
   }
   return ($s > 0 ) ? 1 : -1;

}

function calc_e($i) { global $patterns, $lambda, $b, $w, $e_cache;

   if (isset($e_cache[$i])) {
           return $e_cache[$i];
   }
   $e = $b - $patterns[$i]['k'];
   for ($j=0;$j<count($lambda);$j++) {
           $e += $lambda[$j] * $patterns[$j]['k'] *
                   kernel($patterns[$j], $patterns[$i]);
   }
   $e_cache[$i] = $e;
   return $e;

}

function step($i, $j) { global $patterns, $lambda, $b, $w, $c, $z, $tol, $e_cache;

   if ($i == $j) {
           return false;
   }
   $fx2 = calc_e($j);

   $t1 = $patterns[$i]['k'];
   $t2 = $patterns[$j]['k'];

   $fx1 = calc_e($i);

   $k11 = kernel($patterns[$i], $patterns[$i]);
   $k22 = kernel($patterns[$j], $patterns[$j]);
   $k12 = kernel($patterns[$i], $patterns[$j]);
   $eta = $k11 + $k22 - 2 * $k12;
   if ($eta <= 0) {
           return false;
   }
   $newwj = $lambda[$j] + $t2 * ($fx1 - $fx2) / $eta;
   if ($t1 == $t2) {
           $u = max(0, $lambda[$j] + $lambda[$i] - $c);
           $v = min($c, $lambda[$j] + $lambda[$i]);
   } else {
   $u = max(0, $lambda[$j] - $lambda[$i]);
   $v = min($c, $c + $lambda[$j] - $lambda[$i]);
   }
   if ($u == $v) {
           return false;
   }
   $newwj = max($u, $newwj);
   $newwj = min($v, $newwj);

   $z += abs($lambda[$j] - $newwj);
   $lambda[$i] += $t1 * $t2 * ($lambda[$j] - $newwj);
   $lambda[$j] = $newwj;
   return true;

}

$patterns = array(); for ($i=0;$i<350;$i++) { $x = mt_rand(0,400); $y = mt_rand(0,350); $patterns[] = array( 'k' => (($x * 4 / 400) % 2 + ($y * 3 / 300) % 2 + 1) % 2 * 2 - 1, 'x' => $x, 'y' => $y ); }

learn();[/php]