深度学习实践方法论
在应用机器学习算法时,实践方法论能够帮助我们更好地训练模型。如果在Kaggle上的结果不太好,虽然 Kaggle 上呈现的是测试数据的结果,但要先检查训练数据的损失。看看模型在训练数据上面,有没有学起来,再去看测试的结果,如果训练数据的损失很大,显然它在训练集上面也没有训练好。如下图所示是在训练集上面没有学好的几点原因。
一、模型偏差(Model Bias)
模型偏差可能会影响模型训练。
常见例子:假设模型过于简单,导致该函数的集合太小了,没有包含任何一个函数,可以让损失变低的函数不在模型可以描述的范围内。
形象比喻:想要在大海里面捞针(一个损失低的函数),结果针根本就不在海里。
解决方法:
1、可以增加更多特征,设一个更大的模型;
2、可以使用深度学习,增加更多的灵活性。
但是并不是训练的时候,损失大就代表一定是模型偏差,可能会遇到另外一个问题:优化做得不好。
二、优化问题(Optimization issue)
一般只会用到梯度下降进行优化,但是这种优化的方法很多的问题。
如下图所示,我们可能会卡在局部最小值的地方,无法找到一个真的可以让损失很低的参数。蓝色部分是模型可以表示的函数所形成的集合,可以把 θ 代入不同的数值,形成不同的函数,把所有的函数通通集合在一起,得到这个蓝色的集合。这个蓝色的集合里面,确实包含了一些函数,这些函数它的损失是低的。但问题是梯度下降这一个算法无法找出损失低的函数,梯度下降是解一个优化的问题,找到 θ∗ 就结束了。但 θ∗ 的损失不够低,即这个模型里面存在着某一个函数的损失是够低的,梯度下降却没有给出这一个函数。
形象比喻:想要大海捞针,针确实在海里,但是无法把针捞起来。
那么,训练数据的损失不够低的时候,到底是模型偏差,还是优化的问题呢。找不到一个损失低的函数,到底是因为模型的灵活性不够,海里面没有针。还是模型的灵活性已经够了,只是优化梯度下降不给力,它没办法把针捞出来呢?一个建议判断的方法,通过比较不同的模型来判断模型现在到底够不够大。
例子分析:残差网络的论文“Deep Residual Learning for Image Recognition”
这篇论文在测试集上测试两个网络,一个网络有 20 层,一个网络有 56 层。如下图所示,左边的图横轴指的是训练的过程,就是参数更新的过程,随着参数的更新,损失会越来越低,但是结果20 层的损失比较低,56 层的损失却比较高。残差网络是比较早期(2015 年)的论文,很多人看到这张图误认为这个代表过拟合,深度学习不奏效,56 层太深了不奏效,根本就不需要这么深。但这个不是过拟合,并不是所有的结果不好,都叫做过拟合。在右边的图中的训练集上,20 层的网络损失其实是比较低的,56 层的网络损失却是比较高的,这代表 56 层的网络的优化没有做好,它的优化不给力。
建议:看到一个从来没有做过的问题,可以先跑一些比较小的、比较浅的网络,或甚至用一些非深度学习的方法,比如线性模型、支持向量机(Support Vector Machine,SVM),SVM 可能是比较容易做优化的,它们比较不会有优化失败的问题。接下来还缺一个深的模型,如果深的模型跟浅的模型比起来,深的模型明明灵活性比较大,但损失却没有办法比浅的模型压得更低代表说优化有问题,梯度下降不给力,因此要有一些其它的方法来更好地进行优化。
例子分析:观看人数预测
如下图所示,在训练集上面,2017 年到 2020 年的数据是训练集,1 层的网络的损失是 280,2 层就降到 180,3 层就降到 140,4 层就降到 100。但是测 5 层的时候结果变成 340。损失很大显然不是模型偏差的问题,因为 4 层都可以做到 100了,5 层应该可以做得更低。所以,这个是优化的问题,优化做得不好才会导致造成这样子的问题。
如果训练损失大,可以先判断是模型偏差还是优化。
情况一:如果是模型偏差,就把模型变大。假设经过努力可以让训练数据的损失变小,接下来可以来看测试数据损失;如果测试数据损失也小,比这个较强的基线模型还要小,就结束了。
情况二:如果训练数据上面的损失小,测试数据上的损失大,可能是真的过拟合。在测试上的结果不好,不一定是过拟合。要把训练数据损失记下来,先确定优化没有问题,模型够大了。接下来才看看是不是测试的问题,如果确实是训练损失小,测试损失大,这个有可能是过拟合。
三、过拟合(Overfitting)
如下图所示,举一个极端的例子,这是训练集。
假设根据这些训练集,某一个很废的机器学习的方法找出了一个一无是处的函数。这个一无是处的函数,只要输入 x 有出现在训练集里面,就把它对应的 y 当做输出。如果 x 没有出现在训练集里面,就输出一个随机的值。这个函数啥事也没有干,其是一个一无是处的函数,但它在训练数据上的损失是 0。把训练数据通通丢进这个函数里面,它的输出跟训练集的标签是一模一样的,所以在训练数据上面,这个函数的损失可是 0 呢,可是在测试数据上面,它的损失会变得很大,因为它其实什么都没有预测,这是一个比较极端的例子,在一般的情况下,也有可能发生类似的事情。
如下图所示,举例来说,假设输入的特征为 x,输出为 y,x 和 y 都是一维的。x 和 y之间的关系是 2 次的曲线,曲线用虚线来表示,因为通常没有办法,直接观察到这条曲线。我们真正可以观察到的是训练集,训练集可以想像成从这条曲线上面,随机采样出来的几个点。
模型的能力非常的强,其灵活性很大,只给它这 3 个点。在这 3 个点上面,要让损失低,所以模型的这个曲线会通过这 3 个点,但是其它没有训练集做为限制的地方,因为它的灵活性很大,它灵活性很大,所以模型可以变成各式各样的函数,没有给它数据做为训练,可以产生各式各样奇怪的结果。
那么怎么解决过拟合的问题呢,有两个可能的方向:
第一个方向(往往最有效):即增加训练集。
因此如果训练集,蓝色的点变多了,虽然模型它的灵活性可能很大,但是因为点非常多,它就可以限制住,它看起来的形状还是会很像,产生这些数据背后的 2 次曲线,如下图所示。可以做数据增强(data augmentation),这个方法并不算是使用了额外的数据。
第二个方向:给模型一些限制,让模型不要有过大的灵活性。
假设 x 跟 y 背后的关系其实就是一条 2 次曲线,只是该 2 次曲线里面的参数是未知的。如下图所示,要用多限制的模型才会好取决于对这个问题的理解。因为这种模型是自己设计的,设计出不同的模型,结果不同。假设模型是2次曲线,在选择函数的时候有很大的限制,因为2次曲线要就是这样子,来来去去就是几个形状而已。所以当训练集有限的时候,来来去去只能够选几个函数。所以虽然说只给了3个点,但是因为能选择的函数有限,可能就会正好选到跟真正的分布比较接近的函数,在测试集上得到比较好的结果。
补充:给模型制造限制可以有如下方法:
1、给模型比较少的参数。
如果是深度学习的话,就给它比较少的神经元的数量,本来每层
一千个神经元,改成一百个神经元之类的,或者让模型共用参数,可以让一些参数有一样的数值。全连接网络(fully-connected network)其实是一个比较有灵活性的架构,而卷积神经网络(Convolutional Neural Network,CNN)是一个比较有限制的架构。
2、用比较少的特征
本来给 3 天的数据,改成用给两天的数据,其实结果就好了一些。
3、其他方法
比如早停(early stopping)、正则化(regularization)和丢弃法(dropout method)。
但是,也不要给太多的限制。假设模型是线性的模型,下图中有 3 个点,没有任何一条直线可以同时通过这 3 个点。只能找到一条直线,这条直线跟这些点比起来,它们的距离是比较近的。此时,这个时候模型的限制就太大了,在测试集上就不会得到好的结果。这种情况下的结果不好,并不是因为过拟合了,而是因为给模型太大的限制,大到有了模型偏差的问题。
然而,这边产生了一个矛盾的情况,模型的复杂程度,或这样让模型的灵活性越来越大。但复杂的程度和灵活性都没有给明确的定义。比较复杂的模型包含的函数比较多,参数比较多。
如下图所示,随着模型越来越复杂,训练损失可以越来越低,但测试时,当模型越来越复杂的时候,刚开始,测试损失会跟着下降,但是当复杂的程度超过某一个程度以后,测试损失就会突然暴增了。这就是因为当模型越来越复杂的时候,复杂到某一个程度,过拟合的情况就会出现,所以在训练损失上面可以得到比较好的结果。在测试损失上面,会得到比较大的损失,可以选一个中庸的模型,不是太复杂的,也不是太简单的,刚刚好可以在训练集上损失最低,测试损失最低。
四、交叉验证(Cross Validation)
比较合理选择模型的方法是把训练的数据分成两半,一部分称为训练集(training set),一部分是验证集(validation set)。
比如,我们可以用90% 的数据作为训练集,剩下10% 的数据作为验证集。在训练集上训练出来的模型会使用验证集来衡量它们的分数,根据验证集上面的分数去挑选结果,再把这个结果上传到 Kaggle 上面得到的公开分数。在挑分数的时候,是用验证集来挑模型,所以公开测试集分数就可以反映私人测试集的分数。
但是,根据过去的经验,就在公开排行榜上排前几名的,往往私人测试集很容易就不好。其实最好的做法,就是用验证损失,最小的直接挑就好了,不要管公开测试集的结果。在实现上,不太可能这么做,因为公开数据集的结果对模型的选择,可能还是会有些影响的。理想上就用验证集挑就好,有过比较好的基线(baseline)算法以后,就不要再去动它了,就可以避免在测试集上面过拟合。
然而,这边会有一个问题,如果随机分验证集,可能会分得不好,分到很奇怪的验证集,会导致结果很差,如果有这个担心的话,可以用 k 折交叉验证(k-fold cross validation),如下图所示。k 折交叉验证就是先把训练集切成 k 等份。在这个例子,训练集被切成 3 等份,切完以后,拿其中一份当作验证集,另外两份当训练集,这件事情要重复 3 次。即第1份和第 2 份当训练时,第 3 份当验证;第1份和第 3 份当训练时,第 2 份当验证;第1份当验证时,第 2 份第 3 份当训练。
上图中的 3 个模型,不知道哪一个是最好的。我们把这 3 个模型,在这 3 个设置(3 个训练跟验证的数据集)下通通跑一次,再把这 3 个模型,在这 3 种情况的结果都平均起来,再看看谁的结果最好。最终,3 折交叉验证得出来的结果是,模型 1 最好。再把模型 1 用在全部的训练集上,训练出来的模型再用在测试集上面。
五、不匹配(Mismatch)
如下图所示,横轴是从 2021 年的 1 月 1 号开始一直往下,红色的线是真实的数字,蓝色的线是预测的结果。可以看到,2 月 26 日是 2021 年观看人数最高的一天了,但是机器的预测差距却非常的大,差距有 2580。
我们跑了一层至四层的数据来看,发现所有模型的结果都不好,两层跟 3 层的错误率都是 2 千多,其实四层跟一层比较好,都是 1800左右,但是这四个模型不约而同的,觉得 2 月 26 日应该是个低点,但实际上 2 月 26 日是一个峰值,模型其实会觉得它是一个低点,也不能怪它,因为根据过去的数据,周五晚上大家都出去玩了。但是 2 月 26 日出现了反常的情况。这种情况应该算是另外一种错误的形式,这种错误的形式称为不匹配(mismatch)。
区别:不匹配跟过拟合其实不同,一般的过拟合可以用搜集更多的数据来克服,但是不匹配是指训练集跟测试集的分布不同,训练集再增加数据也没有帮助。
假设数据在分训练集跟测试集的时候,使用 2020 年的数据作为训练集,使用 2021 年的数据作为测试集,不匹配的问题可能就很严重。如果今天用 2020 年当训练集,2021 年当测试集,根本预测不准。因为 2020年的数据跟 2021 年的数据背后的分布不同。
下图是图像分类中的不匹配问题。增加数据也不能让模型做得更好,所以这种问题要怎么解决,匹不匹配要看对数据本身的理解了,我们可能要对训练集跟测试集的产生方式有一些理解,才能判断它是不是遇到了不匹配的情况。
标签:03,函数,训练,模型,损失,新手入门,测试,数据,夏令营 From: https://blog.csdn.net/2302_78188618/article/details/141687685