OpenCV学习笔记(8)-机器学习

什么是机器学习

机器学习的目的是把数据转换成信息.在学习了一系列的数据之后,我们需要机器能够回答与这些数据有关的问题:其他还有哪些数据和本数据最相似?图像中有没有汽车?哪个广告最能得到消费者的响应?由于消费者经常考虑价格因素,这个问题会变成"在我们销售的所有产品中,如果要做广告,哪个产品会最热销?"机器学习通过从数据里提取规则或模式来把数据转换成信息.

训练集和测试集

机器学习针对温度,股票价格,色度等之类的数据.这些数据经常被预处理成特征.举个例子,我们有一个数据库,他是对10000张人脸图像进行边缘检测,然后收集特征,如边缘方向,边缘长度,边缘相对脸中心的偏移度.我们从每张脸上获取一个含有500个数据的500项特征向量.然后我们通过机器学习技术根据这些特征数据创建某种模型.如果我们仅仅想把这些数据分成不同的类(粗分,细分或其他),一个"聚类"算法就足够了.如果项学习从人脸的边缘的模式预测他的年龄,我们需要一个"分类"算法.为了达到这个目的,机器学习算法分析我们收集的数据,分配权重,阈值和其他参数来提高性能.这个调整参数来达到目的的过程被称为"学习";

知道机器学习方法的性能很重要,而且这是一个精细的问题.一般情况下,我们把原始数据分成一个大的训练集(在我们的例子中,大约9000张脸)和一个小的测试集(剩下的1000张脸).我们雷永训练集来训练我们的分类器,学习年龄的预测模型.当训练结束,我们用测试集来测试年龄预测分类器.

测试集不能被用来训练分类器,我们不让分类器知道测试集的年龄标签.我们让分类器对测试集的数据预测,记录预测的结果,考查预测年龄和真实年龄的符合程度.如果分类器效果不好,就尝试增加新的特征或者考虑不同类型的分类器.本章将描述多种分类器和多种训练分类器的方法.

如果分类器效果好,我们就有了一个有潜在价值的模型,我们可以在真实世界里应用它.这个系统可能被用来根据用户的年龄来设置视频游戏的行为.人们准备玩游戏的时候,他们的脸的图像将被处理成500个特征.这个数据被分类器分类,得到的预测年龄将被用来设置游戏行为.在系统部署之后,分类器看到以前没有见过的脸就会根据学习结果作出判断.

最后,在开发训练分类系统的时候,经常使用验证集.有的时候,在最后测试整个系统是一个太大的工作.我们需要在提交分类器进行最终测试之前调整的参数.为此,我们可以把原始的10000个数据分为三部分,8000个训练集,1000个验证集,1000个测试集.现在,训练完之后,我们尝试性地提前用验证集来测试分类器的效果.只有对分类器的性能感到满意,才能用测试集来做最后的判断. 

监督数据和无监督数据

有的时候,数据没有标签.我们仅仅想根据边缘信息看看人脸倾向于哪个组.有的时候,数据有标签,比如年龄.这类有标签的机器学习是有监督的(即可利用数据特征向量附带的"信号"或"标签").如果数据向量没有标签,则表明这种机器学习是无监督的.

有监督的学习可以来判断种类,比如把名字和脸对应起来,或赋予一个数字标签(如年龄).当数据以名字(种类)作为标签,则表明我们在做分类(classification);如果输出的是数值,则表明我们在进行回归,回归是通过类别的或数值的输入数据来拟合一个数值输出.

有监督的学习也有一些模糊领域:它包括数据向量和标签的一一匹配,也包括强化学习(deferred learning).在强化学习中,数据标签(也叫奖励或惩罚)能在单独的数据向量被观察之后存在很久.当一个老鼠走迷宫寻找食物的时候,它经历一系列的转弯,最后找到了食物,这是对它的奖励.奖励必须反馈回去,对老鼠寻找食物的过程产生影响.强化学习也是一样:系统获得一个延时信号(奖励或惩罚),根据这个信号推断下一步的策略(如在迷宫中的每一步怎么走).监督学习也适用于不完整的标签,此时意味着标签缺损(这中情况下称作半监督学习),或噪声标签(标签是错的).大部分机器学习的方法只能处理以上讨论的一种或两种情况.例如:某算法可以处理分类,但不可以处理回归;某个可以处理半监督学习,但不能进行强化学习;某算法可以处理数字数据,但是不可以处理类别数据;等等;

