深度学习--解决模型过拟合的问题

文章目录
一、过拟合
1.什么是过拟合
2.模型为什么会产生过拟合呢?这是因为:
3.调参训练模型的目的:
4.对欠拟合的说明
二、如何降低过拟合
1.获取更多的训练数据。
2.减小网络大小
3.添加权重正则化
4.添加 dropout 正则化 (丢弃一些输出数据)
三、实战操作减低过拟合
1.减小网络大小
2.添加权重正则化
3.添加 dropout 正则化
一、过拟合
1.什么是过拟合
你刚开始训练出来的模型是不是在留出的验证数据上的性能总是在几轮后达到最高点,然后开始下降。
如下图所示,模型在训练集上的精度一直不断上升,但模型在验证集上的精度在第二轮就达到最高点然后就开始下降,这时模型在训练数据上开始出现过拟合的现象,模型开始学习仅和训练数据有关的模式,但这种模式对新数据来说是错误的或无关紧要的。

2.模型为什么会产生过拟合呢?这是因为:
(1)很多数据都有噪声。模型会尽量去覆盖噪音点,导致对数据过拟合。
(2)训练数据不足,导致模型只能过度提取与预测方向无关特征。
(3)构建的模型太复杂,对训练数据特征提取过度,并不适用与测试集。

3.调参训练模型的目的:
训练模型是为了得到好的神经网络,好的网络要求能够对数据有高的预测准确率,这就要求:
1.要调节模型以在训练数据上得到最佳性能,即优化,这很好实现。
2.但同时,要让训练好的模型在前所未见的数据上的性能表现良好,即好的泛化能力,基于训练数据调节模型就是为了提高模型的泛化能力。
深度学习模型通常都很擅长拟合训练数据,但真正的挑战在于泛化,而不是拟合。

4.对欠拟合的说明
对于训练好的模型,若在训练集表现差,在测试集表现同样会很差,这可能是欠拟合导致。欠拟合是指模型拟合程度不高,数据距离拟合曲线较远,或指模型没有很好地捕捉到数据特征,不能够很好地拟合数据。若存在训练数据上的损失越小,测试数据上的损失也越小。这时的模型是欠拟合的,一般是因为网络太小,网络还没有对训练数据中所有相关模式建模,适当加大网络隐藏单元或者层数可以基本解决。

二、如何降低过拟合
1.获取更多的训练数据。
为了防止模型从训练数据中学到错误或无关紧要的模式,最优解决方法是获取更多的训练数据。模型的训练数据越多,泛化能力自然也越好。

如果无法获取更多数据,次优解决方法是调节模型允许存储的信息量,或对模型允许存储的信息加以约束。如果一个网络只能记住几个模式,那么优化过程会迫使模型集中学习最重要的模式,这样更可能得到良好的泛化。
这种降低过拟合的方法叫作正则化。

2.减小网络大小
防止过拟合的最简单的方法就是减小模型大小,即减少模型中可学习参数的个数(这由层数和每层的单元个数决定)。但同时使用的模型应该具有足够多的参数,以防欠拟合,这是需要你去寻找的一个平衡。
为了寻找这个平衡,我们需要评估一系列不同的网络架构(在验证集上评估),以便为数据找到最佳的模型大小。要找到合适的模型大小,一般的工作流程是开始时选择相对较少的层和参数,然后逐渐增加层的大小或增加新层,直到这种增加对验证损失的影响变得很小。

3.添加权重正则化
简单模型比复杂模型更不容易过拟合。简单模型是指参数更少的模型,另一种常见的降低过拟合的方法就是强制让模型权重只能取较小的值,从而限制模型的复杂度,这使得权重值的分布更加规则。这种方法叫作权重正则化。
实现方法是向网络损失函数中添加与较大权重值相关的成本(cost)。 这个成本有两种形式。
L1 正则化(L1 regularization):添加的成本与权重系数的绝对值(权重的 L1 范数)成正比。
L2 正则化(L2 regularization):添加的成本与权重系数的平方(权重的 L2 范数)成正比。 神经网络的 L2 正则化也叫权重衰减。

4.添加 dropout 正则化 (丢弃一些输出数据)
dropout 是神经网络最有效也最常用的正则化方法之一,对某一层使用 dropout,就是在训练过程中随机将该层的一些输出特征舍弃(设置为 0)。假设在训练过程中,某一层对给定输入样本的返回值应该是向量 [0.2, 0.5, 1.3, 0.8, 1.1]。使用 dropout 后,这个向量会有几个随机的元素变成 0,比如 [0, 0.5,1.3, 0, 1.1]。dropout 比率(dropout rate)是被设为 0 的特征所占的比例,通常在 0.2~0.5 范围内。测试时没有单元被舍弃,而该层的输出值需要按 dropout 比率缩小,因为这时比训练时有更多的单元被激活,需要加以平衡。

