封装Libsvm与Liblinear
开篇我们基于以下场景:
假设我们已经用libsvm或者是Liblinear训练了一个模型,现在需要读入该模型并基于该模型对一个样本进行预测,返回预测的类标签以及相应的隶属度分数。
从封装的角度我们需要考虑一下几个问题:
- 如何规范输入,使得读入的数据在Libsvm与Liblinear上都可以直接运行
- 系统如何识别读入的模型的类别,并根据模型类别,选择Libsvm或者是Liblinear中合适的函数进行预测
- 如何预测该样本对应的标签以及得分
系统输入
因为我们对单个样本进行预测,所以这里直接定义单个节点的格式即可。对于多个样本,则可以循环调用。
在上一篇文章中,我们看到虽然Libsvm与Liblinear在向量节点的定义上有所差别,但是其中的成员变量还是一致的,因此为了统一,我们只需要重新定义一个新的类。
public class SvmNode {
/** 封装的Libsvm与Liblinear的节点格式**/
private final int index;
private double value;
public SvmNode( final int index, final double value ) {
if (index < 0) throw new IllegalArgumentException("index must be >= 0");
this.index = index;
this.value = value;
}
/**以下Getter和Setter、hashCode、equals函数省略**/
}
模型读入
我们首先来剖析一下Libsvm与Liblinear生成的模型的文件格式
![](https://img-my.csdn.net/uploads/201204/08/1333882054_6176.jpg)
从上述文件中,我们看到两者的模型文件存在很大的差异,因此我们只需要写一个解析函数直接读取模型的格式来判断到底属于那种模型。
最简单的形式就是直接通过第一行来判断,因为其模型的文件都是固定的,所以这种最简单的方式也是很有效的。
/**
* 读入模型文件。通过文件中的格式来判断到底属于Libsvm还是liblinear
* @param model_filename 模型文件保存的路径及名称
*/
public void load_model(String model_filename){
BufferedReader fp;
try {
InputStream in = new FileInputStream(model_filename);
fp = new BufferedReader(new InputStreamReader(in,"UTF-8"));
String line = null;
try {
while((line = fp.readLine())!=null){
String[] arg = whitespace.split(line);
//通过判断文件中每行第一个字符是否包含"svm_type"或者是"solver_type"
//来判断是Libsvm还是Liblinear
if(arg[0].equals("svm_type")){
svm_type = "libsvm";
svmModel = svm.svm_load_model(model_filename);
nr_class = svmModel.nr_class;
linearModel = null;
break;
}
if(arg[0].equals("solver_type")){
svm_type="liblinear";
svmModel = null;
linearModel = Linear.