有的时候,数据是没有标签的,但我们对数据是否能够自然归类感兴趣.这种无监督的学习算法叫聚类算法(clustring algorithm).目的是把这些无标签的数据按照他们的距离(预先确定的或感觉上的)远近归类.我们仅仅想看脸是这吗分布的:它们是胖还是瘦,是长还是方?如果我们观察癌症方面的数据,能否将拥有不同化学信号的癌症方面的数据聚集在一起?无监督的聚类数据经常形成一个特征向量供更高层的有监督的分类器使用.我们可以先把脸聚类成脸型(宽,窄,长,方),然后把脸型作为输入,可能在加上其他的一些数据(声音的平均频率),以此来预测人的性别;

这两个典型的机器学习任务(分类和聚类)与计算机视觉中的两个基本任务(识别和分割)有共通之处.我们需要计算机判断物体是什么的时候,我们使用识别;我们需要计算机说出物体位置的时候,我们使用分割.因为计算机视觉大量依靠机器学习,opencv在ML部分包含大量的机器学习算法,库位于/opencv/ml目录之中.

生成模型和判别模型

很多算法被设计用于解决学习和聚类问题.openCV囊括了一些当前用得最多的统计机器学习方法.概率机器学习方法,像像贝叶斯网络和图模型,在OpenCV中支持的比较少,部分原因是这些算法还很新,还在成长中,变化会很大.OpenCV倾向于支持判别算法,即通过给定数据来判断类别(P(L\D)),而不倾向于产生式算法,产生是算法是通过给定类别来生成数据的分布(P(D|L)).虽然这二者的区别不是非常清晰,但是判别模型在根据给定的数据作出预测上有优势,而生成模型则是在为你提供强大的数据表达式或者有条件地生成新数据时有优势,(比如,想想一个大象的样子;你是在根据条件"大象"来生成数据)

产生式模式很容易理解,是因为它是对数据的产生进行建模.判别是学习算法经常根据一些看似武断的阈值作出判断.例如:假设一小片区域在某个场景中被定义为路仅仅因为它的红色分量小于125.但是是否意味着红色分量等于126就不是路?这类问题很难解释的清楚.产生式模型中经常给定类别,得到数据的条件分布所以你可以很容易看出这个分布跟真正的分布是否相似.

OpenCV机器学习算法

openCv中的机器学习算法如下所示.除了Mahalanobis和K均值算法在CXCORE库中,人脸检测算法在CV库中,其他算法都在ML库中

算法名称:

Mahalanobis:通过除以协方差来对数据空间进行变换,然后计算距离.如果写方差矩阵是单位矩阵,那么该度量等价于欧式距离

K均值:这是一种非监督的聚类方法,使用K个均值来表示数据的分布.其中K的大小由用户定义.该方法跟期望最大化方法(expection maximization)的区别是K均值的中心不是高斯分布,而且因为各个中心竞争去"俘获"最近的点,所以聚类的结果更像是肥皂泡.聚类区域经常被用做稀疏直方图的bin,用来描述数据.

正态/朴素贝叶斯分布器: 这是一个通用的分类器,它假设特征是高斯分布而且统计上相互独立.这个假定过于苛刻,在很多条件下不能满足,正因如此,它也被称作"朴素贝叶斯"分类器.但是,在许多情况下,这个分类器效果却出奇的好.

决策树:这是一个判别分类器.该树在当前节点通过寻找数据特征和一个阈值.来最优划分数据到不同的类别.处理流程是不停地划分数据并向下到树的左侧子节点或右侧子节点.虽然它一般不具有最优性能,但是往往是测试算法的最优选择,因为他处理速度比较快,而且具有不错的功能.

