SVM 类库研究历程

开始接到SVM的研究任务,心里其实感觉svm是够难的。因为我大学在人脸识别项目中曾经研究过一段时间。但是因为不知道为何matlab中svm类库有点小问题,就
被迫终止了研究。所以心里一直发憷。

当然这件事如果我不做,估计没有人去做。为了自己的信息检索大作业(文本分类)。还是要好好的努力下。

之后在google上搜索各种svm相关的代码和使用方法。(这估计是我研究的第一步,收集大量资料)

第二步,找到可能有关的类库文件或者代码保存下来。这时我搜索到libsvm,其实还有各种关于svm的matlab版。

第三步,决定使用那个svm。1.libsvm当时只搜到c版本。2.svm的matlab版本也有。这时我的项目使用的是java语言。虽然语言具有无关性。但是还
是要看看各种语言之间是怎么调用。matlab版本说要使用一个tooljar文件。但是这个文件在我的matlab中没有找到。所以先搁置一下。libsvm的c版
本用vs2005打开,发现竟然编译不通过。于是在网上查为啥不通过。后来解决。然后生成svm-train.exe ,svm-predict.exe,和svm-
scale.exe.但是这个怎么用?还是在网上搜索下。

第四步,搜索如何使用libsvm类库。这里可以说研究的对象更加明确了。应该使用什么类库也比较清楚。然后搜到了一篇写的很好的libsvm如何使用的文章。
_ http://www.csie.ntu.edu.tw/~piaip/docs/svm/ _
感觉写的很不错。我这里就不重复写了。

第五步,确定文件存储格式。那个使用简介上说要下一个heart.scale,最后历经千辛万苦终于在libsvm的网站上找到了。 _
http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/ _

这里有很多数据文件,找到classification的download下来看看就知道了。其实文件是由  :对应于我的文件存储就是
类号 词号:词个数 词号:词个数…但是这里有一点要注意:最后一行数据必须敲一个回车。就是说以空行做结束。否则程序就不会终止。另外偶然发现svm可以直接
处理字符串,文件格式是: 类号 字符串。我心想这个不正适合我的文本分类吗?而且我根本就不需要做分词就可将整个content当作一个字符串。我试了下作者给的其
他的svm版本。都不支持。我看了下这个作者给的svm的源代码libsvm-2.88-string中其实是含有这段代码的。但是没有使用宏进行编译。所以要使用这
个libsvm来处理字符串,需要对代码进行宏编译。

第六步。宏编译? -D …而且后面还有一大堆看不懂的参数。作者倒是给了makefile文件。下面采用两个方向:

1.在windows下进行编译。2。在linux等操作系统下编译。但但是我的数据文件3个G左右,linux下并没有足够大的空间来放这些文件。所以只有在win
dows下了。然后又在google上搜索了如何使用vs的编译器来执行makefile文件。搜到几个网页。发现vs的编译器就是cl.exe文件。但是它依旧不支
持这个makefile。无奈打开makefile文件。看到makefile中第一行CXX? = g++。改为CXX = cl.exe
依旧不行。(其实我是乱改的。)

2.下一个windows下的g++,安装后,去掉CXX?=g++中的?.然后生成成功。

(其实这两步没有这么麻烦的。作者在libsvm-2.88中给了makefile.win就可以用cl.exe来生成windows下的exe。但是还是要改动一下
才能用于处理字符串的svm,要加-D _STRING
才可以。但是libsvm-2.88的代码可能不含处理字符串的代码。用的时候看看源代码中是否包含宏定义_STRING )

第七步。研究下java是如何调用exe的?找了几段网上的代码…发现均不满足要求。于是写了 _
http://blog.csdn.net/cctt_1/archive/2008/11/14/3300789.aspx _
不过这篇文章里只是说exe运行
正确的情况下可以正常退出。如果exe抛出异常。那么程序就会卡死。所以你还有在得到一个类似error的输入输出流。这个也是Process的函数。然后你反复试试
就知道error流放前还是正常输入输出放前了。:)当做练习吧

第八步。我使用十几个content做了测试。效果不错。然后用了26000多个content再做测试。发现运行了几个小时依旧没有啥结果。前面其实就不抱有什么期
望。因为这个libsvm对字符串的串的处理是用的字符串子串匹配算法。效率能高才怪了。但是我的content不只26000个。大概有1500000个左右…那
需要跑多久呀…所以只得放弃。

第九步。重新使用正常的libsvm。采用类号 词号:词个数…作为文件存储方式。这时看到了libsvm-2.88,哈哈竟然有java的代码。于是采用之。但
是在libsvm中抛了Outofmemory异常。我按网上的做法,将eclipse的eclipse.ini文件中的xmx的大小改为1024m。重启之。还是不
行。于是再搜索…结果还是没有啥新发现。(后来才知道这里的1024m是对于eclipse来说的。如果eclipse运行程序的话,要在Run
…这个选项中的jvm的参数中设置-xmx1024m才可以。网上的教材不可轻信呀!)当时我还是使用了调用exe的方式。

第十步。一切ok,测试…发现正确率偏低最好达到28%。后来看到有scale的exe。想着可以找到训练的最好参数。但是我看着我的硬盘一点点的被吃掉,那个生
成scale的程序还没有终止。一个30M的小文件耗费了我6G左右的硬盘…而且还没有将scale生成完毕。scale这个方法就不能用来
。如果只有几百个content使用-c的参数竟然达到了100%。但是交叉训练还是25%左右。

