《TensorFlow 2.0深度学习算法实战教材》重点内容摘录(八、过拟合)
机器学习的主要目的是从训练集上学习到数据的真实模型,从而能够在未见过的测试集上面也能够表现良好,我们把这种能力叫做泛化能力。
提到了模型的表达能力,也称之为模型的容量(Capacity)。当模型的表达
能力偏弱时,比如单层线性层,它只能学习到线性模型,无法良好地逼近非线性模型;但模型的表达能力过强时,他就有可能把训练集的噪声模态也学到,导致在测试机上面表现不佳的现象(泛化能力偏弱)。因此针对不同的任务,设计相应的模型算法才能取得较好的泛化性能。
模型的容量
通俗的讲,模型的容量或表达能力,是指模型拟合复杂函数的能力。一种体现模型容量的指标为模型的假设空间(Hypothesis Space)大小,即模型可以表示的函数集的大小。假设空间越大越完备,从假设空间中搜索出逼近真实模型的函数也就越有可能;反之,如果假设空间非常受限,就很难从中找到逼近真实模型的函数。
过拟合与欠拟合
当模型的容量过大时,网络模型除了学习到训练集数据的模态之外,还把额外的观测误差也学习进来,导致学习的模型在训练集上面表现较好,但是在未见的样本上表现不佳,也就是泛化能力偏弱,我们把这种现象叫做过拟合(Overfitting)。当模型的容量过小时,模型不能够很好的学习到训练集数据的模态,导致训练集上表现不佳,同时在未见的样本上表现也不佳,我们把这种现象叫做欠拟合(Underfitting)。
尽管统计学习理论很难给出神经网络所需要的最小容量,但是我们却可以根据奥卡姆剃刀原理(Occam’s razor)来指导神经网络的设计和训练。奥卡姆剃刀原理是由14 世纪逻辑学家、圣方济各会修士奥卡姆的威廉(William of Occam)提出的一个解决问题的法则,他在《箴言书注》2 卷15 题说“切勿浪费较多东西,去做‘用较少的东西,同样可以做好的事情’。”1。也就是说,如果两层的神经网络结构能够很好的表达真实模型,那么三层的神经网络也能够很好的表达,但是我们应该优先选择使用更简单的两层神经网络,因为它的参数量更少,更容易训练、更容易通过较少的训练样本获得不错的泛化误差。
欠拟合
当我们发现当前的模型在训练集上面误差一直维持较高的状态,很难优化减少,同时在测试集上也表现不佳时,我们可以考虑是否出现了欠拟合的现象,这个时候可以通过增加神经网络的层数、增大中间维度的大小等手段,比较好的解决欠拟合的问题。
过拟合
现代深度神经网络中过拟合现象非常容易出现,主要是因为神经网络的表达能力非常强,很容易就出现了神经网络的容量偏大的现象。
数据集划分
数据集需要划分为训练集(Train set)和测试集(Test set),但是为了挑选模型超参数和检测过拟合现象,一般需要将原来的训练集再次切分为新的训练集和验证集(Validation set),即数据集需要切分为训练集、验证集和测试集3 个子集。
验证集与超参数
将数据集划分为训练集与测试集是不够的,由于测试集的性能不能作为模型训练的反馈,而我们需要在模型训练时能够挑选出较合适的模型超参数,判断模型是否过拟合等,因此需要将训练集再次切分为训练集????train和验证集????????????????。划分过的训练集与原来的训练集的功能一致,用于训练模型的参数,而验证集则用于选择模型的超参数(称为模型选择,Model selection),它的功能包括:
❑ 根据验证集的性能表现来调整学习率,权值衰减系数,训练次数等
❑ 根据验证集的性能表现来重新调整网络拓扑结构
❑ 根据验证集的性能表现判断是否过拟合和欠拟合
验证集与测试集的区别在于,算法设计人员可以根据验证集的表现来调整模型的各种超参数的设置,提升模型的泛化能力,但是测试集的表现却不能用来反馈模型的调整,否则测试集将和验证集的功能重合,因此在测试集上面的性能表现将无法代表模型的泛化能力。
提前停止
把对训练集中的一个Batch 运算更新一次叫做一个Step,对训练集的所有样本循环迭代一次叫做一个Epoch。
由于网络的实际容量可以随着训练的进行发生改变,因此在相同的网络设定下,随着训练的进行,可能观测到不同的过拟合/欠拟合状况。
神经网络的有效容量和网络参数的状态息息相关,神经网络的有效容量可以很大,也可以通过稀疏化参数、添加正则化等手段降低
模型设计
通过验证集可以判断网络模型是否过拟合或者欠拟合,从而为调整网络模型的容量提供判断依据。对于神经网络来说,网络的层数和参数量是网络容量很重要的参考指标,通过减少网络的层数,减少每层中网络参数量的规模可以有效降低网络的容量。反之,如果发现模型欠拟合,需要增大网络的容量,可以通过增加层数,增大每层的参数量等方式实现。
正则化
通过限制网络参数的稀疏性,可以来约束网络的实际容量。
这种约束一般通过在损失函数上添加额外的参数稀疏性惩罚项实现。,在未加约束之前的优化目标是
新的优化目标除了要最小化原来的损失函数ℒ( , ????)之外,还需要约束网络参数的稀疏性,优化算法会在降低ℒ( , ????)的同时,尽可能地迫使网络参数????????变得稀疏,他们之间的权重关系通过超参数????来平衡,较大的????意味着网络的稀疏性更重要;较小的????则意味着网络的训练误差更重要。通过选择合适的????超参数可以获得较好的训练性能,同时保证网络的稀疏性,从而获得不错的泛化能力。
常用的正则化方式有L0,L1,L2 正则化。
L0 正则化
L0 正则化是指采用L0 范数作为稀疏性惩罚项????(????)的正则化方式,即
L1 正则化
采用 L1 范数作为稀疏性惩罚项????(????)的正则化方式叫做L1 正则化,即
L1 正则化可以实现如下:
# 创建网络参数w1,w2
w1 = tf.random.normal([4,3])
w2 = tf.random.normal([4,2])
# 计算L1 正则化项
loss_reg = tf.reduce_sum(tf.math.abs(w1))+ tf.reduce_sum(tf.math.abs(w2))
L2 正则化
采用 L2 范数作为稀疏性惩罚项????(????)的正则化方式叫做L2 正则化,即
L2 正则化项实现如下:
# 计算L2 正则化项
loss_reg = tf.reduce_sum(tf.square(w1))+ tf.reduce_sum(tf.square(w2))
Dropout
Dropout 通过随机断开神经网络的连接,减少每次训练时实际参与计算的模型的参数量;但是在测试时,Dropout 会恢复所有的连接,保证模型测试时获得最好的性能。
在 TensorFlow 中,可以通过tf.nn.dropout(x, rate)函数实现某条连接的Dropout 功能,其中rate 参数设置断开的概率值????:
# 添加dropout 操作
x = tf.nn.dropout(x, rate=0.5)
也可以将Dropout 作为一个网络层使用,在网络中间插入一个Dropout 层:
# 添加Dropout 层
model.add(layers.Dropout(rate=0.5))
数据增强
除了上述介绍的方式可以有效检测和抑制过拟合现象之外,增加数据集大小是解决过拟合最重要的途径。数据增强(DataAugmentation)是指在维持样本标签不变的条件下,根据先验知识改变样本的特征,使得新产生的样本也符合或者近似符合数据的真实分布。
以图片数据为例,可以通过如下方式进行数据增强。
旋转
通过 tf.image.rot90(x, k=1)可以实现图片按逆时针方式旋转k 个90 度:
# 图片逆时针旋转180 度
x = tf.image.rot90(x,2)
翻转
通过tf.image.random_flip_left_right 和tf.image.random_flip_up_down 实现图片在水平方向和竖直方向的随机翻转操作:
# 随机水平翻转
x = tf.image.random_flip_left_right(x)
# 随机竖直翻转
x = tf.image.random_flip_up_down(x)
裁剪
在实际裁剪时,一般先将图片缩放到略大于网络输入尺寸的大小,再进
行裁剪到合适大小
# 图片先缩放到稍大尺寸
x = tf.image.resize(x, [244, 244])
# 再随机裁剪到合适尺寸
x = tf.image.random_crop(x, [224,224,3])
生成数据
通过生成模型在原有数据上学习到数据的分布,从而生成新的样本,这种方式也可以在一定程度上提升网络性能。如通过条件生成对抗网络(Conditional GAN, CGAN)可以生成带标签的样本数据.
其他方式
- 添加高斯噪声
- 变换视角图
- 随机擦除