赞
踩
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')
防止过拟合的最简单的方法就是减小模型大小,即减少模型中可学习参数的个数(这由层数和每层的单元个数决定)。在深度学习中,模型中可学习参数的个数通常被称为模型的容量(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'])
(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'])
比较了原始网络与更小网络的验证损失。圆点是更小网络的验证损失值,十字是原始网络的验证损失值
original_hist = original_model.fit(x_train, y_train,
epochs=20,
batch_size=512,
validation_data=(x_test, y_test))
smaller_model_hist = smaller_model.fit(x_train, y_train,
epochs=20,
batch_size=512,
validation_data=(x_test, y_test))
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
# 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()
更小的网络开始过拟合的时间要晚于参考网络
(前者 6 轮后开始过拟合,而后者 4 轮后开始),而且开始过拟合之后,它的性能变差的速度也更慢
。
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'))
l2_model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['acc'])
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))
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()
即使两个模型的参数个数相同,具有 L2
正则化的模型(圆点)比参考模型(十字)更不容易过拟合
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)
array([0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1])
测试时,我们将输出按 dropout 比率缩小。这里乘以 0.5(因为前面舍弃了一半的单元)。
# 测试
layer_output *= 0.5
为了实现这一过程,还可以让两个运算都在训练时进行,而测试时输出保持不变。
# 训练
layer_output *= np.randint(0, high=2, size=layer_output.shape)
# 是成比例放大而不是成比例缩小
layer_output /= 0.5
我们向 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'])
dpt_model_hist = dpt_model.fit(x_train, y_train,
epochs=20,
batch_size=512,
validation_data=(x_test, y_test))
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()
总结一下,防止神经网络过拟合的常用方法包括:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。