cvSVM及trainSVM参数详解Word文档下载推荐.docx

上传人:b****6 文档编号:20199308 上传时间:2023-01-17 格式:DOCX 页数:49 大小:855.65KB
下载 相关 举报
cvSVM及trainSVM参数详解Word文档下载推荐.docx_第1页
第1页 / 共49页
cvSVM及trainSVM参数详解Word文档下载推荐.docx_第2页
第2页 / 共49页
cvSVM及trainSVM参数详解Word文档下载推荐.docx_第3页
第3页 / 共49页
cvSVM及trainSVM参数详解Word文档下载推荐.docx_第4页
第4页 / 共49页
cvSVM及trainSVM参数详解Word文档下载推荐.docx_第5页
第5页 / 共49页
点击查看更多>>
下载资源
资源描述

cvSVM及trainSVM参数详解Word文档下载推荐.docx

《cvSVM及trainSVM参数详解Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《cvSVM及trainSVM参数详解Word文档下载推荐.docx(49页珍藏版)》请在冰豆网上搜索。

cvSVM及trainSVM参数详解Word文档下载推荐.docx

intkernel_type;

doubledegree;

/forpolydoublegamma;

/forpoly/rbf/sigmoiddoublecoef0;

/forpoly/sigmoiddoubleC;

/forCV_SVM_C_SVC,CV_SVM_EPS_SVRandCV_SVM_NU_SVRdoublenu;

/forCV_SVM_NU_SVC,CV_SVM_ONE_CLASS,andCV_SVM_NU_SVRdoublep;

/forCV_SVM_EPS_SVRCvMat*class_weights;

/forCV_SVM_C_SVCCvTermCriteriaterm_crit;

/terminationcriteria;

svm_type,SVM的类型:

CvSVM:

C_SVC-n(n=2)分类器,允许用异常值惩罚因子C进行不完全分类。

NU_SVC-n类似然不完全分类的分类器。

参数nu取代了c,其值在区间【0,1】中,nu越大,决策边界越平滑。

ONE_CLASS-单分类器,所有的训练数据提取自同一个类里,然后SVM建立了一个分界线以分割该类在特征空间中所占区域和其它类在特征空间中所占区域。

EPS_SVR-回归。

训练集中的特征向量和拟合出来的超平面的距离需要小于p。

异常值惩罚因子C被采用。

NU_SVR-回归;

nu代替了pkernel_type/核类型:

LINEAR-没有任何向映像至高维空间,线性区分(或回归)在原始特征空间中被完成,这是最快的选择。

d(x,y)=xy=(x,y)CvSVM:

POLY-多项式核:

d(x,y)=(gamma*(xy)+coef0)degreeCvSVM:

RBF-径向基,对于大多数情况都是一个较好的选择:

d(x,y)=exp(-gamma*|x-y|2)CvSVM:

SIGMOID-sigmoid函数被用作核函数:

d(x,y)=tanh(gamma*(xy)+coef0)degree,gamma,coef0:

都是核函数的参数,具体的参见上面的核函数的方程。

C,nu,p:

在一般的SVM优化求解时的参数。

class_weights:

可选权重,赋给指定的类别。

一般乘以C以后去影响不同类别的错误分类惩罚项。

权重越大,某一类别的误分类数据的惩罚项就越大。

term_crit:

SVM的迭代训练过程的中止。

(解决了部分受约束二次最优问题)该结构需要初始化,并传递给CvSVM的训练函数。

train训练SVMboolCvSVM:

