Tensorflow2.0學習(十一) — 貓狗分類遷移學習實戰

這一節我們將用Tensorflow2.0完成一個圖像領域處理的重要任務,即是“遷移學習”。遷移學習簡單來說就是一個預訓練的模型(已經在別的數據集上訓練過的)重新使用在另一個數據集或任務中。遷移學習不僅大大減小了我們的新數據集的訓練時間和難度,而且使得模型的泛化能力更強。那麼這一節課我們就通過遷移學習來完成一個貓狗分類的例子。關於遷移學習的底層原理或更多信息,朋友們可以觀看其它博主更詳細的博客,或者博主在後續的博客更新中也會提到更深的原理部分。

順便附上Tensorflow官方教程的鏈接:https://tensorflow.google.cn/tutorials/images/transfer_learning

一.數據集的加載

1.導入相關庫。

from __future__ import absolute_import, division, print_function, unicode_literals
import os 
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import tensorflow_datasets as tfds
import tensorflow.contrib.eager as tfe

2.允許Tensorflow的eager execution模塊運行。

tf.enable_eager_execution()

3.數據集的劃分和加載。其中(8,1,1)分別代表訓練集、測試集和驗證集的比例。tfds.load中的with_info如果是true代表返回的數據集是一個元組,裏面不僅僅包含了數據集還包含了和數據集有關的一切信息。而as_supervised=True則代表返回的是數據集特徵+標籤,如果是False那麼只僅僅返回了數據集特徵而沒有標籤。

split_weights = (8,1,1) #數據劃分的比例
splits = tfds.Split.TRAIN.subsplit(weighted=split_weights)
(raw_train,raw_validation,raw_test),metadata = tfds.load('cats_vs_dogs',split=list(splits),with_info=True,as_supervised=True)

4.查看切分的數據集信息。

print(raw_train)
print(raw_validation)
print(raw_test)

可以看出返回的types中包含了unit8(圖片)和int64(標籤)。

5.將標籤轉爲字符串並定義顯示函數查看圖片。

get_label_name = metadata.features['label'].int2str #數字轉字符串
for image, label in raw_train.take(2): #顯示2張圖片
  plt.figure()
  plt.imshow(image)
  plt.title(get_label_name(label))

6.定義圖片預處理函數並用tf.dataset相關的映射函數對數據集進行預處理以及劃定batch_size的大小。

IMG_SIZE =100

def format_example(image,label):
  image = tf.cast(image,tf.float32) #將圖片轉爲float32格式
  image = image/255.0 #圖片歸一化
  image = tf.image.resize(image,(IMG_SIZE,IMG_SIZE)) #修改圖片尺寸
  return image,label

train = raw_train.map(format_example) #將預處理函數映射到數據中
valiadation = raw_validation.map(format_example)
test = raw_test.map(format_example)
batch_size = 32
shuffle_buffer_size = 1000 #訓練緩存空間大小
train_batches = train.shuffle(shuffle_buffer_size).batch(batch_size)
valiadation_batches = valiadation.batch(batch_size)
test_batches = test.batch(batch_size)

7.查看經過預處理後,圖片的尺寸。

for image_batch,label_batch in train_batches.take(1): #取一張圖片
  pass
image_batch.shape

可以看出圖片尺寸已成功被預處理了。

二.預訓練模型的加載

1.在這次訓練遷移學習中,我們使用google的預訓練後的MobileNetV2來作爲base_model,在這裏我們的include_top參數設爲False,因爲我們只需要預訓練模型的前面層,而最後一層(分類的輸出個數)必須要滿足我們現在任務的需求,因此需要重新定義。而weight='imagenet'的意思則爲,該預訓練模型的權重是採用在imagenet數據上訓練後的權重。

image_shape = (IMG_SIZE,IMG_SIZE,3)
base_model = tf.keras.applications.MobileNetV2(input_shape=image_shape,include_top=False,weights='imagenet')

2.查看一個image_batch輸入模型後的輸出是什麼樣的。

feature_batch = base_model(image_batch)
print(feature_batch.shape)

3.將模型的可訓練模式設爲False。這裏的意思是說我模型訓練時權重參數不可再改變,凍結所有層並以之前imagenet訓練的權重參數進行訓練。

base_model.trainable = False

4.定義top層來滿足我們本次任務的需要(分類個數),原因看第1點。這裏globalaveragepooling2D層相當於全連接層,基本在遷移學習中都是用它來將前面特徵數量轉爲單維向量。

global_average_layer = tf.keras.layers.GlobalAveragePooling2D() 
feature_batch_average = global_average_layer(feature_batch) #輸入該層並查看輸出
print(feature_batch_average.shape)

5.定義最後的分類結果層並查看輸出結果。

prediction_layer = tf.keras.layers.Dense(1)
prediction_batch = prediction_layer(feature_batch_average)
print(prediction_batch.shape)

6.將base_model和後面top層混合一起。

model = tf.keras.Sequential([
    base_model,
    global_average_layer,
    prediction_layer                 
])

三.模型的參數設置及訓練。

1.模型相關參數設置。因爲爲二分類任務(貓和狗),因此loss函數爲binary_crossentropy。

base_learning_rate = 0.0001
model.compile(optimizer=tf.keras.optimizers.RMSprop(lr=base_learning_rate),
              loss='binary_crossentropy',
              metrics=['accuracy'])

2.打印模型概要。

model.summary()

3.設置模型訓練次數。爲了加快訓練時間,這裏epochs選爲2。

initial_epochs = 2
steps_per_epoch = 10
validation_steps = 20

4.模型訓練。

history = model.fit(train_batches,epochs=initial_epochs,validation_data=valiadation_batches)

5.定義函數訓練過程顯示函數並查看結果曲線。

def show_train_history(train_history,train,validation):
    plt.plot(train_history.history[train]) #繪製訓練數據的執行結果
    plt.plot(train_history.history[validation]) #繪製驗證數據的執行結果
    plt.title('Train History') #圖標題 
    plt.xlabel('epoch') #x軸標籤
    plt.ylabel(train) #y軸標籤
    plt.legend(['train','validation'],loc='upper left') #添加左上角圖例
show_train_history(history,'acc','val_acc')

四.對模型進行微調並訓練。

我們還可以通過微調的方式提高模型的訓練成功率。什麼是微調?這裏指的是凍結預訓練模型MobileNetV2的基礎層(基礎層提取的圖片特徵基本適用於大部分圖片,所以不微調這部分),微調它的後面一些重要的分類層,對它們進行解凍然後訓練。

1.將模型首先設爲可訓練的,然後查看模型的總層數,設置101層-155層爲可訓練,前面100層爲不可訓練。

base_model.trainble = True
print(len(base_model.layers))
fine_tune_at = 100
for layer in base_model.layers[:fine_tune_at]:
  layer.trainble = False

2.模型參數重新設置,調低學習率。

model.compile(loss='binary_crossentropy',optimizer=tf.keras.optimizers.RMSprop(lr=base_learning_rate/10),metrics=['accuracy'])

3.模型重新訓練次數設置。訓練次數同樣爲2次。

fine_tune_epochs=2
total_epochs =  initial_epochs + fine_tune_epochs

4.模型重新訓練。這邊initial_epoch的意思爲從上次的訓練之後再接着訓練。

history_fine = model.fit(train_batches,epochs=total_epochs,initial_epoch=history.epoch[-1],validation_data=valiadation_batches)

5.查看訓練結果曲線。

 

本節分享了一個遷移學習的實例,朋友們如果有興趣還可以試試其它的pretrained的base_model並看看結果如何。謝謝你們的觀看和支持!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章