# 七、遷移學習
遷移學習的作用恰如其名。 這個想法是將從一項任務中學到的東西遷移到另一項任務上。 為什么? 實際上,每次都從頭開始訓練整個模型的效率很低,其成功取決于許多因素。 另一個重要原因是,對于某些應用,公開可用的數據集不夠大,無法訓練出像 AlexNet 或 ResNet 這樣的深層架構而又不會過擬合,這意味著無法推廣。 示例應用可以從用戶給出的一些示例中進行在線學習,也可以是細粒度的分類,其中類別之間的差異很小。
一個非常有趣的觀察結果是,由于您凍結了所有其余部分(無論是檢測還是分類),最終的層可以用于完成不同的任務,最終權重看起來非常相似。
這導致了遷移學習的想法。 這意味著在大量數據上訓練的深度架構(例如 ImageNet)可以很好地概括化,以至于其卷積權重可以充當特征提取器,類似于常規的視覺表示,并且可以用于為各種任務訓練線性分類器。
本章旨在教讀者如何在 TensorFlow 中采用現成的訓練有素的模型,更改其結構以及為特定任務重新訓練某些層。 我們將看到遷移學習將如何幫助改善結果并加快訓練時間。
本章涵蓋的主要主題如下:
* 使用來自另一個訓練過的模型的權重預先初始化一個模型
* 在需要時使用 TensorFlow 加載模型并凍結/解凍層
# 什么時候?
研究表明,在 ImageNet 上訓練的卷積網絡權重中的特征提取優于常規特征提取方法,例如 SURF,可變形部分描述符(**DPD**),**直方圖定向梯度**(**HOG**)和**詞袋**(**BoW**)。 這意味著無論常規視覺表示如何工作,卷積特征都可以同樣好地使用,唯一的缺點是更深的架構可能需要更長的時間來提取特征。
當在 ImageNet 上訓練深層卷積神經網絡時,第一層中的卷積過濾器的可視化(請參見下圖)顯示,他們學習了*低層*特征,類似于邊檢測過濾器,而卷積過濾器在最后一層學習*高級*功能,這些功能捕獲特定于類的信息。 因此,如果我們在第一個池化層之后提取 ImageNet 的特征并將其嵌入 2D 空間(例如,使用 t-SNE),則可視化將顯示數據中存在一些無中心狀態,而如果在全連接層上執行相同操作,我們將注意到具有相同語義信息的數據被組織成簇。 這意味著網絡可以在更高層次上很好地概括,并且有可能將這種知識遷移到看不見的類別中。

