当前位置:   article > 正文

过拟合解决办法(代码)--python深度学习_python机器学习复杂模型正则化解决过拟合代码

python机器学习复杂模型正则化解决过拟合代码

过拟合解决办法(代码)--python深度学习


以imdb分类为例:

from keras.datasets import imdb
import numpy as np

(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)

def vectorize_sequences(sequences, dimension=10000):   # One-hot编码
    # 创建一个零矩阵
    results = np.zeros((len(sequences), dimension))
    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1.  # 将指定位置设为 1
    return results

# 训练数据向量化
x_train = vectorize_sequences(train_data)
# 测试数据向量化
x_test = vectorize_sequences(test_data)
# 将标签向量化
y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

1.减小网络大小

防止过拟合的最简单的方法就是减小模型大小,即减少模型中可学习参数的个数(这由层数和每层的单元个数决定)。在深度学习中,模型中可学习参数的个数通常被称为模型的容量(capacity)。

(1)原始模型:

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'])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

(2)容量更小的模型:

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'])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

比较了原始网络与更小网络的验证损失。圆点是更小网络的验证损失值,十字是原始网络的验证损失值

original_hist = original_model.fit(x_train, y_train,
                                   epochs=20,
                                   batch_size=512,
                                   validation_data=(x_test, y_test))
  • 1
  • 2
  • 3
  • 4
smaller_model_hist = smaller_model.fit(x_train, y_train,
                                       epochs=20,
                                       batch_size=512,
                                       validation_data=(x_test, y_test))
  • 1
  • 2
  • 3
  • 4
epochs = range(1, 21)
original_val_loss = original_hist.history['val_loss']
smaller_model_val_loss = smaller_model_hist.history['val_loss']
  • 1
  • 2
  • 3
import matplotlib.pyplot as plt

# b+ is for "blue cross"
plt.plot(epochs, original_val_loss, 'b+', label='Original model')
# "bo" is for "blue dot"
plt.plot(epochs, smaller_model_val_loss, 'bo', label='Smaller model')
plt.xlabel('Epochs')
plt.ylabel('Validation loss')
plt.legend()

plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z90KjVgj-1685807604487)(output_12_0.png)]

更小的网络开始过拟合的时间要晚于参考网络(前者 6 轮后开始过拟合,而后者 4 轮后开始),而且开始过拟合之后,它的性能变差的速度也更慢

2. 添加权重正则化

from keras import regularizers
L1正则化:
regularizers.l1(0.001)
L2正则化:
egularizers.l2(0.001)
L1和L2正则化:
regularizers.l1_l2(l1=0.001, l2=0.001)

简单模型比复杂模型更不容易过拟合。

这里的简单模型(simple model)是指参数值分布的熵更小的模型(或参数更少的模型)。因此,一种常见的降低过拟合的方法就是强制让模型权重只能取较小的值,从而限制模型的复杂度,这使得权重值的分布更加规则(regular)。这种方法叫作权重正则化(weight regularization),其实现方法是向网络损失函数中添加与较大权重值相关的成本(cost)。
这个成本有两种形式。

  • L1 正则化(L1 regularization):添加的成本与权重系数的绝对值[权重的 L1 范数(norm)]成正比。
  • L2 正则化(L2 regularization):添加的成本与权重系数的平方(权重的 L2 范数)成正比。

神经网络的 L2 正则化也叫权重衰减(weight decay),权重衰减与 L2 正则化在数学上是完全相同的。
在 Keras 中,添加权重正则化的方法是向层传递权重正则化项实例(weight regularizer instance)作为关键字参数。下列代码将向电影评论分类网络中添加 L2 权重正则化。

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'))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
l2_model.compile(optimizer='rmsprop',
                 loss='binary_crossentropy',
                 metrics=['acc'])
  • 1
  • 2
  • 3

l2(0.001) 的意思是该层权重矩阵的每个系数都会使网络总损失增加 0.001 * weight_coefficient_value 注意,由于这个惩罚项只在训练时添加,所以这个网络的训练损失会比测试损失大很多。

l2_model_hist = l2_model.fit(x_train, y_train,
                             epochs=20,
                             batch_size=512,
                             validation_data=(x_test, y_test))
  • 1
  • 2
  • 3
  • 4
l2_model_val_loss = l2_model_hist.history['val_loss']

plt.plot(epochs, original_val_loss, 'b+', label='Original model')
plt.plot(epochs, l2_model_val_loss, 'bo', label='L2-regularized model')
plt.xlabel('Epochs')
plt.ylabel('Validation loss')
plt.legend()

plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

即使两个模型的参数个数相同,具有 L2在这里插入图片描述

正则化的模型(圆点)比参考模型(十字)更不容易过拟合

3. 添加 dropout 正则化

model.add(layers.Dropout(0.5))

对某一层使用 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 比率缩小,因为这时比训练时有更多的单元被激活,需要加以平衡。

import numpy as np
np.random.randint(0, high=2, size=16)   # 范围为[low, high)
  • 1
  • 2

array([0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1])

测试时,我们将输出按 dropout 比率缩小。这里乘以 0.5(因为前面舍弃了一半的单元)。

# 测试
layer_output *= 0.5
  • 1
  • 2

为了实现这一过程,还可以让两个运算都在训练时进行,而测试时输出保持不变。

# 训练
layer_output *= np.randint(0, high=2, size=layer_output.shape)
# 是成比例放大而不是成比例缩小
layer_output /= 0.5
  • 1
  • 2
  • 3
  • 4

我们向 IMDB 网络中添加两个 Dropout层,来看一下它们降低过拟合的效果。

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'])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
dpt_model_hist = dpt_model.fit(x_train, y_train,
                               epochs=20,
                               batch_size=512,
                               validation_data=(x_test, y_test))
  • 1
  • 2
  • 3
  • 4

Let’s plot the results:

dpt_model_val_loss = dpt_model_hist.history['val_loss']

plt.plot(epochs, original_val_loss, 'b+', label='Original model')
plt.plot(epochs, dpt_model_val_loss, 'bo', label='Dropout-regularized model')
plt.xlabel('Epochs')
plt.ylabel('Validation loss')
plt.legend()

plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nHSbuD3c-1685807604490)(output_34_0.png)]

总结一下,防止神经网络过拟合的常用方法包括:

  • 获取更多的训练数据
  • 减小网络容量
  • 添加权重正则化
  • 添加 dropout
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/688190
推荐阅读
相关标签
  

闽ICP备14008679号