机器学习的性能优化方法

1. 引言

最近看吴恩达深度学习的深度学习课程笔记,笔记公布网站:https://github.com/fengdu78/deeplearning_ai_books

http://www.ai-start.com。看到第三门课:结构化机器学习项目,看完很有感触,感觉大牛确实是牛,比自己当初做项目单独摸索时使用的方法强太多,自己当初也能按照这些方法做就好了。为了以后自己少走弯路,将课程中好的执行策略加上自己的理解记录在此,以后做项目遇到困难多翻翻。

 2. 实用的机器学习策略

什么是机器学习策略呢?就是你做项目时搭建好一个原型后怎么一步步的优化,使得其接近可用、可部署的模型。

2.1 选算法模型

这一步最好不要自己造轮子,首先理清自己要解决的问题所在的学术领域,到百度学术找找学术文献看看专业的研究者都是怎么做的,看的多了就有自己选什么样算法和模型的思路了;遇到比较好的论文,可能还有github的实现,那就更好了,抓一部分自己真正要用的样本,代入到github项目里调一调,这样对是否借鉴相关算法、以及算法要注意的各种重要问题都能心里有谱,而且还不怎么花时间。

    另外,如果你要解决的问题,恰好已经在工业界有很好的公认的好的实现了,那你要做的就更简单了,算法和模型可以直接借鉴,剩下的就是怎么将你自己的数据与公开的算法模型对齐了。当然,这里面也会涉及到很多优化问题,不仅需要好好调调模型参数,可能还需要借助学术文献做做更深入的优化。如果不幸的是工业界没有公认的好实现,那你就要借助开源算法平台,例如深度学习tensoflow或者传统机器学习scikit-learn,自己做模型验证了,验证的算法模型来自之前研究的学术论文,或多个学术论文模型的综合。

2.2 数据集划分

 

一般来讲,需要将数据集划分成训练集、验证集(深度学习课程中将其叫做开发集)和测试集。其中:

1. 训练集用来训练不同的算法模型;

2. 用开发集评估不同的模型选择最优的一个,然后不断迭代去改善开发集的性能;

3.用测试集去评估最终应用效果。

    需要注意的是开发集和测试集要来自同一数据分布,一种可行的方法是将所有数据随机洗牌,放入开发集和测试集,此时二者处于同一分布。另外,设立开发集和测试集时,要能够反映你未来会得到的数据、认为很重要的数据、必须得到好结果的数据。

     训练集是否需要与开发集/测试集来自同一数据分布呢?要看收集数据的来源。以图像猫的分类为例,我们的目标是分类用户手机上传的图片是否是猫,而用户手机上传的样本规模小,例如10000个;所以需要从网络上爬取更多的猫图像,这些图像一般都是取景专业、高分辨率、拍摄专业的猫图片例如200000个,与用户手机上传的业余的、取景不太好、甚至模糊的图片显然不在同一个数据分布里。根据我们的优化目标,显然网络上爬取的图片不能划入开发集/测试集,而训练集更多的是包含爬取的图片,即训练集和开发集/测试集不在同一数据分布。

 

        假设收集数据来源于同一数据分布,数据集的划分方法是:在数据集较小时,一条经验性的法则是:70/30比例划分训练集和测试集,或者60/20/20划分训练集、开发集和测试集。当数据集很大时,比如一百万以上训练样本,则98%作为训练集、1%开发集、1%测试集可能更合理。

        假设收集的数据来源于不同的数据分布。我们的数据集划分方法是什么呢?按照深度学习课程中《2.4 在不同的划分上进行训练并测试》中的方法,以上面的猫分类器为例,将用户手机上传的样本随机分成3份,5000个样本与网络爬取的20万个猫图片构成训练集,2500个作为开发集,2500个作为测试集。为了搞清楚开发集上的错误率是由于模型偏差还是由于与训练集数据分布不一致导致的,需要进一步将训练集划分成两个子集:将训练集打乱随机抽取一个子集,例如10000个样本的训练-开发子集,剩余的作为新的训练集,此时新的训练集和训练-开发子集处于同一数据分布。总结一下,此时样本集被划分成4个子集:训练集、训练-开发集、开发集、测试集,而且训练集和训练-开发集处于同一数据分布,开发集和测试集处于同一数据分布。为什么这么划分呢,看下面的2.3节的误差分析章节。

