一.遷移學習的概念
什麼是遷移學習呢?遷移學習可以由下面的這張圖來表示:
這張圖最左邊表示了遷移學習也就是把已經訓練好的模型和權重直接納入到新的資料集當中進行訓練,但是我們只改變之前模型的分類器(全連線層和softmax/sigmoid),這樣就可以節省訓練的時間的到一個新訓練的模型了!
但是為什麼可以這麼做呢?
二.為什麼可以使用遷移學習?
一般在影像分類的問題當中,卷積神經網路最前面的層用於識別影像最基本的特徵,比如物體的輪廓,顏色,紋理等等,而後面的層才是提取影像抽象特徵的關鍵,因此最好的辦法是我們只需要保留卷積神經網路當中底層的權重,對頂層和新的分類器進行訓練即可。那麼在影像分類問題當中,我們如何使用遷移學習呢?一般使用遷移學習,也就是預訓練神經網路的步驟如下;
1.凍結預訓練網路的卷積層權重
2.置換舊的全連線層,換上新的全連線層和分類器
3.解凍部分頂部的卷積層,保留底部卷積神經網路的權重
4.同時對卷積層和全連線層的頂層進行聯合訓練,得到新的網路權重
既然我們知道了遷移學習的基本特點,何不試試看呢?
三.遷移學習的程式碼實現
我們使用遷移學習的方法來進行貓狗影像的分類識別,貓貓的影像在我的資料夾裡如下圖所示:
然後導包:
import tensorflow as tf from tensorflow import keras import matplotlib.pyplot as plt import numpy as np import glob import os
獲取圖片的路徑,標籤,製作batch資料,圖片的路徑我存放在了F盤下的train資料夾下,路徑為:F://UNIVERSITY STUDY/AI/dataset/catdog/train/。
程式碼如下:
keras=tf.keras layers=tf.keras.layers #得到圖片的所有label train_image_label=[int(p.split("\\")[1]=='cat') for p in train_image_path ] #現在我們的jpg檔案進行解碼,變成三維矩陣 def load_preprosess_image(path,label): #讀取路徑 image=tf.io.read_file(path) #解碼 image=tf.image.decode_jpeg(image,channels=3)#彩色影像為3個channel #將影像改變為同樣的大小,利用裁剪或者扭曲,這裡應用了扭曲 image=tf.image.resize(image,[360,360]) #隨機裁剪影像 image=tf.image.random_crop(image,[256,256,3]) #隨機上下翻轉影像 image=tf.image.random_flip_left_right(image) #隨機上下翻轉 image=tf.image.random_flip_up_down(image) #隨機改變影像的亮度 image=tf.image.random_brightness(image,0.5) #隨機改變對比度 image=tf.image.random_contrast(image,0,1) #改變資料型別 image=tf.cast(image,tf.float32) #將影像進行歸一化 image=image/255 #現在還需要對label進行處理,我們現在是列表[1,2,3], #需要變成[[1].[2].[3]] label=tf.reshape(label,[1]) return image,label train_image_ds=tf.data.Dataset.from_tensor_slices((train_image_path,train_image_label)) AUTOTUNE=tf.data.experimental.AUTOTUNE#根據計算機效能進行運算速度的調整 train_image_ds=train_image_ds.map(load_preprosess_image,num_parallel_calls=AUTOTUNE) #現在train_image_ds就讀取進來了,現在進行亂序和batchsize的規定 BATCH_SIZE=32 train_count=len(train_image_path) #現在設定batch和亂序 train_image_ds=train_image_ds.shuffle(train_count).batch(BATCH_SIZE) train_image_ds=train_image_ds.prefetch(AUTOTUNE)#預處理一部分處理,準備讀取 imags,labels=iter(train_image_ds).next()#放到生成器裡,單獨取出資料 plt.imshow(imags[30])
顯示出製作batch資料當中的貓貓圖片:
搭建網路架構,引入經典影像分類模型VGG16,同時呼叫VGG16預訓練網路的權重。最後調整卷積層的最後三層為可訓練的,也就是說頂層的卷積神經網路可以和全連線層分類器一起進行聯合訓練:
conv_base=keras.applications.VGG16(weights='imagenet',include_top=False) #weights設定為imagenet表示使用imagebnet訓練出來的權重,如果填寫False表示不使用權重 #僅適用網路架構,include_top表示是否使用用於分類的全連線層 #我們在這個卷積層上新增全連線層和輸出層即可 model=keras.Sequential() model.add(conv_base) model.add(layers.GlobalAveragePooling2D()) model.add(layers.Dense(512,activation='relu')) model.add(layers.Dense(1,activation='sigmoid')) conv_base.trainable=True#一共有19層 for layer in conv_base.layers[:-3]: layer.trainable=False #從第一層到倒數第三層重新設定為是不可訓練的,現在卷積的頂層已經解凍,開始聯合訓練 #編譯這個網路 model.compile(optimizer=keras.optimizers.Adam(lr=0.001), loss='binary_crossentropy', metrics=['acc']) history=model.fit( train_image_ds, steps_per_epoch=train_count//BATCH_SIZE, epochs=1 )
僅僅訓練一個epoch的結果如下所示;
Train for 62 steps 62/62 [==============================] - 469s 8s/step - loss: 0.6323 - acc: 0.6159
一次迭代準確率已經達到了百分之六十。怎麼樣呢?你現在對遷移學習有一定的感覺了嗎?