Boosting:多个判别子分类器的组合.最终的分类决策是由各个子分类器的加权组合来决定.在训练时,逐个训练子分类器,且每个子分类器是一个弱分类器(只是优于随机选择的性能).这些弱分类器由单变量决策树构成,被称为"树桩".在训练时,"树桩"不仅从数据中学习分类决策,而且还根据识别精度学习投票的权重.当逐个训练分类器的时候,数据样本的权重被重新分配,使之能够给予分错数据更多的注意力.训练过程不停的进行,直到总错误(加权组合所有决策树组成的分类器产生的错误)低于某个已经设置好的阈值.为了达到好的效果,这个方法通常需要很大数据量的训练.

随机森林:这是由许多决策树组成的"森林",每个决策树向下递归以获取最大深度.在学习的过程中,每棵树的每个节点只从特征数据的一个随机子集中选择.这保证了每棵树是统计上不相关的分类器.在识别的过程中,将每棵树的结果进行投票来确定最终的结果,每棵树的权重相同.这个分类方法经常很有效,而且对每棵树的输出进行平均,可以处理回归问题.

人脸检测/Haar分类器 :这个物体检测方法巧妙地使用了boosting算法.OpenCV提供了正面人脸检测器,它的检测效果非常好.你也可以使用OpenCV提供的软件训练算法,使之能够检测其他物体.该算法非常擅长检测特定视角的刚性物体.

期望最大化(EM):一种用于聚类的非监督生成算法,它可以拟合N个多维高斯到数据上,此处N的大小由用户决定.这样仅仅使用几个参数(均值和方差)就可以非常有效的表达一个比较负责的分布.该方法经常用于分科.

K近邻:K近邻可能是最简单的分类器.训练数据跟类别标签存放在一起,离测试数据最近的(欧式距离最近)K个样本进行投票,确定测试数据的分类结果.这可能是你想到的最简单的方法,该方法通常比较有效,但是速度比较慢,且对内存的需求比较大.

神经网络/多层感知器:该分类算法在输入节点和输出节点之间具有隐藏节点,这可以更好的表示输入信号.训练该分类器很慢,但是识别的很快.对于一些识别问题.如字符识别,他具有非常不错的性能.

支持向量机(SVM):它可以进行分类.也可以进行回归.该算法需要定一个高维空间中任意两点的距离函数.(将数据投影到高维空间会使数据更容易地线性可分).该算法可以学习一个分类的超平面,用来在高维空间里实现最优分类.当数据有限的时候,该算法可以获得非常好的性能,而boosting和随机森林只能在拥有大量训练数据时才有好的效果.

视觉中使用机器学习

基本上,所有算法都使用特征构成的数据向量作为输入,特征的个数可以以千计.假设你的任务是识别特定的物体(例如,人).你遇到的第一个问题是怎么采集数据并给数据定标签(场景里有人还是没有人).你会发现人以不同的方式出现:人的图像可能只包含一点点像素,或者你只能看到一只耳朵出现在整个屏幕上.更坏的情况下,人可能处于遮挡状态下:在车中的人,女人的脸,树后面的一条腿.你需要定义有人在场景的确切定义.

下面将遇到采集数据的问题.使用自己的摄像头采集,还是使用公共数据库尝试寻找"人物"标签,或者两种方法都使用?采集运动信息吗?采集其他信息吗?如场景中的门是开的,时间,季节,温度.用于海滩上检测人的算法说不定不适用于滑雪场.需要捕获数据的各种变化:不同视角,不同光线,不同天气,阴影,等等.

获取了很多数据之后,该怎么给数据定标签?首先需要决定标签的意义.需要知道场景中的人在什么位置吗?运动信息重要吗?如果有大量的图像,又应该怎样给所有的图像定标签?有很多诀窍,比如在约束情况下中做背景减除,收集运动前景.

数据定好标签之后,需要决定需要提取那些特征.再一次,必须知道自己的目的.如果人们总是正面出现,就没有必要使用旋转不变的特性,也没有必要预先旋转物体.总之,必须寻找表达物体固有属性的特征,比如梯度直方图,色彩,或目前流行的SIFT特征.如果有背景信息,可能首先把背景去除,提取物体,然后进行图像处理(归一化图像,尺度改变,旋转,直方图均衡),计算很多特征.物体的特征向量将于物体的标签对应.

