深度學習-遷移學習流程及代碼解析

遷移學習

是機器學習方法之一,它可以把為一個任務開發的模型重新用在另一個不同的任務中,並作為另一個任務模型的起點。

這在深度學習中是一種常見的方法。由於在計算機視覺和自然語言處理上,開發神經網絡模型需要大量的計算和時間資源,技術跨度也比較大。所以,預訓練的模型通常會被重新用作計算機視覺和自然語言處理任務的起點。

遷移學習一般流程

  1. 訓練好一個網絡(base network)
  2. 把前n層複製到target network的前n層
  3. target network剩下的其他層隨機初始化
  4. 開始訓練target task。在做backpropogate(反向傳播)的時候

有兩種方法:

  • 把遷移過來的這前n層frozen(凍結)起來,即在訓練target task的時候,不改變這n層的值;
  • 不凍結這前n層,而是會不斷調整它們的值,稱為fine-tune(微調)。

這個主要取決於target數據集的大小和前n層的參數個數,

如果target數據集很小,而參數個數很多,為了防止overfitting(過擬合),

通常採用frozen方法;反之,採用fine-tune。

Keras模型

Kera的應用模塊Application提供了帶有預訓練權重的Keras模型,這些模型可以用來進行預測、特徵提取和遷移學習/finetune。

比如常見模型:

  • Xception
  • VGG16
  • VGG19
  • ResNet50
  • InceptionV3

vgg16_weights_th_dim_ordering_th_kernels_notop.h5

vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5

vgg16_weights_tf_dim_ordering_tf_kernels.h5

對於tf和th說明

Keras提供了兩套後端,Theano和Tensorflow,

th和tf的大部分功能都被backend統一包裝起來了,但二者還是存在衝突,

比如:

dim_ordering,也就是維度順序。比方說一張224*224的彩色圖片,theano的維度順序是(3,224,224),即通道維在前。而tf的維度順序是(224,224,3),即通道維在後。

所以不同的後端,需要選用不同的權重文件。

notop說明:

是否包含最後的全連接層,notop表示沒有包括最後的全連接層。

為何把全連接層和卷積層分開:

一般來說卷積層用於特徵提取,全連接層用於分類。這也是為什麼一般來說,在較多的情況下,卷積層的權重進行凍結或finetune,而全連接層用於重新設計和新的訓練。當然,如果在包括全連接層的情況下,根據已有模型與自己分類任務的契合度,也是可以用新的數據進行finetune全連接層的。

流程分析:

1. 訓練好一個網絡(稱它為base network)

2. 把它的前n層複製到target network的前n層

3. target network剩下的其他層隨機初始化

注意看前面講過的遷移學習的基本流程,是把已有模型的前n層的權重數據複製來,大家是否有思考過這個n怎麼來合理的確定呢?

根據前面的講述,一般這個n層就是前面的所有卷積層,但是在實際應用中,是可以根據實驗來測試一個更加有效的n值,即:只是固定使用或finetune部分的卷積層,其他卷積層仍然是隨機初始化後進行訓練。

VGG16的一個例子分析


# coding: utf-8

# In[1]:

import numpy as np

from keras.datasets import mnist

import gc

from keras.models import Sequential, Model

from keras.layers import Input, Dense, Dropout, Flatten

from keras.layers.convolutional import Conv2D, MaxPooling2D

from keras.applications.vgg16 import VGG16

from keras.optimizers import SGD

import cv2

import h5py as h5py

import numpy as np

# In[2]:

def tran_y(y):

y_ohe = np.zeros(10)

y_ohe[y] = 1

return y_ohe

# In[4]:

# 直接使用下載的數據

data_dir = 'F:/2019-notebook/2017_2018_2/python_code/MTrain/MachineLearn/3_ML/20_TransferLearn/'

path=data_dir + 'mnist.npz'

f = np.load(path)

X_train, y_train = f['x_train'], f['y_train']

X_test, y_test = f['x_test'], f['y_test']

#(X_train, y_train), (X_test, y_test) = mnist.load_data()

# print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)

# VGG模型需要的圖像的大小至少48,三個通道

ishape=48

X_train = [cv2.cvtColor(cv2.resize(i, (ishape, ishape)), cv2.COLOR_GRAY2BGR) for i in X_train]

#(48,48,3) -> (60000,48,48,3)

X_train = np.concatenate([arr[np.newaxis] for arr in X_train]).astype('float32')

X_train /= 255.0

X_test = [cv2.cvtColor(cv2.resize(i, (ishape, ishape)), cv2.COLOR_GRAY2BGR) for i in X_test]

X_test = np.concatenate([arr[np.newaxis] for arr in X_test]).astype('float32')

X_test /= 255.0

#0-9 轉為one hot數據

# 0 -> 1 0 0 0 0 0 0 0 0 0

# 1 -> 0 1 0 0 0 0 0 0 0 0

y_train_ohe = np.array([tran_y(y_train[i]) for i in range(len(y_train))])

y_test_ohe = np.array([tran_y(y_test[i]) for i in range(len(y_test))])

y_train_ohe = y_train_ohe.astype('float32')

y_test_ohe = y_test_ohe.astype('float32')

# In[4]:

print(X_train.shape)

# VGG16 全參重訓遷移學習,包括卷積層參數,在原來的基礎上訓練

# In[5]:

# 使用已經下載的權重

# 如果使用weights = 'imagenet'參數,系統會自動將model文件下載到 C:\\Users\\Think\\.keras\\models

# model_vgg = VGG16(include_top = False, weights = 'imagenet', input_shape = (ishape,ishape,3))

weights_path = data_dir + 'vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5'

model_vgg = VGG16(include_top = False, weights = weights_path, input_shape = (ishape,ishape,3))

# 卷積層的權重也參與訓練

for layer in model_vgg.layers:

layer.trainable = True

model = Flatten(name = 'flatten')(model_vgg.output)

model = Dense(4096, activation='relu', name='fc1')(model)

model = Dense(4096, activation='relu', name='fc2')(model)

model = Dropout(0.5)(model)

model = Dense(10, activation = 'softmax')(model)

model_vgg_mnist = Model(model_vgg.input, model, name = 'vgg16')

model_vgg_mnist.compile(loss = 'categorical_crossentropy', optimizer = 'adagrad', metrics = ['accuracy'])

model_vgg_mnist.summary()

# In[6]:

# fine tune

model_vgg_mnist.fit(X_train, y_train_ohe, validation_data = (X_test, y_test_ohe), epochs = 2, batch_size = 128)

# 直接使用VGG16如果發現擬合效果不好。一個解決辦法是將卷積層的參數固化,不參與訓練,只是訓練全連接層權重。

深度學習-遷移學習流程及代碼解析

樣本遷移



分享到:


相關文章: