首頁人工智能技術資訊正文

什么是微調模型?微調模型實現熱狗識別

更新時間:2023-06-07 來源:黑馬程序員 瀏覽量:

微調的原理

如何在只有6萬張圖像的MNIST訓練數據集上訓練模型。學術界當下使用最廣泛的大規(guī)模圖像數據集ImageNet,它有超過1,000萬的圖像和1,000類的物體。然而,我們平常接觸到數據集的規(guī)模通常在這兩者之間。假設我們想從圖像中識別出不同種類的椅子,然后將購買鏈接推薦給用戶。一種可能的方法是先找出100種常見的椅子,為每種椅子拍攝1,000張不同角度的圖像,然后在收集到的圖像數據集上訓練一個分類模型。另外一種解決辦法是應用遷移學習(transfer learning),將從源數據集學到的知識遷移到目標數據集上。例如,雖然ImageNet數據集的圖像大多跟椅子無關,但在該數據集上訓練的模型可以抽取較通用的圖像特征,從而能夠幫助識別邊緣、紋理、形狀和物體組成等。這些類似的特征對于識別椅子也可能同樣有效。

微調由以下4步構成。

1.在源數據集(如ImageNet數據集)上預訓練一個神經網絡模型,即源模型。

2.創(chuàng)建一個新的神經網絡模型,即目標模型。它復制了源模型上除了輸出層外的所有模型設計及其參數。我們假設這些模型參數包含了源數據集上學習到的知識,且這些知識同樣適用于目標數據集。我們還假設源模型的輸出層跟源數據集的標簽緊密相關,因此在目標模型中不予采用。

3.為目標模型添加一個輸出大小為目標數據集類別個數的輸出層,并隨機初始化該層的模型參數。

4.在目標數據集(如椅子數據集)上訓練目標模型。我們將從頭訓練輸出層,而其余層的參數都是基于源模型的參數微調得到的。

當目標數據集遠小于源數據集時,微調有助于提升模型的泛化能力。

熱狗模型

接下來我們利用微調模型來實踐一個具體的例子:熱狗識別。將基于一個小數據集對在ImageNet數據集上訓練好的ResNet模型進行微調。該小數據集含有數千張熱狗或者其他事物的圖像。我們將使用微調得到的模型來識別一張圖像中是否包含熱狗。

首先,導入實驗所需的工具包。

import tensorflow as tf
import numpy as np

獲取數據集

我們首先將數據集放在路徑hotdog/data之下:

1686036589873_82.png

每個類別文件夾里面是圖像文件。

上一節(jié)中我們介紹了ImageDataGenerator進行圖像增強,我們可以通過以下方法讀取圖像文件,該方法以文件夾路徑為參數,生成經過圖像增強后的結果,并產生batch數據:

flow_from_directory(self, directory,
                            target_size=(256, 256), color_mode='rgb',
                            classes=None, class_mode='categorical',
                            batch_size=32, shuffle=True, seed=None,
                            save_to_dir=None)

主要參數:

directory: 目標文件夾路徑,對于每一個類對應一個子文件夾,該子文件夾中任何JPG、PNG、BNP、PPM的圖片都可以讀取。

target_size: 默認為(256, 256),圖像將被resize成該尺寸。

batch_size: batch數據的大小,默認32。

shuffle: 是否打亂數據,默認為True。

我們創(chuàng)建兩個tf.keras.preprocessing.image.ImageDataGenerator實例來分別讀取訓練數據集和測試數據集中的所有圖像文件。將訓練集圖片全部處理為高和寬均為224像素的輸入。此外,我們對RGB(紅、綠、藍)三個顏色通道的數值做標準化。

# 獲取數據集
import pathlib
train_dir = 'transferdata/train'
test_dir = 'transferdata/test'
# 獲取訓練集數據
train_dir = pathlib.Path(train_dir)
train_count = len(list(train_dir.glob('*/*.jpg')))
# 獲取測試集數據
test_dir = pathlib.Path(test_dir)
test_count = len(list(test_dir.glob('*/*.jpg')))
# 創(chuàng)建imageDataGenerator進行圖像處理
image_generator = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
# 設置參數
BATCH_SIZE = 32
IMG_HEIGHT = 224
IMG_WIDTH = 224
# 獲取訓練數據
train_data_gen = image_generator.flow_from_directory(directory=str(train_dir),
                                                    batch_size=BATCH_SIZE,
                                                    target_size=(IMG_HEIGHT, IMG_WIDTH),
                                                    shuffle=True)
# 獲取測試數據
test_data_gen = image_generator.flow_from_directory(directory=str(test_dir),
                                                    batch_size=BATCH_SIZE,
                                                    target_size=(IMG_HEIGHT, IMG_WIDTH),
                                                    shuffle=True)

下面我們隨機取1個batch的圖片然后繪制出來。

import matplotlib.pyplot as plt
# 顯示圖像
def show_batch(image_batch, label_batch):
    plt.figure(figsize=(10,10))
    for n in range(15):
        ax = plt.subplot(5,5,n+1)
        plt.imshow(image_batch[n])
        plt.axis('off')
# 隨機選擇一個batch的圖像        
image_batch, label_batch = next(train_data_gen)
# 圖像顯示
show_batch(image_batch, label_batch)

微調模型

模型構建與訓練

我們使用在ImageNet數據集上預訓練的ResNet-50作為源模型。這里指定weights='imagenet'來自動下載并加載預訓練的模型參數。在第一次使用時需要聯網下載模型參數。

Keras應用程序(keras.applications)是具有預先訓練權值的固定架構,該類封裝了很多重量級的網絡架構,如下圖所示:

模型構建與訓練

實現時實例化模型架構:

tf.keras.applications.ResNet50(
    include_top=True, weights='imagenet', input_tensor=None, input_shape=None,
    pooling=None, classes=1000, **kwargs)

主要參數:

include_top: 是否包括頂層的全連接層。

weights: None 代表隨機初始化, 'imagenet' 代表加載在 ImageNet 上預訓練的權值。

input_shape: 可選,輸入尺寸元組,僅當 include_top=False 時有效,否則輸入形狀必須是 (224, 224, 3)(channels_last 格式)或 (3, 224, 224)(channels_first 格式)。它必須為 3 個輸入通道,且寬高必須不小于 32,比如 (200, 200, 3) 是一個合法的輸入尺寸。

在該案例中我們使用resNet50預訓練模型構建模型:

# 加載預訓練模型
ResNet50 = tf.keras.applications.ResNet50(weights='imagenet', input_shape=(224,224,3))
# 設置所有層不可訓練
for layer in ResNet50.layers:
    layer.trainable = False
# 設置模型
net = tf.keras.models.Sequential()
# 預訓練模型
net.add(ResNet50)
# 展開
net.add(tf.keras.layers.Flatten())
# 二分類的全連接層
net.add(tf.keras.layers.Dense(2, activation='softmax'))

接下來我們使用之前定義好的ImageGenerator將訓練集圖片送入ResNet50進行訓練。

# 模型編譯:指定優(yōu)化器,損失函數和評價指標
net.compile(optimizer='adam',
            loss='categorical_crossentropy',
            metrics=['accuracy'])
# 模型訓練:指定數據,每一個epoch中只運行10個迭代,指定驗證數據集
history = net.fit(
                    train_data_gen,
                    steps_per_epoch=10,
                    epochs=3,
                    validation_data=test_data_gen,
                    validation_steps=10
                    )
Epoch 1/3
10/10 [==============================] - 28s 3s/step - loss: 0.6931 - accuracy: 0.5031 - val_loss: 0.6930 - val_accuracy: 0.5094
Epoch 2/3
10/10 [==============================] - 29s 3s/step - loss: 0.6932 - accuracy: 0.5094 - val_loss: 0.6935 - val_accuracy: 0.4812
Epoch 3/3
10/10 [==============================] - 31s 3s/step - loss: 0.6935 - accuracy: 0.4844 - val_loss: 0.6933 - val_accuracy: 0.4875

分享到:
在線咨詢 我要報名
和我們在線交談!