一旦数据被转换特征向量,便需要把数据分成训练集,验证集和测试集.在这里,我推荐交叉使用训练集,验证集,和测试集.也就是说:所有的数据分成K个子集,然后每次随机选取其中一部分来训练,剩余分用来测试.测试结果求平均,得到最终的性能结果.使用交叉验证,我们能够更清楚地看到处理异常数据时分类器的性能.

数据已经准备好,下面是选择分类器.一般分类器的选择需要考虑计算速度,数据形式和内存大小.一些应用中,在线用户优先选择建模,所以分类器需要能够快速完成训练.在这种情况下,最邻近算法,正太贝叶斯的决策树是不错的选择.如果选哟考虑内存因素,决策树和神经网络是理想的选择.如果不需要训练很快,而需要判断很快,但是需要进度很高,可选择boosting和随机森林.如果选取的特征比较好,仅仅需要一个简单易懂的分类器,就选择决策树和最邻近算法.要获得最好的性能,还是离不开boosting和随机森林算法.

变量的重要性

上面有两个算法可用来评估变量的重要性.拿到一个特征向量,我们怎么才知道哪个特征对分类器的准确性有较大的贡献?二进制决策树可以解决这个问题:通过在每个节点选择最能够分裂出数据的变量.最上面的变量是最重要的变量,第二层的变量第二重要,以此类推.随机森林采用Leo Breiman发明的一项计数来测量变量的重要性.这个技术可以用于任何分类器,但是在OpenCV中,仅仅决策树和随机森林实现了这个计数.

变量重要性的一个用途是减少分类器需要考虑的特征的个数.一开始有很多特征,你训练分类器,发现其中一个特征与另外一些特征有关联.你可以去掉其中一些不重要的特征.排除不重要的特征可以特高速度,可以是训练和测试更快.还有,如果没有足够的数据,去除不重要的变量可以提高分类器的准确率.这也可以使处理更快,效果更好.

Breiman的变量重要性算法的步骤如下.

1.用训练集训练一个分类器

2.使用验证集或测试集来确定分类器的准确率.

3.对于每一个数据样本和一个选择的特征,随机选择其他特征数据中的该特征的值来替代(替补抽样法).这样可以保证特征的分布与原始数据集的一样,但是特征的结构或者意义被抹去了(因为它的值是从剩余的数据中随机选择的).

4.用改变后的训练集训练分类器,然后用改变后的测试集或者验证集来评价分类器.如果完全打乱特征使正确率降低很多,那么这个特征很重要.如果完全打乱特征并没有使正确率下降多少,那么这个特征并没有多重要,可以考虑删除.

5.把原始数据重新换一个特征按照3和4操作,直到所有的特征全部分析完毕,得到的结果就是每个特征的重要性.

这个过程被内置到随机森林和决策树中,所以可以使用他们来确定使用那些变量做特征,然后使用被删减的特征向量来训练分类器.

诊断机器学习中的问题

将机器学习用好,不仅仅是一门技术,更是一门艺术.算法经常"有些时候"能用,但又不能完全与要求一致.这就是艺术的所在:需要指出哪些地方出问题了并解决问题.尽管在这里我不能详细说明,但我讲列举一些常见问题.首先介绍一些重要的规律:大量数据比少量数据好;好的特征比好的算法更重要.如果选取的特征好,最大化他们的独立性,最小化他们在不同环境之下的变化,那么大部分算法都可以获得比较好的效果.除此之外,还有两个经常遇到的问题.

欠拟合:模型假设太严格,所以模型不能拟合到实际数据上.

过拟合:算法不仅学了了数据,而且把噪声也当作信号学习了,这样算法的推广能力很差.

有些时候,需要注意是否正在解决自己想要解决的问题.如果训练和测试结果都很好,但是算法在实际应用中效果不好,则表名数据集可能是从非实际条件中获得的,也许是因为这些条件可使收集时模拟这些数据更容易.如果算法不能重现训练集或者测试集,表名问题出在算法,或者从数据中提取的特征是无效的,或者有用的信息不在收集的数据中.