train(constCvMat*_train_data,constCvMat*_responses,constCvMat*_var_idx=0,constCvMat*_sample_idx=0,CvSVMParams_params=CvSVMParams();

训练SVM模型的方法。

它遵循的泛型训练方法的约定具有以下限制:

仅支持CV_ROW_SAMPLE的数据布局、所有命令输入的变量、输出变量可以是断然(_params.svm_type=CvSVM:

C_SVC或_params.svm_type=CvSVM:

NU_SVC)或命令(_params.svm_type=CvSVM:

EPS_SVR或_params.svm_type=CvSVM:

NU_SVR)或不需要在所有(_params.svm_type=CvSVM:

ONE_CLASS),不支持缺省值。

所有的参数都被集成在CvSVMParams这个结构中。

get_support_vector*得到支持矢量和特殊矢量的数intCvSVM:

get_support_vector_count()const;

constfloat*CvSVM:

get_support_vector(inti)const;

这个方法可以被用来得到支持矢量的集合。

在前面的几篇文章中,我们介绍了EasyPR中车牌定位模块的相关内容。

本文开始分析车牌定位模块后续步骤的车牌判断模块。

车牌判断模块是EasyPR中的基于机器学习模型的一个模块,这个模型就是作者前文中从机器学习谈起中提到的SVM(支持向量机)。

我们已经知道,车牌定位模块的输出是一些候选车牌的图片。

但如何从这些候选车牌图片中甄选出真正的车牌,就是通过SVM模型判断/预测得到的。

图1从候选车牌中选出真正的车牌简单来说,EasyPR的车牌判断模块就是将候选车牌的图片一张张地输入到SVM模型中,然后问它,这是车牌么?

如果SVM模型回答不是,那么就继续下一张,如果是,则把图片放到一个输出列表里。

最后把列表输入到下一步处理。

由于EasyPR使用的是列表作为输出,因此它可以输出一副图片中所有的车牌,不像一些车牌识别程序,只能输出一个车牌结果。

图2EasyPR输出多个车牌现在,让我们一步步地,进入这个SVM模型的核心看看,它是如何做到判断一副图片是车牌还是不是车牌的?

本文主要分为三个大的部分:

1.SVM应用:

描述如何利用SVM模型进行车牌图片的判断。

2.SVM训练:

说明如何通过一系列步骤得到SVM模型。

3.SVM调优:

讨论如何对SVM模型进行优化,使其效果更加好。

一.SVM应用人类是如何判断一个张图片所表达的信息呢?

简单来说,人类在成长过程中,大脑记忆了无数的图像,并且依次给这些图像打上了标签,例如太阳,天空,房子,车子等等。

你们还记得当年上幼儿园时的那些教科书么,上面一个太阳,下面是文字。

图像的组成事实上就是许多个像素,由像素组成的这些信息被输入大脑中,然后得出这个是什么东西的回答。

我们在SVM模型中一开始输入的原始信息也是图像的所有像素,然后SVM模型通过对这些像素进行分析,输出这个图片是否是车牌的结论。

图3通过图像来学习SVM模型处理的是最简单的情况,它只要回答是或者不是这个“二值”问题,比从许多类中检索要简单很多。

我们可以看一下SVM进行判断的代码:

intCPlateJudge:

plateJudge(constvector&

inVec,vector&

resultVec)intnum=inVec.size();

for(intj=0;

jnum;

j+)MatinMat=inVecj;

Matp=histeq(inMat).reshape(1,1);

p.convertTo(p,CV_32FC1);

intresponse=(int)svm.predict(p);

if(response=1)resultVec.push_back(inMat);

return0;

ViewCode首先我们读取这幅图片,然后把这幅图片转为OPENCV需要的格式;

接着调用svm的方法predict;

perdict方法返回的值是1的话,就代表是车牌,否则就不是;

svm是类CvSVM的一个对象。

这个类是opencv里内置的一个机器学习类。

CvSVMsvm;

opencv的CvSVM的实现基于libsvm(具体信息可以看opencv的官方文档的介绍)。

libsvm是台湾大学林智仁(LinChih-Jen)教授写的一个世界知名的svm库(可能算是目前业界使用率最高的一个库)。

官方主页地址是这里。

libsvm的实现基于SVM这个算法,90年代初由Vapnik等人提出。

国内几篇较好的解释svm原理的博文:

cnblog的LeftNotEasy(解释的易懂),pluskid的博文(专业有配图)。

作为支持向量机的发明者,Vapnik是一位机器学习界极为重要的大牛。

最近这位大牛也加入了Facebook。

图4SVM之父Vapniksvm的perdict方法的输入是待预测数据的特征,也称之为features。

在这里,我们输入的特征是图像全部的像素。

由于svm要求输入的特征应该是一个向量,而Mat是与图像宽高对应的矩阵,因此在输入前我们需要使用reshape(1,1)方法把矩阵拉伸成向量。

除了全部像素以外,也可以有其他的特征,具体看第三部分“SVM调优”。

predict方法的输出是float型的值,我们需要把它转变为int型后再进行判断。

如果是1代表就是车牌,否则不是。

这个1的取值是由你在训练时输入的标签决定的。

标签,又称之为label,代表某个数据的分类。

如果你给SVM模型输入一个车牌,并告诉它,这个图片的标签是5。

那么你这边判断时所用的值就应该是5。

以上就是svm模型判断的全过程。

事实上,在你使用EasyPR的过程中,这些全部都是透明的。

你不需要转变图片格式,也不需要调用svm模型preditct方法,这些全部由EasyPR在内部调用。

那么,我们应该做什么?

这里的关键在于CvSVM这个类。

我在前面的机器学习论文中介绍过,机器学习过程的步骤就是首先你搜集大量的数据,然后把这些数据输入模型中训练,最后再把生成的模型拿出来使用。

训练和预测两个过程是分开的。

也就是说你们在使用EasyPR时用到的CvSVM类是我在先前就训练好的。

我是如何把我训练好的模型交给各位使用的呢?

CvSVM类有个方法,把训练好的结果以xml文件的形式存储,我就是把这个xml文件随EasyPR发布,并让程序在执行前先加载好这个xml。

这个xml的位置就是在文件夹Model下面-svm.xml文件。

图5model文件夹下的svm.xml如果看CPlateJudge的代码,在构造函数中调用了LoadModel()这个方法。

CPlateJudge:

CPlateJudge()/coutCPlateJudge学习数据(未标签)预处理步骤主要处理的是原始数据到学习数据的转换过程。

原始数据(rawdata),表示你一开始拿到的数据。

这些数据的情况是取决你具体的环境的,可能有各种问题。

学习数据(learndata),是可以被输入到模型的数据。

为了能够进入模型训练,必须将原始数据处理为学习数据,同时也可能进行了数据的筛选。

比方说你有10000张原始图片,出于性能考虑,你只想用1000张图片训练,那么你的预处理过程就是将这10000张处理为符合训练要求的1000张。

你生成的1000张图片中应该包含两类数据:

真正的车牌图片和不是车牌的图片。

如果你想让你的模型能够区分这两种类型。

你就必须给它输入这两类的数据。

通过EasyPR的车牌定位模块PlateLocate可以生成大量的候选车牌图片,里面包括模型需要的车牌和非车牌图片。

但这些候选车牌是没有经过分类的,也就是说没有标签。

下步工作就是给这些数据贴上标签。

2.label(学习数据(未标签)-学习数据)训练过程的第二步就是将未贴标签的数据转化为贴过标签的学习数据。

我们所要做的工作只是将车牌图片放到一个文件夹里,非车牌图片放到另一个文件夹里。

在EasyPR里,这两个文件夹分别叫做HasPlate和NoPlate。

如果你打开train/data/plate_detect_svm后,你就会看到这两个压缩包,解压后就是打好标签的数据(1.1版本在同层learndata文件夹下面)。

如果有人问我开发一个机器学习系统最耗时的步骤是哪个,我会毫不犹豫的回答:

“贴标签”。

诚然,各位看到的压缩包里已经有打好标签的数据了。

但各位可能不知道作者花在贴这些标签上的时间。

粗略估计,整个EasyPR开发过程中有70%的时间都在贴标签。

SVM模型还好,只有两个类,训练数据仅有1000张。

到了ANN模型那里,字符的类数有40多个,而且训练数据有4000张左右。

那时候的贴标签过程,真是不堪回首的回忆,来回移动文件导致作者手经常性的非常酸。

后来我一度想找个实习生帮我做这些工作。

但转念一想,这些苦我都不愿承担,何苦还要那些小伙子承担呢。

“己所不欲,勿施于人”。

算了,既然这是机器学习者的命,那就欣然接受吧。

幸好在这段磨砺的时光,我逐渐掌握了一个方法,大幅度减少了我贴标签的时间与精力。

不然,我可能还未开始写这个系列的教程,就已经累吐血了。

开发EasyPR1.1版本时,新增了一大批数据,因此又有了贴标签的过程。

幸好使用这个方法,使得相关时间大幅度减少。

这个方法叫做逐次迭代自动标签法。

在后面会介绍这个方法。

贴标签后的车牌数据如下图:

图7在HasPlate文件夹下的图片贴标签后的非车牌数据下图:

图8在NoPlate文件夹下的图片拥有了贴好标签的数据以后,下面的步骤是分组,也称之为divide过程。

3.divide(学习数据-分组数据)分组这个过程是EasyPR1.1版新引入的方法。

在贴完标签以后,我拥有了车牌图片和非车牌图片共几千张。

在我直接训练前,不急。

先拿出30%的数据,只用剩下的70%数据进行SVM模型的训练,训练好的模型再用这30%数据进行一个效果测试。

这30%数据充当的作用就是一个评判数据测试集,称之为testdata,另70%数据称之为traindata。

于是一个完整的learndata被分为了traindata和testdata。

图9数据分组过程在EasyPR1.0版是没有testdata概念的,所有数据都输入训练,然后直接在原始的数据上进行测试。

直接在原始的数据集上测试与单独划分出30%的数据测试效果究竟有多少不同?

事实上,我们训练出模型的根本目的是为了对未知的,新的数据进行预测与判断。

当使用训练的数据进行测试时,由于模型已经考虑到了训练数据的特征,因此很难将这个测试效果推广到其他未知数据上。

如果使用单独的测试集进行验证,由于测试数据集跟模型的生成没有关联,因此可以很好的反映出模型推广到其他场景下的效果。

这个过程就可以简单描述为你不可以拿你给学生的复习提纲卷去考学生,而是应该出一份考察知识点一样,但题目不一样的卷子。

前者的方式无法区分出真正学会的人和死记硬背的人,而后者就能有效地反映出哪些人才是真正“学会”的。

在divide的过程中,注意无论在traindata和testdata中都要保持数据的标签,也就是说车牌数据仍然归到HasPlate文件夹,非车牌数据归到NoPlate文件夹。

于是,车牌图片30%归到testdata下面的hasplate文件夹,70%归到traindata下面的hasplate文件夹,非车牌图片30%归到testdata下面的noplate文件夹,70%归到traindata下面的noplate文件夹。

于是在文件夹train和test下面又有两个子文件夹,他们的结构树就是下图:

图10分组后的文件树divide数据结束以后,我们就可以进入真正的机器学习过程。

也就是对数据的训练过程。

4.train(训练数据-模型)模型在代码里的代表就是CvSVM类。

在这一步中所要做的就是加载traindata,然后用CvSVM类的train方法进行训练。

这个步骤只针对的是上步中生成的总数据70%的训练数据。

具体来说,分为以下几个子步骤:

1)加载待训练的车牌数据。