2.2 确定优化目标

优化目标就是表明模型达到什么样的数值指标认为是好的模型。这个优化目标,不仅可以指导我们选择算法,也能帮助我们调整模型参数。最有效的方法是设立一个单一数值的指标这会加快你的模型迭代,每次迭代后告诉你模型是变好还是变差。

    那么单一数值指标怎么定呢?一般分类算法要考察查准率precision和查全率recall,我们将其转换为单一数值指标的方法是计算F1=2/(1/P+1/R),其中,P是查准率,R是查全率。

    很多时候,指定这样的一个单一数值指标是困难的。例如很多系统在实际部署时,要考虑内存、运行时间等开销。此时你要考虑这些性能指标是否是刚性的:如果是刚性的,那就将这些指标作为必须满足的约束条件,在满足这些约束条件的前提下再比较F1这种单一指标;如果不是刚性的,那么你可以将这些指标进行组合加权,构建一个新的单一指标,尽量满足你的实际需要。

2.3 误差分析(偏差-方差分析)

我们选定算法模型,给定模型参数迭代一次得到模型的优化目标之后,如何分析模型的误差呢?假设我们有一个单一实数的优化目标叫做错误率(来源可能是F1,也可能是自定义的指标),那么模型跑一遍可以至少得到两个结果:训练集上的错误率和开发集上的错误率。

    首先看训练集上的错误率,它表明了模型对训练数据的拟合能力,深度学习的对比基准一般是人类的表现水平(常用来近似贝叶斯最优错误率,人类表现的指标有三类:普通人的典型错误率、专家的典型错误率、专家团队的典型错误率,可以根据实际需要选择)。例如模型的错误率是6%,而人类表现水平是1%,那么二者的差值就是模型在训练集上的偏差。经验性的,研究团队在研究一个问题时,当你开始往人类水平努力时,进步是很快的,但过了一段时间,当这个算法表现比人类更好时,进展和精确度的提升就会变慢,直至达到某个理论上限,这个上限就是贝叶斯最优错误率。

    然后看开发集上的错误率,它表明了模型的泛化能力,开发集上错误率与训练集上错误率的差值衡量了方差的大小。当然,如果训练集和开发集不是同一数据分布,例如2.2节猫分类的例子,方差就不能这么简单衡量了。对2.2节猫分类的例子,我们划分了训练集、训练-开发集、开发集和测试集。训练集错误率与训练-开发集错误率的差值衡量了方差的大小,因为这两个集合来自于同一数据分布;训练-开发集错误率与开发集错误率的差值,衡量了数据不匹配问题的大小,即这两个集合数据分布不一致程度高带来的问题,解决方法是增加训练集的数据,使得二者数据分布趋向一致,虽然这很困难,没有系统性的方法能做到,但还是有一些办法,例如可以做错误分析,尝试了解训练集和开发测试集的具体差异,你应该人工去看开发集,分析开发集误差的原因,再分析分析训练-开发子集误差的原因,通过对比知道二者的差异性质,然后有意识的收集更多带有这种差异性质的样本到训练集中,一种可行的技术是人工合成数据(artificial data synthesis),例如在音频中加入噪声:录一小时的车辆北京噪音,然后将其回放10000次,并叠加到安静背景下录得的10000小时的训练数据中,这种人工合成方法存在的风险是,模型对这一小时的噪音过拟合。在语音识别中,我们已经看到人工数据合成显著提升了已经非常好的语音识别系统的表现,所以这是可行的。但当你使用人工数据合成时,一定要谨慎,要记住你有可能从所有可能性的空间只选了很小一部分去模拟数据。

        以上分析了模型的偏差-方差,这指引了我们模型下一次迭代的优化方法。如果偏差大,则表明模型的拟合能力还不够,