机器学习中遇到的问题以及可能的解决方案,采用更好的特征对任何问题都有帮助

欠拟合:使用更多的特征有利于拟合,选用一个学习能力更好的拟合算法

过拟合:增加训练数据的数量可使得拟合曲线更光滑,减少特征的数量可降低过拟合程度,使用一个学习能力差一点的算法

训练和测试比较好,但是实际应用效果不好:采集更加真实的数据;

模型无法学习数据 :重新选择特征,使特征更能表达数据的不变特性;采集更新,更相关的数据,选用一个学习能力更好的拟合算法.

交叉验证,自抽样法,ROC曲线和混淆矩阵

最后,介绍一些用来评估机器学习结果的工具.在监督学习中,最基本的问题之一是知道算法的性能:分类器准确么?你可能会说"简单,我只需要在测试集或者验证集上运行以下,接可以获得结果."但是在实际情况中,我们必须考虑噪声,才用误差和采样错误.测试集或验证集可能并不能精确地反映数据的真是分布.为了更准确的评估分类器性能,我们可以采用交叉验证(cross-validation)的计数或者与之比较相近的自抽样法.

交叉验证首先把数据分为k个不同的子集.然后用k-1个子集进行训练,用没有用来训练的子集进行测试.这样做k次(每个子集都有一次机会做测试集),然后把结果平均.

自抽样法跟交叉验证法类似,但是验证集是从训练集中随机选取的.选择的点仅用于测试,不在训练中使用.这样做N次,每次随机选择一些验证集,最后把得到的结果平均.这意味着一些数据样本会出现在不同的验证集中,自抽样发效果一般胜于交叉验证.

使用其中的任意一种技术都可以使实际效果的评估更准确,更高精确度可以用来指导学习系统的参数调整.再训练,再评估,再调整,如此继续.

在评估和调整分类器的方法中,还有两个比较有用的方法,它们是画ROC曲线和填充混淆矩阵.ROC曲线评估了分类器参数的变换对分类器性能的影响.假设这个参数是一个阈值.更具体一点,假设我们需要在图中识别黄色的话,探测器使用一个阈值来定义黄色.黄色的阈值设置的非常高,则意味这我们的分类器的错误识别率为0,同事将正确识别率也为0.另一方面,如果黄色的阈值设置的非常低,则意味着所有的信号都被识别成黄色.分类器的错误识别率为100%,同事正确的识别率为100%.最好的ROC曲线是从原点沿Y轴上升到100%,在沿X轴到达右上角的折线.如果做不到这样,那么,曲线越靠近左上角越好.我们可以计算ROC曲线下方的面积和整个ROC图的面积之比,越接近于1,就表明分类器越好.

分错类的代价

下面我们讨论分错类的代价.假设我们要设计分类器来检测毒蘑菇,我们希望错误拒绝率(可食用的蘑菇被认为有毒)很大,错误识别率(有毒的蘑菇却被认为可食用)很小.ROC曲线可以处理这种情况:我们设置ROC参数使得操作点下降.还有另一种方法是生成ROC曲线的时候对错误识别赋更大的权值.可以把每个错误识别的权值设置为错误拒绝权值的10倍.一些OpenCV算法(如决策树和SVM),能够通过指定类别的先验概率或者指定个别的训练样本的权重,来自动平衡"击中率和误报率"

特征方差不一致

另一个训练分类器的问题是特征向量中,特征的方差不一致.例如,如果一个特征是由小写的ASCII码字母表示的,那么它最多有25个值.于此不同的是,显微镜载物片上的生物细胞数目是以亿计的.类似k均值算法的一类算法会认为第一个特征相比于第二个特征可以忽略.解决这个问题的方法是预处理每个特征变量,使他们方差一致.如果特征不相关,这个步骤很重要;如果特征相关,你可以用他们的协方差或者平均方差来归一化.决策树等一类算法不受方差不一致的影响,所以不需要预先处理.如果算法以距离度量为准则,就需要预先将方差归一化.我们可以利用Mahalanobis距离来归一化特征方差.

你可能感兴趣的:(openCV)