三、实战操作减低过拟合
以下使用 IMDB 数据集作为实战数据集,研究减低模型过拟合方法,它包含来自互联网电影数据库(IMDB)的 50 000 条严重两极分化的评论,,IMDB 数据集内置于 Keras 库。它已经过预处理:评论(单词序列) 已经被转换为整数序列,其中每个整数代表字典中的某个单词。

from keras.datasets import imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
# 数据标签向量化
x_train = np.asarray(train_data).astype('float32')
x_test = np.asarray(test_data).astype('float32')
y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')


为了在训练过程中要监控模型在前所未见的数据上的精度,来调整模型,需要将原始训练数据留出 10000个样本作为验证集。在调整模型过程中,最终形成模型前不能学到任何测试集的数据。

x_val = x_train[:10000]
partial_x_train = x_train[10000:]
y_val = y_train[:10000]
partial_y_train = y_train[10000:]


使用 512 个样本组成的小批量,将模型训练 20 个轮次,同时监控在留出的 10 000 个样本上的损失和精度。

训练一个网络
from keras import models
from keras import layers
original_model = models.Sequential()
original_model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
original_model.add(layers.Dense(16, activation='relu'))
original_model.add(layers.Dense(1, activation='sigmoid'))
original_model.compile(optimizer='rmsprop',
                       loss='binary_crossentropy',
                       metrics=['acc'])
original_hist = original_model.fit(partial_x_train,
                                   partial_y_train,
                                   epochs=20,
                                   batch_size=512,
                                   validation_data=(x_val, y_val))

可以看到,随着每次迭代,训练集损失每轮都在减低。但验证精度并非如此:它仅在第4轮达到最低值。在第5轮之后,因为对训练数据过度优化,最终学到的表示仅针对于训练数据,无法泛化到训练集之外的数据。

1.减小网络大小
尝试用下面这个更小的网络来替换它。

smaller_model = models.Sequential()
smaller_model.add(layers.Dense(4, activation='relu', input_shape=(10000,)))
smaller_model.add(layers.Dense(4, activation='relu'))
smaller_model.add(layers.Dense(1, activation='sigmoid'))
smaller_model.compile(optimizer='rmsprop',
                      loss='binary_crossentropy',
                      metrics=['acc'])
smaller_model_hist = smaller_model.fit(partial_x_train,
                                   partial_y_train,
                                   epochs=20,
                                   batch_size=512,
                                   validation_data=(x_val, y_val))
                                   epochs = range(1, 21)
epochs = range(1, 21)
original_val_loss = original_hist.history['val_loss']
smaller_model_val_loss = smaller_model_hist.history['val_loss']
import matplotlib.pyplot as plt
plt.plot(epochs, original_val_loss, 'b+', label='Original model')
plt.plot(epochs, smaller_model_val_loss, 'bo', label='Smaller model')
plt.xlabel('Epochs')
plt.ylabel('Validation loss')
plt.legend()
plt.show()

更小的网络开始过拟合的时间要晚于参考网络而且开始过拟合之后,它的性能变差的速度也更慢。

2.添加权重正则化
在层参数中加入kernel_regularizer参数

from keras import regularizers
l2_model = models.Sequential()
l2_model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
                          activation='relu', input_shape=(10000,)))
l2_model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
                          activation='relu'))
l2_model.add(layers.Dense(1, activation='sigmoid'))

可见,即使两个模型的参数个数相同,具有 L2正则化的模型(圆点)比参考模型(十字)更不容易过拟合。

3.添加 dropout 正则化
在网络中添加layers.Dropout(0.5)层

dpt_model = models.Sequential()
dpt_model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
dpt_model.add(layers.Dropout(0.5))
dpt_model.add(layers.Dense(16, activation='relu'))
dpt_model.add(layers.Dropout(0.5))
dpt_model.add(layers.Dense(1, activation='sigmoid'))

dpt_model.compile(optimizer='rmsprop',
                  loss='binary_crossentropy',
                  metrics=['acc'])

再次看到,这种方法的性能相比原始网络有明显提高。
以上就是减低过拟合的常用方法。
————————————————
版权声明:本文为CSDN博主「马里奥w」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45949840/article/details/124251900

猜你喜欢

转载自blog.csdn.net/modi000/article/details/130380277