根據對與 ImageNet 相似度較小的數據集進行的實驗,在以下任務上,基于 ImageNet 訓練的基于卷積神經網絡權重的特征比常規特征提取方法的表現更好:
* **對象識別**:此 CNN 特征提取器可以成功地對其他類別不可見的數據集執行分類任務。
* **域適應**:這是當訓練和測試數據來自不同的分布,而標簽和類別數相同時。 不同的域可以考慮使用不同的設備或在不同的設置和環境條件下捕獲的圖像。 具有 CNN 功能的線性分類器可以在不同域中成功地將具有相同語義信息的圖像聚類,而 SURF 功能則可以針對特定領域的特征進行過擬合。
* **精細分類**:這是我們要在同一高級類中的子類之間進行分類的時候。 例如,我們可以對鳥類進行分類。 盡管沒有對細粒度數據進行訓練,但 CNN 功能以及邏輯回歸功能的表現優于基線方法。
* **場景識別**:在這里,我們需要對整個圖像的場景進行分類。 在對象分類數據庫上經過訓練的 CNN 特征提取器,頂部帶有一個簡單的線性分類器,其表現優于應用于識別數據的傳統特征提取器的復雜學習算法。
這里提到的某些任務與圖像分類沒有直接關系,圖像分類是 ImageNet 訓練的主要目標,因此有人希望 CNN 功能無法推廣到看不見的場景。 但是,這些功能與簡單的線性分類器相結合,表現優于手工制作的功能。 這意味著 CNN 的學習權重是可重用的。
那么什么時候應該使用遷移學習呢? 當我們有一個任務時,由于問題的性質,可用數據集很小(例如對螞蟻/蜜蜂進行分類)。 在這種情況下,我們可以在包含相似語義信息的較大數據集上訓練我們的模型,然后用較小的數據集僅訓練最后一層(線性分類器)。 如果我們只有足夠的可用數據,并且有一個更大的相似數據集,則對該相似數據集進行預訓練可能會導致模型更健壯。 通常情況下,我們使用隨機初始化的權重來訓練模型,在這種情況下,將使用在其他數據集上訓練過的權重來初始化模型。 這將有助于網絡更快地融合并更好地推廣。 在這種情況下,僅微調模型頂端的幾層是有意義的。
經驗法則是,從網絡頂部開始,可用數據越多,可以訓練的層就越多。 通過預訓練(例如在 ImageNet 上)模型初始化模型權重。
# 怎么樣? 概述
我們應該如何使用轉學? 有兩種典型的解決方法。 第一種不太及時的方法是使用所謂的預訓練模型,即預先在大型數據集(例如 ImageNet 數據集)上訓練過的模型。 這些經過預先訓練的模型可以在不同的深度學習框架中輕松獲得,并且通常被稱為“模型動物園”。 預訓練模型的選擇在很大程度上取決于當前要解決的任務是什么,以及數據集的大小。 選擇模型后,我們可以使用全部或部分模型作為要解決的實際任務的初始化模型。
深度學習的另一種不太常見的方式是自己預先訓練模型。 當可用的預訓練網絡不適合解決特定問題時,通常會發生這種情況,我們必須自己設計網絡架構。 顯然,這需要更多的時間和精力來設計模型和準備數據集。 在某些情況下,用于進行網絡預訓練的數據集甚至可以是合成的,可以從計算機圖形引擎(例如 3D Studio Max 或 Unity)或其他卷積神經網絡(例如 GAN)生成。 可以對虛擬數據進行預訓練的模型在真實數據上進行微調,并且可以與僅對真實數據進行訓練的模型一起很好地工作。
例如,如果我們想區分貓和狗,而我們沒有足夠的數據,則可以從“模型動物園”下載在 ImageNet 上訓練的網絡,并使用除最后一層以外的所有層的權重。 最后一層必須調整為具有與類數量相同的大小,在本例中為兩個,并且權重需要重新初始化和訓練。 這樣,通過將這些層的學習率設置為零或非常小的值(請參見下圖),我們將凍結那些不需訓練的層。 如果有更大的數據集,我們可以訓練最后三個全連接層。 有時,預訓練網絡只能用于初始化權重,然后再進行正常訓練。
遷移學習之所以有效,是因為在初始層計算出的特征更通用并且看起來很相似。 在頂層提取的特征對于我們要解決的問題變得更加具體。
為了進一步研究如何使用遷移學習,以及對該主題的更深刻理解,讓我們看一下代碼。

# 怎么樣? 代碼示例
在本節中,我們將學習在 TensorFlow 中進行遷移學習所需的實用技能。 更具體地說,我們將學習如何從檢查點選擇要加載的層,以及如何指示我們的求解器僅優化特定的層而凍結其他層。
# TensorFlow 有用的元素
由于遷移學習是關于訓練一個網絡的權重,而該網絡已從另一個訓練后的模型中獲取了權重,因此我們將需要找到一個。 在我們的示例中,我們將使用預訓練卷積自編碼器的編碼部分,該部分在第 6 章中進行了說明。 使用自編碼器的優點是我們不需要標記的數據,也就是說,可以完全不受監督地對其進行訓練。
# 沒有解碼器的自編碼器
包含兩個卷積層和一個完全連接層的編碼器(不帶解碼器部分的自編碼器)如下所示。 父自編碼器在 MNIST 數據集上進行了訓練。 因此,網絡將大小為`28x28x1`的圖像作為輸入,并在潛在空間將其編碼為 10 維向量,每個類別一維:
```py
# Only half of the autoencoder changed for classification
class CAE_CNN_Encoder(object):
......
def build_graph(self, img_size=28):
self.__x = tf.placeholder(tf.float32, shape=[None, img_size * img_size], name='IMAGE_IN')
self.__x_image = tf.reshape(self.__x, [-1, img_size, img_size, 1])
self.__y_ = tf.placeholder("float", shape=[None, 10], name='Y')
with tf.name_scope('ENCODER'):
##### ENCODER
# CONV1: Input 28x28x1 after CONV 5x5 P:2 S:2 H_out: 1 + (28+4-5)/2 = 14,
# W_out= 1 + (28+4-5)/2 = 14
self.__conv1_act = tf.layers.conv2d(inputs=self.__x_image, strides=(2, 2), name='conv1',
filters=16, kernel_size=[5, 5], padding="same", activation=tf.nn.relu)
# CONV2: Input 14x14x16 after CONV 5x5 P:0 S:2 H_out: 1 + (14+4-5)/2 = 7,
# W_out= 1 + (14+4-5)/2 = 7
self.__conv2_act = tf.layers.conv2d(inputs=self.__conv1_act, strides=(2, 2),
name='conv2', filters=32, kernel_size=[5, 5], padding="same", activation=tf.nn.relu)
with tf.name_scope('LATENT'):
# Reshape: Input 7x7x32 after [7x7x32]
self.__enc_out = tf.layers.flatten(self.__conv2_act, name='flatten_conv2')
self.__dense = tf.layers.dense(inputs=self.__enc_out, units=200, activation=tf.nn.relu, name='fc1')
self.__logits = tf.layers.dense(inputs=self.__dense, units=10, name='logits')
def __init__(self, img_size=28):
if CAE_CNN_Encoder.__instance is None:
self.build_graph(img_size)
@property
def output(self):
return self.__logits
@property
def labels(self):
return self.__y_
@property
def input(self):
return self.__x
@property
def image_in(self):
return self.__x_image
```
# 選擇層
一旦定義了模型`model = CAE_CNN_Encoder` `()`,選擇將要使用預訓練權重初始化的層就很重要。 請注意,兩個網絡的結構(要初始化的網絡和提供訓練后的權重的網絡)必須相同。 因此,例如,以下代碼片段將選擇名稱為`convs`為`fc`的所有層:
```py
from models import CAE_CNN_Encoder
model = CAE_CNN_Encoder()
list_convs = [v for v in tf.global_variables() if "conv" in v.name]
list_fc_linear = [v for v in tf.global_variables() if "fc" in v.name or "output" in v.name]
```
請注意,這些列表是從`tf.global_variables()`填充的; 如果選擇打印其內容,則可能會發現它包含所有模型變量,如下所示:
```py
[<tf.Variable 'conv1/kernel:0' shape=(5, 5, 1, 16) dtype=float32_ref>,
<tf.Variable 'conv1/bias:0' shape=(16,) dtype=float32_ref>,
<tf.Variable 'conv2/kernel:0' shape=(5, 5, 16, 32) dtype=float32_ref>,
<tf.Variable 'conv2/bias:0' shape=(32,) dtype=float32_ref>,
<tf.Variable 'fc1/kernel:0' shape=(1568, 200) dtype=float32_ref>,
<tf.Variable 'fc1/bias:0' shape=(200,) dtype=float32_ref>,
<tf.Variable 'logits/kernel:0' shape=(200, 10) dtype=float32_ref>,
<tf.Variable 'logits/bias:0' shape=(10,) dtype=float32_ref>]
```
將定義圖的層分為卷積和完全連接兩個列表后,您將使用`tf.Train.Saver`加載所需的權重。 首先,我們需要創建一個保存器對象,將要從檢查點加載的變量列表作為輸入,如下所示:
```py
# Define the saver object to load only the conv variables
saver_load_autoencoder = tf.train.Saver(var_list=list_convs)
```
除了`saver_load_autoencoder`,我們還需要創建另一個`saver`對象,該對象將允許我們將要訓練的網絡的所有變量存儲到檢查點中。
```py
# Define saver object to save all the variables during training
saver = tf.train.Saver()
```
然后,在使用`init = tf.global_variables_initializer()`初始化圖并創建會話之后,我們可以使用`saver_load_autoencoder`從檢查點恢復卷積層,如下所示:
```py
# Restore only the weights (From AutoEncoder)
saver_load_autoencoder.restore(sess, "../tmp/cae_cnn/model.ckpt-34")
```
請注意,調用`restore`會覆蓋`global_variables_initializer`,所有選定的權重都將替換為檢查點的權重。
# 僅訓練一些層
遷移學習的另一個重要部分是凍結不需要訓練的層的權重,同時允許對某些層(通常是最后一層)進行訓練。 在 TensorFlow 中,我們可以僅將要優化的層傳遞給求解器(在此示例中,僅將 FC 層傳遞給):
```py
train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss, var_list=list_fc_linear)
```
# 完整代碼
在此示例中,我們將從 MNIST 卷積自編碼器示例中加載權重。 我們將僅恢復編碼器部分的權重,凍結卷積層,并訓練 FC 層以執行數字分類:
```py
import tensorflow as tf
import numpy as np
import os
from models import CAE_CNN_Encoder
SAVE_FOLDER='/tmp/cae_cnn_transfer'
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
model = CAE_CNN_Encoder(latent_size = 20)
model_in = model.input
model_out = model.output
labels_in = model.labels
# Get all convs weights
list_convs = [v for v in tf.global_variables() if "conv" in v.name]
# Get fc1 and logits
list_fc_layers = [v for v in tf.global_variables() if "fc" in v.name or "logits" in v.name]
# Define the saver object to load only the conv variables
saver_load_autoencoder = tf.train.Saver(var_list=list_convs)
# Define saver object to save all the variables during training
saver = tf.train.Saver()
# Define loss for classification
with tf.name_scope("LOSS"):
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=model_out, labels=labels_in))
correct_prediction = tf.equal(tf.argmax(model_out,1), tf.argmax(labels_in,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# Solver configuration
with tf.name_scope("Solver"):
train_step = tf.train.AdamOptimizer(1e-4).minimize(loss, var_list=list_fc_layers)
# Initialize variables
init = tf.global_variables_initializer()
# Avoid allocating the whole memory
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.200)
sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options))
sess.run(init)
# Restore only the CONV weights (From AutoEncoder)
saver_load_autoencoder.restore(sess, "/tmp/cae_cnn/model.ckpt-34")
# Add some tensors to observe on tensorboad
tf.summary.image("input_image", model.image_in, 4)
tf.summary.scalar("loss", loss)
merged_summary = tf.summary.merge_all()
writer = tf.summary.FileWriter(SAVE_FOLDER)
writer.add_graph(sess.graph)
#####Train######
num_epoch = 200
batch_size = 10
for epoch in range(num_epoch):
for i in range(int(mnist.train.num_examples / batch_size)):
# Get batch of 50 images
batch = mnist.train.next_batch(batch_size)
# Dump summary
if i % 5000 == 0:
# Other summaries
s = sess.run(merged_summary, feed_dict={model_in:batch[0], labels_in:batch[1]})
writer.add_summary(s,i)
# Train actually here (Also get loss value)
_, val_loss, t_acc = sess.run((train_step, loss, accuracy), feed_dict={model_in:batch[0], labels_in:batch[1]})
print('Epoch: %d/%d loss:%d' % (epoch, num_epoch, val_loss))
print('Save model:', epoch)
saver.save(sess, os.path.join(SAVE_FOLDER, "model.ckpt"), epoch)
```
# 總結
在本章中,我們學習了如何,何時以及為什么使用遷移學習。 這被認為是一個非常強大的工具,因為它使我們能夠使用從其他領域學到的功能來以較少的數據很好地概括。 我們看了一些示例,現在應該清楚如何在自己的任務中實現遷移學習。
在下一章中,我們將看到如何組織我們的數據以及如何擴展 CNN 架構,以構建準確而實用的機器學習系統。
- TensorFlow 1.x 深度學習秘籍
- 零、前言
- 一、TensorFlow 簡介
- 二、回歸
- 三、神經網絡:感知器
- 四、卷積神經網絡
- 五、高級卷積神經網絡
- 六、循環神經網絡
- 七、無監督學習
- 八、自編碼器
- 九、強化學習
- 十、移動計算
- 十一、生成模型和 CapsNet
- 十二、分布式 TensorFlow 和云深度學習
- 十三、AutoML 和學習如何學習(元學習)
- 十四、TensorFlow 處理單元
- 使用 TensorFlow 構建機器學習項目中文版
- 一、探索和轉換數據
- 二、聚類
- 三、線性回歸
- 四、邏輯回歸
- 五、簡單的前饋神經網絡
- 六、卷積神經網絡
- 七、循環神經網絡和 LSTM
- 八、深度神經網絡
- 九、大規模運行模型 -- GPU 和服務
- 十、庫安裝和其他提示
- TensorFlow 深度學習中文第二版
- 一、人工神經網絡
- 二、TensorFlow v1.6 的新功能是什么?
- 三、實現前饋神經網絡
- 四、CNN 實戰
- 五、使用 TensorFlow 實現自編碼器
- 六、RNN 和梯度消失或爆炸問題
- 七、TensorFlow GPU 配置
- 八、TFLearn
- 九、使用協同過濾的電影推薦
- 十、OpenAI Gym
- TensorFlow 深度學習實戰指南中文版
- 一、入門
- 二、深度神經網絡
- 三、卷積神經網絡
- 四、循環神經網絡介紹
- 五、總結
- 精通 TensorFlow 1.x
- 一、TensorFlow 101
- 二、TensorFlow 的高級庫
- 三、Keras 101
- 四、TensorFlow 中的經典機器學習
- 五、TensorFlow 和 Keras 中的神經網絡和 MLP
- 六、TensorFlow 和 Keras 中的 RNN
- 七、TensorFlow 和 Keras 中的用于時間序列數據的 RNN
- 八、TensorFlow 和 Keras 中的用于文本數據的 RNN
- 九、TensorFlow 和 Keras 中的 CNN
- 十、TensorFlow 和 Keras 中的自編碼器
- 十一、TF 服務:生產中的 TensorFlow 模型
- 十二、遷移學習和預訓練模型
- 十三、深度強化學習
- 十四、生成對抗網絡
- 十五、TensorFlow 集群的分布式模型
- 十六、移動和嵌入式平臺上的 TensorFlow 模型
- 十七、R 中的 TensorFlow 和 Keras
- 十八、調試 TensorFlow 模型
- 十九、張量處理單元
- TensorFlow 機器學習秘籍中文第二版
- 一、TensorFlow 入門
- 二、TensorFlow 的方式
- 三、線性回歸
- 四、支持向量機
- 五、最近鄰方法
- 六、神經網絡
- 七、自然語言處理
- 八、卷積神經網絡
- 九、循環神經網絡
- 十、將 TensorFlow 投入生產
- 十一、更多 TensorFlow
- 與 TensorFlow 的初次接觸
- 前言
- 1.?TensorFlow 基礎知識
- 2. TensorFlow 中的線性回歸
- 3. TensorFlow 中的聚類
- 4. TensorFlow 中的單層神經網絡
- 5. TensorFlow 中的多層神經網絡
- 6. 并行
- 后記
- TensorFlow 學習指南
- 一、基礎
- 二、線性模型
- 三、學習
- 四、分布式
- TensorFlow Rager 教程
- 一、如何使用 TensorFlow Eager 構建簡單的神經網絡
- 二、在 Eager 模式中使用指標
- 三、如何保存和恢復訓練模型
- 四、文本序列到 TFRecords
- 五、如何將原始圖片數據轉換為 TFRecords
- 六、如何使用 TensorFlow Eager 從 TFRecords 批量讀取數據
- 七、使用 TensorFlow Eager 構建用于情感識別的卷積神經網絡(CNN)
- 八、用于 TensorFlow Eager 序列分類的動態循壞神經網絡
- 九、用于 TensorFlow Eager 時間序列回歸的遞歸神經網絡
- TensorFlow 高效編程
- 圖嵌入綜述:問題,技術與應用
- 一、引言
- 三、圖嵌入的問題設定
- 四、圖嵌入技術
- 基于邊重構的優化問題
- 應用
- 基于深度學習的推薦系統:綜述和新視角
- 引言
- 基于深度學習的推薦:最先進的技術
- 基于卷積神經網絡的推薦
- 關于卷積神經網絡我們理解了什么
- 第1章概論
- 第2章多層網絡
- 2.1.4生成對抗網絡
- 2.2.1最近ConvNets演變中的關鍵架構
- 2.2.2走向ConvNet不變性
- 2.3時空卷積網絡
- 第3章了解ConvNets構建塊
- 3.2整改
- 3.3規范化
- 3.4匯集
- 第四章現狀
- 4.2打開問題
- 參考
- 機器學習超級復習筆記
- Python 遷移學習實用指南
- 零、前言
- 一、機器學習基礎
- 二、深度學習基礎
- 三、了解深度學習架構
- 四、遷移學習基礎
- 五、釋放遷移學習的力量
- 六、圖像識別與分類
- 七、文本文件分類
- 八、音頻事件識別與分類
- 九、DeepDream
- 十、自動圖像字幕生成器
- 十一、圖像著色
- 面向計算機視覺的深度學習
- 零、前言
- 一、入門
- 二、圖像分類
- 三、圖像檢索
- 四、對象檢測
- 五、語義分割
- 六、相似性學習
- 七、圖像字幕
- 八、生成模型
- 九、視頻分類
- 十、部署
- 深度學習快速參考
- 零、前言
- 一、深度學習的基礎
- 二、使用深度學習解決回歸問題
- 三、使用 TensorBoard 監控網絡訓練
- 四、使用深度學習解決二分類問題
- 五、使用 Keras 解決多分類問題
- 六、超參數優化
- 七、從頭開始訓練 CNN
- 八、將預訓練的 CNN 用于遷移學習
- 九、從頭開始訓練 RNN
- 十、使用詞嵌入從頭開始訓練 LSTM
- 十一、訓練 Seq2Seq 模型
- 十二、深度強化學習
- 十三、生成對抗網絡
- TensorFlow 2.0 快速入門指南
- 零、前言
- 第 1 部分:TensorFlow 2.00 Alpha 簡介
- 一、TensorFlow 2 簡介
- 二、Keras:TensorFlow 2 的高級 API
- 三、TensorFlow 2 和 ANN 技術
- 第 2 部分:TensorFlow 2.00 Alpha 中的監督和無監督學習
- 四、TensorFlow 2 和監督機器學習
- 五、TensorFlow 2 和無監督學習
- 第 3 部分:TensorFlow 2.00 Alpha 的神經網絡應用
- 六、使用 TensorFlow 2 識別圖像
- 七、TensorFlow 2 和神經風格遷移
- 八、TensorFlow 2 和循環神經網絡
- 九、TensorFlow 估計器和 TensorFlow HUB
- 十、從 tf1.12 轉換為 tf2
- TensorFlow 入門
- 零、前言
- 一、TensorFlow 基本概念
- 二、TensorFlow 數學運算
- 三、機器學習入門
- 四、神經網絡簡介
- 五、深度學習
- 六、TensorFlow GPU 編程和服務
- TensorFlow 卷積神經網絡實用指南
- 零、前言
- 一、TensorFlow 的設置和介紹
- 二、深度學習和卷積神經網絡
- 三、TensorFlow 中的圖像分類
- 四、目標檢測與分割
- 五、VGG,Inception,ResNet 和 MobileNets
- 六、自編碼器,變分自編碼器和生成對抗網絡
- 七、遷移學習
- 八、機器學習最佳實踐和故障排除
- 九、大規模訓練
- 十、參考文獻