這一節我們將用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並看看結果如何。謝謝你們的觀看和支持!