原文出处:原文链接
overlast(さとうとしのり)です。
僕は普段、自然言語処理技術を活用する仕事に従事しています。
Perl は「アイディアが浮かんでからコードを実行するまでの早さ」や「急で無茶な仕様変更への対応のしやすさ」などが好きで使っています。最初に Perl で実装して、後日速度が求められるようになったら、遅い部分だけ C / C++ で書き直すことが多いです。
Perl の CPAN モジュールの Author の方にはいつもお世話になっております。本当にいつもどうもありがとうございます。
さて今回は、教師あり学習を用いる識別手法の一つである Support Vector Machine(以下では SVM と略す) の実装の一つである SVMlight のための Perl モジュールの一つである「Algorithm::SVMLight」のインストール方法をご紹介します。
Support Vector Machine(SVM)はどんなことをしてくれるの?
Support Vector Machine はパターン認識のための手法です。
SVM を分かりやすく説明するのは、思わず放棄したくなるほど困難なことなのですが、頑張ってみます。
たとえば、床にばらまかれた沢山のボールがあるとします。
ボールが落ちている位置に基づいて、すべてのボールを 2 つのバケツのどちらかに分けようと思います。
ボールの分け方には様々な方法があると思うのですが、
SVM による分け方は、ボール分けるときにロープを一直線に床に置いて、
ボールがロープより右にあるか左にあるかでバケツを分けるような分け方です。
大変にいい加減な図ですが、こんな図を思い浮かべてください。
o
o
o o
--------------
o o
o
o
ロープの置き方は、なんでも良い、というわけではありません。
ボールを分けたときに、ロープの左右にあるボールとロープの距離の合計が最大となるようなロープの置き方をします。
ボールの位置が変わったときでも、このロープの置き方のルールを適用すれば、ボールは迷わずに 2 つのバケツに分けることができます。
ところで、もしもボールが明らかに 2 色にだけ別れているなら、以下のように分かれていても大丈夫な気分がしますね。
o
o
o o
--------------
x x
x
x
では、ボールがこんな感じでバラまかれていたら、どこにロープを置くのでしょうか。
x
o
o o
x x
x
o
なんというか、どうやってロープを置いても、まっすぐに置く限りは上手く2つのバケツに分けられなさそうですよね。
でも、もしも上の図が実は2次元の図ではなく3次元の図だったらどうでしょうか。
図を回転してあげたら、ロープをまっすぐ引いてボールを綺麗に分けられるような位置を見つけられるかもしれません。
SVM のすごいところは、これらのボールを何とか分けられるような空間にボールを写像して、なんとか線を引いてしまいます。
x |
| o
| oo
|
xx |
x |
| o
で、たとえば、こんな感じで線を引いてしまうのです。SVM にちょっと興味が出てきましたか?
ほんのりと SVM のことが分かってもらえれば、この説明は成功です。
SVM についてちゃんと知りたい方は、キチンと別の文献を読んで理解をし直してください。
今回ご紹介するモジュール「Algorithm::SVMLight」
今回、ご紹介する「Algorithm::SVMLight」は CPAN にある SVM 向けの Perl モジュールのうち、一番ちゃんと動きそうだから選びました。
でも、多少試行錯誤しないとインストールできなかったのでネタとして丁度良かったです。
インストールできなくて諦めてしまう人も多いかと思いますので、この記事を読んでガンバってみてください。
「Algorithm::SVMLight」を使うと何が嬉しいのか
SVMlightをPerlから扱えると何が嬉しいのかというと、インスタンスの読み込み、学習の実行、モデルの書き出し・読み込み、分類結果の取得などの動作を、Perl で書いたアプリケーションの任意の位置で実行できる点にあるのかな、と思います。
分類対象のデータを素性エンコーディングして、即、SVMlight で分類しようと思うようなときには、SVMlight が Perl から扱えると嬉しいです。分類結果を出力したあと、改めて素性エンコードする前のデータに結果に適用しようとすると、面倒くさいことが多いです。
Algorithm::SVMLight の作者である Ken Williams は、このモジュールにファイルからの分類対象データの読み込み処理を書いていません。「分類対象のデータに関しては Perl で扱え!」ということですかね。。。
ちなみに、学習データを SVM の学習用の素性にエンコードする処理に関しては SVMlight とは無関係に書けます。
でも、このエンコーディング処理は複雑になりがちなので、もろもろ柔軟な Perl はかなり重宝します。
SVM light と、Algorithm::SVMLight のインストール
SVMlightの最新のソースコードは以下のURLからダウンロードできます。
今回、利用したソースコードは以下から取得しました。
その後は、以下のようにしてインストールしました。適時 sudo してください。
% wget http://search.cpan.org/CPAN/authors/id/K/KW/KWILLIAMS/Algorithm-SVMLight-0.09.tar.gz
% tar xfvz Algorithm-SVMLight-0.09.tar.gz
% mkdir ./svm_light
% cd ./svm_light
% wget http://download.joachims.org/svm_light/current/svm_light.tar.gz
% tar xfvz svm_light.tar.gz
% patch -p1 < ../Algorithm-SVMLight-0.09/SVMLight.patch
% make all
% mkdir /usr/local/bin/svm_light/
% cp ./svm_learn /usr/local/bin/svm_light/
% cp ./svm_classify /usr/local/bin/svm_light/
% mkdir /usr/local/include/svm_light/
% cp ./svm_learn.h /usr/local/include/svm_light/
% cp ./svm_common.h /usr/local/include/svm_light/
% cp ./libsvmlight.a /usr/local/lib
% cp ./libsvmlight.so /usr/local/lib
% ldconfig
% cd ../Algorithm-SVMLight-0.09/
バイナリファイルの名前を変えてコピーしているのは、変更前のファイル名が TinySVM と同じだったからです。
でも、このままだと Algorithm::SVMLight のコンパイル中に、SVMlight のヘッダファイルが見つからなくてエラーが出てしまいました。
仕方がないので、エディタで Algorithm-SVMLight-0.09/lib/Algorithm/SVMLight.c の 30・31 行目を編集し
#include "svm_common.h"
#include "svm_learn.h"
に、ヘッダの絶対パスを追記して、
#include "/usr/local/include/svm_light/svm_common.h"
#include "/usr/local/include/svm_light/svm_learn.h"
にしました。
あとは、以下を実行するだけでした。
% perl Makefile.PL
% perl Build
% perl Build test
% perl Build install
これで SVMlight のインストールが終わり、Perl スクリプトからは Algorithm::SVMLight が使えます。
SVMlight の素性エンコード
一番面倒なのが、データを素性形式にエンコード部分です。
素性の文字列表現と番号を対応づけるコードは、一回書くと使い回しが効いて楽です。
例えば以下のように実行できるエンコーダーを書いてしまって、
% perl feature_encoder.pl "入力の学習データファイルのパス" "出力の素性エンコード済みデータファイルのパス"
その後で、素性の作り方を工夫してみるのはどうでしょうか。
feature_encoder.plの例
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Encode;
use TokyoCabinet;
use MeCab;
# MeCabオブジェクト
my @mecab_opt = ();
my $mecab = new MeCab::Tagger(join " ", @mecab_opt);
my $inputdata = $ARGV[0];
my $outputdata = $ARGV[1];
my ($in, $out);
# TokyoCabinetの初期化
my $tchdb_file_path = $FindBin::Bin."/../feature_num.tch";
my $hdb = TokyoCabinet::HDB->new();
$hdb->tune(2000000);
$hdb->open($tchdb_file_path, $hdb->OWRITER | $hdb->OCREAT | $hdb->OREADER);
# 素性番号カウンタ
my $gloval_counter = 1;
# 素性番号カウンタの値をHDBから取り出すためのキー
my $gkey = "GLOBALCOUNTER";
# 素性番号カウンタの値を取得
my $tmp_gloval_counter = $hdb->get($gkey);
if (defined $tmp_gloval_counter) {
$gloval_counter = $tmp_gloval_counter;
}
else {
# 取得できなかったら初期値「1」を登録
$hdb->put($gkey, 1);
$gloval_counter = 1;
}
open ($in, "< $inputdata");
open ($out, ">> $outputdata");
# 素性の書き出し
while(my $line = <$in>){
chomp $line;
next unless ($line);
# MeCabの結果を取得する
my @mecab_arr = @{get_mecab_result_arr($line)};
next unless (@mecab_arr);
my $count = 0;
# ラベル
my $label = 0;
# 出力用に素性番号を突っ込む配列
my @feature_arr = ();
# 素性の材料を得る
my $entry = $mecab_arr[$i];
my $key = $entry->[0];
my $pos = $entry->[1];
my $keypos = "$key:-:$pos";
# 素性番号の取得と登録
my @keyarr = ($key, $pos, $keypos);
foreach my $k (@keyarr) {
# 素性番号を取得してみる
my $tmp_feature_num = $hdb->get($k);
my $feature_num = 0;
if (defined $tmp_feature_num) {
# 取得できたら、そのまま出力用の配列に突っ込む
push @feature_arr, "$tmp_feature_num";
}
else {
# 取得できなかったら、素性番号カウンタの値を取得
$feature_num = $gloval_counter;
# カウンタの値を、キーに対する素性番号にして登録
$hdb->put($k, $feature_num);
# 素性番号カウンタ++
$gloval_counter++;
# 素性番号カウンタのバックアップ
$hdb->put($gkey, $gloval_counter);
push @feature_arr, "$feature_num";
}
}
# ソート、ユニークする。
@feature_arr = sort {$a < = > $b} @feature_arr;
my $x = '-';
my @uniq_arr = grep( $_ ne $x && ($x = $_), @feature_arr);
# この例では、最後に全ての素性に一様な重みをつけている
my $features = join ":0.1 ", @uniq_arr;
my $entry = "$label $features:0.1\n";
print $out $entry;
}
close ($out);
close ($in);
$hdb->close();
# 1行のテキストを受け取り、MeCabでparseしたあと、結果を配列に入れて返す。
sub get_mecab_result_arr {
my ($line) = @_;
my $parsed = $mecab->parse($line);
$parsed = decode_utf8($parsed) unless utf8::is_utf8($parsed);
my @pos_arr = split('\n', $parsed);
my @result = ();
if(@pos_arr){
my $i = 0;
foreach my $pos (@pos_arr){
my @info_arr = split(/\t/, $pos);
my @mecab_arr = split(/\,/, $info_arr[1]);
my @mec = ($info_arr[0], @mecab_arr);
$result[$i] = \@mec;
$i++;
}
}
return \@result;
}
このファイルの中には TokyoCabinetを使った素性番号管理と、MeCab を使った形態素解析の処理が含まれています。
TokyoCabinetのHDBに、現在の素性番号の最大値を格納してあるので、追加も楽にできます。
SVMlight の素性エンコード時の注意点
SVMlight に素性エンコードしたインスタンスを読み込ませるには、以下のような注意が必要です。
- インスタンス中の素性番号は昇順に並べること
- 良い例:-1 10:0.1 20:0.2 30:0.3
- 悪い例:-1 10:0.1 40:0.4 30:0.3
- インスタンス中の素性番号はユニークにすること
- 良い例:-1 10:0.1 20:0.2 30:0.3
- 悪い例:-1 10:0.1 20:0.2 20:0.3
- 学習データ以外の、分類対象のデータをエンコードする場合にもラベルを付与する
Algorithm::SVMLight を使ったモデル構築
Algorithm::SVMLight を使うと、モデルの構築は例えば以下のように書けます。
% perl ./make_model.pl "入力のインスタンスファイルのパス" "出力のモデルファイルのパス"
素性にエンコード済みなインスタンスファイルを用意できれば、上記を実行してあげるとモデルが得られます。
make_model.pl の例
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
# オブジェクト作成
use Algorithm::SVMLight;
my $svm = new Algorithm::SVMLight;
# 入出力ファイルのパス
my $inputdata = $ARGV[0];
my $outputdata = $ARGV[1];
# インスタンスの読み込み
$svm->read_instances($inputdata);
# 学習開始
$svm->train();
# モデルの書き出し
$svm->write_model($outputdata);
Algorithm::SVMLight があれば、モデル構築以外の処理も Perl で手軽に書けます。
まとめ
今回は SVMLight の Perl モジュールである Algorithm::SVMLight をインストールしました。
SVM は使いどころを間違えなければ大変に便利です。SVM を扱った学術論文は多数あるので、そちらもご覧下さい。
さてさて、明日は pixiv のエンジニアである kamipo さんです。楽しみですね!
分享到:
相关推荐
SVM-RFE algorithm:SVM-RFE算法.pdf
java.lang.RuntimeException: Unsupported algorithm: HmacSHA1 解决方法,阿里云
Maven坐标:org.pentaho:pentaho-aggdesigner-algorithm:5.1.5-jhyde; 标签:aggdesigner、pentaho、algorithm、jar包、java、API文档、中文版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,...
面向初学者,深入浅出,通俗易懂的算法介绍。Once Upon an Algorithm: How Stories Explain Computing
张正友标定法基础上的深入理解与实现
解决 Cannot resolve org.pentaho:pentaho-aggdesigner-algorithm:5.1.5-jhyde jar放入D根目录执行: 以下命令加入本地maven库 mvn install:install-file -DgroupId=org.pentaho -DartifactId=pentaho-aggdesigner-...
解决maven引入hive的jar包时依赖报错Could not find artifact org.pentaho:pentaho-aggdesigner-algorithm:pom:5.1.5-jhyde in xxx的问题,maven路径org/pentaho/pentaho-aggdesigner-algorithm/5.1.5-jhyde/pentaho...
可以解决,maven引入hive jar包时,hive Could not find artifact org.pentaho:pentaho-aggdesigner-algorithm:jar:5.1.5-jhyde 问题
# 自作モジュールから必要な部分をインポート from global_variable import selected_value, selected_number, route_name_entry, num, start, half, stop, gool, route_names, angles import Algorithm_test_window...
NIPALS algorithm:NIPALS算法.pdf
pentaho-aggdesigner-algorithm / 5.1.5-jhyde / pentaho-aggdesigner-algorithm-5.1.5-jhyde.jar,解决maven引入hive的jar包时依赖报错Could not find artifact org.pentaho:pentaho-aggdesigner-algorithm:...
あくまで趣味ベースで作ったものなので,プルリクエストは受け付けてますが依頼などは一切受け付けませんそこをご理解顶けた方のみご利用下さいもしこれがみなさんのお役に立ったらGithub赞助商になってください!...
A Gaussian Firefly Algorithm:高斯萤火虫算法.pdf
Algorithm:为了在2021年找份好的实习!加油
Proof for Dijkstra´s Algorithm:Dijkstra算法证明.pdf
CHAMELEON A Hierarchical Clustering Algorithm :变色龙的层次聚类算法.ppt
java maven 仓库包 pentaho-aggdesigner-algorithm-5.1.3-jhyde.jar
经典的算法分析和设计的课程考试题目。并配有答案可供联系