libsvm代码阅读:关于svm_train函数分析(转)

在svm中,训练是一个十分重要的步骤,下面我们来看看svm的train部分。

在libsvm中的svm_train中分别有回归和分类两部分,我只对其中分类做介绍。

分类的步骤如下:

  • 统计类别总数,同时记录类别的标号,统计每个类的样本数目
  • 将属于相同类的样本分组,连续存放
  • 计算权重C
  • 训练n(n-1)/2 个模型
    • 初始化nozero数组,便于统计SV
    • //初始化概率数组
    • 训练过程中,需要重建子数据集,样本的特征不变,但样本的类别要改为+1/-1
    • //如有必要,先调用svm_binary_svc_probability
    • 训练子数据集svm_train_one
    • 统计一下nozero,如果nozero已经是真,就不变,否则改为真
  • 输出模型
    • 主要是填充svm_model
  • 清除内存

函数中调用过程如下:

svm_train-->svm_train_one-->solve_c_svc(for example)-->s.Solve

[cpp]   view plain copy  

<EMBED id=ZeroClipboardMovie_1 height=18 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=1&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. //
  2. // Interface functions
  3. //重点函数:svm训练函数
  4. //根据选择的算法,来组织参加训练的分样本,以及进行训练结果的保存。其中会对样本进行初步的统计。
  5. svm_model *svm_train(const svm_problem *prob, const svm_parameter *param)
  6. {
  7. svm_model *model = Malloc(svm_model,1);//#define Malloc(type,n) (type *)malloc((n)*sizeof(type))
  8. model->param = *param;
  9. model->free_sv = 0;  // XXX
  10. if(param->svm_type == ONE_CLASS ||
  11. param->svm_type == EPSILON_SVR ||
  12. param->svm_type == NU_SVR)
  13. {
  14. // regression or one-class-svm
  15. model->nr_class = 2;
  16. model->label = NULL;
  17. model->nSV = NULL;
  18. model->probA = NULL; model->probB = NULL;
  19. model->sv_coef = Malloc(double *,1);
  20. if(param->probability &&
  21. (param->svm_type == EPSILON_SVR ||
  22. param->svm_type == NU_SVR))
  23. {
  24. model->probA = Malloc(double,1);
  25. model->probA[0] = svm_svr_probability(prob,param);
  26. }
  27. decision_function f = svm_train_one(prob,param,0,0);
  28. model->rho = Malloc(double,1);
  29. model->rho[0] = f.rho;
  30. int nSV = 0;
  31. int i;
  32. for(i=0;i<prob->l;i++)
  33. if(fabs(f.alpha[i]) > 0) ++nSV;
  34. model->l = nSV;
  35. model->SV = Malloc(svm_node *,nSV);
  36. model->sv_coef[0] = Malloc(double,nSV);
  37. model->sv_indices = Malloc(int,nSV);
  38. int j = 0;
  39. for(i=0;i<prob->l;i++)
  40. if(fabs(f.alpha[i]) > 0)
  41. {
  42. model->SV[j] = prob->x[i];
  43. model->sv_coef[0][j] = f.alpha[i];
  44. model->sv_indices[j] = i+1;
  45. ++j;
  46. }
  47. free(f.alpha);
  48. }
  49. else
  50. {
  51. // classification
  52. int l = prob->l;
  53. int nr_class;
  54. int *label = NULL;
  55. int *start = NULL;
  56. int *count = NULL;
  57. int *perm = Malloc(int,l);
  58. // group training data of the same class对训练样本进行处理,同类整合到一起
  59. svm_group_classes(prob,&nr_class,&label,&start,&count,perm);
  60. if(nr_class == 1)
  61. info("WARNING: training data in only one class. See README for details.\n");
  62. svm_node **x = Malloc(svm_node *,l);
  63. int i;
  64. for(i=0;i<l;i++)
  65. x[i] = prob->x[perm[i]];
  66. // calculate weighted C
  67. double *weighted_C = Malloc(double, nr_class);
  68. for(i=0;i<nr_class;i++)
  69. weighted_C[i] = param->C;
  70. for(i=0;i<param->nr_weight;i++)
  71. {
  72. int j;
  73. for(j=0;j<nr_class;j++)
  74. if(param->weight_label[i] == label[j])
  75. break;
  76. if(j == nr_class)
  77. fprintf(stderr,"WARNING: class label %d specified in weight is not found\n", param->weight_label[i]);
  78. else
  79. weighted_C[j] *= param->weight[i];
  80. }
  81. // train k*(k-1)/2 models
  82. bool *nonzero = Malloc(bool,l);
  83. for(i=0;i<l;i++)
  84. nonzero[i] = false;
  85. decision_function *f = Malloc(decision_function,nr_class*(nr_class-1)/2);
  86. double *probA=NULL,*probB=NULL;
  87. if (param->probability)
  88. {
  89. probA=Malloc(double,nr_class*(nr_class-1)/2);
  90. probB=Malloc(double,nr_class*(nr_class-1)/2);
  91. }
  92. int p = 0;
  93. for(i=0;i<nr_class;i++)
  94. for(int j=i+1;j<nr_class;j++)
  95. {
  96. svm_problem sub_prob;
  97. int si = start[i], sj = start[j];
  98. int ci = count[i], cj = count[j];
  99. sub_prob.l = ci+cj;
  100. sub_prob.x = Malloc(svm_node *,sub_prob.l);
  101. sub_prob.y = Malloc(double,sub_prob.l);
  102. int k;
  103. for(k=0;k<ci;k++)
  104. {
  105. sub_prob.x[k] = x[si+k];
  106. sub_prob.y[k] = +1;
  107. }
  108. for(k=0;k<cj;k++)
  109. {
  110. sub_prob.x[ci+k] = x[sj+k];
  111. sub_prob.y[ci+k] = -1;
  112. }
  113. if(param->probability)
  114. svm_binary_svc_probability(&sub_prob,param,weighted_C[i],weighted_C[j],probA[p],probB[p]);
  115. f[p] = svm_train_one(&sub_prob,param,weighted_C[i],weighted_C[j]);
  116. for(k=0;k<ci;k++)
  117. if(!nonzero[si+k] && fabs(f[p].alpha[k]) > 0)
  118. nonzero[si+k] = true;
  119. for(k=0;k<cj;k++)
  120. if(!nonzero[sj+k] && fabs(f[p].alpha[ci+k]) > 0)
  121. nonzero[sj+k] = true;
  122. free(sub_prob.x);
  123. free(sub_prob.y);
  124. ++p;
  125. }
  126. // build output
  127. model->nr_class = nr_class;
  128. model->label = Malloc(int,nr_class);
  129. for(i=0;i<nr_class;i++)
  130. model->label[i] = label[i];
  131. model->rho = Malloc(double,nr_class*(nr_class-1)/2);
  132. for(i=0;i<nr_class*(nr_class-1)/2;i++)
  133. model->rho[i] = f[i].rho;
  134. if(param->probability)
  135. {
  136. model->probA = Malloc(double,nr_class*(nr_class-1)/2);
  137. model->probB = Malloc(double,nr_class*(nr_class-1)/2);
  138. for(i=0;i<nr_class*(nr_class-1)/2;i++)
  139. {
  140. model->probA[i] = probA[i];
  141. model->probB[i] = probB[i];
  142. }
  143. }
  144. else
  145. {
  146. model->probA=NULL;
  147. model->probB=NULL;
  148. }
  149. int total_sv = 0;
  150. int *nz_count = Malloc(int,nr_class);
  151. model->nSV = Malloc(int,nr_class);
  152. for(i=0;i<nr_class;i++)
  153. {
  154. int nSV = 0;
  155. for(int j=0;j<count[i];j++)
  156. if(nonzero[start[i]+j])
  157. {
  158. ++nSV;
  159. ++total_sv;
  160. }
  161. model->nSV[i] = nSV;
  162. nz_count[i] = nSV;
  163. }
  164. info("Total nSV = %d\n",total_sv);
  165. model->l = total_sv;
  166. model->SV = Malloc(svm_node *,total_sv);
  167. model->sv_indices = Malloc(int,total_sv);
  168. p = 0;
  169. for(i=0;i<l;i++)
  170. if(nonzero[i])
  171. {
  172. model->SV[p] = x[i];
  173. model->sv_indices[p++] = perm[i] + 1;
  174. }
  175. int *nz_start = Malloc(int,nr_class);
  176. nz_start[0] = 0;
  177. for(i=1;i<nr_class;i++)
  178. nz_start[i] = nz_start[i-1]+nz_count[i-1];
  179. model->sv_coef = Malloc(double *,nr_class-1);
  180. for(i=0;i<nr_class-1;i++)
  181. model->sv_coef[i] = Malloc(double,total_sv);
  182. p = 0;
  183. for(i=0;i<nr_class;i++)
  184. for(int j=i+1;j<nr_class;j++)
  185. {
  186. // classifier (i,j): coefficients with
  187. // i are in sv_coef[j-1][nz_start[i]...],
  188. // j are in sv_coef[i][nz_start[j]...]
  189. int si = start[i];
  190. int sj = start[j];
  191. int ci = count[i];
  192. int cj = count[j];
  193. int q = nz_start[i];
  194. int k;
  195. for(k=0;k<ci;k++)
  196. if(nonzero[si+k])
  197. model->sv_coef[j-1][q++] = f[p].alpha[k];
  198. q = nz_start[j];
  199. for(k=0;k<cj;k++)
  200. if(nonzero[sj+k])
  201. model->sv_coef[i][q++] = f[p].alpha[ci+k];
  202. ++p;
  203. }
  204. free(label);
  205. free(probA);
  206. free(probB);
  207. free(count);
  208. free(perm);
  209. free(start);
  210. free(x);
  211. free(weighted_C);
  212. free(nonzero);
  213. for(i=0;i<nr_class*(nr_class-1)/2;i++)
  214. free(f[i].alpha);
  215. free(f);
  216. free(nz_count);
  217. free(nz_start);
  218. }
  219. return model;
  220. }
