目录
(2)N折交叉验证(N-foldcross validation)(老师讲的),又称k折交叉验证(k-foldcross validation)
一、学习资料
Datawhale提供的pdf:Datawhale (linklearner.com)
李宏毅老师对应视频课程:机器学习任务攻略_哔哩哔哩_bilibili
二、学习笔记
(〇)前情提要
上节课中我们学到:
1、视频点击量并不能简单地用直线型函数y=wx+b来概括,要结合实际,不仅要考虑周期性,还要使用更复杂的模型,因此我们修改模型为分段线性模型。
分段线型模型既可以处理直线(线性关系)也可以处理曲线(非线性关系)。曲线可以在其上取点,连城多条线段,以近似直线的方式求解。
那么像这样的“折线型”图像要怎么表示呢?(机器学习第一步:写出含有未知数的表达式)我们可以通过使用激活函数:Sigmoid函数(S函数)和修正线性单元(ReLU),来逼近线性或非线性函数。
注:a个Hard Sigmoid=a个Sigmoid函数=2a个ReLU(因为2个ReLU合起来才是一个Hard Sigmoid)
然后是机器学习第二步计算损失,操作和以前一样,此处略写:求出预测值与实际值(label标签),定义二者差距为e。以此类推,得到一串e1~en的数值,再将之求和取平均,得到L。
第三步最佳化,梯度下降,Adam优化器等,在进阶班学到的那些调整学习率。
2、为方便理解课程,稍微梳理下各个新学名词的关系。我个人总结为:激活函数决定神经元的输出;多个神经元构成隐藏层;多个隐藏层构成神经网络;神经网络是深度学习的一种技术。
复习完毕,接下来开始本次task3的学习内容~
(一)一图流
老师给出来的一图流,即机器学习出现的所有问题都能通过本图找到答案。
先把图放在这里,后面会具体阐述其中的释义。
(截图自李宏毅老师视频课程,如无特殊标注,下同)
(二)训练集上损失大的成因
如果你在kaggle上对测试集的分数不满意,首先检验在训练集上的loss:
为什么要看训练集而不是验证集或测试集?因为首先要检验的是你的模型在训练集上有没有训练起来。
如果在训练集上loss就很大,说明在训练集上就没有学好。
1、模型偏差(model bias)
(我觉得这个似乎也叫欠拟合)
(1)导致模型偏差的原因
模型与实际不匹配,例如模型过于简单。
能让loss变低的function不在模型可以描述的范围内,即使在模型内找到了能让loss最低的点,也不是实际上的最优解。
老师评价:想大海捞针,但是针根本不在这片海。
(2)解决方法
重新设计模型,如通过增加特征,来提高模型灵活性。如之前讲的,从y=wx+b进化成:
(截图来自我第二次课的笔记)
或更进一步,进化成:
2、优化做得不好(optimization issue)
(1)导致优化差的原因
有可能是卡在临界点,即局部极小值或鞍点上了,找到的只是局部最优解。
老师评价:想大海捞针,但是找不到针。
(2)解决方法
调整学习率。老师说下节课再讲。
但我在进阶班第二课学到了自适应学习率等方法,此处不再详细叙述,贴一下我自己的笔记链接,方便对照查看:Datawhale X 李宏毅苹果书 AI夏令营 深度学习进阶笔记02-CSDN博客
3、如何确定是哪种成因
现在我们已经学到了导致训练集损失大的原因,那么如何确定到底是哪种原因导致问题的出现呢?
老师:到底是海里无针,还是捞不到针?
(1)比较不同模型
(我理解的意思可能是比较同一模型不同layer数量的情况?)
我们可以通过比较不同的模型,判断我们的模型到底够不够大。
如图所示,某个模型的测试集上有两个网络。一个网络有20层,一个网络有56层。
从左图的测试集数据我们可以看到,20层的损失较低,56层的损失反而更高。很多人在此时就会称之为“过拟合”,但是实际上,并不是所有的结果不好都是过拟合,比如本题。
我们可以回到训练集上检查,即右图。可以看到,训练集依旧是20层的损失低,56层的损失高。
那么是否是因为56层还不够大?需要156层才够大?
通过前面的学习我们可以知道,56层的灵活性一定是比20层更好的,前者一定可以做到后者能做的事情(比如只取前20层的参数,后36层不动,只复制前面层的)如果优化正常的话,56层一定会比20层做的更好。
所以说明,问题既不是模型过于简单、灵活性不够,也不是过拟合,而是56层的优化没有20层的优化做的好。
引申问题:如何知道优化有没有做好呢?
假如我们遇到的是一个从来没有做过的问题,可以尝试先跑一些比较小的、比较浅的网络,或甚至用一些非深度学习的方法,比如线性模型、支持向量机(Support Vector Machine,SVM)。
这些是比较容易做优化的,因为模型完全可以在能力范围之内找出一组最好的参数,即很少出现优化失败的问题。因此,我们可以先train一些比较浅层或比较简单的模型,先知道这些模型到底可以得到什么样的损失。
接下来再train层数深的模型,如果深的模型跟浅的模型比起来,深的模型明明本身灵活性比较大,但损失却不能比浅的模型更低,就说明优化有问题,梯度下降不给力,因此要使用其它的方法来更好地进行优化。
举例:还是用之前学的点击率的问题。
(2017-2020的数据是训练集)从训练集中我们可以看出,1-4层的loss在逐渐降低,但是加到5层后,结果变成340,比4层反而升高了。
首先我们排除模型偏差的问题,因为4层都可以做到100了,5 层本来应该可以更低。所以确定了,这个是优化做得不好。
Datawhale教程补充:如果训练损失大,可以先判断是模型偏差还是优化。如果是模型偏差,就把模型变大。假设经过努力可以让训练数据的损失变小,接下来可以来看测试数据损失;如果测试数据损失也小,比这个较强的基线模型还要小,就结束了。
(三)测试集上损失大的成因
刚才我们讨论的情况是,测试集上损失大,训练集上损失也大,那么就是训练集出了问题。
现在我们要讨论,在训练集上损失小,测试集上损失大的情况出现的原因。
举一个极端的例子:
假设有一个函数,它的输出分为两种情况:如果x能在训练集中找到,则输出它对应的y;如果找不到,则随意输出一个结果。
在训练集上的loss非常小,loss=0,因为它就是直接输出训练集中既有的数据。但是如果把它放进测试集(未知的,需要预测的数据),它的loss就会非常高,因为它会随机输出一个数。这个函数相当于啥也没学、啥也没干。
1、过拟合(overfitting)
(1)是什么
再举个例子,直接在图上写了注释:
所以,灵活的模型更容易过拟合,具体的原理后面的课再讲。
(2)怎么解决
A. 增加训练资料
直接扩充训练数据一般是最有效的方式,但是老师不倡导大家在学习中这样做。
更建议大家做数据增强(data augmentation),即对数据本身做处理,并不算是增加数据。
所以,数据增强要根据对数据的特性和要处理的问题的理解,来选择合适的数据增强方式。
B. 限制模型灵活性
a. 更少的参数或共用参数
如果是深度学习的话,就给更少的神经元。
此处补充一下全连接网络和卷积神经网络的概念:
全连接网络(fully-connected network)是一个更有灵活性的架构,而卷积神经网络(Convolutional Neural Network,CNN)是一个比较有限制的架构,它会针对图像的特性来限制模型的灵活性。
所以全连接神经网络可以找出来的函数所形成的集合更大,CNN所找出来的函数形成的集合更小(如图所示,包含关系,全连接神经网络包含CNN)。但就是因为CNN给了比较大的限制,所以CNN在图像上反而做得比全连接网络更好。
b. 更少的特征(feature)
比如本来给了3天的数据做训练,改成只给2天的数据,结果会好一些。
c. 其他方法
早停(early stopping)、正则化(regularization)、丢弃法(dropoutmethod),以后再讲。
但是也不要给太多限制了,限制太大会让模型失去灵活性,可能就会偏向另一个方向,也就是我们前面讲到的模型偏差(欠拟合)。
2、不匹配(mismatch)
插播一则“新闻”:
上节课老师说到的预测点击量的事情:
(截图自我自己上节课的笔记)
这期的结果出炉啦~
机器预测点击量超低,但实际点击量超高,成为今年以来点击量最高的一天。
这波啊这波是human caused bias(doge)
这种错误的情况就属于不匹配(mismatch),指训练集与测试集分布不同。
这种情况下,通过使用解决过拟合的方法(如增加数据量)是无法解决问题的。
区分此时是否为过拟合还是不匹配,要看自己对数据本身的理解。
(四)模型选择
1、引入
随着模型越来越复杂,训练集上的loss会越来越低。
但在测试集中,刚开始损失也在下降,但是当复杂的程度超过某一个界限以后,损失就会突然暴增了,即出现了过拟合的情况。
我们更期望的是选一个中庸的模型,不是太复杂,也不是太简单,刚刚好可以做到在训练集上损失最低,测试损失最低。
其中一个方法就是把所有你做出来的模型,全部放到kaggle上测评分,找到损失最低的那个。
但是也有例外,此时再拿出之前我们举过的极端例子:如果x能在训练集中找到,则输出它对应的y;如果找不到,则随意输出一个结果。
假设我们手握1兆个这种模型,然后把它们全部放进kaggle上测评分。既然是在测试集上随机生成,那么总会有一个模型走了狗屎运,蒙对了更多的y,得到了比其他模型更低的损失。
但我们就能说这个模型是最好的模型吗?不是,因为这1兆个模型一模一样,每个的kaggle分数纯粹靠运气。
我自己理解:在比赛中,测试集都会分为公开测试集和私人测试集。赛事主办方会给出公开测试集,我们提交的分数也都是在公开测试集上的打分。但主办方还会手握另一份不公开的测试集,就是为了应对万一有人使劲贴合公开测试集而忽略其他情况的。在私人测试集上如果该模型表现和在公开测试集上一样优秀,才能说这个模型是真正好的。
老师:如果根据公开数据集来选择模型,可能会出现这种情况:在公开的排行榜上面排前十,但是截止日期一结束,可能掉到 300 名之外。因为计算分数的时候,会同时考虑公开和私人的分数。这并不是讲故事,每年都会发生这种事。如果只有公开的测试集,没有私人测试集,写一个程序不断随机产生输出就好的模型,不断把随机的输出上传到 Kaggle,总能随机出一个好的结果。但是这件事有意义吗,这是模型训练的目的吗,并不是。
排除了错误方法,那么正确的究竟该怎么做呢?
2、交叉验证(cross validation)
(1)概述(是什么+优点)
不管公开测试集还是私人测试集,既然本质都是在两组部分实际数据上验证两次模型预测的准确程度,那么我们自己做个公共和私人测试集。
我们可以把训练的数据分成两部分(不一定是均分哈),一部分为训练集(training set),一部分为验证集(validation set)。比如把90%的数据划分进训练集,剩下10%的数据划分进验证集。
我们用验证集来检验在训练集上训练出来的模型的成果,即根据在验证集上得到的分数去挑选模型,再把这个结果上传到Kaggle得到的在公开测试集上的分数。
这样一来,我们自己划分出来的验证集,替代了原本公开测试集的功能;原本的公开测试集,就相当于替代了私人测试集的功能。这样就可以挑出在两组数据集上都表现得好的模型了。
但假设这个循环做太多次,就又有可能在私人测试集上过拟合,得到差的结果。不过上传的次数有限制,所以无法走太多次循环,也不会太差。根据过去的经验,就在公开排行榜上排前几名的,往往私人测试集很容易就不好。
老师建议:其实最好的做法,就是用验证损失最小的直接挑就好了,不要管公开测试集的结果。
虽然在现实情况中不太可能这么做,因为公开数据集的结果对模型的选择,可能还是会有些影响的。理想上就用验证集挑就好,有过比较好的基线(baseline)算法以后不要再去动它,就可以避免在测试集上面过拟合。
(2)N折交叉验证(N-foldcross validation)(老师讲的),又称k折交叉验证(k-foldcross validation)
步骤:
①把训练集平均分为N个子集,取一个子集作为验证集(或者说作为测试集也行),剩下的子集合并为训练集。
②训练模型,并在验证集上进行验证,记录验证指标(如准确率、召回率等)。
③然后开始轮换,新拿出原本作为训练集的子集之一作为新验证集,原验证集放回去当训练集。
④如此重复N次,直到所有的子集都成为过验证集。这样每个子集都会被用作验证集的一部分恰好一次,确保所有数据都被用于验证模型,同时模型也在不同的训练集组合上进行了训练。
⑤将N次轮换迭代得到的验证指标平均化,得到总体表现最好的模型。
举个例子:
把训练集被平均分为3份。取1份作为验证集,余下2份作为训练集。然后开始轮换,这件事情要重复3次,即第1、2份训练,在第3份当验证;第1、3 份训练,在第2份验证;第2、3份训练,第1分当验证集。
把三个模型在验证集上的评估结果取平均,得到最好的是模型1。
再把模型1用在全部的训练集上,训练出来的模型再用在公开测试集上。