tf.keras入门(4) Explore over-fitting and under-fitting

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Feynman1999/article/details/84567342

探索过拟合与欠拟合

我们将探索两种常见的正则化技术(权重正则化丢弃),并使用它们改进我们的 IMDB 影评分类笔记本。

我们不会像在上一次那样使用嵌入,而是对句子进行独热编码。该模型将很快过拟合训练集。它将用来演示何时发生过拟合,以及如何防止过拟合。

务必谨记:深度学习模型往往善于与训练数据拟合,但真正的挑战是泛化,而非拟合。

数据预处理与网络结构

和之前采用嵌入方法不同,这里我们直接使用one hot 编码,该模型将很快过拟合训练集。

从上往下一共有5个模型,我们来对比它们在validation上的结果:

  • baseline_model

img

  • smaller_model

img

  • bigger_model

img

  • baseline_model_l2

img

  • baseline_model_dropout

img

接口解释

  • 将数据转为二维矩阵,注意enumerate操作,可同时获得索引和值
def multi_hot_sequences(sequences, dimension):
    # create an all_zero matrix of shape(len(sequences), dimension)
    results = np.zeros(  (len(sequences), dimension)  ) # 参数应该提供一个元组
    for i, word_indices in enumerate(sequences): # 可同时获得索引和值
        results[i,word_indices] = 1.0
    return results

要缓解过拟合,一种常见方法是限制网络的复杂性,具体方法是强制要求其权重仅采用较小的值,使权重值的分布更“规则”。这称为“权重正则化”,通过向网络的损失函数添加与权重较大相关的代价来实现。这个代价分为两种类型:

扫描二维码关注公众号,回复: 4457343 查看本文章
  • L1 正则化,其中所添加的代价与权重系数的绝对值(即所谓的权重“L1 范数”)成正比。
  • L2 正则化,其中所添加的代价与权重系数值的平方(即所谓的权重“L2 范数”)成正比。L2 正则化在神经网络领域也称为权重衰减。不要因为名称不同而感到困惑:从数学角度来讲,权重衰减与 L2 正则化完全相同。
  • 添加L2正则化 表示层的权重矩阵中的每个系数都会将 0.001 * weight_coefficient_value**2 添加到网络的总损失中。请注意,由于此惩罚仅在训练时添加,此网络在训练时的损失将远高于测试时。
  keras.layers.Dense(16,activation=tf.nn.relu,kernel_regularizer=keras.regularizers.l2(0.001),input_shape=(NUM_WORDS, )),

  • 添加dropout层(目前最有效且最常用的神经网络正则化技术之一)。假设某个指定的层通常会在训练期间针对给定的输入样本返回一个向量 [0.2, 0.5, 1.3, 0.8, 1.1];在应用丢弃后,此向量将随机分布几个 0 条目,例如 [0, 0.5, 1.3, 0, 1.1]。“丢弃率”指变为 0 的特征所占的比例,通常设置在 0.2 和 0.5 之间在测试时,网络不会丢弃任何单元,而是将层的输出值按等同于丢弃率的比例进行缩减,以便平衡以下事实:测试时的活跃单元数大于训练时的活跃单元数。
keras.layers.Dense(16, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
   				 keras.layers.Dropout(0.5),
    ...
    ...

  • 作图函数
def plot_history(histories, key='binary_crossentropy'):
    plt.figure(figsize=(16,10))
    for name,history in histories:
        val = plt.plot(history.epoch, history.history['val_'+key],'--
                       ',label=name.title()+' Val')
        plt.plot(history.epoch, history.history[key], color=val[0].get_color(),
                 label=name.title()+' Train')

    plt.xlabel('Epochs')
    plt.ylabel(key.replace('_',' ').title())
    plt.legend()
    plt.xlim([0,max(history.epoch)])

总结

  • 三种不同容量的网络的训练效果:

实线表示训练损失,虚线表示验证损失(谨记:验证损失越低,表示模型越好)。在此示例中,较小的网络开始过拟合的时间比基准模型晚(前者在 6 个周期之后,后者在 4 个周期之后),并且开始过拟合后,它的效果下降速度也慢得多。

img

  • 加入L2正则化的模型:

可以看到,L2 正则化模型的过拟合抵抗能力比基准模型强得多,虽然这两个模型的参数数量相同。:

img

  • 添加dropout层可明显改善基准模型:

img

下面总结一下防止神经网络出现过拟合的最常见方法:

  • 获取更多训练数据
  • 降低网络容量
  • 添加权重正则化
  • 添加dropout层

还有两个重要的方法在本指南中没有介绍:数据增强批次标准化

Code

import tensorflow as tf 
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt


'''
数据预处理
'''
NUM_WORDS = 10000
(train_data, train_labels), (test_data, test_labels) = keras.datasets.imdb.load_data(num_words=NUM_WORDS)
print(train_data.shape)

def multi_hot_sequences(sequences, dimension):
    # create an all_zero matrix of shape(len(sequences), dimension)
    results = np.zeros(  (len(sequences), dimension)  ) #提供一个元组
    for i, word_indices in enumerate(sequences): # 可同时获得索引和值
        results[i,word_indices] = 1.0
    return results

train_data = multi_hot_sequences(train_data, NUM_WORDS)
test_data  = multi_hot_sequences(test_data, NUM_WORDS)
# plt.plot(train_data[0])
# plt.show()


'''
建立模型
'''
baseline_model = keras.Sequential([
    # 'input_shape' is only required here so that '.summary' works
    keras.layers.Dense(16, activation=tf.nn.relu, input_shape=(NUM_WORDS, )),
    keras.layers.Dense(16, activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])
baseline_model.compile( optimizer = 'adam',
                        loss='binary_crossentropy',
                        metrics=['accuracy','binary_crossentropy'])
baseline_model.summary()



smaller_model = keras.Sequential([
    keras.layers.Dense(4,activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(4,activation=tf.nn.relu),
    keras.layers.Dense(1,activation=tf.nn.sigmoid)
])
smaller_model.compile(optimizer='adam',
                      loss='binary_crossentropy',
                      metrics=['accuracy','binary_crossentropy'])
smaller_model.summary()



bigger_model =  keras.Sequential([
    keras.layers.Dense(512, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(512, activation=tf.nn.relu),
    keras.layers.Dense(1,   activation=tf.nn.sigmoid)
])
bigger_model.compile(optimizer='adam',
                     loss='binary_crossentropy',
                     metrics=['accuracy','binary_crossentropy'])
bigger_model.summary()



baseline_model_l2 = keras.Sequential([
    keras.layers.Dense(16, activation=tf.nn.relu, kernel_regularizer=keras.regularizers.l2(0.001),
                        input_shape=(NUM_WORDS, )),
    keras.layers.Dense(16, activation=tf.nn.relu, kernel_regularizer=keras.regularizers.l2(0.001)),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])
baseline_model_l2.compile(optimizer='adam',
                            loss='binary_crossentropy',
                            metrics=['accuracy','binary_crossentropy'])
baseline_model_l2.summary()



baseline_model_dropout = keras.Sequential([
    keras.layers.Dense(16, activation=tf.nn.relu, input_shape=(NUM_WORDS, )),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(16, activation=tf.nn.relu),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])
baseline_model_dropout.compile(optimizer='adam',
                                loss='binary_crossentropy',
                                metrics=['accuracy','binary_crossentropy'])
baseline_model_dropout.summary()                                



'''
训练模型
'''
def train_model(model):
    history = model.fit(train_data,
                        train_labels,
                        epochs=20,
                        batch_size=512,
                        validation_data=(test_data, test_labels),
                        verbose=2) 
    return history

a= train_model(baseline_model)
# b= train_model(smaller_model)
# c= train_model(bigger_model)
# d = train_model(baseline_model_l2)
e = train_model(baseline_model_dropout)


'''
作图 查看模型效果
'''
def plot_history(histories, key='binary_crossentropy'):
    plt.figure(figsize=(16,10))
    for name,history in histories:
        val = plt.plot(history.epoch, history.history['val_'+key],'--',label=name.title()+' Val')
        plt.plot(history.epoch, history.history[key], color=val[0].get_color(),
                 label=name.title()+' Train')

    plt.xlabel('Epochs')
    plt.ylabel(key.replace('_',' ').title())
    plt.legend()
    plt.xlim([0,max(history.epoch)])


plot_history([('baseline',a),
              #('smaller_model',b),
              #('bigger_model',c),
              #('baseline_l2',d),
              ('baseline_dropout',e)])
plt.show()

猜你喜欢

转载自blog.csdn.net/Feynman1999/article/details/84567342