由于DSP片上存储空间有限,只有2M,放了一个Haar特征检测模型之后,再没有多少存储空间了。用libsvm训练出来一个11M的模型没法移植上去,于是想到了试试liblinear。结果发现liblinear训练好的模型小了很多,精度和libsvm差不多。
在vs2012建立一个工程,把liblinear里的blas.h 、blasp.h、linear.h、tron.h、daxpy.cpp、ddot.cpp、dnrm2.cpp、dscal.cpp、linear.cpp、tron.cpp导入你的项目中。
CxLibLinear.h
#ifndef _CXLIBLINEAR_H_H_
#define _CXLIBLINEAR_H_H_
#include
#include
#include
#include "linear.h"
using namespace std;
//内存分配
#define Malloc(type,n) (type *)malloc((n)*sizeof(type))
class CxLibLinear
{
public:
struct parameter param;
private:
struct feature_node *x_space;
struct problem prob;
struct model* model_;
public:
CxLibLinear();
~CxLibLinear();
void init_linear_param(struct parameter& param);
void train_model(const vector>& x, const vector& y, const struct parameter& param);
int do_predict(const vector& x,double& prob_est);
void do_cross_validation(const vector>& x, const vector& y, const struct parameter& param, const int & nr_fold);
int load_linear_model(string model_path);
int save_linear_model(string model_path);
void free_model();
};
#endif
CxLibLinear.cpp
#include "stdafx.h"
#include "CxLibLinear.h"
CxLibLinear::CxLibLinear()
{
model_ = NULL;
}
CxLibLinear::~CxLibLinear()
{
free_model();
}
void CxLibLinear::init_linear_param(struct parameter& param)
{
//参数初始化,参数调整部分在这里修改即可
// 默认参数
param.solver_type = L2R_L2LOSS_SVC;
param.eps = 0.001;
param.C = 2;
param.nr_weight = 0;
param.weight_label = NULL;
param.weight = NULL;
param.p = 0.001;
param.init_sol = NULL;
}
void CxLibLinear::train_model(const vector>& x, const vector& y, const struct parameter& param)
{
if (x.size() == 0)
{
return;
}
//释放先前的模型
free_model();
/*初始化*/
long len = x.size();
long dim = x[0].size();
long elements = len * dim;
//转换数据为liblinear格式
prob.l = len;
prob.n = dim;
prob.bias = -1.0;
prob.y = Malloc(double, prob.l);
prob.x = Malloc(struct feature_node *, prob.l);
x_space = Malloc(struct feature_node, elements + len);
int j = 0;
for (int l = 0; l < len; l++)
{
prob.x[l] = &x_space[j];
for (int d = 0; d < dim; d++)
{
x_space[j].index = d+1;
x_space[j].value = x[l][d];
j++;
}
x_space[j++].index = -1;
prob.y[l] = y[l];
}
/*训练*/
model_ = train(&prob, ¶m);
}
int CxLibLinear::do_predict(const vector& x,double& prob_est)
{
//int nr_class=get_nr_class(model_);
//double *prob_estimates=NULL;
//int n;
//int nr_feature=get_nr_feature(model_);
//if(model_->bias>=0)
// n=nr_feature+1;
//else
// n=nr_feature;
//double predict_label;
//feature_node* x_test = Malloc(struct feature_node, x.size()+1);
//for (unsigned int i = 0; i < x.size(); i++)
//{
// if(model_->bias>=0)
// {
// x_test[i].index = n;
// x_test[i].value = model_->bias;
// }
// else
// {
// x_test[i].index = i + 1;
// x_test[i].value = x[i];
// }
//
//}
//x_test[x.size()].index = -1;
//
//predict_label = predict(model_,x_test);
//
//return (int)predict_label;
//数据转换
feature_node* x_test = Malloc(struct feature_node, x.size()+1);
for (unsigned int i = 0; i < x.size(); i++)
{
x_test[i].index = i + 1;
x_test[i].value = x[i];
}
x_test[x.size()].index = -1;
double *probs = new double[model_->nr_class];//存储了所有类别的概率
//预测类别和概率
int value = (int)predict_values(model_, x_test, probs);
for (int k = 0; k < model_->nr_class; k++)
{//查找类别相对应的概率
if (model_->label[k] == value)
{
prob_est = probs[k];
break;
}
}
delete[] probs;
return value;
}
void CxLibLinear::do_cross_validation(const vector>& x, const vector& y, const struct parameter& param, const int & nr_fold)
{
if (x.size() == 0)
return;
/*初始化*/
long len = x.size();
long dim = x[0].size();
long elements = len*dim;
//转换数据为liblinear格式
prob.l = len;
prob.n = dim;
prob.y = Malloc(double, prob.l);
prob.x = Malloc(struct feature_node *, prob.l);
x_space = Malloc(struct feature_node, elements + len);
int j = 0;
for (int l = 0; l < len; l++)
{
prob.x[l] = &x_space[j];
for (int d = 0; d < dim; d++)
{
x_space[j].index = d + 1;
x_space[j].value = x[l][d];
j++;
}
x_space[j++].index = -1;
prob.y[l] = y[l];
}
int i;
int total_correct = 0;
double total_error = 0;
double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0;
double *target = Malloc(double, prob.l);
cross_validation(&prob, ¶m, nr_fold, target);
if(param.solver_type == L2R_L2LOSS_SVR ||
param.solver_type == L2R_L1LOSS_SVR_DUAL ||
param.solver_type == L2R_L2LOSS_SVR_DUAL)
{
for (i = 0; i < prob.l; i++)
{
double y = prob.y[i];
double v = target[i];
total_error += (v - y)*(v - y);
sumv += v;
sumy += y;
sumvv += v*v;
sumyy += y*y;
sumvy += v*y;
}
printf("Cross Validation Mean squared error = %g
", total_error / prob.l);
printf("Cross Validation Squared correlation coefficient = %g
",
((prob.l*sumvy - sumv*sumy)*(prob.l*sumvy - sumv*sumy)) /
((prob.l*sumvv - sumv*sumv)*(prob.l*sumyy - sumy*sumy))
);
}
else
{
for (i = 0; i < prob.l; i++)
if (target[i] == prob.y[i])
++total_correct;
printf("Cross Validation Accuracy = %g%%
", 100.0*total_correct / prob.l);
}
free(target);
}
int CxLibLinear::load_linear_model(string model_path)
{
//释放原来的模型
free_model();
//导入模型
model_ = load_model(model_path.c_str());
if (model_ == NULL)
return -1;
return 0;
}
int CxLibLinear::save_linear_model(string model_path)
{
int flag = save_model(model_path.c_str(), model_);
return flag;
}
void CxLibLinear::free_model()
{
if (model_ != NULL)
{
free_and_destroy_model(&model_);
destroy_param(¶m);
if (prob.y != NULL)
{
free(prob.y);
prob.y = NULL;
}
if (prob.x != NULL)
{
free(prob.x);
prob.x = NULL;
}
if (x_space != NULL)
{
free(x_space);
x_space = NULL;
}
}
}
main.cpp
#include "stdafx.h"
#include "CxLibLinear.h"
#include
#include
using namespace std;
void gen_train_sample(vector>& x, vector& y, long sample_num, long dim, double scale);
void gen_test_sample(vector& x, long sample_num, long dim, double scale);
int _tmain(int argc, _TCHAR* argv[])
{
//初始化liblinear对象
CxLibLinear linear;
linear.init_linear_param(linear.param);
/*1、准备训练数据*/
vector> x; //样本集
vector y; //样本类别标签集
gen_train_sample(x, y, 2000, 288, 1);
/*1、交叉验证*/
int fold = 10;
linear.do_cross_validation(x, y, linear.param, fold);
/*2、训练*/
linear.train_model(x, y, linear.param);
/*3、保存模型*/
string model_path = "linear_model.txt";
linear.save_linear_model(model_path);
/*4、导入模型*/
linear.load_linear_model(model_path);
/*5、预测*/
//生成随机测试数据
vector x_test;
gen_test_sample(x_test, 2000, 288, -1);
double prob_est;
//预测
int value = linear.do_predict(x_test, prob_est);
//打印预测类别和概率
printf("label: %d ", value);
return 0;
}
void gen_train_sample(vector>& x, vector& y, long sample_num, long dim, double scale)
{
srand((unsigned)time(NULL));//随机数
//生成随机的正类样本
for (int i = 0; i < sample_num; i++)
{
vector rx;
for (int j = 0; j < dim; j++)
{
rx.push_back(scale*(rand() % dim));
}
x.push_back(rx);
y.push_back(1);
//printf("y = %d
",(int)y[i]);
}
//生成随机的负类样本
for (int m = 0; m < sample_num; m++)
{
vector rx;
for (int n = 0; n < dim; n++)
{
rx.push_back(-scale*(rand() % dim));
}
x.push_back(rx);
y.push_back(2);
//printf("y = %d
",(int)y[sample_num + m]);
}
}
void gen_test_sample(vector& x, long sample_num, long dim, double scale)
{
srand((unsigned)time(NULL));//随机数
//生成随机的正类样本
for (int j = 0; j < dim; j++)
{
x.push_back(-scale*(rand() % dim));
}
}