Keras 入門課6:使用Inception V3模型進行遷移學習


1)這里的steps_per_epoch是針對fit_generation特有的一個參數。輸入數據仍然是每次64張,由於是采用了flow_from_directory方法,會不斷的一次次從文件夾里取64張圖像輸入網絡,直到滿足800次之后才進入下一個epoch。由於加了圖像增強,所以不論多少次,網絡輸入都是不一樣的。事實上steps_per_epoch可以簡單的設置為data_size/batch_size。基本上保證了每一輪一張圖像過一遍。

深度學習可以說是一門數據驅動的學科,各種有名的CNN模型,無一不是在大型的數據庫上進行的訓練。像ImageNet這種規模的數據庫,動輒上百萬張圖片。對於普通的機器學習工作者、學習者來說,面對的任務各不相同,很難拿到如此大規模的數據集。同時也沒有谷歌,Facebook那種大公司驚人的算力支持,想從0訓練一個深度CNN網絡,基本是不可能的。但是好在已經訓練好的模型的參數,往往經過簡單的調整和訓練,就可以很好的遷移到其他不同的數據集上,同時也無需大量的算力支撐,便能在短時間內訓練得出滿意的效果。這便是遷移學習。究其根本,就是雖然圖像的數據集不同,但是底層的特征卻是有大部分通用的。

遷移學習主要分為兩種

  • 第一種即所謂的transfer learning,遷移訓練時,移掉最頂層,比如ImageNet訓練任務的頂層就是一個1000輸出的全連接層,換上新的頂層,比如輸出為10的全連接層,然后訓練的時候,只訓練最后兩層,即原網絡的倒數第二層和新換的全連接輸出層。可以說transfer learning將底層的網絡當做了一個特征提取器來使用。
  • 第二種叫做fine tune,和transfer learning一樣,換一個新的頂層,但是這一次在訓練的過程中,所有的(或大部分)其它層都會經過訓練。也就是底層的權重也會隨着訓練進行調整。

一個典型的遷移學習過程是這樣的。首先通過transfer learning對新的數據集進行訓練,訓練過一定epoch之后,改用fine tune方法繼續訓練,同時降低學習率。這樣做是因為如果一開始就采用fine tune方法的話,網絡還沒有適應新的數據,那么在進行參數更新的時候,比較大的梯度可能會導致原本訓練的比較好的參數被污染,反而導致效果下降。

本課,我們將嘗試使用谷歌提出的Inception V3模型來對一個花朵數據集進行遷移學習的訓練。

數據集為17種不同的花朵,每種有80張樣本,一共1360張圖像,屬於典型的小樣本集。數據下載地址:http://www.robots.ox.ac.uk/~vgg/data/flowers/17/
官方沒有給出圖像對應的label,我寫了一段代碼,把每張圖像加上標簽,https://gist.github.com/tsycnh/177bbf7d93adc6207242fd334ce3bb60
同時,Keras對於數據的格式要求如下:我也寫了一個腳本來做轉換https://gist.github.com/tsycnh/1b35103adec1ad2be5090c486354859f

這個腳本我將訓練集划分為800張,驗證集和測試集分別為260張,圖片順序做了隨機打亂

如果你懶得自己轉換,我已經把處理好的數據進行上傳,直接下載即可:https://download.csdn.net/download/tsyccnh/10581591

請注意,這里的花朵識別仍屬於最簡單的單分類任務,樣張如下

這個腳本我將訓練集划分為800張,驗證集和測試集分別為260張,圖片順序做了隨機打亂

如果你懶得自己轉換,我已經把處理好的數據進行上傳,直接下載即可:https://download.csdn.net/download/tsyccnh/10581591

請注意,這里的花朵識別仍屬於最簡單的單分類任務,樣張如下

這個腳本我將訓練集划分為800張,驗證集和測試集分別為260張,圖片順序做了隨機打亂

如果你懶得自己轉換,我已經把處理好的數據進行上傳,直接下載即可:https://download.csdn.net/download/tsyccnh/10581591

請注意,這里的花朵識別仍屬於最簡單的單分類任務,樣張如下

這個腳本我將訓練集划分為800張,驗證集和測試集分別為260張,圖片順序做了隨機打亂

如果你懶得自己轉換,我已經把處理好的數據進行上傳,直接下載即可:https://download.csdn.net/download/tsyccnh/10581591

請注意,這里的花朵識別仍屬於最簡單的單分類任務,樣張如下

from keras.preprocessing.image import ImageDataGenerator
from keras.applications.inception_v3 import InceptionV3,preprocess_input
from keras.layers import GlobalAveragePooling2D,Dense
from keras.models import Model
from keras.utils.vis_utils import plot_model
from keras.optimizers import Adagrad
# 數據准備
train_datagen = ImageDataGenerator(
    preprocessing_function=preprocess_input,# ((x/255)-0.5)*2  歸一化到±1之間
    rotation_range=30,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
)
val_datagen = ImageDataGenerator(
    preprocessing_function=preprocess_input,
    rotation_range=30,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
)

