您好,登錄后才能下訂單哦!
這篇文章主要介紹“Tensorflow2.4怎么完成遷移和模型微調”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Tensorflow2.4怎么完成遷移和模型微調”文章能幫助大家解決問題。
首先我們要使用 tensorflow 的內置函數,從網絡上下載貓狗圖片集,訓練數據中的貓、狗圖片各 1000 張,驗證數據中的貓、狗圖片各 500 張。每張圖片的大小都是(160, 160, 3),每個 batch 中有 32 張圖片。
import matplotlib.pyplot as plt import numpy as np import os import tensorflow as tf URL = 'https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip' BATCH_SIZE = 32 IMG_SIZE = (160, 160) path_to_zip = tf.keras.utils.get_file('cats_and_dogs.zip', origin=URL, extract=True) PATH = os.path.join(os.path.dirname(path_to_zip), 'cats_and_dogs_filtered') train_dir = os.path.join(PATH, 'train') validation_dir = os.path.join(PATH, 'validation') train_dataset = tf.keras.utils.image_dataset_from_directory(train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE) validation_dataset = tf.keras.utils.image_dataset_from_directory(validation_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE) class_names = train_dataset.class_names
在這里我們挑選了部分圖片和標簽進行展示。
plt.figure(figsize=(10, 10)) for images, labels in train_dataset.take(1): for i in range(3): ax = plt.subplot(3, 3, i + 1) plt.imshow(images[i].numpy().astype("uint8")) plt.title(class_names[labels[i]]) plt.axis("off")
(1)由于我們沒有測試集數據,使用 tf.data.experimental.cardinality 確定驗證集中有多少個 batch 的數據,然后將其中的 20% 的 batch 編程測試集。
val_batches = tf.data.experimental.cardinality(validation_dataset) test_dataset = validation_dataset.take(val_batches // 5) validation_dataset = validation_dataset.skip(val_batches // 5)
(2)為了保證在加載數據的時候不會出現 I/O 不會阻塞,我們在從磁盤加載完數據之后,使用 cache 會將數據保存在內存中,確保在訓練模型過程中數據的獲取不會成為訓練速度的瓶頸。如果說要保存的數據量太大,可以使用 cache 創建磁盤緩存提高數據的讀取效率。另外我們還使用 prefetch 在訓練過程中可以并行執行數據的預獲取。
AUTOTUNE = tf.data.AUTOTUNE train_dataset = train_dataset.prefetch(buffer_size=AUTOTUNE) validation_dataset = validation_dataset.prefetch(buffer_size=AUTOTUNE) test_dataset = test_dataset.prefetch(buffer_size=AUTOTUNE)
(3)因為我們沒有大量的圖片數據,我們將現有的圖片數據進行旋轉或者翻轉操作可以增加樣本的多樣性,這樣也有助于減少過擬合現象。RandomFlip 函數將根據 mode 屬性將圖片進行水平或垂直翻轉圖像。"可選的有 "horizontal" 、 "vertical" 或 "horizontal_and_vertical" 。"horizontal" 是左右翻轉, "vertical" 是上下翻轉。RandomRotation 函數通過設置 factor 來講圖片進行旋轉,假如 factor=0.2 會將圖片在 [-20% * 2pi, 20% * 2pi] 范圍內隨機旋轉。
data_augmentation = tf.keras.Sequential([ tf.keras.layers.RandomFlip('horizontal'), tf.keras.layers.RandomRotation(0.1), ])
我們這里將隨便使用一張圖片,使用數據增強的方法對其進行變化,第一張圖是原圖,其他的都是進行了變化的圖片
for image, _ in train_dataset.take(1): plt.figure(figsize=(10, 10)) first_image = image[0] for i in range(3): if i==0: ax = plt.subplot(3, 3, i + 1) plt.imshow(first_image/ 255) plt.axis('off') else: ax = plt.subplot(3, 3, i + 1) augmented_image = data_augmentation(tf.expand_dims(first_image, 0)) plt.imshow(augmented_image[0] / 255) plt.axis('off')
(4)由于 MobileNetV2 模型的輸入值范圍是在 [-1, 1] 范圍內,但此時我們的圖片數據中的像素值處于 [0, 255] 范圍內,所以要重新縮放這些像素值, Rescaling 函數可以實現該操作。如果將 [0, 255] 范圍的輸入縮放到 [0, 1] 的范圍,我們可以通過設置參數 scale=1./255 來實現。如果將 [0, 255] 范圍內的輸入縮放到 [-1, 1] 范圍內,我們可以通過設置參數 scale=1./127.5, offset=-1 來實現。
rescale = tf.keras.layers.Rescaling(1./127.5, offset=-1)
(1)我們將 MobileNet V2 模型當做一個基礎模型,此模型已基于 ImageNet 數據集進行完美的預訓練,一般來說最后一層就是一個分類器,我們選擇將在 MobileNet V2 的倒數第二個網絡層上搭建自己的分類器,與最后一層相比倒數第二層能夠保留更豐富的圖片特征。在實際操作中我們實例化 MobileNetV2 模型,通過指定 include_top=False 參數,可以加載不包括最頂層的整個預訓練網絡結果。 該模型的作用就是將(160,160,3)大小的圖片轉換為(5,5,1280)的特征輸出。
(2)第一層是將我們的訓練數據都進行數據增強操作,也就是隨機的翻轉和旋轉。
(3)第二層是接收輸入為 (160,160,3)大小的圖片的輸入層。
(4)第三層是我們直接拿來用的 MobileNetV2 ,因為我們要直接使用基礎模型的圖片特征提取能力,所以為了在訓練過程中其權重不發生變化,我們將基礎模型中的權重參數都凍結。
(5)第四層是一個池化層,可以將每個 batch 從 (32,5,5,1280) 壓縮為 (32,1280) 大小的輸出。
(6)第五層是 Dropout ,防止過擬合。
(7)第六層是對該圖片一個預測值,也就是 logit 。如果是正數預測標簽 1 ,如果是負數預測標簽 0 。
(8)我們從模型的 summary 中可以看到,此時我們的模型中的 2259265 個參數被凍結,只有 1281 個參數是可以訓練的,它們是分屬兩個變量的可訓練參數,即最后一個全連接層即權重 1280 個可訓練參數和偏差 1 個可訓練參數。
IMG_SHAPE = IMG_SIZE + (3,) inputs = tf.keras.Input(shape=(160, 160, 3)) x = data_augmentation(inputs) x = tf.keras.applications.mobilenet_v2.preprocess_input(x) base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE, include_top=False, weights='imagenet') base_model.trainable = False x = base_model(x, training=False) x = tf.keras.layers.GlobalAveragePooling2D()(x) x = tf.keras.layers.Dropout(0.2)(x) outputs = tf.keras.layers.Dense(1)(x) model = tf.keras.Model(inputs, outputs) model.summary()
模型結構如下:
Model: "model_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_8 (InputLayer) [(None, 160, 160, 3)] 0 sequential_2 (Sequential) (None, 160, 160, 3) 0 tf.math.truediv_3 (TFOpLamb (None, 160, 160, 3) 0 da) tf.math.subtract_3 (TFOpLam (None, 160, 160, 3) 0 bda) mobilenetv2_1.00_160 (Funct (None, 5, 5, 1280) 2257984 ional) global_average_pooling2d_3 (None, 1280) 0 (GlobalAveragePooling2D) dropout_2 (Dropout) (None, 1280) 0 dense_2 (Dense) (None, 1) 1281 ================================================================= Total params: 2,259,265 Trainable params: 1,281 Non-trainable params: 2,257,984
可以看到模型中的可訓練的 2 個變量:
model.trainable_variables
結果如下:
[<tf.Variable 'dense_2/kernel:0' shape=(1280, 1) dtype=float32, numpy=
array([[ 0.08899798],
[-0.06681276],
[ 0.00906871],
...,
[-0.00114891],
[-0.01134416],
[-0.02000826]], dtype=float32)>,
<tf.Variable 'dense_2/bias:0' shape=(1,) dtype=float32, numpy=array([0.03746362], dtype=float32)>]
(9)選擇 Adam 優化器,將我們的學習率設置為 0.0003 。選擇 BinaryCrossentropy 作為損失函數。選擇常規的 accuracy 作為評估指標。此時我們先對基礎模型訓練 10 個 epoch 。
lr = 0.0003 initial_epochs = 10 model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=lr), loss=tf.keras.losses.BinaryCrossentropy(from_logits=True), metrics=['accuracy']) history = model.fit(train_dataset, validation_data=test_dataset, epochs=initial_epochs)
訓練過程如下:
Epoch 1/10 63/63 [==============================] - 24s 352ms/step - loss: 0.5517 - accuracy: 0.6835 - val_loss: 0.2720 - val_accuracy: 0.8958 Epoch 2/10 63/63 [==============================] - 21s 327ms/step - loss: 0.2792 - accuracy: 0.8865 - val_loss: 0.1499 - val_accuracy: 0.9531 ... Epoch 9/10 63/63 [==============================] - 20s 321ms/step - loss: 0.1075 - accuracy: 0.9530 - val_loss: 0.0766 - val_accuracy: 0.9740 Epoch 10/10 63/63 [==============================] - 21s 329ms/step - loss: 0.1040 - accuracy: 0.9560 - val_loss: 0.0742 - val_accuracy: 0.9740
(10)使用測試數據對模型進行評估。
model.evaluate(validation_dataset)
結果如下:
loss: 0.0664 - accuracy: 0.9765
(1)在上面的操作中,我們僅僅在 MobileNetV2 基礎模型的頂部添加了一層池化層、一層 Dropout、一層全連接層作為我們的自定義分類器。預訓練模型 MobileNetV2 中權重在訓練過程中未曾發生過更新。
(2)我們還有一種被稱為微調的方法,可以在訓練基礎模型權重的同時,同時訓練我們上面自定義添加的用于分類的分類器。這個微調的訓練過程可以將基礎模型的通用的圖片特征提取能力調整為專門提取本任務中貓狗數據集特征的能力。這個微調的操作只能在我們進行了上面的遷移學習操作之后才能進行,否則如果一開始直接將基礎模型和我們自定義的若干層分類器一起進行訓練,則會由于隨機初始化的分類器導致整個模型的更新梯度太大,從而使得基礎模型喪失了其預訓練的有效能力。其次在微調過程中我們應該選擇性地去微調少量頂部的網絡層而不是整個 MobileNet 模型,因為在卷積神經網絡中,低層的網絡層一般捕獲到的是通用的圖片特征,這個能力可以泛化應用到幾乎所有類型的圖片,但是越往頂部的網絡層,越來越聚焦于捕獲訓練時所用到的訓練數據的特征,而微調的目標正是是讓這個模型更加適用于所用的專門的數據集,也就是本次進行的貓狗圖片。
(3)MobileNetV2 模型一共有 154 層結構,我們將模型的前 100 層的參數進行凍結,對頂部的 54 層網絡結構中的參數與我們自定義的分類器的若干層一起進行訓練,我們通過打印模型的 summary 可以看到,此時共有 54 個可以訓練的變量,這些變量中共有可訓練的參數 1862721 個。
base_model.trainable = True fine_tune_at = 100 for layer in base_model.layers[:fine_tune_at]: layer.trainable = False print("%d trainable variables "%len(model.trainable_variables)) model.summary()
結果如下:
56 trainable variables
Model: "model_2"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_8 (InputLayer) [(None, 160, 160, 3)] 0
sequential_2 (Sequential) (None, 160, 160, 3) 0
tf.math.truediv_3 (TFOpLamb (None, 160, 160, 3) 0
da)
tf.math.subtract_3 (TFOpLam (None, 160, 160, 3) 0
bda)
mobilenetv2_1.00_160 (Funct (None, 5, 5, 1280) 2257984
ional)
global_average_pooling2d_3 (None, 1280) 0
(GlobalAveragePooling2D)
dropout_2 (Dropout) (None, 1280) 0
dense_2 (Dense) (None, 1) 1281
=================================================================
Total params: 2,259,265
Trainable params: 1,862,721
Non-trainable params: 396,544
(4)之前我們對基礎模型訓練了 10 個 epoch ,現在我們進行微調過程中再對模型訓練 10 個 epoch ,且我們將從上面訓練結束的 epoch 開始恢復并進行現在的訓練過程。
(5)這里我們改用 RMSprop 優化器,且因為此時我們是要對整體模型進行微調,所以設置的學習率比之前降低 10 倍,否則如果較大會很快產生過擬合。
fine_tune_epochs = 10 total_epochs = initial_epochs + fine_tune_epochs model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True), optimizer = tf.keras.optimizers.RMSprop(learning_rate=lr/10), metrics=['accuracy']) history_fine = model.fit(train_dataset, epochs=total_epochs, initial_epoch=history.epoch[-1], validation_data=validation_dataset)
訓練結果輸出:
Epoch 10/20
63/63 [==============================] - 39s 561ms/step - loss: 0.1073 - accuracy: 0.9570 - val_loss: 0.1017 - val_accuracy: 0.9592
Epoch 11/20
63/63 [==============================] - 34s 538ms/step - loss: 0.0688 - accuracy: 0.9725 - val_loss: 0.0448 - val_accuracy: 0.9827
...
Epoch 19/20
63/63 [==============================] - 34s 537ms/step - loss: 0.0244 - accuracy: 0.9900 - val_loss: 0.0709 - val_accuracy: 0.9777
Epoch 20/20
63/63 [==============================] - 33s 528ms/step - loss: 0.0220 - accuracy: 0.9905 - val_loss: 0.0566 - val_accuracy: 0.9851
(6)使用測試數據對模型進行評估。
model.evaluate(test_dataset)
結果輸出:
loss: 0.0544 - accuracy: 0.9792
之前模型最后的驗證準確率為 0.9740 ,測試準確率為 0.9765 ,而經過微調的模型,最后餓驗證準確率為 0.9851 ,測試準確率為 0.9792 ,都有所提升。
我們隨機挑選一個 batch 進行預測,并將圖片與預測標簽進行顯示,結果表明預測全都正確。
image_batch, label_batch = test_dataset.as_numpy_iterator().next() predictions = model.predict_on_batch(image_batch).flatten() predictions = tf.nn.sigmoid(predictions) predictions = tf.where(predictions < 0.5, 0, 1) plt.figure(figsize=(10, 10)) for i in range(9): ax = plt.subplot(3, 3, i + 1) plt.imshow(image_batch[i].astype("uint8")) plt.title(class_names[predictions[i]]) plt.axis("off")
關于“Tensorflow2.4怎么完成遷移和模型微調”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。