perlでSGD版SVMを書いてみた

SVM(Support Vector Machine, サポートベクターマシン, サポートベクトルマシン)をperlで書いてみた。
実装が簡単という理由からSGDによるオンライン学習を行っている。カーネル行列(グラム行列)をメモリに持っておかないといけないので本当の意味ではオンライン化されていないが、SVMを理解するためのサンプルとしてはSGDで実装するのは手頃ではないかと思う。

#!/usr/local/bin/perl
# $Id$
use strict;
use warnings;

my $d = 3;  # x ∈ R^3
my $n = 6;  # number of training data
my $t = 10; # iteration

# label (warm color:1, cold color:-1)
my @yy = (1, -1, -1, -1, 1, 1);
# training data
my @xx = ([1, 0, 0], # red
          [0, 1, 0], # green
          [0, 0, 1], # blue
          [0, 1, 1], # cyan
          [1, 0, 1], # magenta
          [1, 1, 0]  # yellow
         );
# alpha parameter
my @aa = (0, 0, 0, 0, 0, 0);
# bias parameter
my $bias = 0;

# estimate alpha
for (my $s = 0; $s < $t; $s++) {
  for (my $i = 0; $i < $n; $i++) {
    $aa[$i] += (1 - $yy[$i] * margin($xx[$i]));
    if ($aa[$i] < 0) { $aa[$i] = 0; }
  }
}
# estimate bias
my $max = 0;
my $min = 0;
for (my $i = 0; $i < $n; $i++) {
  my $m = margin($xx[$i]);
  if ($yy[$i] == -1 and $m > $max) { $max = $m; }
  if ($yy[$i] ==  1 and $m < $min) { $min = $m; }
}
$bias = ($max + $min) / 2;

# estimate label for new data
while (<>) {
  chomp;
  my @x = split(/ /);
  for (my $i = 0; $i < $d; $i++) { $x[$i] /= 255; }
  my $m = margin(\@x) + $bias;
  if ($m > 0) { print "> warn color\n"; }
  else        { print "> cold color\n"; }
}


#### sub routines ####

sub margin {
  my $x = shift;

  my $m = 0;
  for (my $i = 0; $i < $n; $i++) {
    $m += ($aa[$i] * $yy[$i] * kernel($xx[$i], $x));
  }
  return $m;
}

sub kernel {
  my $x1 = shift;
  my $x2 = shift;

  my $k = 0;
  for (my $i = 0; $i < $d; $i++) {
    $k += ($x1->[$i] * $x2->[$i]);
  }
  return $k;
}

このサンプルは色のRGB値を入力すると、その色が暖色系なのか寒色系なのかを教えてくれるというもの。例えば

WEBセーフカラー216色−WEBカラーリファレンス

を参考にwebセーフカラーをいくつか入力してみる。

$$ ./svm.pl
102 204 255
> cold color
255 51 102
> warn color
00 255 153
> cold color
255 255 51
> warn color

というわけで割と正しく推定されている。

本記事では理論的な部分はほとんど書いていない。なぜこんな記事を書いたかというと、SVMの入門記事を読むと大抵カーネル関数やマージン最大化などの概要がふわっと書いてあるだけで、結局初心者にとってはよく分からないのでいいや、ってなってしまいがちだと思ったから。プログラムがすべてではないけどSVMにはこういう簡単な実装もあるよとわかったら勉強する気も出てくるんじゃないかな、と。

なお本実装は「サポートベクターマシン入門」という書籍の6章から7章を参考にした。翻訳の質はアレだが元が良書なのでSVM作りたい、理解したいという人にはオススメ。(英語に自信のある方は原書で!)