过度拟合与欠缺拟合
克服过度拟合的过程叫做正则化。让我们仔细看看最普通的正则化技术,以及它们的实际应用:本笔记 4.3 电影评论分类的改进。
减小网络尺寸
防止过度拟合最简单的办法是减小网络尺寸,即减少模型可学习参数的数目。决定模型参数多少的,是层的数目和每层单元的数目。模型的参数越多,存储容量越大,表示训练样本及其目标影射关系的词典性能越好。例如,具有 500,000 二值参数的模型,可以轻松学会 MNIST 训练集全部数字的分类。要永远记住:深度学习模型可以很好地拟合训练数据,但真正的挑战是泛化,不是拟合。
同时也要记住,你的模型应当有足够的存储资源,以使用足够的参数,防止欠缺拟合。网络的大小应该适中,不宜过大或过小、
不幸的是,无法简单确定正确的网络层数和每层单元数。你必须评估不同架构的数组,以找到适合你的数据的模型大小。评估要用你的验证数据,不能用测试数据。通常的流程是这样:起初用相对很少的网络层和参数,然后逐渐增大层的容量,或者增加新层,直到你看见验证损失的逐渐降低。
用电影评论分类的问题做下实验:
原始模型
from keras import models
from keras import layers
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
减少容量后的模型
model = models.Sequential()
model.add(layers.Dense(4, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(4, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
增加容量后的模型
model = models.Sequential()
model.add(layers.Dense(512, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
使用权重正则化技术
你可能熟悉奥卡姆剃刀定律(Occam's Razor):对某一问题有两种解释,用的假设最少、最简单的往往是正确的解释。相同的理念也可用于神经网络的学习模型:给出网络架构和一些训练数据、多组权重值(多个模型),可以解释这些数据。简单的模型比复杂的模型更少出现过度拟合。这里所说的简单模型是这样的:它的各参数值的分布熵较小,或者,如你前面见到的,它的参数较少。“熵”的物理意义是体系混乱程度的度量。减缓过度拟合的通常做法,是限制网络的复杂程度,强制它的权重取值范围很小,权重分布更为规范。这就是权重正则化,在网络的损失函数中,对较大权重增加成本。这种成本出自两种计算:
- L1 范式 —— 增加的成本是权重系数有比例的绝对值。
- L2 范式 —— 增加的成本是权重系数有比例的平方值。
Keras 权重正则化的实现,是把正则生成器的实例作为关键字参数,传递给各层。让我们给影评分类网络增加 L2 范式正则化。
给模型增加 L2 范式正则化
from keras import regularizers
model = models.Sequential()
model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
l2(0.001) 的含意是:网络层权重矩阵的每一系数增加 0.001与权重系数值的乘积,从而加大网络的总损失。注意,因为这一惩罚只在训练时采用,网络训练时的损失远大于测试时的损失。
你还可以这样使用 Keras 的正则化生成器。
from keras import regularizers
regularizers.l1(0.001) # L1 正则生成器
regularizers.l1_l2(l1=0.001, l2=0.001) # L1 和 L2 同步的正则生成器
使用舍弃技术
舍弃,是神经网络正则化技术最有效、最常用的之一。舍弃技术用于网络层,把训练过程中层输出特征的数字,随机舍弃(设置为零)。假如训练过程中,对于某个输入,一个层返回向量 [0.2, 0.5, 1.3, 0.8, 1.1] 。在应用舍弃技术后,向量中的几个值随机地变为零,例如 [0, 0.5, 1.3, 0, 1.1]。舍弃率是归零的个数在全部特征中的占比,通常 0.2 至 0.5。在测试阶段,并不舍弃特征值,相反地,层的输出值按舍弃率同等缩小,因此,测试时得到的特征值比训练时多。
设想有个 Numpy 矩阵包含某层的输出 layer_output,形状是(批量大小,特征值)。训练时,我们把矩阵的一些值随机归零:
layer_output *= np.random.randint(0, high=2, size=layer_output.shape)# 训练时,舍弃过 50% 的输出
测试时,我们按舍弃率缩小输出值。在此,缩小0.5(因为此前舍弃过这些输出):
layer_output *= 0.5 # 测试时
注意,这种处理的实现,可在训练时采取两种操作,测试时保留输出不变。这是实践中经常用到的:
layer_output *= np.random.randint(0, high=2, size=layer_output.shape) # 训练时
layer_output /= 0.5 # 注意,这里是放大不是缩小
在 Keras 中,你可以用 Dropout 层把舍弃技术引入神经网络。 Dropout 层用于舍弃前面层的输出:
model.add(layers.Dropout(0.5))
我们在 IMDB 网络中增加两个 Dropout 层,看看它们降低过度拟合的效果。
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1, activation='sigmoid'))
概括起来,防止神经网络过度拟合的常用方法有:
- 使用更多的训练数据
- 减小网络容量
- 使用权重正则化技术
- 使用舍弃技术
大