『サポートベクターマシン入門』とか
購入したのはいいんだが、
どうにも数式ばかりで、
なかなか読む気にならない。
ってか、
理屈はもう諦めて、
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]