时间: 2024-08-29 12:56:05

libsvm代码阅读:关于svm_train函数分析(转)的相关文章

libsvm代码阅读(2):svm.cpp浅谈和函数指针(转)

svm.cpp浅谈 svm.cpp总共有3159行代码,实现了svm算法的核心功能,里面总共有Cache.Kernel.ONE_CLASS_Q.QMatrix.Solver.Solver_NU.SVC_Q.SVR_Q 8个类(如下图1所示),而它们之间的继承和组合关系如图2.图3所示.在这些类中Cache.Kernel.Solver是核心类,对整个算法起支撑作用.在以后的博文中我们将对这3个核心类做重点注解分析,另外还将对svm.cpp中的svm_train函数做一个注解分析. 图1 图2 图3

libsvm代码阅读(1):基础准备与svm.h头文件(转)

libsvm是国立台湾大学Chih-Jen Lin开发的一个SVM的函数库,是当前应用最广泛的svm函数库,从2000年到2010年,该函数库的下载量达到250000之多.它的最新版本是version 3.17,主要是对是svm_group_classes做了修改. 主页:LIBSVM -- A Library for Support Vector Machines 下载地址:zip.file ortar.gz 我下载后的解压文件如下所示: libsvm函数包的组织结构如下: 1.主文件路径:包

