这里写下关于libsvm中,从MATLAB文件夹中的svmtrain.c和svmpredict.c入口,如何调用svm.cpp的过程进行详细的解析。当遇到比较重要的新的函数时,会在后面列出这个函数的作用和详细执行的过程,以便自己能看懂。
注:这里主要侧重调用C_SVC的情况,以及当置b=1时的情况分析。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
首先列在前面的是,头文件中需要了解并在后面函数中会用到的两个结构。
struct svm_problem
{
int l; 样本个数
double *y; 类别
struct svm_node **x; 一条样本的特征
};
struct svm_node 一个特征节点
{
int index; 特征序号
double value; 特征值
};
Svm整个过程:
一、训练过程(直接进入svm.cpp进行分析)
进入函数,进行执行,最后会输出一个model
svm_model *svm_train(const svm_problem *prob, const svm_parameter *param)
1.先对同label的进行归纳
svm_group_classes(prob,&nr_class,&label,&start,&count,perm);
2.对两两各个类进行计算:
1)选出两类的数据,由于pro=1,故执行
svm_binary_svc_probability(&sub_prob,param,weighted_C[i],weighted_C[j],probA[p],probB[p]);
这里填充probA,probB的值
2)decision_function svm_train_one(const svm_problem *prob, const svm_parameter *param,double Cp, double Cn) (decision_function包含alpha/rho系数的系数)
其中的solve_c_svc(prob,param,alpha,&si,Cp,Cn);函数进行求解,得到alpha/rho系数。
最后进行模型model的属性赋值。
细节/需要改的地方具体分析:
函数:
static void svm_binary_svc_probability(
const svm_problem *prob, const svm_parameter *param,
double Cp, double Cn, double& probA, double& probB)
作用:
对该函数,输入参数和数据,对proA/proB进行训练并赋值。
解析该函数:
该函数默认进行5折交叉,先交叉,得到部分数据,进行部分训练,
struct svm_model *submodel = svm_train(&subprob,&subparam);
然后进行其他数据进行验证,
svm_predict_values(submodel,prob->x[perm[j]],&(dec_values[perm[j]]));
dec_values[perm[j]] *= submodel->label[0];
(输入刚刚训练好的模型,一个样本的特征,来得到决策值f(x),再求y*f(x))
最后,将得到的决策值,和样本输入,进行sigmoid训练,得到系数A.B的值
sigmoid_train(prob->l,dec_values,prob->y,probA,probB);
函数:
double svm_predict_values(const svm_model *model, const svm_node *x, double* dec_values)
作用:
给定model和一个样本的特征,得到决策值。返回的是投票最多的类别。
注:dec_values是一个数组,有nr_class*(nr_class-1)/2个值。
解析该函数:
对两两类的向量进行比较,找出比较的两个不同类别的向量(start是每类开始的位置,nSV是支持向量的个数)
sum += coef1[si+k] * kvalue[si+k]; 将第一类的式子进行计算, alpha*K(X,xi)
最后得到,y=alpha*K(x,xi)-b的值dec_values
若要得到这个样本属于哪一类,则进行两两类测试,并投票,票数多的决定它的类别。
函数:
static void sigmoid_train(int l, const double *dec_values, const double *labels, double& A, double& B)
输入决策之和label,训练系数A和B
二、预测过程
在svmpredict.c文件中。进入predict函数
若Pro=1,则执行函数
predict_label = svm_predict_probability(model, x, prob_estimates);
得到预测的label。也得到估计概率prob_estimates 若有三类,则prob_estimates有三个值。
然后将得到的概率值返回到 ptr_prob_estimates
ptr_prob_estimates[instance_index + i * testing_instance_number] = prob_estimates[i];
*ptr_prob_estimates指针指向tplhs[2]。(pro=1)
*ptr_dec_values也指向tplhs[2]。(pro=0)
给指针ptr_prob_estimates赋值就是给tplhs[2]赋值。而tplhs[2]赋值给plhs。
plhs就是predict(int nlhs, mxArray *plhs[], const mxArray *prhs[], struct svm_model *model, const int predict_probability)中的参数。
Prhs 是从MATLAB输入的测试标记,测试特征。
plhs是从MATLAB返回的三个参数。
tplhs有三个参数,第一个是预测的label
Tplhs[0] = ptr_predict_label
Tplhs[1] = 三个值 return accuracy, mean squared error, squared correlation coefficient
Tplhs[2] = ptr_prob_estimates(概率值) 或者 ptr_dec_values(预测值)
(注:该函数中,prhs[0]对应输入的测试标记Y_test,prhs[1]对应输入的预测特征。)
若pro=0,则执行函数
predict_label = svm_predict_values(model, x, dec_values);
函数(在svm.cpp中):
double svm_predict_probability(const svm_model *model, const svm_node *x, double *prob_estimates)
作用:输入模型model,一个样本的特征,得到概率估计的值prob_estimates。同时返回该样本的label。
解析该函数:
1. 若pro=1,
1)则先调用svm_predict_values(model, x, dec_values);得到样本x对应的nr_class*(nr_class-1)/2个值。
2)然后进行两两类别,得到属于这两两类别的概率值,即调用static double sigmoid_predict(double decision_value, double A, double B)得到sigmoid的函数值。
注:进行的两两比较是这样进行的:如有三个类别0,1,2.则进行0->1,0->2,1->2.进行两两类别对峙。
3)然后调用函数
multiclass_probability(nr_class,pairwise_prob,prob_estimates);
得到每个类别的概率值,如prob_estimates有三个值,分别对应3个类别的概率值。
4)最后计算哪个类别的概率最大,返回该类别的值。
2. 若pro-0, 则调用double svm_predict(const svm_model *model, const svm_node *x),这个函数是调用函数double pred_result = svm_predict_values(model, x, dec_values); 得到最后属于哪个类别的值pred_result。
至此,能够把整体的顺序过了一遍。这里只列出比较重点的函数分析,其他的函数和结构自己依照svm.cpp中的函数过程去看。