本文的keras后台為tensorflow,介紹如何利用預編譯的模型進行遷移學習,以訓練和識別自己的圖片集。
官網 https://keras.io/applications/ 已經介紹了各個基於ImageNet的預編譯模型,對於我們來說,既可以直接為我所用進行圖片識別,也可在其基礎上進行遷移學習,以滿足自己的需求。
但在遷移學習的例子中,並不描述的十分詳細,我將給出一個可運行的代碼,以介紹如何進行遷移學習。
from tensorflow.keras.applications.vgg19 import VGG19, preprocess_input from tensorflow.keras.models import Model from tensorflow.keras.layers import GlobalAveragePooling2D, Dense from tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array from tensorflow.keras.optimizers import SGD import tensorflow.keras.backend as K # 訓練和測試的圖片分為'bus', 'dinosaur', 'flower', 'horse', 'elephant'五類 # 其圖片的下載地址為 http://pan.baidu.com/s/1nuqlTnN ,總共500張圖片,其中圖片以3,4,5,6,7開頭進行按類區分 # 訓練圖片400張,測試圖片100張;注意下載后,在train和test目錄下分別建立上述的五類子目錄,keras會按照子目錄進行分類識別 NUM_CLASSES = 5 TRAIN_PATH = '/home/yourname/Documents/tensorflow/images/500pics/train' TEST_PATH = '/home/yourname/Documents/tensorflow/images/500pics/test' # 代碼最后挑出一張圖片進行預測識別 PREDICT_IMG = '/home/yourname/Documents/tensorflow/images/500pics/test/elephant/502.jpg' # FC層定義輸入層的大小 FC_NUMS = 1024 # 凍結訓練的層數,根據模型的不同,層數也不一樣,根據調試的結果,VGG19和VGG16c層比較符合理想的測試結果,本文采用VGG19做示例 FREEZE_LAYERS = 17 # 進行訓練和測試的圖片大小,VGG19推薦為224×244 IMAGE_SIZE = 224 # 采用VGG19為基本模型,include_top為False,表示FC層是可自定義的,拋棄模型中的FC層;該模型會在~/.keras/models下載基本模型 base_model = VGG19(input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3), include_top=False, weights='imagenet') # 自定義FC層以基本模型的輸入為卷積層的最后一層 x = base_model.output x = GlobalAveragePooling2D()(x) x = Dense(FC_NUMS, activation='relu')(x) prediction = Dense(NUM_CLASSES, activation='softmax')(x) # 構造完新的FC層,加入custom層 model = Model(inputs=base_model.input, outputs=prediction) # 可觀察模型結構 model.summary() # 獲取模型的層數 print("layer nums:", len(model.layers)) # 除了FC層,靠近FC層的一部分卷積層可參與參數訓練, # 一般來說,模型結構已經標明一個卷積塊包含的層數, # 在這里我們選擇FREEZE_LAYERS為17,表示最后一個卷積塊和FC層要參與參數訓練 for layer in model.layers[:FREEZE_LAYERS]: layer.trainable = False for layer in model.layers[FREEZE_LAYERS:]: layer.trainable = True for layer in model.layers: print("layer.trainable:", layer.trainable) # 預編譯模型 model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy', metrics=['accuracy']) # 給出訓練圖片的生成器, 其中classes定義后,可讓model按照這個順序進行識別 train_datagen = ImageDataGenerator() train_generator = train_datagen.flow_from_directory(directory=TRAIN_PATH, target_size=(IMAGE_SIZE, IMAGE_SIZE), classes=['bus', 'dinosaur', 'flower', 'horse', 'elephant']) test_datagen = ImageDataGenerator() test_generator = test_datagen.flow_from_directory(directory=TEST_PATH, target_size=(IMAGE_SIZE, IMAGE_SIZE), classes=['bus', 'dinosaur', 'flower', 'horse', 'elephant']) # 運行模型 model.fit_generator(train_generator, epochs=5, validation_data=test_generator) # 找一張圖片進行預測驗證 img = load_img(path=PREDICT_IMG, target_size=(IMAGE_SIZE, IMAGE_SIZE)) # 轉換成numpy數組 x = img_to_array(img) # 轉換后的數組為3維數組(224,224,3), # 而訓練的數組為4維(圖片數量, 224,224, 3),所以我們可擴充下維度 x = K.expand_dims(x, axis=0) # 需要被預處理下 x = preprocess_input(x) # 數據預測 result = model.predict(x, steps=1) # 最后的結果是一個含有5個數的一維數組,我們取最大值所在的索引號,即對應'bus', 'dinosaur', 'flower', 'horse', 'elephant'的順序 print("result:", K.eval(K.argmax(result)))
需要說明的是,各個預編譯模型在面臨不同的數據集時,其訓練效果表現不一,需要我們不斷地調整各種超參數,以期找到滿意的模型