见下面这段代码。

voidgetPlate(Mat&

trainingImages,vector&

trainingLabels)char*filePath=train/data/plate_detect_svm/HasPlate/HasPlate;

vectorfiles;

getFiles(filePath,files);

intsize=files.size();

if(0=size)coutNoFileFoundintrainHasPlate!

endl;

for(inti=0;

isize;

i+)coutfilesi.c_str()endl;

Matimg=imread(filesi.c_str();

img=img.reshape(1,1);

trainingImages.push_back(img);

trainingLabels.push_back

(1);

ViewCode注意看,车牌图像我存储在的是一个vector中,而标签数据我存储在的是一个vector中。

我将train/HasPlate中的图像依次取出来,存入vector。

每存入一个图像,同时也往vector中存入一个int值1,也就是说图像和标签分别存在不同的vector对象里,但是保持一一对应的关系。

2)加载待训练的非车牌数据,见下面这段代码中的函数。

基本内容与加载车牌数据类似,不同之处在于文件夹是train/NoPlate,并且我往vector中存入的是int值0,代表无车牌。

voidgetNoPlate(Mat&

trainingLabels)char*filePath=train/data/plate_detect_svm/NoPlate/NoPlate;

if(0=size)coutNoFileFoundintrainNoPlate!

trainingLabels.push_back(0);

