我想制作一个Java应用程序来识别字符,使用libsvm,但当我开始研究时,我不明白如何将图像数据训练成libsvm可以使用的格式?
最近为了学习,我使用现有数据进行了一次测试:
我还创建了基于32x32
的训练图像数据,通过将每个像素转换为0,1
,但我不知道这是否可以用来创建libsvm的训练数据格式?另外,libsvm的测试数据是如何创建的?
转换后的图像像素(0,1)
示例:
0000000000000111100000000000000000000000000011111110000000000000000000000011111111110000000000000000000111111111111110000000000000000001111111011111100000000000000000111111100000111100000000000000001111111000000011100000000000000011111110000000111100000000000000111111100000000111000000000000001111111000000001110000000000000011111100000000011110000000000000111111000000000011100000000000001111110000000000111000000000000001111110000000000111000000000000011111100000000001110000000000000111111000000000011100000000000001111110000000000111000000000000111111100000000011110000000000001111011000000000111100000000000011110000000000011110000000000000011110000000000011110000000000000111100000000001111100000000000001111000000000111110000000000000011110000000011111000000000000000011100000011111100000000000000000111100011111110000000000000000001111111111111100000000000000000001111111111111000000000000000000011111111111100000000000000000000011111111100000000000000000000000011111000000000000000000000000000011000000000000000000 0000000000000011111111100000000000000000000111111111111100000000000000000011111111111111100000000000000000111111111111111000000000000000001111111111111111000000000000001111111111111111100000000000000011111000001111110000000000000000000000000001111100000000000000000000000000011111000000000000000000000000000111110000000000000000000000000011111000000000000000000000000001111110000000000000000000000000011111100000000000000000000000000111111000000000000000000000000011111100000000000000000001111111111111111100000000000000111111111111111111100000000000001111111111111111111000000000000011111111111111111110000000000001111111111111111110000000000000011111111111100000000000000000000111111111111000000000000000000000111111111110000000000000000000000000111110000000000000000000000000001111100000000000000000000000000011111000000000000000000000000001111110000000000000000000000000011111100000000000000000000000001111110000000000000000000000000111111100000000000000000000000000111110000000000000000000000000001111100000000000000000 7
如何将其转换为libsvm (训练、测试数据)
格式?
回答:
libsvm
有一个特定的数据格式,每一行是一个训练/测试向量,格式为
LABEL INDEX0:VALUE0 INDEX1:VALUE1 … INDEXN:VALUEN
所以在最“简单”的方法中,你只需将矩阵表示转换为行表示,通过连接连续的行,像这样的图像
010011000
将变成
010011000
在libsvm格式中(假设我们标记为“5”):
5 0:0 1:1 2:0 3:0 4:1 5:1 6:0 7:0 8:0 9:0
由于libsvm支持“稀疏”表示,你可以省略值为“0”的部分
5 1:1 4:1 5:1
这是一种手动方式,样本数据位于此处: http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary/a1a
最简单的“自动”方式是将你的数据表示为.csv格式(再次 – 将数据转换为行状格式,然后转换为.csv),这是一种相当标准的方法:
LABEL,PIXEL_0,PIXEL_1,…,PIXEL_N
…
然后使用此程序进行转换
/* convert cvs data to libsvm/svm-light format */#include <stdio.h>#include <stdlib.h>#include <string.h>char buf[10000000];float feature[100000];int main(int argc, char **argv){ FILE *fp; if(argc!=2) { fprintf(stderr,"Usage %s filename\n",argv[0]); } if((fp=fopen(argv[1],"r"))==NULL) { fprintf(stderr,"Can't open input file %s\n",argv[1]); } while(fscanf(fp,"%[^\n]\n",buf)==1) { int i=0,j; char *p=strtok(buf,","); feature[i++]=atof(p); while((p=strtok(NULL,","))) feature[i++]=atof(p); // --i; /* if ((int) feature[i]==1) printf("-1 "); else printf("+1 "); */ // printf("%f ", feature[1]); printf("%d ", (int) feature[0]); for(j=1;j<i;j++) printf(" %d:%f",j,feature[j]); printf("\n"); } return 0;}
训练和测试文件的结构完全相同,只需按一定比例(如3:1或9:1)随机将数据分成training
和testing
文件,但请记住,在每个文件中包含每个类别的训练向量的平衡数量。
特别是 – 你的数据看起来有点像MNIST数据集,如果是这种情况,这已经为libsvm准备好了:
http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass.html
MNIST训练: http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass/mnist.scale.bz2
MNIST测试: http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass/mnist.scale.t.bz2
如果你的数据允许的话,将图像转换为[0,1]区间内的实值数据比二进制数据(会丢失很多信息)更有价值。
编辑
例如,如果你的图像是8位灰度图像,那么每个像素实际上是一个介于0到255之间的数字v
。你现在所做的,是某种阈值处理,当v > T
时设置为1,当v <= T
时设置为0,而将这些值映射到实值会为模型提供更多信息。这可以通过简单的压缩v / 255
来实现。结果,所有值都在[0,1]
区间内,但也包括中间值,如0.25
等。