第11步。检查了自己的程序。发现竟然词号那里有错误。每统计一个文件,重新生成了一个词号…这怎么可能是对的。(唉,估计自己的当时脑子不清醒)重新改正,生成新
的数据文件。再跑一遍。发现这次svm-train.exe抛异常了。竟然是status_access_valid。。查了下是共享内存出了问题。但是我这个是单线
程的。于是把几乎所有能关的程序全部关闭。再跑。依旧同样的错误。

第12步。给作者发信。因为作者是熟悉英文者。虽然是台湾的,但是我还是给他发英文。谁知道他有没有台
独倾向呢?询问我这个问题,为啥他的那个鬼东东没有跑出结果,却报了异常。当然说话要含蓄。

第13步。作者竟然给我回信了。说这个libsvm可以跑出结果呀。又把他的log给了我。我发现确实跑出来了。这里要发点感慨,你看人家那教授。一天内必回信,而且
还将整个data都训练一下。我想应该有一个小时吧。在想想大陆的教授…无限感慨!

第14步。和同组成员一起分析原因。为啥这个东西人家就能跑出来,自己却跑不出来呢?再看libsvm的异常信息,上面有stack的信息。我再分析了下作者给的lo
g。发现我没有跑出来的那个log,其迭代次数达到了3000多次。而之前的最高次数也就是1000次。难道是stack溢出?(真是佩服自己的运气,啥情况都碰上了
)于是使用vs打开源代码,将工程中的properties->system->stack commit size
调为10,意为10M。再各个编译。再运行,果然成功。

第15步。26000个content需要1个小时。我还要训练26000*7以上的content。并且我以我刚刚的经验来看这个svm的训练不是线性的。是指数的
,或者是多项式级的。所以训练如此大的文件…我的机器我的时间是根本不允许的。因为没有那个精力。而且还面临着调优。

第16步。向信息检索老师argue一下。结果老师说你就这样吧。算工作量,正确率不高没有关系。

第17步。正确率不高…我估计也没有时间这样去跑呀…所以另想它法,能不能将几篇文档整合?于是将全部的文档按照doc个数为n进行整合,然后最后再除以n.所以
现在维数据不是词个数(整数),而是浮点数。然后将测试文档放入预测。发现全为0了,根本预测不出。可能是因为这样除n不具有一般意义。比如一个词只出现1次,但是再
除以n,那就是0.0001或者更小。而预测文档中此词就是1,所以根本不可能匹配。另外一种方法。如果n个文档不匹配。那么如果是全部的文档,是否符合统计的规律?
结果测试说明,还是不匹配。原因相同。这里其实还有一个想法。就是将这个统计得到的训练文档中维数据整理成整数。就是如果此时维数据是0.0001,还有的维数据是0
.002,那么如果真实测试文档中有这两个词,那么必定至少是1。如果每个维数据都乘以一个代价常数,变为一个大于等于1的维数据。这样做就有可能得到正确的预测。另
外还要考虑到有些词是偶尔出现在此类中,也就是基本与此类无关。那么的它的维数据中可能有更小的例如0.000001.那么这样的数据怎么考虑?还有如果全部的维数据
都乘以一个相同的代价常数。那么当维数据0.0001变为1时,(假设)维数据1(表示这个词与此类有极大的关联),将变为10000,在一篇文档中不可能有一个词个
数是10000的。即使这个词在每个文档中都出现。所以我们还是不能这样直接乘以一个相同代价的常数。这里因为时间关系,并没有做一个代价函数。

第18步。采用所有的数据进行训练。26000个doc不一定能说明什么问题。当数据量极大的时候。或许能产生一个好结果。但是这是我们希望发生的事情。借用了别人实
验室中的机器。发现虽然他的机器是4核4G的。但是跑svm依旧很慢。原因在于svm是一个单线程单进程的程序。所以和一个核去跑本质上没有啥区别。另外也发现一个问
题。就是libsvm在测试2.57G的数据时,crash了。这真的不是内存或者是其他的错误。因为生产的向量维数太大。以至于申请一个向量空间就被操作系统拒绝了
。因为访问到了操作系统的保护段数据。所以可能要进行“缩水”。

第19步。我这里说的“缩水”是一种自己的算法。我认为每个文档在训练集中的地位不是一样的。那么可能有些文档没有必要存在在训练集中。或者说每个文档存在在训练集中
的概率是不同的。所以我这里做一个“缩水”。将大文档尽可能的排除,设为20%概率保留。小文档尽可能的保留,设为80%,中等大小的文档50%保留。这样做完后,只
剩下500M左右的数据。我希望这些数据可能保持原来的特性。并且训练速度要提高。可惜结果还是一样的差。

第20步。查询相关论文资料。(这一步感觉应该提前去做。竟然因为时间关系忘记了,因为一直以为这是一个工程的活,和研究没有太多的关联。谁知道在数据量如此大时候,
这些工程的方法都不起作用。)找到很多论文。同时也发现了这些论文之间的一致性:降维,找特征值。可是这个矩阵太大了。这方法有问题。另外还有一种方法,就是在这个类
中找n多感觉上一定相关的词(人肉的方法)。然后用这些词进行筛选。当然这个方法是可行的。可惜没有时间和精力去每个类找这么多相关的词。

第21步。我觉得我还是暂时放弃它好了。毕竟数据量太大的时候,效果很不好,这也是各个svm论文中提到的一点。而且至今没有很好的解决方案。另外即使是降维,最后还
是要调节参数。看了各个文献,发现调参数也是很有讲究的(使用人工智能等等方法)。

最后的总结:

svm地区是能跑了,但是训练时间太长了。另外数据集太大,svm就显得太笨重了。还有正确率必须用参数调优。要调优的前提就必须生成scale文件。大数据量所生成
的scale文件太大了。所以就不可能去调优(对于我那机器而言)。这样比较起来还是朴素贝叶斯方法较好。简单,而且速度快。