继续降低训练偏差;而当训练集的偏差接近或高于人类的识别能力时,算法的训练误差很难继续降低,应更关注减少方差的手段,例如正则化(L2正则、dropout正则、早停)、或者收集更多的训练数据(或者数据集增强)。当然,这些只是经验性的泛泛而谈,更有指向性的方法是做人工误差分析。

        通常人们鄙视手工分析,但简单的人工错误分析统计,可以节省大量时间,迅速决定什么是最重要的,或者最有希望的方向。我们可以根据开发集错误率,抽样选择开发集上分类错误的100个样本,人工列表格100行*M列(100行表示100个样本,M表示分类错误的原因),分析一下每个样本分类错误的原因,然后统计每种原因所占的比例,这样我们就知道下一次迭代努力的方向:减少最大比例的错误原因。

 

2.4 模型调参

    机器学习算法我们一般都用开源的算法库,我们需要做的就是模型调参。参数分为超参数和内部参数。内部参数通过迭代被算法不断调整,例如神经网络中的权重W和偏置b,而超参数需要在算法学习过程开始前设置好就不再变化,最重要的超参数是学习率。有两种调参策略:混合调整参数和正交化调整参数。

        对于混合调整参数,如果参数的数量少,例如2~3个,可以用笛卡尔乘积的方式计算参数不同取值的所有组合,然后并行地训练绘制优化目标随参数取值的变化曲线,根据曲线的变化趋势选择最优的参数组合。如果参数的数量较多,比较有效的是建立随机向量,向量的每一维是一个参数的一个取值,不断迭代地比较保留优化性能最好的一组参数向量,直至达到给定迭代限制条件。

     对于正交化的调整参数,我们判断影响机器学习有很多因素,我们应该将其分成相对独立的组(相互正交化),然后按照重要性依次调参,而不是混合在一起调参,深度学习课程里认为这种调参更有效率。

2.5 错误标注

   在2.3节的开发集误差分析过程中,可能出现的一个分类错误的原因是数据人工预设的标记是错误的。那么时候有必要修正这些人工错误标注的样本标记吗?如果需要修正,对于训练集、开发集、测试集的样本哪些样本需要修正呢?

      首先考虑训练集,深度学习算法对训练集中的随机错误是相当健壮的(算法一般都有很好的正则化设置),预设标记错误如果是随机的(不是人为故意标错的、或者认为系统性错误标记,对某一类型有错误的认知使得整个类别都错误),则不需要修改它们。

    在开发集和测试集中有错误标记的样本,则需要用2.3节误差分析中的方法,例如人工采样100个开发集上分类错误样本,列表格统计分析人工标记错误的样本所占比例,看看统计上对开发集错误率的影响。如果影响很大,需要修改开发集上的错误率,由于必须保证开发集和测试集处于同一数据分布,所以测试集中的人工错误标记也需要修正。另外需要考虑的一点,人工标注错误不仅要考虑将开发集/测试集上分类错误的样本中人工错误标记,还要考虑模型分类正确的样本中也可能存在的人工错误标记,由于模型通常错误率较低,排查模型分类正确样本中的人工错误标记由于样本数量多而难以实施,但要考虑这样的部分修正(只修正分类错误样本中的人工标注错误)对算法整体性能的影响:算法会看上去比实际更好。

3. 总结

机器学习算法用于实际的分类问题,有很多使用的机器学习策略,最重要的一点是:一般而言,对于几乎所有的机器学习程序可能会有50个不同的方向可以前进,而且每个方向都是相对合理的可以改善你的系统。但挑战在于,你如何选择一个方向集中精力处理。我的建议是,快速搭建好你的第一个系统,然后开始迭代:快速设立训练集、开发集、测试集和指标,这就决定了你的目标所在;然后马上搭建一个机器学习系统原型,训练一下看看效果,开始理解你的算法表现如何,用之前说的偏差、方差分析确定下一步优先做什么,然后一步步迭代。

 

   

 

你可能感兴趣的:(机器学习,技术布道)