SVM(支持向量机)一种训练分类器的学习方法
mnist 是一个手写字体图像数据库,训练样本有60000个,测试样本有10000个
LibSVM 一个常用的SVM框架
OpenCV3.0 中的ml包含了很多的ML框架接口,就试试了。
详细的OpenCV文档:
mnist数据下载:
LibSVM下载:~cjlin/libsvm/
========================我是分割线=============================
训练的过程大致如下:
1. 读取mnist训练集数据
2. 训练
3. 读取mnist测试数据,对比预测结果,得到错误率
具体实现:
1. mnist给出的数据文件是二进制文件
四个文件,解压后如下
"train-images.idx3-ubyte" 二进制文件,存储了头文件信息以及60000张28*28图像pixel信息(用于训练)
"train-labels.idx1-ubyte" 二进制文件,存储了头文件信息以及60000张图像label信息
"t10k-images.idx3-ubyte"二进制文件,存储了头文件信息以及10000张28*28图像pixel信息(用于测试)
"t10k-labels.idx1-ubyte"二进制文件,存储了头文件信息以及10000张图像label信息
因为OpenCV中没有直接导入MINST数据的文件,所以需要自己写函数来读取
首先要知道,MNIST数据的数据格式
IMAGE FILE包含四个int型的头部数据(magic number,number_of_images, number_of_rows, number_of_columns)
余下的每一个byte表示一个pixel的数据,范围是0-255(可以在读入的时候scale到0~1的区间)
LABEL FILE包含两个int型的头部数据(magic number, number of items)
余下的每一个byte表示一个label数据,范围是0-9
注意(第一个坑):MNIST是大端存储,然而大部分的Intel处理器都是小端存储,所以对于int、long、float这些多字节的数据类型,就要一个一个byte地翻转过来,才能正确显示。
1 //翻转 2 int reverseInt(int i) { 3 unsigned char c1, c2, c3, c4; 4 5 c1 = i & 255; 6 c2 = (i >> 8) & 255; 7 c3 = (i >> 16) & 255; 8 c4 = (i >> 24) & 255; 9 10 return ((int)c1 << 24) + ((int)c2 << 16) + ((int)c3 << 8) + c4; 11 }
View Code然后读取MNIST文件,但是它是二进制文件,打开方式
所以不能用
ifstream file(fileName);
而要改成
ifstream file(fileName, ios::binary);
注意(第二个坑):如果用第一条指令来打开文件,不会报错,但是数据会出现错误,头部数据仍然正确,但是后面的pixel数据大部分都是0,我刚开始没注意,开始training的时候发现等了很久...真的是很久...(7+ hours)...估计是达到迭代终止的最大次数了,才停下来的
嗯,stack overflow上也有类似的提问:
注意(第三个坑):
training时,IMAGE和LABEL的数据分别都放进一个MAT中存储,但是只能是CV32_F或者CV32_S的格式,不然会assertion报错
OPENCV给出的文档中,例子是这样的:(但是predict的时候又会要求label的格式是unsigned int)所以...可以设置data的Mat格式为CV_32FC1,label的Mat格式为CV_32SC1
顺便地,图像训练数据的转换存储格式(?rq=1)
最后,为了验证读取数据的正确性,一个有效的办法就是输出第一个和最后一个数据(可以输出答应第一个/最后一个image以及label)
2. 训练
(此处我是直接对原图像训练,并没有提取任何的特征)
也有人建议这里应该对图像做HOG特征提取,再配合label训练(我还没试过...不知道效果如何...)
opencv3.0和2.4的SVM接口有不同,基本可以按照以下的格式来执行: