【火爐煉AI】深度學習007-Keras微調進一步提高性能

【火爐煉AI】深度學習007-Keras微調進一步提高性能

(本文所使用的Python庫和版本號: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2, Keras 2.1.6, Tensorflow 1.9.0)html

本文使用微調(Fine-tune)技術來提高模型的性能,是前面的兩篇文章(編號爲005和006)的延續。前面咱們經過遷移學習(文章006)將這個貓狗大戰二分類問題的預測準確率提高到了90%左右,可是還能不能進一步提高了?git

前面咱們沒有對VGG16的卷積層進行參數的優化,那麼咱們這裏就能夠來優化這部分的參數,固然,優化是很細微的調整,因此稱爲Fine-tune。github

微調也不是對VGG16的全部結構參數都進行調整,而是僅僅調整後面幾個卷積層的參數,由於有不少學者發現,對不一樣的數據集,VGG16提取的特徵在底層基本同樣,主要區別在於高層,即卷積層的後面幾層,因此只須要對這幾層進行修改便可。以下咱們要調整的層數爲:算法

能夠看出,主要調整Conv block 5,前面的4個block不需調整。網絡

我這篇博文主要參考了:keras系列︱圖像多分類訓練與利用bottleneck features進行微調(三),這篇博文也是參考的Building powerful image classification models using very little data,但我發現這兩篇博文有不少地方的代碼跑不起來,主要緣由多是Keras或Tensorflow升級形成的,因此我作了一些必要的修改。app


1. 準備數據集

這一部分和前面文章(編號005)如出一轍,故而省略。函數


2. 構建模型

在模型的構建上,至關因而取VGG16模型的「身子」,再加上本身定義的模型做爲「頭」,將這兩部分加在一塊兒,組成一個完整的模型,「身子」模型仍然採用VGG16在ImageNet上獲得的weights,而「頭」模型則採用咱們上一篇文章中訓練獲得的weights,而後用這個模型來訓練和預測,將「身子」的一部分weights和「頭」的所有weights都進行調整。性能

這裏有幾個注意點:學習

1,本身定義的分類器模型做爲「頭」,可是「頭」的weights不能是隨機初始值,而應該用已經訓練好的weights,由於隨機初始值會產生較大的梯隊,會破壞前面VGG16卷積層的預訓練後weights。優化

2,微調僅僅針對VGG16網絡的後面幾層卷積層,而不是所有卷積層,是爲了防止過擬合,整個模型結構具備絕大的熵容量,所以有很高的過擬合傾向。而且底層的特徵更加具備通常性,不須要調整。

3,在learning rate上,訓練「頭」的weights時能夠用較大的lr,使其快速收斂,而在微調階段,須要用較小的lr,使其性能達到最優,而且使用的optimizer也一般使用SGD而不是其餘自適應學習率的優化算法,好比RMSProp,就是爲了保證每次改進的幅度比較低,以避免破壞VGG16提取的特徵。

# 上面的build_model2中間的my_model.layers[:25]要修改成my_model.layers[:15],原博文此處也是錯的。
# 4,構建模型
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense
from keras import applications
from keras import optimizers
from keras.models import Model
def build_model2():
    base_model = applications.VGG16(weights='imagenet', include_top=False,input_shape=(IMG_W, IMG_H,IMG_CH))
    # 此處咱們只須要卷積層不須要全鏈接層,故而inclue_top=False,必定要設置input_shape,不然後面會報錯
    # 這一步使用applications模塊自帶的VGG16函數直接加載了模型和參數,做爲咱們本身模型的「身子」
    
    # 下面定義咱們本身的分類器,做爲咱們本身模型的「頭」
    top_model = Sequential()
    top_model.add(Flatten(input_shape=base_model.output_shape[1:])) # 若是沒有設置input_shape,這個地方報錯,顯示output_shape有不少None
    top_model.add(Dense(256, activation='relu'))
    top_model.add(Dropout(0.5))
    top_model.add(Dense(1, activation='sigmoid')) # 二分類問題
    
    top_model.load_weights('E:\PyProjects\DataSet\FireAI\DeepLearning\FireAI006/top_FC_model') 
    # 上面定義了模型結構,此處要把訓練好的參數加載進來,
    
    my_model = Model(inputs=base_model.input, outputs=top_model(base_model.output)) # 將「身子」和「頭」組裝到一塊兒
    # my_model就是咱們組裝好的完整的模型,也已經加載了各自的weights
    
    # 普通的模型須要對全部層的weights進行訓練調整,可是此處咱們只調整VGG16的後面幾個卷積層,因此前面的卷積層要凍結起來
    for layer in my_model.layers[:15]: # 15層以前都是不需訓練的,原博文此處也是錯的。我暈。。。。
        layer.trainable = False
        
    # 模型的配置
    my_model.compile(loss='binary_crossentropy',
                  optimizer=optimizers.SGD(lr=1e-4, momentum=0.9), # 使用一個很是小的lr來微調
                  metrics=['accuracy'])
    return my_model
複製代碼

這個模型的構建中須要將不訓練的層凍結,如上設置trainable=False便可,下面進行微調訓練:

# 開始用train set來微調模型的參數
print('start to train model2')
my_model2=build_model2()
history_ft2 = my_model2.fit_generator(
        train_generator,
        steps_per_epoch=train_samples_num // batch_size,
        epochs=epochs,
        validation_data=val_generator,
        validation_steps=val_samples_num // batch_size)
複製代碼

-------------------------------------輸---------出--------------------------------

start to train model2 Epoch 1/20 125/125 [==============================] - 727s 6s/step - loss: 0.3288 - acc: 0.8865 - val_loss: 0.2991 - val_acc: 0.9113 Epoch 2/20 125/125 [==============================] - 732s 6s/step - loss: 0.1822 - acc: 0.9395 - val_loss: 0.2988 - val_acc: 0.9113 Epoch 3/20 125/125 [==============================] - 724s 6s/step - loss: 0.1557 - acc: 0.9445 - val_loss: 0.2742 - val_acc: 0.9125

...

Epoch 18/20 125/125 [==============================] - 703s 6s/step - loss: 0.0260 - acc: 0.9905 - val_loss: 0.3304 - val_acc: 0.9313 Epoch 19/20 125/125 [==============================] - 704s 6s/step - loss: 0.0138 - acc: 0.9955 - val_loss: 0.3267 - val_acc: 0.9413 Epoch 20/20 125/125 [==============================] - 705s 6s/step - loss: 0.0103 - acc: 0.9960 - val_loss: 0.3551 - val_acc: 0.9325

--------------------------------------------完-------------------------------------

在我這個破筆記本上訓練很是耗時,20個epoch花了將近四個小時,唉。因此就不打算繼續訓練下去了。看一下loss和acc的結果:

能夠看出test上的acc還能夠繼續改進一下,train 和test上的loss也沒有達到平臺期,能夠增大epoch繼續訓練。可是也能夠看出有些過擬合現象。

########################小**********結###############################

1,Fine-Tune的核心是對原始的骨架網絡(此處爲VGG16)進行參數的微調,因此須要用很是小的學習率,並且要用SGD優化器。

2,在使用微調以後,準確率從90%左右提高到了約93%,增長epoch數目能夠提高的更多。

#################################################################


注:本部分代碼已經所有上傳到(個人github)上,歡迎下載。

相關文章
相關標籤/搜索