应用机器学习的建议
第八十三课:决定下一步做什么?
在懂得学习算法的人中仍然存在着很大的差距,一些人掌握了怎样高效有力地运用学习算法,而另一些人没有完全理解如何运用这些算法?总是把时间浪费到毫无意义的尝试上面!
在设计机器学习系统时,怎么样选择一条最合适最高效的道路?
假如你在开发一个机器学习系统,或者改进一个机器学习系统的性能,你应该如何决定接下来应该选择哪条道路?
举个例子:
假如说你在预测房价时产生了巨大的误差,如何改进这个算法?
1.使用更多的训练样本(如何避免把时间浪费在收集更多的训练数据上)
2.尝试选用更少的特征(防止过拟合)
3.尝试更多的特征
4.增加多项式特征
5.增大或缩小正则化参数lambda的值
...
幸运的是,有一系列的方法能让你事半功倍!排除掉上述一半不太有效的改进方法,节省时间!
那么,怎么评估机器学习算法的性能?
机器学习诊断法!
这是一种测试法,通过执行这种测试,能够了解算法在哪里出了问题,也可以告诉你要想改进一种算法的效果,什么样的尝试才是有意义的!
第八十四课:评估假设
怎么评价你的算法?如何防止过拟合和欠拟合的问题?
当我们确定学习算法的参数时,我们考虑的是选择参数,来使训练误差最小化,有人认为,仅仅是因为这个函数有很小的训练误差并不能说明它一定是一个好的假设,它也有可能过拟合,即对新的数据没有好的预测结果,那么怎么判断一个假设是否过拟合呢?我们可以画出假设函数h(x),然后观察。但一般情况下,对于特征不止一个的例子,想要画出假设函数来观察是不可能的。
因此,我们需要一种评价假设函数的方法:
首先将数据分成两部分,第一部分成为我们的训练集,第二部分成为我们的测试集,将所有数据分成训练集和测试集,其中一种 典型的分割方法是按照七比三的比例。m表示训练样本的总数,mtest表示测试样本的总数。
最后再提醒一点,在这里我是选择了前70%的数据作为训练集,后30%的数据作为测试集,但如果这组数据有某种规律或顺序的话,那么最好是随机选择70%作为训练集,剩下的30%作为测试集。当然如果你的数据已经随机分布了,你就可以选择前70%和后30%。但如果你的数据不是随机排列的,最好还是打乱顺序,或者使用一种随机的顺序来构建你的数据。
一种典型的方法来训练和测试你的学习算法,比如线性回归算法。首先你需要对训练集进行学习得到参数θ。具体来讲,就是最小化训练误差J(θ),这里的J(θ)是使用那70%数据来定义得到的,也就是仅仅是训练数据。接下来你要计算测试误差,用Jtest来表示测试误差,那么你要做的就是把从训练集中学习得到的参数θ放到这里来计算测试误差。
当然这是我们使用线性回归和平方误差标准时,测试误差的定义。如果考是考虑分类问题逻辑回归问题呢?
训练和测试逻辑回归的步骤和之前所说的非常类似。首先训练数据,从70%的训练样本中学习得到参数θ,然后计算测试误差,目标函数和我们平常做逻辑回归的一样,唯一的区别是,现在我们使用的是mtest个测试样本。此外还可以使用错误分类误差来检验预测值和实际值之间的差距(使用0/1错误分类度量来定义的测试误差)。
如何进行诸如特征选择一类的问题?比如学习算法多项式选择的问题,或者学习算法正则化参数的选择?
第八十五课:模型选择和训练、验证、测试集
对于一个数据集最合适的多项式次数,怎么选用正确的特征来构造学习算法?或者如何选择学习算法中的正则化参数lambda?
模型选则问题:
不仅仅把数据分为训练集和测试集,还要把数据分为三个数据组,也就是训练集、验证集和测试集。
为什么训练集误差不能用来判断该假设对新样本的拟合好坏,因为存在过拟合问题!即就算你的假设在训练集上表现得很好,也并不意味着该假设对训练集中没有的新样本有多好的泛化能力。
更为普遍的规律是:如果你的参数对某个训练集拟合的很好,比如训练集或其他数据集,那么用同一数据集计算得到的误差,比如训练误差,并不能很好的估计出实际的泛化误差,即该假设对新样本的泛化能力。
所以除了参数θ还有一个参数d需要用你的数据集来确定!
比如说你想选择一个模型,就是选择一个多项式次数,从这10个模型中选择一个,拟合这个模型并且估计这个拟合好的模型假设对新样本的泛化能力。
具体你可以这样做,首先选择第一个模型,然后最小化训练误差,这样你就会得到一个参数向量θ,然后你再选择第二个模型,二次函数,用它来拟合你的训练集,这样就得到另外一个参数向量θ。
接下来要做的是对所有这些模型求出测试集误差,计算出它在测试集的性能。为了在这些模型中选择最好的那个,应该看哪个模型有最小的测试误差。选择模型后,如何得到这个模型的泛化能力怎么样?
我们可以观察这个五次多项式假设模型对测试集的拟合情况。虽然这样做仍然不能公平地估计出这个假设的泛化能力。其原因在于虽然我们拟合了一个额外的参数d,也就是多项式的次数,我们用测试集拟合了参数d,我们选择了一个能最好地拟合测试集参数d的值。因此我们的参数向量在测试集上的性能很可能是对泛化误差过于乐观的估计。因为我是用测试集拟合得到的参数d,再在测试集上评估假设,就不公平了。因为我用测试集拟合得到的参数,用测试机选择了多项式的次数,所以假设很可能对于测试集的表现好过对于新的它没见过的样本。
即假设在测试集上的效果并不能用来公正地估计这个假设对从未见过的新样本的效果。
为了解决模型选择出现的问题:
我们通常采用:
对于给定的训练集,我们不是把它分为训练集和测试集,而是分为三部分,第一部分和之前一样,还是训练集。第二部分我们将其成为交叉验证集,简称cv,有时候也叫做验证集。最后一部分还是叫做测试集。这些数据典型的分配比例是:60%、20%、20%。
定义完成后,同样地我们可以定义训练误差,交叉验证误差和测试误差。
当面对这样的模型选择问题时,我们要做的是用验证集来选择模型,而不是用原来的测试集。
具体来讲,我们首先要选取第一种假设,第一个模型,然后最小化代价函数,得到对应一次模型的一个参数向量θ,一直求得各个对应模型的参数变量。接着要做的不是像原来一样用测试集来测试这些假设,而是用验证集来测试,然后计算出Jcv来观察这些假设模型在验证集上的效果如何。我们要做的就是用验证集拟合出最佳参数d,这样省下了测试集,可以用它来衡量或者估计算法选出的模型的泛化误差。
用测试集选择你的模型,然后使用相同的测试集来计算误差,这不是一个好主意,通过测试集来选择多项式的系数,然后仍在测试集上计算误差,把它当做理想的泛化误差,但是最好不要这样做!分成训练集、验证集和测试集是更好地选择。
第八十六课:诊断偏差和方差
如果你在运行算法的时候,运行的不是很理想,多半是出现了偏差或方差过大的问题,换句话说要么是过拟合问题,要么是欠拟合问题,这种情况下,搞清楚是偏差问题还是方差问题或者两者都有关是很重要的,因为这有利于我们找到有效的方法和途径来改进算法。
如何观察算法然后判断是偏差问题还是方差问题?这对于改进你的学习算法的效果非常重要!
我们沿用之前所使用的训练误差和验证误差的定义,分别是用训练集计算的,和利用验证集计算的均方误差,可以利用下面的函数图像来分析出最佳d值。
具体来说,假设你得出了一个学习算法,而这个算法并没有表现地像你期望的那么好,如果你的交叉验证误差或者测试集误差都非常大,那么怎么判断此时的学习算法出现了高偏差的问题还是高方差问题。
如果你的算法处于高偏差的情况,那么你的训练集误差会很大,因为你的假设不能很好地拟合训练集数据。而你处于高方差的问题时,你的训练误差通常都会很小,并且远远小于交叉验证误差。
采取什么措施来应对高方差和高偏差?
第八十七课:正则化和偏差、方差
算法正则化可以有效的防止过拟合,但正则化跟算法的偏差和方差又有什么关系呢?正则化又是如何影响偏差和方差的?
如何自动地选择出一个最合适的正则化参数λ的值呢?
我们把训练集误差Jtrain定义为训练集的平方误差之和,或者训练集上平均的平方误差,但不考虑正则化项。
自动化选择正则化参数λ的方法:
选取一系列我想要尝试的λ值,因此首先我可能考虑不使用正则化以及一系列可能使用的值,比方说0.01、0.02、0.04等。这样就得到了12个备选模型,对应了12个不同的正则化参数λ,接下来要做的是选用第一个模型,然后最小化代价函数J(θ),这样就得到了某个参数向量θ,用θ(1)表示,以此类推,分别求得θ(2、3...12)。接下来就可以用所有这些假设、所有这些参数用交叉验证集来评价它们了,用不同的正则化参数进行拟合,然后用交叉验证集进行评价,即测出每一个参数θ在交叉验证集上的平均的误差平方和。然后我就选取这12个模型中,交叉验证集误差最小的那个模型作为最终选择。
注意:我们用交叉验证集拟合参数,但是还是留下了单独的测试集,可以用它来更准确地估计出参数向量θ对于新样本的泛化能力。这就是模型选择在选取正则化参数λ时的应用。
当改变正则化参数λ时,交叉验证误差和训练误差怎么变化?
注意:训练误差和交叉验证误差不包括正则化项。
当我尝试为学习算法选择正则化参数λ时,类似这样一张图可以帮助我们更好的理解各种情况,同时也帮助我们确认选择的正则化参数值λ到底好不好!
对方差和偏差有了一定认识以后,在此基础上,建立一个诊断方法,也称为学习曲线,诊断学习算法是处在偏差问题还是方差问题上。
第八十九课:学习曲线
绘制学习曲线非常有用,也许你想检查你的学习算法运行是否一切正常,或者你想改进算法的表现,那么学习曲线就是一个很好的工具。它可以判断算法是否处于偏差、方差问题或是两者皆有。
为了绘制学习曲线,通常需要先绘制Jtrain,也就是训练集的平均误差平方和,或者Jcv即交叉验证集的平均误差平方和。
当训练样本数很大,但是人为地限制训练集的大小来画Jtrain,随着训练集容量的增大,不难发现,平均训练误差在增大,因此如果你画出这条曲线,你会发现训练集误差,也就是假设的平均误差随着m的增大而增大。
但对于交叉验证集的误差,当训练集很小的时候,泛化程度不会很好,意思是不能很好地适应新样本,因此这个假设就不是一个理想的假设,只有当使用一个更大的训练集时,才有可能得到能够更好拟合数据的假设。因此验证集误差和测试集误差都会随着训练集样本容量m的增加而减小。因为你使用的数据越多,越能获得更好的泛化表现。
对于高方差和高偏差的情况:
当训练集样本增大到某个值的时候,你就会找到那条最有可能拟合数据的那条直线,并且此时即便你继续增大训练集的样本容量m,还是会得到一条差不多的直线。交叉验证集误差或者测试集误差将很快变为水平而不再变化,只要达到或者超过一定数量的训练样本。训练误差则会随着样本数m的增大而增大,直到最终接近交叉验证集误差。
最后补充一点;高偏差问题,可以由很高的交叉验证误差和训练误差反映出来,即得到一个较大值的Jcv和Jtrain。
结论:如果一个学习算法有高偏差,随着增加训练样本,会发现交叉验证误差不会明显下降了,基本变成平的了,所以如果学习算法正处于高偏差的情形,那么选用更多的训练集数据对于改善算法无益。
所以能够知道你的算法是否处于高偏差是一件非常有用的事,因为这样可以让你避免把时间浪费在收集更多的训练数据上。
当学习算法出现高偏差时的情况:
算法处于高方差情形很明显的一个特点:在训练误差和交叉验证误差之间有一段很大的距离,而曲线图也反映出如果我们考虑增大训练集的样本数,随着训练样本数的增大,训练误差会逐渐增大,而交叉验证集误差则会持续下降。所以在高偏差的情况下,增大样本数,对改进算法是有帮助的。
总的来说,像这样画出学习曲线,确实能帮助判断出学习算法是否出现了高偏差、高方差或两者皆有的情况。所以当我打算改进学习算法的时候,我通常会进行的一项工作就是画出这些学习曲线,通常这样可以让你更好地判断偏差或者方差的问题。
学习算法如何指引我们采取或者不采取某些方法来改进学习算法?
第九十一课:决定接下来做什么
我们已经学会怎么评价算法,讨论了模型选择以及方差和偏差问题,以上问题怎么具体帮助我们弄清哪些方法有助于改进学习算法的效果呢?哪些又是徒劳呢?
回到我们最初的问题:
如何为神经网络选择结构或者连接形式?
一般来说,使用一个大型的神经网络并使用正则化来修正过拟合问题通常比使用一个小型的神经网络效果更好,但主要可能出现的一个问题就是计算量相对较大。通常使用一个隐藏层是比较合理的默认选项,但如果你想要找到一个最合适的隐藏层层数,你可以试试把数据分割成训练集、验证集和测试集然后训练一个隐含层的神经网络,然后试试两个、三个隐藏层,然后看看哪个神经网络在交叉验证集上表现得最理想。
你已经能够有效的用学习算法解决问题了,希望这些关于偏差、方差、学习曲线和判断方法的建议能够真正帮助你更有效地应用学习算法,让它们高效工作。