1. 下载源代码和移植代码
源代码可以在libsvm官网下载:https://www.csie.ntu.edu.tw/~cjlin/libsvm/;
移植代码这里用的是C# Can Erhan版本,下载地址是:https://github.com/ccerhan/LibSVMsharp
2. 嵌入项目
2.1 C++动态库(dll)函数的导入
新建C++项目,头文件添加libsvm源代码的 svm.h文件,源文件添加svm.cpp文件
在C#接口文件中,可通过以下代码的方法添加,这里函数svm_check_parameter中的参数为什么没直接用指向数据结构的指针,而使用这样笼统的指针的原因是:如果使用数据结构,那么代码中每次使用都需要重新申请内存,分配内存大小,结构体的指针也比较繁琐,代码结构比较混乱。具体指针和数据结构的相互转换,涉及到的函数如何变换,都可以从C# Can Erhan版本中找到(这版的代码很详细)。
[DllImport("libsvm.dll"), EntryPoint = "svm_check_parameter", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl]
public extern static string svm_check_parameter(Intptr prob, Intptr para)
注意一下:这个版本中,SVMNode.cs文件中有一处错误:(node.index > 0)改为(node.index >= 0),因为开始第一个node的index为0,所以会直接break掉;导致model的SV参数不能返回,程序的表现结果是,无论什么输入,输出都完全一致(小数点都不会变动)
while (true)
{
svm_node node = (svm_node)Marshal.PtrToStructure(i_ptr_nodes, typeof(svm_node));
i_ptr_nodes = IntPtr.Add(i_ptr_nodes, Marshal.SizeOf(typeof(svm_node)));
if (node.index > 0)
{
nodes.Add(new SVMNode(node.index, node.value));
}
else
{
break;
}
}
还有一处值得注意的是,原始svm_node进入程序计算前,要加入{index = -1, value = whatever},否则程序可能间发错误。其中原因是程序在计算向量距离时,截至条件所用的是index=-1;
2.2 测试代码
C#计算结果和C++计算结果应该完全一致;
C#测试可用上述方法尝试,C++测试可用libsvm源码中的svm-train;
3. 超参寻优
超参寻优对于分类而言,可用tools/grid.py执行,对于回归而言,需要自行下载一个gridregression.py文件。
因为我这边做的是回归,所以用到了gridregression.py,网上大部分使用的是python 2版本,我这边用的是python3,因此需要对gridregression.py进行改造,除了下述问题,其余都可以百度得到。
最后可使用博客https://blog.youkuaiyun.com/le_zhou/article/details/40371231中所述,运行程序,找到c g的最优值,但是这仅仅是训练集上的表现,不排除有过拟合倾向。
原来 | 现在 |
| 直接注释掉,涉及到split, join, find, python3直接用str.find, str.split, str.join即可 atof直接用float代替 |
svmtrain_exe,gnuplot_exe路径 | 分别改为正确路径(这里的gnuplot需要额外安装) |
lambda (x):x[2] | lambda x:x[2] |
import Queue | import queue |
4. 输出结果一致
svm或SVR输出都一致(无论什么输入,输出都一样),原因可能有:C# Can Erhan版本中的那一处错误(上面有提到),或者参数选择不合理。