编者按:在日常工作和学习中,数据科学家最常遇到的问题之一就是过拟合。您是否遇到过在训练集上表现良好但在测试集上表现不佳的模型?你是否有过这样的经历,当你参加模特比赛时,你的模特本应在跑分上名列前茅,但在比赛公布的分数榜单中,却差了几百?后。如果你有过类似的经历,这篇文章就是为了——它会告诉你如何避免过拟合来提高模型性能。在本文中,我们将详细描述过拟合的概念,并使用几种正则化方法来解决过拟合问题,并辅以Python案例讲解,进一步巩固这些知识。请注意,本文假定读者在神经网络和Keras实现方面具有一定的经验。内容1.什么是正则化2.正则化和过拟合3.深度学习中的正则化L2和L1正则化Dropout数据增强EarlyStopping什么是正则化这张图会不时被拉出来“鞭尸”。如上图所示,一开始模型并不能很好地拟合所有的数据点,也就是不能反映数据的分布,此时是欠拟合的。随着训练次数的增加,逐渐找出数据的规律,在拟合尽可能多的数据点的同时,能够反映数据的趋势。这时,它是一个性能更好的模型。在此基础上,如果我们继续训练,模型会进一步挖掘训练数据中的细节和噪声,为了“肆无忌惮”地拟合所有数据点,那么就会过拟合。也就是说,从左到右,模型的复杂度逐渐增加,在训练集上的预测误差逐渐减小,但其在测试集上的错误率呈向下凸曲线。资料来源:Slideplayer如果您以前构建过神经网络,您可能已经吸取了这一教训:随着网络的复杂性,过度拟合很容易发生。为了使模型在拟合数据的同时更具泛化性,我们可以使用正则化对学习算法做一些小的改动,从而提高模型的整体性能。正则化和过拟合过拟合与神经网络的设计密切相关,所以让我们先来看一个过拟合的神经网络:初步了解神经网络正则化的概念,应该知道上图中带箭头的线其实是有权重的,神经元是存储输入和输出的地方。为了公平起见,也就是为了防止网络在优化的方向上过于自由,这里我们还需要加入一个priori-regularizationpenaltyterm,用来惩罚神经元的权重矩阵。如果我们将正则化系数设置得如此之大以至于一些权重矩阵几乎为零——那么我们最终会得到一个更简单的线性网络,它很可能是欠拟合的。因此,系数并不是越大越好。我们需要优化这个正则化系数的值,才能得到一个拟合良好的模型,如下图所示。深度学习中的正则化L2和L1正则化L1和L2是最常见的正则化方法,它们的做法是在成本函数之后加一个正则化项。成本函数=损失(如二元交叉熵)+正则化项。由于增加了这个正则化项,权重减少了。换句话说,降低了神经网络的复杂性。结合“网络有多复杂,就有多容易过拟合”,从理论上讲,这样做相当于直接防止过拟合(奥卡姆剃刀法则)。当然这个正则化项在L1和L2中是不同的。对于L2,其代价函数可以表示为:这里λ是正则化系数,是一个超参数,可以通过优化得到更好的结果。通过推导上面的公式,权重w之前的系数为1?ηλ/m,因为η,λ,m都是正数,1?ηλ/m小于1,w的趋势是减小的,所以L2正则化又称为weightdecay。对于L1,它的costfunction可以表示为:L2,这里我们惩罚权重w的绝对值,经过上式推导,得到的方程中包含一项-sgn(w),表示当w为正时,w减小并趋于0;当w为负的,w增加,趋于0。所以L1的思路是让权重向0倾斜,从而降低网络的复杂性。因此,当我们要对模型进行压缩时,L1会起到很好的作用,但如果单纯为了防止过拟合,一般会使用L2。在Keras中,我们可以直接调用正则化器在任意一层进行正则化。例子:全连接层使用L2正则化的代码:fromkerasimportregularizersmodel.add(Dense(64,input_dim=64,kernel_regularizer=regularizers.l2(0.01)注:这里的0.01是正则化系数λ的值,我们可以通过网络可以通过网格搜索进一步优化,DropoutDropout可以说是最有趣的正则化方法了,效果也很不错,所以是深度学习领域常用的方法之一。再解释一下,我们首先假设我们的神经网络是这样的:那么Dropout到底丢了什么?我们看下图:在每次迭代中,它会随机选择一些神经元,“全部砍掉”——神经元连同被“删除”的相应的输入和输出。相对于成本函数的L1和L2修改,Dropout更像是一种训练网络的技术。随着训练的进行,神经网络忽略了一些(过参数,通常half)隐藏层/输入层的神经元,这就导致了不同的输出,有的是正确的,有的是错误的。这种方法有点类似于集成学习,可以捕获更多的随机性。集成学习分类器通常优于单个分类器。同样,由于网络要对数据分布进行拟合,所以模型在Dropout之后的大部分输出必须是正确的,噪声数据的影响只是一小部分,不会对最终结果产生太大的影响。由于这些因素,当我们的神经网络更大、更随机时,我们一般使用dropout。在Keras中,我们可以使用keras核心层来实现dropout。这是它的Python代码:fromkeras.layers.coreimportDropoutmodel=Sequential([Dense(output_dim=hidden1_num_units,input_dim=input_num_units,activation='relu'),Dropout(0.25),Dense(output_dim=output_num_units,input_dim=hidden5_num_units,activation='softmax'),])注意:这里我们设置0.25作为Dropout的超参数(每次“删除”1/4),我们可以通过网格搜索进一步优化。DataAugmentation由于过拟合是模型对数据集中的噪声和细节的过度捕获,因此防止过拟合最简单的方法是增加训练数据量。但是在机器学习任务中,增加数据量并不是那么容易实现的,因为收集和标注数据的成本太高了。假设我们正在处理一些手写的数字图像,为了扩大训练集,我们可以采取的方法有——旋转、翻转、缩小/放大、位移、截取、添加随机噪声、添加失真等。下面是一些处理图:这些方法是数据扩充。从某种意义上说,机器学习模型的性能取决于数据量,因此数据增强可以大大提高模型预测的准确性。这也是有时改进模型的必要技术。在Keras中,我们可以使用ImageDataGenerator执行所有这些转换,它提供了大量可用于预处理训练数据的参数。下面是实现它的示例代码:fromkeras.preprocessing.imageimportImageDataGeneratordatagen=ImageDataGenerator(horizo??ntalflip=True)datagen.fit(train)earlystopping这是一种交叉验证策略。在训练之前,我们抽取一部分训练集作为验证集。随着训练的进行,当模型在验证集上的表现越来越差时,我们立即手动停止训练。这种早停法就是早停法。在上图中,我们应该在虚线处停止训练,因为在那之后,模型开始过度拟合。在Keras中,我们可以调用回调函数提前停止训练。下面是它的示例代码:fromkeras.callbacksimportEarlyStoppingEarlyStopping(monitor='val_err',patience=5)这里的monitor是指需要监控的epoch数;val_err表示验证错误(validationerror)。耐心意味着连续5个epoch之后,模型的预测结果没有进一步提升。结合上图可以理解,虚线之后,模型每训练一个epoch都会有更高的验证错误(验证准确率更低),所以连续训练5个epoch后,就会提前停止训练。注意:在一种情况下,当模型训练5个epoch时,它的验证精度可能会增加,所以我们在选择超参数时一定要小心。
