【深度学习】迁移学习理论与实践
?遷移學習
Author:louwill
From:深度學習筆記
? ? ?在深度學習模型日益龐大的今天,并非所有人都能滿足從頭開始訓練一個模型的軟硬件條件,稀缺的數據和昂貴的計算資源都是我們需要面對的難題。遷移學習(Transfer Learning)可以幫助我們緩解在數據和計算資源上的尷尬。作為當前深度學習領域中最重要的方法論之一,遷移學習有著自己自身的理論依據和實際效果驗證。
? ?
遷移學習:深度學習未來五年的驅動力?
? ? ?作為一門實驗性學科,深度學習通常需要反復的實驗和結果論證。在現在和將來,是否有海量的數據資源和強大的計算資源,這是決定學界和業界深度學習和人工智能發展的關鍵因素。通常情況下,獲取海量的數據資源對于企業而言并非易事,尤其是對于像醫療等特定領域,要想做一個基于深度學習的醫學影像的輔助診斷系統,大量且高質量的打標數據非常關鍵。但通常而言,不要說高質量,就是想獲取大量的醫療數據就已困難重重。
圖9.1 吳恩達說遷移學習
? ? ?那怎么辦呢?是不是獲取不了海量的數據研究就一定進行不下去了?當然不是。因為我們有遷移學習。那究竟什么是遷移學習?顧名思義,遷移學習就是利用數據、任務或模型之間的相似性,將在舊的領域學習過或訓練好的模型,應用于新的領域這樣的一個過程。從這段定義里面,我們可以窺見遷移學習的關鍵點所在,即新的任務與舊的任務在數據、任務和模型之間的相似性。
? ? ?在很多沒有充分數據量的特定應用上,遷移學習會是一個極佳的研究方向。正如圖9.1中吳恩達所說,遷移學習會是機器學習在未來五年內的下一個驅動力量。
遷移學習的使用場景
? ? ?遷移學習到底在什么情況下使用呢?是不是我模型訓練不好就可以用遷移學習進行改進?當然不是。如前文所言,使用遷移學習的主要原因在于數據資源的可獲得性和訓練任務的成本。當我們有海量的數據資源時,自然不需要遷移學習,機器學習系統很容易從海量數據中學習到一個很穩健的模型。但通常情況下,我們需要研究的領域可獲得的數據極為有限,僅靠有限的數據量進行學習,所習得的模型必然是不穩健、效果差的,通常情況下很容易造成過擬合,在少量的訓練樣本上精度極高,但是泛化效果極差。另一個原因在于訓練成本,即所依賴的計算資源和耗費的訓練時間。通常情況下,很少有人從頭開始訓練一整個深度卷積網絡,一個是上面提到的數據量的問題,另一個就是時間成本和計算資源的問題,從頭開始訓練一個卷積網絡通常需要較長時間且依賴于強大的GPU計算資源,對于一門實驗性極強的領域而言,花費好幾天乃至一周的時間去訓練一個深度神經網絡通常是代價巨大的。
? ? ?所以,遷移學習的使用場景如下:假設有兩個任務系統A和B,任務A擁有海量的數據資源且已訓練好,但并不是我們的目標任務,任務B是我們的目標任務,但數據量少且極為珍貴,這種場景便是典型的遷移學習的應用場景。那究竟什么時候使用遷移學習是有效的呢?對此我們不敢武斷地下結論。但必須如前文所言,新的任務系統和舊的任務系統必須在數據、任務和模型等方面存在一定的相似性,你將一個訓練好的語音識別系統遷移到放射科的圖像識別系統上,恐怕結果不會太妙。所以,要判斷一個遷移學習應用是否有效,最基本的原則還是要遵守,即任務A和任務B在輸入上有一定的相似性,即兩個任務的輸入屬于同一性質,要么同是圖像、要么同是語音或其他,這便是前文所說到的任務系統的相似性的含義之一。
深度卷積網絡的可遷移性
? ? ?還有一個值得探討的問題在于,深度卷積網絡的可遷移性在于什么?為什么說兩個任務具有同等性質的輸入舊具備可遷移性?一切都還得從卷積神經網絡的基本原理說起。由之前的學習我們知道,卷積神經網絡具備良好的層次結構,通常而言,普通的卷積神經網絡都具備卷積-池化-卷積-池化-全連接這樣的層次結構,在深度可觀時,卷積神經網絡可以提取圖像各個level的特征。如圖9.2所示,當我們要從圖像中識別一張人臉的時候,通常在一開始我們會檢測到圖像的橫的、豎的等邊緣特征,然后會檢測到臉部的一些曲線特征,再進一步會檢測到臉部的鼻子、眼睛和嘴巴等具備明顯識別要素的特征。
圖9.2 CNN人臉特征的逐層提取
? ? ?這便揭示了深度卷積網絡可遷移性的基本原理和卷積網絡訓練過程的基本事實。具備良好層次的深度卷積網絡通常都是在最初的前幾層學習到圖像的通用特征(General Feature),但隨著網絡層次的加深,卷積網絡便逐漸開始檢測到圖像的特定的特征,兩個任務系統的輸入越相近,深度卷積網絡檢測到的通用特征越多,遷移學習的效果越好。
遷移學習的使用方法
? ? ?通常而言,遷移學習有兩種使用方式。第一種便是常說的Finetune,即微調,簡單而言就是將別人訓練好的網絡拿來進行簡單修改用于自己的學習任務。在實際操作中,通常用預訓練的網絡權值對自己網絡的權值進行初始化,以代替原先的隨機初始化。第二種稱為 Fixed Feature Extractor,即將預訓練的網絡作為新任務的特征提取器,在實際操作中通常將網絡的前幾層進行凍結,只訓練最后的全連接層,這時候預訓練網絡便是一個特征提取器。
? ? ?Keras為我們提供了經典網絡在ImageNet上為我們訓練好的預訓練模型,預訓練模型的基本信息如表1所示。
表1?Keras主要預訓練模型
? ? ?以上是遷移學習的基本理論和方法簡介,下面來看一個簡單的示例,來看看遷移學習的實際使用方法。
基于ResNet的遷移學習實驗
? ? ?我們以一組包含五種類別花朵數據為例,使用ResNet50預訓練模型進行遷移學習嘗試。數據地址為https://www.kaggle.com/fleanend/flowers-classification-with-transfer-learning/#data。下載數據后解壓可見共有5個文件夾,每個文件夾是一種花類,具體信息如下表2所示。
? ? ?5種花型加起來不過是3669張圖片,數據量不算小樣本但也絕對算不上多。所以我們采取遷移學習的策略來搭建花朵識別系統。花型圖片大致如圖所示。
圖 flowers數據集示例
需要導入的package,如代碼9.1所示。
# 導入相關模塊 import os import pandas as pd import numpy as np import cv2 import matplotlib.pyplot as plt from PIL import Image from sklearn.preprocessing import LabelEncoder from sklearn.model_selection import train_test_split import keras from keras.models import Model from keras.layers import Dense, Activation, Flatten, Dropout from keras.utils import np_utils from keras.applications.resnet50 import ResNet50 from?tqdm?import?tqdm提取數據標簽
數據沒有單獨給出標簽文件,需要我們自行通過文件夾提取每張圖片的標簽,建立標簽csv文件,如代碼所示。
def generate_csv(path):labels = pd.DataFrame()# 目錄下每一類別文件夾items = [f for f in os.listdir(path)]# 遍歷每一類別文件夾for i in tqdm(items):# 生成圖片完整路徑images = [path + I + '/' + img for img in os.listdir(path+i)]# 生成兩列:圖像路徑和對應標簽labels_data = pd.DataFrame({'images': images, ‘labels’: i})# 逐條記錄合并labels = pd.concat((labels, labels_data))# 打亂順序labels = labels.sample(frac=1, random_state=42)return labels# 生成標簽并查看前5行 labels = generate_csv('./flowers/') labels.head()標簽提取結果示例如圖9.4所示。
圖9.4 提取標簽結果
圖片預處理
通過試驗可知每張圖片像素大小并不一致,所以在搭建模型之前,我們需要對圖片進行整體縮放為統一尺寸。我們借助opencv的Python庫cv2可以輕松實現圖片縮放,因為后面我們的遷移學習策略采用的是ResNet50作為預訓練模型,所以我們這里將圖片縮放大小為 224*224*3。單張圖片的resize示例如下。圖9.5所示是一張玫瑰的原圖展示。
圖9.5 縮放前的原圖
縮放如代碼所示。縮放后的效果和尺寸如圖9.6所示。
# resize縮放 img = cv2.resize(img, (224, 224)) # 轉換成RGB色彩顯示 img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) plt.imshow(img) plt.xticks([]) plt.yticks([])圖9.6 縮放后的效果
批量讀取縮放如代碼所示。
# 定義批量讀取并縮放 def read_images(df, resize_dim):total = 0images_array = []# 遍歷標簽文件中的圖像路徑for i in tqdm(df.images):# 讀取并resizeimg = cv2.imread(i)img_resized = cv2.resize(img, resize_dim)total += 1# 存入圖像數組中images_array.append(img_resized)print(total, 'iamges have resized.')return images_array# 批量讀取 images_array = read_images(labels, (224, 224))原始圖片并不復雜,所以除了對其進行縮放處理之外基本無需多做處理。下一步我們需要準備訓練和驗證數據。
準備數據
處理好的圖片無法直接拿來訓練,我們需要將其轉化為Numpy數組的形式,另外,標簽也需要進一步的處理,如代碼所示。
# 轉化為圖像數組 X = np.array(images_array) # 標簽編碼 lbl = LabelEncoder().fit(list(labels['labels'].values)) labels['code_labels']=pd.DataFrame(lbl.transform(list(labels['labels'].values))) # 分類標簽轉換 y = np_utils.to_categorical(labels.code_labels.values, 5)轉化后的圖像數組大小為 3669*224*224*3,標簽維度為3669*5,跟我們的實際數據一致。數據的準備好后,可以用Sklearn劃分一下數據集:
# 劃分為訓練和驗證集 X_train, X_valid, y_train, y_valid = train_test_split(X,y,test_size=0.2, random_state=42)然后可以用Keras的ImageDataGenerator模塊來按批次生成訓練數據,并對訓練集做一些簡單的數據增強,如下代碼所示。
# 訓練集生成器,中間做一些數據增強 train_datagen = ImageDataGenerator(rescale=1./255,rotation_range=40,width_shift_range=0.4,height_shift_range=0.4,shear_range=0.2,zoom_range=0.3,horizontal_flip=True )# 驗證集生成器,無需做數據增強 val_datagen = ImageDataGenerator(rescale=1./255 )# 按批次導入訓練數據 train_generator = train_datagen.flow(X_train,y_train,batch_size=32 )# 按批次導入驗證數據 val_generator = val_datagen.flow(X_valid,y_valid,batch_size=32 )訓練和驗證數據劃分完畢,現在我們可以利用遷移學習模型進行訓練了。
基于resnet50的遷移學習模型
試驗模型的基本策略就是使用預訓練模型的權重作為特征提取器,將預訓練的權重進行凍結,只訓練全連接層。構建模型如下代碼所示。
# 定義模型構建函數 def flower_model():base_model=ResNet50(include_top=False,weights='imagenet', input_shape=(224, 224, 3))# 凍結base_model的層,不參與訓練 for layers in base_model.layers:layers.trainable = False# base_model的輸出并展平model = Flatten()(base_model.output)# 添加批歸一化層model = BatchNormalization()(model)# 全連接層model=Dense(2048,activation='relu', kernel_initializer=he_normal(seed=42))(model)# 添加批歸一化層model = BatchNormalization()(model)# 全連接層model=Dense(1024,activation='relu', kernel_initializer=he_normal(seed=42))(model)# 添加批歸一化層model = BatchNormalization()(model)# 全連接層并指定分類數和softmax激活函數model = Dense(5, activation='softmax')(model)model = Model(inputs=base_model.input, outputs=model)# 指定損失函數、優化器、性能度量標準并編譯model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])return model最后執行訓練:
# 調用模型 model = flower_model() # 使用fit_generator方法執行訓練 flower_model.fit_generator(generator=train_generator,steps_per_epoch=len(train_data)/32, epochs=30,validation_steps=len(val_data)/32,validation_data=val_generator,verbose=2)訓練過程如圖9.7所示。
圖9.7 遷移學習訓練過程
經過20個epoch訓練之后,驗證集準確率會達到90%以上,讀者朋友們可自行嘗試一些模型改進方案來達到更高的精度。各位讀者可以嘗試分別使用VGG16、Inception v3和Xception來測試本講的花朵識別實驗。
往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習及深度學習筆記等資料打印機器學習在線手冊深度學習筆記專輯《統計學習方法》的代碼復現專輯 AI基礎下載機器學習的數學基礎專輯獲取一折本站知識星球優惠券,復制鏈接直接打開:https://t.zsxq.com/662nyZF本站qq群1003271085。加入微信群請掃碼進群(如果是博士或者準備讀博士請說明):總結
以上是生活随笔為你收集整理的【深度学习】迁移学习理论与实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【小白学PyTorch】7.最新版本to
- 下一篇: 【学术相关】数学公式如何用Markdow