第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

TensorFlow 入門教程

過擬合問題

在我們之前的學(xué)習(xí)之中,我們或多或少都會遇到一些訓(xùn)練時間的問題。比如“訓(xùn)練時間越長是不是最后的結(jié)果就會越好?”等問題。答案當(dāng)然是否定的,這是因為在訓(xùn)練的過程之中會遭遇到“過擬合”的問題,這是一種隨著訓(xùn)練時間不斷加長而產(chǎn)生的問題,那么這節(jié)課我們就來學(xué)習(xí)一下什么是過擬合,同時了解一下 TensorFlow 之中的避免過擬合的簡單的方法。

這節(jié)課之中,我們使用之前學(xué)習(xí)過的貓狗分類的例子進(jìn)行示例演示。

1. 什么是過擬合

過擬合,簡單來說就是“學(xué)習(xí)過度”,也就是說模型在訓(xùn)練集合上的精度越來越高,但是卻在測試集上的精度越來越低的情況。

這是因為網(wǎng)絡(luò)模型在訓(xùn)練集合上學(xué)習(xí)到了太多的“沒用的”特征,以至于模型的泛化能力下降。如下面兩幅圖所示,其中藍(lán)色代表訓(xùn)練集合上的指標(biāo),而黃色代表測試集合上的指標(biāo)。

圖片描述

改圖為準(zhǔn)確率的曲線,通過上圖我們可以看到,隨著不斷地訓(xùn)練,模型在訓(xùn)練集合上的準(zhǔn)確率逐漸逼近100%,而訓(xùn)練集合上的準(zhǔn)確率卻一直在70%徘徊。

圖片描述

改圖為損失 Loss 的曲線,通過上圖我們可以看到,隨著不斷地訓(xùn)練,模型在訓(xùn)練集合上的損失逐漸逼近0,而訓(xùn)練集合上的損失卻在第三個迭代之后不斷升高。

那么接下來我們就來學(xué)習(xí)一下如何在 TensorFlow 之中簡單地避免過擬合。這節(jié)課之中,我們要學(xué)習(xí)的方法有三種:

  • 使用 DropOut ;
  • 使用正則化;
  • 使用早停策略。

值得注意的是,上述圖表已經(jīng)在之前的課程使用 tf.keras 進(jìn)行圖片分類之中給出,它的完整代碼為:

import tensorflow as tf
import os
import matplotlib.pyplot as plt

# 獲取數(shù)據(jù)
dataset_url = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip'
path_download = os.path.dirname(tf.keras.utils.get_file('cats_and_dogs.zip', origin=dataset_url, extract=True))

# 獲得數(shù)據(jù)的路徑
train_dataset_dir = path_download + '/cats_and_dogs_filtered/train'
valid_dataset_dir = path_download + '/cats_and_dogs_filtered/validation'

# 定義相關(guān)的超參數(shù)
BATCH_SIZE = 64
TRAIN_NUM = 2000
VALID_NUM = 1000
EPOCHS = 15
Height = 128
Width = 128

# 創(chuàng)建訓(xùn)練集與測試集的迭代器
train_image_generator = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
valid_image_generator = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)

train_data_generator = train_image_generator.flow_from_directory(batch_size=BATCH_SIZE,
                              directory=train_dataset_dir,
                              shuffle=True,
                              target_size=(Height, Width),
                              class_mode='binary')
valid_data_generator = valid_image_generator.flow_from_directory(batch_size=BATCH_SIZE,
                              directory=valid_dataset_dir,
                              shuffle=True,
                              target_size=(Height, Width),
                              class_mode='binary')

# 定義一個線性模型
model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(16, 3, padding='same', activation='relu',
                input_shape=(Height, Width ,3)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(512, activation='relu'),
    tf.keras.layers.Dense(1)
])

# 編譯模型
model.compile(optimizer='adam',
       loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
       metrics=['accuracy'])
model.summary()

# 訓(xùn)練模型
history = model.fit_generator(
    train_data_generator,
    steps_per_epoch=TRAIN_NUM // BATCH_SIZE,
    epochs=EPOCHS,
    validation_data=valid_data_generator,
    validation_steps=VALID_NUM // BATCH_SIZE)

# 獲取訓(xùn)練的記錄
acc = history.history['accuracy']
loss=history.history['loss']

val_acc = history.history['val_accuracy']
val_loss=history.history['val_loss']

epochs_ran = range(EPOCHS)

# 繪制訓(xùn)練過程中的各種指標(biāo)
plt.plot(epochs_ran, acc, label='Train Acc')
plt.plot(epochs_ran, val_acc, label='Valid Acc')
plt.show()

plt.plot(epochs_ran, loss, label='Train Loss')
plt.plot(epochs_ran, val_loss, label='Valid Loss')
plt.show()

2. 使用 DropOut

在產(chǎn)生過擬合的原因之中,一個重要的原因就是“網(wǎng)絡(luò)參數(shù)過多”,也就是網(wǎng)絡(luò)模型的學(xué)習(xí)能力過強(qiáng),從而導(dǎo)致它會學(xué)習(xí)到很多沒用的信息,從而導(dǎo)致過擬合情況的發(fā)生。而使用 DropOut 就是在一定程度上降低網(wǎng)絡(luò)參數(shù),降低它的學(xué)習(xí)能力。

它的實現(xiàn)比較簡單:

tf.keras.layers.Dropout(frac)

可以看出,它是一個網(wǎng)絡(luò)層,它的參數(shù) frac 是一個 0 到 1 的小數(shù),該網(wǎng)絡(luò)層會按照 frac 的概率隨機(jī)丟掉一些參數(shù),從而達(dá)到降低網(wǎng)絡(luò)參數(shù)數(shù)量的目的。在使用的過程之中,我們只需要將該網(wǎng)絡(luò)層嵌入到模型的需要 DropOut 的網(wǎng)絡(luò)層之前即可。

于是我們可以將上述的網(wǎng)絡(luò)模型修改為:

model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(16, 3, padding='same', activation='relu',
                input_shape=(Height, Width ,3)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Conv2D(32, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(512, activation='relu'),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(1)
])

然后我們運行代碼,便可以得到網(wǎng)絡(luò)的結(jié)構(gòu)為:

Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_3 (Conv2D)            (None, 128, 128, 16)      448       
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 64, 64, 16)        0         
_________________________________________________________________
dropout (Dropout)            (None, 64, 64, 16)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 64, 64, 32)        4640      
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 32, 32, 32)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 32, 32, 32)        0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 32, 32, 64)        18496     
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 16, 16, 64)        0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 16, 16, 64)        0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 16384)             0         
_________________________________________________________________
dropout_3 (Dropout)          (None, 16384)             0         
_________________________________________________________________
dense_2 (Dense)              (None, 512)               8389120   
_________________________________________________________________
dropout_4 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_3 (Dense)              (None, 1)                 513       
=================================================================
Total params: 8,413,217
Trainable params: 8,413,217
Non-trainable params: 0

然后我們在訓(xùn)練結(jié)束后便可以看到模型訓(xùn)練結(jié)果的準(zhǔn)確率曲線為:

圖片描述

而模型訓(xùn)練結(jié)果的損失Loss曲線為:

圖片描述

可以看到,與之前的模型相比,我們現(xiàn)在的模型在一定程度上降低了過擬合。對于準(zhǔn)確率,它并沒有像之前一樣保持徘徊,而是和訓(xùn)練集保持了一致;對于損失,它也沒有上升,反而是一直處于一個較低的值。

3. 使用正則化

正則化是一種比較高級的防止過擬合產(chǎn)生的方法。它是通過網(wǎng)絡(luò)的參數(shù)來計算網(wǎng)絡(luò)的“代價”,然后將代價最小化來實現(xiàn)降低網(wǎng)絡(luò)規(guī)模的目的。它主要包括兩種方式, L1 正則化與 L2 正則化,這兩種方式都涉及到很多的數(shù)學(xué)原理,因此這里不做過多的展開,我們可以進(jìn)行一個簡單的區(qū)分:

  • L1 正則化,代價與網(wǎng)絡(luò)參數(shù)成正比;
  • L2 正則化,代價與網(wǎng)絡(luò)參數(shù)的平方成正比。

在實踐的過程之中,我們最常使用的就是 L2 正則化。

具體來說,我們可以通過將支持正則化的網(wǎng)絡(luò)層添加相應(yīng)的正則化參數(shù)即可實現(xiàn)該網(wǎng)絡(luò)層的正則化。比如對于 Dense 網(wǎng)絡(luò)層來說,我們可以添加參數(shù):

tf.keras.laysers.Dense(64, kernel_regularizer=tf.keras.regularizers.l2(0.001)),

而其中的 0.001 參數(shù)就是“代價”與網(wǎng)絡(luò)參數(shù)的平方成正比的參數(shù)。也就是說:

代價 = 0.001 * (網(wǎng)絡(luò)參數(shù)**2)

于是我們可以將我們的模型再次修改為:


model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(16, 3, padding='same', activation='relu',
                input_shape=(Height, Width ,3),
                kernel_regularizer=tf.keras.regularizers.l2(0.001)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, padding='same', activation='relu',
                kernel_regularizer=tf.keras.regularizers.l2(0.001)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu',
                kernel_regularizer=tf.keras.regularizers.l2(0.001)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(512, activation='relu',
                kernel_regularizer=tf.keras.regularizers.l2(0.001)),
    tf.keras.layers.Dense(1)
])

在這里,我們?yōu)榫矸e層和稠密層增加了L2正則化。我們可以看到網(wǎng)絡(luò)的模型結(jié)構(gòu)為:

Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_9 (Conv2D)            (None, 128, 128, 16)      448       
_________________________________________________________________
max_pooling2d_9 (MaxPooling2 (None, 64, 64, 16)        0         
_________________________________________________________________
conv2d_10 (Conv2D)           (None, 64, 64, 32)        4640      
_________________________________________________________________
max_pooling2d_10 (MaxPooling (None, 32, 32, 32)        0         
_________________________________________________________________
conv2d_11 (Conv2D)           (None, 32, 32, 64)        18496     
_________________________________________________________________
max_pooling2d_11 (MaxPooling (None, 16, 16, 64)        0         
_________________________________________________________________
flatten_3 (Flatten)          (None, 16384)             0         
_________________________________________________________________
dense_4 (Dense)              (None, 512)               8389120   
_________________________________________________________________
dense_5 (Dense)              (None, 1)                 513       
=================================================================
Total params: 8,413,217
Trainable params: 8,413,217
Non-trainable params: 0

我們可以發(fā)現(xiàn),網(wǎng)絡(luò)的參數(shù)并沒有發(fā)生變化,這是因為正則化并不會引入新的參數(shù),也不會減少參數(shù)。

在訓(xùn)練結(jié)束后我們可以得到模型訓(xùn)練結(jié)果的準(zhǔn)確率曲線為:

圖片描述

而模型訓(xùn)練結(jié)果的損失Loss曲線為:

圖片描述

可以看到,與之前的模型相比,我們現(xiàn)在的模型在一定程度上降低了過擬合。對于損失這一點尤為明顯,它只在第 7 個 Epoch 出現(xiàn)了上升,同時并沒有像之前一樣上升的如此劇烈。

4. 使用早停策略

這個策略會使用到我們下節(jié)課學(xué)習(xí)到的回調(diào)函數(shù),但是這也是方式過擬合產(chǎn)生的一種手段。它的思想比較簡單:

如果你在驗證集上的準(zhǔn)確率或者損失持續(xù)沒有提升,那么我就把你停止掉,不讓你繼續(xù)訓(xùn)練。

在 TensorFlow 之中,我們可以通過以下的回調(diào)方式來實現(xiàn)早停:

callback = tf.keras.callbacks.EarlyStopping(monitor='loss', patience=3)

其中EarlyStopping的常用參數(shù)包括:

  • monitor: 指定哪一個指標(biāo)作為監(jiān)控的標(biāo)準(zhǔn),一般為損失或者準(zhǔn)確率,這里是損失;
  • patience:忍耐限度,如果經(jīng)過了 patience 個 epoch ,monitor 指標(biāo)還沒有提升,那么會停止訓(xùn)練。

于是我們可以將模型還原為之前的模型,同時在訓(xùn)練的代碼中添加相應(yīng)的早?;卣{(diào)。

callback = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=2)
history = model.fit_generator(
    train_data_generator,
    steps_per_epoch=TRAIN_NUM // BATCH_SIZE,
    epochs=EPOCHS,
    validation_data=valid_data_generator,
    validation_steps=VALID_NUM // BATCH_SIZE,
    callbacks=[callback])

在這里我們在訓(xùn)練的過程之中添加了一個EarlyStopping的回調(diào)。

在訓(xùn)練結(jié)束后我們可以得到損失的準(zhǔn)確率的曲線為:

圖片描述

同時損失的曲線為:

圖片描述

我們可以看到, 該模型在第 7 個 Epoch 就停止了繼續(xù)訓(xùn)練,這是因為它的 Loss 在最近的兩個 Epoch 并沒有持續(xù)的提升,從而避免了后面不必要的訓(xùn)練過程。

5. 小結(jié)

在這節(jié)課之中,我們學(xué)習(xí)了什么是過擬合,同時了解了如何在 TensorFlow 之中避免過擬合的發(fā)生,我們可以采用的方法有 DropOut 、正則化以及早停策略。而在實際的應(yīng)用之中,大家可以根據(jù)自己需要將不同的放過發(fā)結(jié)合起來使用,這樣才能達(dá)到比較良好的效果。

圖片描述