一.遷移學習的概念
什么是遷移學習呢?遷移學習可以由下面的這張圖來表示:
這張圖最左邊表示了遷移學習也就是把已經訓練好的模型和權重直接納入到新的數據集當中進行訓練,但是我們只改變之前模型的分類器(全連接層和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
一次迭代准確率已經達到了百分之六十。怎么樣呢?你現在對遷移學習有一定的感覺了嗎?