要解決一個復雜問題,可能要訓練更深的神經網絡,可能會10層及以上,每層包含數百個神經元,成千上萬個連接。這樣大的神經網絡在訓練的時候可能會遇到以下問題:
- 這樣在進行反向傳播的時候,隨著層數越來越低會遇到梯度越來越小或梯度越來越大的情況。
- 可能沒有足夠的訓練數據或做標簽的成本太高
- 訓練速度可能會非常緩慢
- 固有數百萬個參數的模型會有很高的風險過擬合訓練集,尤其是在沒有足夠的訓練實例或噪聲太大的情況下
一、反向傳播——梯度消失和梯度爆炸
梯度消失:如果梯度通常小于1,多次連乘之后梯度會呈指數級縮小,趨近于0。導致底層神經網絡的權重更新非常緩慢甚至停止更新。
梯度爆炸:如果梯度通常大于1,多次連乘之后梯度會呈指數級增長,變得非常大。這就導致權重更新步長過大,模型無法收斂。
總結來說,深度神經網受梯度不穩定的影響,不曾的層以不同的速度進行學習。
1、權重初始化
(1)理論
針對這一問題,有學者提出:前向傳播的收讓每層的輸入和輸出的方差相等,反向傳播時讓梯度在同一層的輸入和輸出具有相同的方差。但是,如果某一層沒有相同的數量的輸入和輸出,這個輸入和輸出的方差保持一致就不可能實現。因此誕生一個這種的方法Xavier初始化(或者Glorot初始化)
學者指出:對于一個線性層,權重的理想方差應該是??(
是輸入到這個線性層的單元數量?,
是這個線性層的輸出單元數量)。而針對激活函數不同,學者提供類似但有差異的權重初始化方差,如下:
初始化方法 | 在keras中的參數 | 激活函數 | |
---|---|---|---|
Xavier初始化 Glorot初始化 | glorot_normal glorot_uniform | None、tanh、sigmoid、softmax | |
He 初始化 | he_normal 正態,更自然 he_uniform 均勻,更安全 | ReLU、Leaky ReLU 、ELU、GELU、Swish、Mish | in和out的數量一樣 |
LeCun初始化 | lecun_normal | SELU | in和out的數量一樣 |
(2)使用方法
默認情況下,Keras使用具有均勻分布的Xavier初始化。創建層時,可以通過設置kernel_initializer = "he_uniform"`或 kernel_initializer = "he_normal"`來將其更改為He初始化。
import tensorflow as tfdense = tf.keras.layers.Dense(50,activation="relu",kernel_initalizer = "he_normal")
也可以使用VarianceScaling初始化器獲得表中列出的任何初始化以及更多。例如,如果想用均勻分布并且基于fan_avg(而不是fan_in)進行He初始化,則可以使用下面的代碼:
he_avg_init = tf.keras.initializers.VarianceScaling(scale=2., mode="fan_avg",distribution="uniform")
dense = tf.keras.layers.Dense(50, activation="relu", kernel_initializer=he_avg_init)
2、選擇合適的激活函數
在2010年的一篇論文中提到:梯度不穩定的問題的部分原因是因為激活函數選擇不恰當。激活函數的選擇直接決定了導數的行為,是解決梯度消失問題的關鍵。
在使用ReLU激活函數并不完美,因為他在小于0的部分會直接輸出0,這樣會導致梯度下降不會在影響它,致使神經元死亡。
之前的激活函數的優缺點:
激活函數 | 缺點 | 優點 |
---|---|---|
sigmoid函數 | 梯度消失:輸入值很大或很小的時候導數趨近于0,極易導致梯度消失。 非零中心:其輸出恒為正,導致梯度更新的時候權重向量的更新方向全部為正或負,出現“之”字路徑 | 平滑易于求導 輸出范圍時(0,1) 能夠有直觀的解釋 |
Tanh函數 | 雖然比Sigmoid好,但是在輸入和輸出很大或很小的時候同樣存在梯度消失的問題 | 是0中心(輸出范圍是-1~1,解決了Sigmoid函數的非零中心問題) |
ReLU函數 | 一旦輸入負,梯度為0,神經元不會在被激活(神經元死亡),相應的權重無法更新。 | 在正區間導數恒為1,徹底解決了梯度消失問題 計算速度快,只需要一個閾值判斷 |
使用ReLU及其改進版本(如Leaky ReLU, PReLU, ELU)可以顯著緩解梯度消失問題。因為它們的導數是常數(如ReLU正區間的導數為1),在連乘時不會導致梯度縮小。
(1)Leaky ReLU函數和PReLU函數
?超參數?
?定義函數的泄露程度:z<0時它是函數的斜率,以確保函數在梯度傳遞的時候永不死亡(可能會長時間昏迷,但是有機會醒來)。在實際應用的過程中大泄露?
?似乎比小泄露?
?能產生更好的性能。
,這函數是LeakyReLU的一個變體,它將
參數化,讓其變成一個可以在訓練期間可以學習的值。
特性 | Leaky ReLU (超參數) | PReLU (Parametric ReLU, 可學習參數) |
---|---|---|
定義 | ||
固定的常數,由人在訓練前設定。 | 模型的一個參數,像權重(Weight)和偏置(Bias)一樣,在訓練過程中通過反向傳播和梯度下降進行優化。 | |
是否更新 | 否。一旦設定,在整個訓練過程中保持不變。 | 是。它的值會隨著訓練迭代而自動調整。 |
如何設定 | 人工手動設置或通過超參數搜索(如網格搜索)確定。 核心目的是給負輸入一個非零但很小的梯度,防止神經元“死亡”。因此,它的值應該是一個很小的正數,通常在? | 只需要給它一個初始值,然后交給優化器。 |
例子 |
如果效果不好,在? | alpha ?初始化為?0.25 ,訓練后可能變為?0.1 ,?0.15 ,?0.3 ?等。 |
keras使用 | activation="leaky_relu" activation=tf.keras.layers.LeakyReLU() | activation=tf.keras.layers.PReLU() |
(2)ELU和SELU
ReLU,leaky ReLU都有不是光滑函數的缺點:它們的導數會突然變化,這種不連續性會使梯度下降在最優值附近反彈,并減慢收斂速度。所以,關注ReLU激活函數的一些平滑變體:ELU和SELU
指數線性單元ELU:
? ??????????
這個函數和之前函數的主要區別:
? ? ? ? 在負區間ELU不是絕對的零值,而是一個平滑的負飽和值(趨于)。這意味著即使輸入負值,神經元仍有輸出,梯度也不為0(
),從而保持了權重更新的可能性,有效緩解了神經元死亡的問題。
? ? ? ? 相比于之前PReLU和LeakyReLU在負區間時簡單的斜線,ELU的負區間是指數曲線,更加平滑,有助于加速梯度下降。
? ? ? ? ELU在負區間會產生負的輸出,有助于使激活的均值更接近0,有助緩解梯度消失問題。當輸入的是一個很大的負數的時候,ELU函數的輸出值無限逼近。這個
通常設置為1,能夠有很好的收斂效果。
縮放指數線性單元SELU:
??????????????????
該神經網絡通過自歸一化(各層的輸出在訓練過程中自動保持均值為0、方差為1的分布狀態)解決梯度消失和梯度爆炸問題。
自歸一化實現的條件:使用LeCun正態初始化、輸入特征需要標準化、不能使用批歸一化,只能用普通的MLP來保證自歸一化屬性、不能用正則化技術。
特性 | ELU | SELU |
---|---|---|
全稱 | 指數線性單元 | 縮放指數線性單元 |
核心目標 | 改善 ReLU 的缺點,提供平滑負輸出 | 實現自歸一化,替代批歸一化 |
公式特點 | ||
參數 | ||
優點 | 緩解死亡ReLU;輸出接近零均值;平滑 | 自歸一化;緩解梯度消失/爆炸;繼承ELU優點 |
缺點 | 計算量稍大 | 使用限制嚴格(初始化、結構等) |
適用場景 | 替代 ReLU,希望獲得更穩定訓練的通用場景 | 深層全連接網絡,希望嘗試不使用 BN 的架構 |
keras使用 | activation=“elu” activation=tf.keras.layers.ELU() | acivation="selu" |
tf.random.set_seed(42)
model = tf.keras.Sequential()
model.add(tf.keras.layers.Flatten(input_shape=[28, 28]))
for layer in range(100):model.add(tf.keras.layers.Dense(100, activation="selu",kernel_initializer="lecun_normal"))
model.add(tf.keras.layers.Dense(10, activation="softmax"))
(3)GELU、Swish和Mish
這三種函數都是“自門控激活函數”,其核心思想是讓激活函數能夠根據輸入值的大小,自適應的決定“通過”多少信息,而不是像ReLU那樣簡答的二值化。
高斯誤差線性單元GELU:激活值不僅應由輸入是否大于0來決定,還應該考慮到輸入值在有多大的概率會被選中。其公式為:,它是處處平滑的,有利于梯度計算。在x很大的時候,函數的輸出值接近1;當 x 很小的時候函數輸出接近于0;對中間值的x,輸出x的一部分,這樣達到軟門控的效果。
Swish :看作是一個自門控的 Sigmoid 函數。門控信號來自輸入本身,通過一個Sigmoid函數產生一個介于0到1之間的軟門控值,然后用這個值來縮放原始輸入。和GELU一樣是處處平滑的。Sigmoid 函數像一個門控,根據 x?的值來決定讓多少信息通過。大的正值,門控接近1,全部通過;大的負值,門控接近0,完全抑制。有趣的是,在 x?為負的區間,函數值不是0,而是一個很小的負值,這有助于增加梯度流,緩解死神經元問題。
Mish:是在Swish的基礎上進一步改進的激活函數,在許多視覺任務中這個函數會表現的更好。它的設置目標是追求更好的平滑性和非單調性,比上邊兩個函數更加平滑,能夠有助于更好的梯度流動和信息深入網絡。同時,也采用了自門控的思想,使用這個函數在負值區域具有更豐富的表現力。
特性 | GELU | Swish | Mish |
---|---|---|---|
核心思想 | 基于正態分布概率的門控 | 基于Sigmoid的自門控 | 基于tanh(softplus)的自門控 |
公式 | |||
平滑性 | 平滑 | 平滑 | 極致平滑 |
單調性 | 單調 | 單調 | 非單調(負區間有駝峰) |
下界 | ~0 | ~0 | ~-0.31 |
上界 | ∞ | ∞ | ∞ |
主要應用領域 | NLP(Transformer) | CV, NLP | CV(目標檢測等) |
計算成本 | 較高(近似計算) | 中等(需計算sigmoid) | 較高(需計算exp、log、tanh) |
keras使用 | activation="gelu" | activation=“swish” activation=tf.keras.activations.swish def swish(x): | # 方法1:自定義 # 方法2:使用TensorFlow Addons (需安裝) |
(4)如何選擇激活函數
對于隱藏層:
ReLU仍然是簡單任務的良好默認選擇,它通常與更復雜的激活函數一樣好,而且計算速度非常快,許多庫和硬件加速器提供特定于ReLU的優化方式。
對于復雜的任務,Swish可能是更好的默認設置, 對于非常復雜的任務,甚至可以嘗試使用具有可學習的β參數的參數化Swish。Mish可能會帶來更好的結果,但它需要更多的計算量。
如果你非常關心運行時延遲,那可能更喜歡leaky ReLU,或者適合復雜任務的參數化leaky ReLU。
對于深度MLP,請嘗試使用SELU,但請確保遵守前面列出的約束。如果你有空閑時間和計算能力,也可以使用交叉驗證來評估其他激活函數。 Keras開箱即用地支持GELU和Swish;只需使用activation="gelu"或activation="swish"。但是,它還不支持Mish或廣義的Swish激活函數 。
# 隨堂練習:嘗試使用gelu/switch / 參數化的leak relu(tf.keras.Layers.PReLU)
tf.random.set_seed(42)
model = tf.keras.Sequential()
model.add(tf.keras.layers.Flatten(input_shape=[28, 28]))
for layer in range(2):# model.add(tf.keras.layers.Dense(50, activation="gelu",kernel_initializer="lecun_normal"))model.add(tf.keras.layers.Dense(50, kernel_initializer="lecun_normal"))model.add(tf.keras.layers.PReLU())
model.add(tf.keras.layers.Dense(10, activation="softmax"))model.compile(loss="sparse_categorical_crossentropy",optimizer=tf.keras.optimizers.SGD(learning_rate=0.001),metrics=["accuracy"])
3、批量歸一化(Batch Normalization)
(1)理論
該技術包括在模型中每個隱藏層的激活函數之前或之后添加一個操作。該技術的核心思想是在網絡的每一層,對輸入該層的數據進行歸一化,使其均值為0、方差為1之后再進行縮放和平移。
該操作對每個輸入進行零中心并歸一化,為了使輸入零中心化并歸一化,該算法需要估計每個輸入的均值和標準差。我們通過評估當前小批次上的輸入的均值和標準差(因此稱為“批量歸一化”)來實現。
在許多情況下,如果將 BN 層添加為神經網絡的第一層,則無須歸一化訓練集(也就是說,不需要使用 `StandardScaler` 或 `Normalization`),BN 層會為你完成此操作(因為它一次只能查看一個批次,它還可以重新縮放和偏移每個輸入特征)。
工作流程:標準化 —— 縮放平移?
? ? ? ? 標準化:計算該批次數據在每個特征維度上的均值和方差,然后在均值和方差將數據標準化維均值為0、方差為1的分布。
? ? ? ? 縮放平移:僅僅標準化會改變層原本的表示能力。假如使用sigmoid函數,標準化后的數據會集中在線性區域,失去了非線性特征。因此BN引入兩個可學習的參數??,對標準化后的數據進行縮放和平移。
特性 | 描述 |
---|---|
目的 | 減少內部協變量偏移,加速訓練,穩定過程 |
位置 | 通常置于全連接/卷積層 之后,激活函數 之前 |
操作 | 1.?標準化:減去批次均值,除以批次標準差 2.?縮放平移:乘以$\gamma$,加上$\beta$(可學習參數) |
訓練/推理 | 訓練:使用當前批次的統計量 推理:使用全局(移動平均)統計量 |
優點 | 加速收斂、允許高學習率、緩解梯度消失、有正則化效果、j降低對初始化的敏感度 |
局限 | 依賴足夠大的Batch Size,在RNN中應用不便 |
批量歸一化算法的計算過程:
??????????
?是輸入均值的向量,在整個小批次B上評估(每個輸入包含一個均值),
是小批次中的實例數量
?????????,
是輸入標準差的向量,也在整個小批次上的評估(每個輸入一個標準差)
????????,
?是一個平滑項,用于避免除以0(是一個很小的值);
?????????,?
?是層的縮放參數向量(每個輸入一個縮放參數);
是層的偏移參數向量;
?表示逐元素懲罰(每個輸入乘以其相應的輸出縮放參數);
是 BN 操作的輸出,將傳遞給下一層或激活函數。
在測試/推理時,我們常常需要處理單個實例或一個不可靠的小批量,但是無法像訓練時那樣計算出一個有統計意義的批次均值和方差。在理論上,可以在結束訓練后遍歷整個訓練集,之后為每個BN層計算均值和方差;在實際上是在訓練過程中,使用 指數移動平均(EMA) 來動態、平滑地估算整個訓練集地全局統計量。
每個BN層管理四個參數向量:?縮放向量,可學習參數;
偏移向量,可學習參數;
?均值向量,通過指數移動平均估算得到;
標準差向量,通過指數移動平均估算到。
????????γ和 β:像普通的權重一樣,通過反向傳播和梯度下降進行學習和優化。μ 和 σ:在訓練過程中,每個批次都會計算當前的 μ_B 和 σ_B。然后使用這些批次統計量來更新移動平均值和標準差。
????????訓練時:使用當前批次的 μ_B 和 σ_B 來歸一化數據,并使用它們來更新移動平均。
????????測試/推理時:停止更新移動平均。固定使用訓練階段估算好的最終?moving_mean?
和moving_variance?
來歸一化數據。
最后,批量歸一化的作用之一就是正則化,大大減少了對其他正則化技術的需求。但是,批量歸一化確實增加了模型的復雜度。
(2)在keras中的使用
與使用Keras的大多數任務操作一樣,實施批量歸一化非常簡單,只需在每個隱藏層的激活函數之前或之后添加一個BatchNormalization層。也可以添加一個BN層作為模型的第一層,但是普通的Normalization層在這個位置通常也表現得非常好(它唯一的缺點是必須首先調用它的adapt()方法)。例如,此模型在每個隱藏層之后應用BN,并將其作為模型的第一層(展平層之后)。
model = tf.keras.Sequential([tf.keras.layers.Flatten(input_shape=[28, 28]),tf.keras.layers.BatchNormalization(),tf.keras.layers.Dense(300, activation="relu", kernel_initializer="he_normal"),tf.keras.layers.BatchNormalization(),tf.keras.layers.Dense(100, activation="relu", kernel_initializer="he_normal"),tf.keras.layers.BatchNormalization(),tf.keras.layers.Dense(10, activation="softmax")
])
model.summary()Layer (type) Output Shape Param #
=================================================================flatten_3 (Flatten) (None, 784) 0 batch_normalization (Batch (None, 784) 3136 Normalization) dense_205 (Dense) (None, 300) 235500 batch_normalization_1 (Bat (None, 300) 1200 chNormalization) dense_206 (Dense) (None, 100) 30100 batch_normalization_2 (Bat (None, 100) 400 chNormalization) dense_207 (Dense) (None, 10) 1010
其中3136 = 784 * 4,BN層有4個參數,輸入的維度是(784,)
? ? ? ? 235500 = 784 * 300 +300,輸入維度是(784,)?神經元數量300+偏置數量300= 權重參數+偏置參數
要在激活函數之前添加BN層,必須從隱藏層中移除激活函數,并將它們作為單獨的層添加到BN層之后。此外,由于批量歸一化層的每個輸入都包含一個偏移參數,因此你可以在創建它時傳遞use_bias=False,從上一層中刪除偏置項。最后,通常可以刪除第一個BN層以避免將第一個隱藏層夾在兩個BN層之間,更新后的代碼如下所示:
model = tf.keras.Sequential([tf.keras.layers.Flatten(input_shape=[28, 28]),tf.keras.layers.Dense(300, kernel_initializer="he_normal", use_bias=False),tf.keras.layers.BatchNormalization(),tf.keras.layers.Activation("relu"),tf.keras.layers.Dense(100, kernel_initializer="he_normal", use_bias=False),tf.keras.layers.BatchNormalization(),tf.keras.layers.Activation("relu"),tf.keras.layers.Dense(10, activation="softmax")
])
BatchNormalization函數可調整的超參數:momentum的值通常接近1,例如0.9、0.99、0.999,對于較大的數據集和較小的批處理需要更多的9;axis的值確定在哪個軸被歸一化,默認是-1,希望在哪些維度計算統計量把哪些維度放到axis參數中。
4、梯度裁剪
(1)理論
這是專門針對梯度爆炸問題的直接方法。它為梯度設置一個上限閾值,當梯度超過這個閾值時,就將其裁剪到這個值。其核心思想是在反向傳播計算完梯度之后、使用優化器更新模型參數之前,對梯度向量的模長或最大值進行限制,確保不會超過一個預設的閾值。通常用于循環神經網絡(RNN),很難使用批量歸一化。
方法一:按值裁剪
為每個梯度元素設置一個上限和下限,任何超過這個范圍的梯度值都會被截斷(超出最大值就直接按最大值算,超出最小值就按最小值算)。但是這樣可能會改變梯度方向,因為它獨立的處理每個元素,裁剪后的梯度方向可能與原始方向不同。
方法二:按模裁剪(常用的方法)
關注整個梯度向量的模長,如果模長超過閾值,就將整個向量按比例縮放,使其模型等于閾值,而保持方向不變。將梯度向量g進行L2正則化
(2)在keras中的使用
在keras中只需要在創建優化器的時候設置clipvalue\clipnorm參數。
optimizer = tf.keras.optimizers.SGD(clipvalue = 1.0)
clipvalue=1.0是按值裁剪,將梯度向量的每個分量都裁剪為-1~1之間的值,意味著損失函數的所有偏導數將限制在這個范圍之內。可能會改變梯度向量的方向,例如,如果原始梯度向量為[0.9,100.0],則其主要指向第二個軸的方向,但是按值裁剪后,將得到[0.9,1.0],這將大致指向兩個軸之間的對角線。實際上,這種方法非常有效。
optimizer = tf.keras.optimizers.SGD(clipnorm = 1.0)
clipnorm=1.0是按模裁剪,可以將梯度向量的L2范數限制在1.0之內。例如,向量[0.9,100.0]將被裁剪為[0.00899964,0.9999595],它保留了方向,但幾乎消除了第一個分量。
二、有效數據少——重用預訓練層
如果不先嘗試找到一個現有的神經網絡——該神經網絡可以完成與你要處理的任務類似的任務,就從頭開始訓練非常大的DNN,這通常不是一個好主意。如果能夠找到這樣的神經網絡,那么通常可以重用它的大部分層,除了最上面的層。這種技術稱為遷移學習。
它不僅會大大加快訓練速度,而且需要的訓練數據也會大大減少。假設你可以訪問一個訓練過的DNN,它能分類100種不同類別的圖像,其中包括動物、植物、車輛和日常物品,現在想訓練該DNN來對特定類型的車輛進行分類。這些任務非常相似,甚至有部分重疊,因此應該嘗試重用第一個網絡的一部分。
類似地,原始模型上面的隱藏層不太可能像下面的那樣有用,因為對新任務最有用的高級特征可能與對原始任務最有用的特征有很大的不同。需要確定要重用的具體層數。 任務越相似,可重用的層越多(從較低的層開始)?。對于非常相似的任務,請嘗試保留所有的隱藏層,只替換掉輸出層。
首先,嘗試凍結所有可重用的層(即使它們的權重不可訓練,以便梯度下降不會修改它們并且它們將保持固定),訓練模型并查看其表現。然后,嘗試解凍上面隱藏層中的一兩層,使反向傳播可以對其進行調整,再查看性能是否有所提高。擁有的訓練數據越多,可以解凍的層就越多。當解凍重用層時,降低學習率也很有用:這可以避免破壞其已經調整好的權重。 如果,仍然無法獲得良好的性能,并且訓練數據很少,那么試著去掉頂部的隱藏層,然后再次凍結其余所有的隱藏層。不斷迭代,直到找到合適的可以重用的層數。如果有大量的訓練數據,則可以嘗試替換頂部的隱藏層而不是去掉它們,甚至可以添加更多的隱藏層。
1、用keras進行遷移學習
其核心思想是保留這些通用的底層特征,只替換和重新訓練模型的頂層、用于特定分類任務的分類器。一般有兩種方法:特征提取和微調。
遷移學習的流程:創建基礎模型并凍結 —— 添加新的分類頭 —— 編譯和訓練模型 —— 解凍部分層進行訓練
? ? ? ? 如果直接從基礎模型中復制模型的前幾層,這里的賦值得到的 model_B_on_A 和 model_A 共享網絡層。因此,當訓練其中一個模型的時候,另一個模型參數也會同步更新。解決此問題只需要基于 model_A 克隆得到model_A_clone(這里需要手動復制下原模型的權重),之后在進行賦值得到 model_B_on_A 。
model_A = tf.keras.models.load_model("./models/my_model_A.keras")
model_A_clone = tf.keras.models.clone_model(model_A)
model_A_clone.set_weights(model_A.get_weights())model_B_on_A = tf.keras.Sequential(model_A_clone.layers[:-1])
model_B_on_A.add(tf.keras.layers.Dense(1, activation="sigmoid"))
????????在前幾個輪次時凍結重用層,給新層一些時間來學習合理的權重。為此,將每一層的trainable屬性設置為False并編譯模型:
for layer in model_B_on_A.layers[:-1]:layer.trainable = False
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
model_B_on_A.compile(loss="binary_crossentropy", optimizer=optimizer,metrics=["accuracy"])
????????模型訓練幾個輪次之后,解凍重用層(需要再次編譯模型),并繼續進行訓練以基于任務B來微調重用層。解凍重用層之后,降低學習率通常可以再次避免損壞重用權重:
history = model_B_on_A.fit(X_train_B, y_train_B, epochs=4,validation_data=(X_valid_B, y_valid_B))
# 解凍: 將每層的 trainable 設置為 True
for layer in model_B_on_A.layers[:-1]:layer.trainable = True
# 解凍后需要重新編譯模型,降低學習率再次避免重用權重
optimizer = tf.keras.optimizers.SGD(learning_rate=0.001)
model_B_on_A.compile(loss="binary_crossentropy", optimizer=optimizer,metrics=["accuracy"])
history = model_B_on_A.fit(X_train_B, y_train_B, epochs=16,validation_data=(X_valid_B, y_valid_B))
總結:遷移學習在小型密集網絡中不能很好的工作,大概是因為小型網絡能夠學習的模式很少,密集網絡學習的是非常具體的模式,這在其他任務中不是很有用。遷移學習最適合用于深度卷積層神經網絡,后者傾向于學習更為通用的特征檢測器(尤其是在較低層)。
2、無監督預訓練
無監督預訓練主要解決兩個核心問題:數據標簽的稀缺和昂貴、模型泛化能力不足。
如果收集大量未標記的訓練數據,嘗試使用它們來訓練無監督模型,例如自動編碼器或生成對抗網絡(GAN)。然后,可以重用自動編碼器的較低層或GAN判別器的較低層,在頂部添加針對自己的任務的輸出層,并使用監督學習(即使用帶有標簽的訓練實例)來微調最終的網絡。
在監督訓練中,使用無監督學習技術基于所有數據(包括未標記數據)訓練模型,然后使用監督學習技術基于帶標簽的數據針對最終任務進行微調;無監督部分可以一次訓練一層,也可以直接訓練整個模型:
總之,解決的任務復雜,沒有可重用的相似模型,帶標簽的訓練數據很少,但是無標簽的訓練數據很多時,無監督預訓練(GAN/自動編碼器)是個不錯選擇。
3、基于輔助任務的預訓練
其核心思想是:為了讓模型學習到高質量、通用、可遷移的表示,我們不僅僅在最終的目標任務上訓練模型,而是先讓模型在一系列精心設計的“輔助任務”上進行預訓練。
基于輔助任務的預訓練可以理解成方法論,無監督學習是實現這種方法論最主要、最強大的手段。
維度 | 基于輔助任務的預訓練 | 無監督任務的預訓練 |
---|---|---|
核心思想 | 通過完成一個或多個額外任務來學習更好的通用表示。 | 從無標簽數據中自行尋找規律和結構來學習表示。 |
任務性質 | 輔助任務可以是監督、無監督或自監督的。 | 任務一定是無監督或自監督的。 |
監督信號 | 可能有人為設計的信號(如詞性標簽、句法樹),也可能沒有(如MLM)。 | 完全沒有人工標注的標簽。監督信號來自數據自身(如上下文、數據變換)。 |
關系 | 一個更廣泛的概念。無監督預訓練是它的一個子集,并且是 |