ViewCode3)将两者合并。

目前拥有了两个vector和两个vector。

将代表车牌图片和非车牌图片数据的两个vector组成一个新的Mat-trainingData,而代表车牌图片与非车牌图片标签的两个vector组成另一个Mat-classes。

接着做一些数据类型的调整,以让其符合svm训练函数train的要求。

这些做完后,数据的准备工作基本结束,下面就是参数配置的工作。

Matclasses;

/(numPlates+numNoPlates,1,CV_32FC1);

MattrainingData;

/(numPlates+numNoPlates,imageWidth*imageHeight,CV_32FC1);

MattrainingImages;

vectortrainingLabels;

getPlate(trainingImages,trainingLabels);

getNoPlate(trainingImages,trainingLabels);

Mat(trainingImages).copyTo(trainingData);

trainingData.convertTo(trainingData,CV_32FC1);

Mat(trainingLabels).copyTo(classes);

ViewCode4)配置SVM模型的训练参数。

SVM模型的训练需要一个CvSVMParams的对象,这个类是SVM模型中训练对象的参数的组合,如何给这里的参数赋值,是很有讲究的一个工作。

注意,这里是SVM训练的核心内容,也是最能体现一个机器学习专家和新手区别的地方。

机器学习最后模型的效果差异有很大因素取决与模型训练时的参数,尤其是SVM,有非常多的参数供你配置(见下面的代码)。

参数众多是一个问题,更为显著的是,机器学习模型中参数的一点微调都可能带来最终结果的巨大差异。

CvSVMParamsSVM_params;

SVM_params.svm_type=CvSVM:

C_SVC;

SVM_params.kernel_type=CvSVM:

LINEAR;

/CvSVM:

SVM_params.degree=0;

SVM_params.gamma=1;

SVM_params.coef0=0;

SVM_params.C=1;

SVM_params.nu=0;

SVM_params.p=0;

SVM_params.term_crit=cvTermCriteria(CV_TERMCRIT_ITER,1000,0.01);

openc

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1