這里用到的數據集和之前都不同,之前用的是一些公共的、Keras內置的數據集,這次用到的是自己准備的數據集。由於數據的圖像大小比較大,不適合一次全部載入到內存中,所以使用了flow_from_directory方法來按批次從硬盤讀取圖像數據,並實時進行圖像增強

train_generator = train_datagen.flow_from_directory(directory='./flowers17/train',
                                  target_size=(299,299),#Inception V3規定大小
                                  batch_size=64)
val_generator = val_datagen.flow_from_directory(directory='./flowers17/validation',
                                target_size=(299,299),
                                batch_size=64)

首先我們需要加載骨架模型,這里用的InceptionV3模型,其兩個參數比較重要,一個是weights,如果是’imagenet’,Keras就會自動下載已經在ImageNet上訓練好的參數,如果是None,系統會通過隨機的方式初始化參數,目前該參數只有這兩個選擇。另一個參數是include_top,如果是True,輸出是1000個節點的全連接層。如果是False,會去掉頂層,輸出一個8 * 8 * 2048的張量。

ps:在keras.applications里還有很多其他的預置模型,比如VGG,ResNet,以及適用於移動端的MobileNet等。大家都可以拿來玩玩。

一般我們做遷移訓練,都是要去掉頂層,后面接上各種自定義的其它新層。這已經成為了訓練新任務慣用的套路。
輸出層先用GlobalAveragePooling2D函數將8 * 8 * 2048的輸出轉換成1 * 2048的張量。后面接了一個1024個節點的全連接層,最后是一個17個節點的輸出層,用softmax激活函數。

# 構建基礎模型
base_model = InceptionV3(weights='imagenet',include_top=False)

# 增加新的輸出層
x = base_model.output
x = GlobalAveragePooling2D()(x) # GlobalAveragePooling2D 將 MxNxC 的張量轉換成 1xC 張量,C是通道數
x = Dense(1024,activation='relu')(x)
predictions = Dense(17,activation='softmax')(x)
model = Model(inputs=base_model.input,outputs=predictions)
# plot_model(model,'tlmodel.png')

構建完新模型后需要進行模型的配置。下面的兩個函數分別對transfer learning和fine tune兩種方法分別進行了配置。每個函數有兩個參數,分別是model和base_model。這里可能會有同學有疑問,上面定義了model,這里又將base_model一起做配置,對base_model的更改會對model產生影響么?
答案是會的。如果你debug追進去看的話,可以看到model的第一層和base_model的第一層是指向同一個內存地址的。這里將base_model作為參數,只是為了方便對骨架模型進行設置。

setup_to_transfer_learning: 這個函數將骨架模型的所有層都設置為不可訓練
setup_to_fine_tune:這個函數將骨架模型中的前幾層設置為不可訓練,后面的所有Inception模塊都設置為可訓練。
這里面的GAP_LAYER需要配合打印圖和調試的方法確認正確的值,感興趣具體怎么操作的同學,可以私信我,以后看有沒有必要把這個點寫成教程。

'''
這里的base_model和model里面的iv3都指向同一個地址
'''
def setup_to_transfer_learning(model,base_model):#base_model
    for layer in base_model.layers:
        layer.trainable = False
    model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])

def setup_to_fine_tune(model,base_model):
    GAP_LAYER = 17 # max_pooling_2d_2
    for layer in base_model.layers[:GAP_LAYER+1]:
        layer.trainable = False
    for layer in base_model.layers[GAP_LAYER+1:]:
        layer.trainable = True
    model.compile(optimizer=Adagrad(lr=0.0001),loss='categorical_crossentropy',metrics=['accuracy'])

下面開始訓練,這段代碼也演示了如何在全部訓練過程中改變模型。

setup_to_transfer_learning(model,base_model)
history_tl = model.fit_generator(generator=train_generator,
                    steps_per_epoch=800,#800
                    epochs=2,#2
                    validation_data=val_generator,
                    validation_steps=12,#12
                    class_weight='auto'
                    )
model.save('./flowers17_iv3_tl.h5')
setup_to_fine_tune(model,base_model)
history_ft = model.fit_generator(generator=train_generator,
                                 steps_per_epoch=800,
                                 epochs=2,
                                 validation_data=val_generator,
                                 validation_steps=1,
                                 class_weight='auto')
model.save('./flowers17_iv3_ft.h5')

可以看到經過兩個epoch的transfer learning后,驗證集准確率達到89.1%。再經過兩個epoch的fine tune后驗證集准確率達96.88%。可以看到遷移學習的效果還是很好的。

總結

  1. 學習了兩種常用遷移學習方法(tranfer learning,fine tune)及訓練技巧
  2. 學習了使用自己的數據樣本進行訓練
  3. 學習了加載Keras預置的經典模型
  4. 學習了如何在預置模型頂部添加新的層
  5. 學習了如何設置層的參數為不可訓練

本節課也是用Keras做CNN的一個完結,基本上涵蓋了從定義最簡單CNN到使用現成模型進行自己數據的遷移學習。下一階段看情況可能會出一個RNN系列的入門課。

參考

https://deeplearningsandbox.com/how-to-use-transfer-learning-and-fine-tuning-in-keras-and-tensorflow-to-build-an-image-recognition-94b0b02444f2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM