libsvm を JRuby で使う

hfu2007-11-16

libsvmJRuby で使ってみました。

JRuby SVM の実装

libsvm の配布物に添付されている libsvm.jar をクラスパスに置いたら、後は以下のコードだけで libsvm がそれなりに使えるようになるようです:

require 'java'

module SVM
  SVM = JavaUtilities.get_proxy_class('libsvm.svm')
  Model = JavaUtilities.get_proxy_class('libsvm.svm_model')
  Parameter = JavaUtilities.get_proxy_class('libsvm.svm_parameter')
  Problem = JavaUtilities.get_proxy_class('libsvm.svm_problem')
end

上記のコードは、Java のクラスを JRuby にとりこんでいるだけなので、本来自明な処理です。しかし、libsvm.jar では、クラスが Java のクラス名の命名規則に従っておらず、クラス名が小文字で始まっているという問題があります。これにより、JRuby の import や include_class で普通にクラスを取り込もうとすると、うまくいきません。Ruby の定数の命名規約違反になってしまうためです。
そこで、JRuby のメソッド include_class の定義を調べ、上記のようなコードにすればエラーなくクラスを取り込んでくれることが分かりました。
libsvm の構造を調べるに当たり、CRuby 用の libsvm バインディングである、Ruby SVM の RDoc ドキュメントが助けになりました。

クラス構造を調べる

この libsvm ライブラリの使い方は、Web 上にはそれほど書かれていません。しかし、libsvm の配布物に含まれている README と C ソース(コマンドラインツール (svm-scale, svm-train, svm-predict) の C ソース)を読むのが使い方を知る早道のようです。
README, C ソースに加えた補助的なデータとして、主要 Java クラスの構造を javap で調べてみました:

libsvm.svm
$ javap -classpath ~/Library/Java/Extensions/libsvm.jar libsvm.svm
Compiled from "svm.java"
public class libsvm.svm extends java.lang.Object{
    static final java.lang.String[] svm_type_table;
    static final java.lang.String[] kernel_type_table;
    public libsvm.svm();
    static libsvm.svm$decision_function svm_train_one(libsvm.svm_problem, libsvm.svm_parameter, double, double);
    public static libsvm.svm_model svm_train(libsvm.svm_problem, libsvm.svm_parameter);
    public static void svm_cross_validation(libsvm.svm_problem, libsvm.svm_parameter, int, double[]);
    public static int svm_get_svm_type(libsvm.svm_model);
    public static int svm_get_nr_class(libsvm.svm_model);
    public static void svm_get_labels(libsvm.svm_model, int[]);
    public static double svm_get_svr_probability(libsvm.svm_model);
    public static void svm_predict_values(libsvm.svm_model, libsvm.svm_node[], double[]);
    public static double svm_predict(libsvm.svm_model, libsvm.svm_node[]);
    public static double svm_predict_probability(libsvm.svm_model, libsvm.svm_node[], double[]);
    public static void svm_save_model(java.lang.String, libsvm.svm_model)       throws java.io.IOException;
    public static libsvm.svm_model svm_load_model(java.lang.String)       throws java.io.IOException;
    public static java.lang.String svm_check_parameter(libsvm.svm_problem, libsvm.svm_parameter);
    public static int svm_check_probability_model(libsvm.svm_model);
    static {};
}
libsvm.svm_model
$ javap -classpath ~/Library/Java/Extensions/libsvm.jar libsvm.svm_model
Compiled from "svm_model.java"
public class libsvm.svm_model extends java.lang.Object implements java.io.Serializable{
    libsvm.svm_parameter param;
    int nr_class;
    int l;
    libsvm.svm_node[][] SV;
    double[][] sv_coef;
    double[] rho;
    double[] probA;
    double[] probB;
    int[] label;
    int[] nSV;
    public libsvm.svm_model();
}
libsvm.svm_parameter
$ javap -classpath ~/Library/Java/Extensions/libsvm.jar libsvm.svm_parameter
Compiled from "svm_parameter.java"
public class libsvm.svm_parameter extends java.lang.Object implements java.lang.Cloneable,java.io.Serializable{
    public static final int C_SVC;
    public static final int NU_SVC;
    public static final int ONE_CLASS;
    public static final int EPSILON_SVR;
    public static final int NU_SVR;
    public static final int LINEAR;
    public static final int POLY;
    public static final int RBF;
    public static final int SIGMOID;
    public static final int PRECOMPUTED;
    public int svm_type;
    public int kernel_type;
    public int degree;
    public double gamma;
    public double coef0;
    public double cache_size;
    public double eps;
    public double C;
    public int nr_weight;
    public int[] weight_label;
    public double[] weight;
    public double nu;
    public double p;
    public int shrinking;
    public int probability;
    public libsvm.svm_parameter();
    public java.lang.Object clone();
}
libsvm.svm_problem
$ javap -classpath ~/Library/Java/Extensions/libsvm.jar libsvm.svm_problem
Compiled from "svm_problem.java"
public class libsvm.svm_problem extends java.lang.Object implements java.io.Serializable{
    public int l;
    public double[] y;
    public libsvm.svm_node[][] x;
    public libsvm.svm_problem();
}
libsvm.svm_node
$ javap -classpath ~/Library/Java/Extensions/libsvm.jar libsvm.svm_node
Compiled from "svm_node.java"
public class libsvm.svm_node extends java.lang.Object implements java.io.Serializable{
    public int index;
    public double value;
    public libsvm.svm_node();
}

これから

使用例などもあとで書くかもしれません。geotools.rb と同じく、素のラッパの上に、グッドラッパを目指すラッパを作っていくかもしれません。