libsvm代码阅读:关于svm_group_classes函数分析(转)

目前libsvm最新的version是3.17,主要的改变是在svm_group_classes函数中加了几行代码.官方的说明如下: Version 3.17 released on April Fools' day, 2013. We slightly adjust the way class labels are handled internally. By default labels are ordered by their first occurrence in the trainin

libsvm代码阅读(3):关于Cache类的分析(转)

下面来分析Cache类的源码,该类位于svm.cpp中.这个类的主要功能是:负责运算所涉及的内存管理,包括申请.释放等. 简单来说:这个Cache类,首先通过Cache构造函数申请一块空间,这块空间的大小是:L个head_t大小的空间.然后get_data函数保证结构head_t中至少有len个float的内存,并且将可以使用的内存块的指针放在data指针中:而swap_index函数则是用于交换head[i]和head[j]. Cache类的定义如下: [cpp]       view pla

libsvm代码阅读:关于Solver类分析(二)(转)

如果你看完了上篇博文的伪代码,那么我们就可以开始谈谈它的源代码了. 下面先贴出它的类定义,一些成员函数的具体实现先忽略. [cpp]   view plain copy   <EMBED id=ZeroClipboardMovie_1 height=18 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflas

libsvm代码阅读:关于Solver类分析(一)(转)

如果你看完了上篇博文的伪代码,那么我们就可以开始谈谈它的源代码了. 下面先贴出它的类定义,一些成员函数的具体实现先忽略. [cpp]   view plain copy   <EMBED id=ZeroClipboardMovie_1 height=18 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflas

libsvm代码阅读:关于Kernel类分析(转)

这一篇博文来分析下Kernel类,代码上很简单,一般都能看懂.Kernel类主要是为SVM的核函数服务的,里面实现了SVM常用的核函数,通过函数指针来使用这些核函数. 其中几个常用核函数如下所示:(一般情况下,使用RBF核函数能取得很好的效果) 关于基类QMatrix在Kernel中的作用并不明显,只是定义了一些纯虚函数,Kernel继承这些函数,Kernel只对swap_index进行了定义.其余的get_Q和get_QD在Kernel并没有用到. [cpp]   view plain cop

自己学驱动9——uboot代码阅读四(start_armboot函数)

前面分析过在start.S中执行完相关的一些操作之后,会跳转到C语言的部分来执行,跳转到的目标位置就是start_armboot函数,所以现在来看一下这个函数完成了一些什么工作.在这个函数的第一行定义了一个变量如下: init_fnc_t **init_fnc_ptr; 通过查找uboot源码可以得到下面的类型重定义: typedef int (init_fnc_t) (void); typedef的使用方法非常灵活,这里这种定义方式就是定义了init_fnc_t代表一个接收参数为void类型返

代码阅读分析工具Understand 2.0试用

Understand 2.0是一款源码阅读分析软件,功能强大.试用过一段时间后,感觉相当不错,确实能够大大提高代码阅读效率.因为Understand功能十分强大,本文不可能详尽地介绍它的全部功能,所以仅仅列举本人觉得比較重要或有特色的功能,以做抛砖引玉之举. Understand 2.0能够从http://www.scitools.com/下载到,安装后能够试用15天. 使用Understand阅读代码前,要先创建一个Project,然后把全部的源码文件增加到这个Project里.这里我创建了一