深度神經網絡1——梯度問題+標簽數不夠問題

要解決一個復雜問題,可能要訓練更深的神經網絡,可能會10層及以上,每層包含數百個神經元,成千上萬個連接。這樣大的神經網絡在訓練的時候可能會遇到以下問題:

  1. 這樣在進行反向傳播的時候,隨著層數越來越低會遇到梯度越來越小或梯度越來越大的情況。
  2. 可能沒有足夠的訓練數據或做標簽的成本太高
  3. 訓練速度可能會非常緩慢
  4. 固有數百萬個參數的模型會有很高的風險過擬合訓練集,尤其是在沒有足夠的訓練實例或噪聲太大的情況下

一、反向傳播——梯度消失和梯度爆炸

梯度消失:如果梯度通常小于1,多次連乘之后梯度會呈指數級縮小,趨近于0。導致底層神經網絡的權重更新非常緩慢甚至停止更新。

梯度爆炸:如果梯度通常大于1,多次連乘之后梯度會呈指數級增長,變得非常大。這就導致權重更新步長過大,模型無法收斂。

總結來說,深度神經網受梯度不穩定的影響,不曾的層以不同的速度進行學習。

1、權重初始化

(1)理論

針對這一問題,有學者提出:前向傳播的收讓每層的輸入和輸出的方差相等,反向傳播時讓梯度在同一層的輸入和輸出具有相同的方差。但是,如果某一層沒有相同的數量的輸入和輸出,這個輸入和輸出的方差保持一致就不可能實現。因此誕生一個這種的方法Xavier初始化(或者Glorot初始化)

學者指出:對于一個線性層,權重的理想方差應該是?\frac{2}{n_{in}+n_{out}}?(n_{in}是輸入到這個線性層的單元數量?,n_{out}是這個線性層的輸出單元數量)。而針對激活函數不同,學者提供類似但有差異的權重初始化方差,如下:

初始化方法在keras中的參數激活函數\sigma ^2方差

Xavier初始化

Glorot初始化

glorot_normal

glorot_uniform

None、tanh、sigmoid、softmax\frac{1}{n_{in}+n_{out}}
He 初始化

he_normal 正態,更自然

he_uniform 均勻,更安全

ReLU、Leaky ReLU 、ELU、GELU、Swish、Mish

\frac{2}{n_{in}+n_{out}}

in和out的數量一樣

LeCun初始化

lecun_normal

SELU

\frac{1}{n_{in}+n_{out}}

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函數

LeakyReLU_\alpha (z) = max(\alpha z,z)?超參數?\alpha?定義函數的泄露程度:z<0時它是函數的斜率,以確保函數在梯度傳遞的時候永不死亡(可能會長時間昏迷,但是有機會醒來)。在實際應用的過程中大泄露?\alpha?似乎比小泄露?\alpha?能產生更好的性能。

PReLU_\alpha (z) = max(\alpha z,z),這函數是LeakyReLU的一個變體,它將\alpha參數化,讓其變成一個可以在訓練期間可以學習的值。

特性Leaky ReLU (超參數)PReLU (Parametric ReLU, 可學習參數)
定義$\text{LeakyReLU}(x) = \max(\alpha x, x)$$\text{PReLU}(x) = \max(\alpha x, x)$
$\alpha$ 的性質固定的常數,由人在訓練前設定。模型的一個參數,像權重(Weight)和偏置(Bias)一樣,在訓練過程中通過反向傳播和梯度下降進行優化。
是否更新否。一旦設定,在整個訓練過程中保持不變。是。它的值會隨著訓練迭代而自動調整。
如何設定

人工手動設置或通過超參數搜索(如網格搜索)確定。

核心目的是給負輸入一個非零但很小的梯度,防止神經元“死亡”。因此,它的值應該是一個很小的正數,通常在?(0, 1)?范圍內

只需要給它一個初始值,然后交給優化器。
例子

alpha=0.01?(這是最經典、最常用的值)

如果效果不好,在?[0.3, 0.1, 0.01, 0.001]

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_\alpha (x) = \begin{cases} \alpha (e^x-1) ,& x<0 \\x, & x \geqslant 0 \end{cases}? ??????????

這個函數和之前函數的主要區別:

? ? ? ? 在負區間ELU不是絕對的零值,而是一個平滑的負飽和值(趨于-\alpha)。這意味著即使輸入負值,神經元仍有輸出,梯度也不為0($\text{ELU}'(x<0) = \text{ELU}(x) + \alpha$),從而保持了權重更新的可能性,有效緩解了神經元死亡的問題。

? ? ? ? 相比于之前PReLU和LeakyReLU在負區間時簡單的斜線,ELU的負區間是指數曲線,更加平滑,有助于加速梯度下降。

? ? ? ? ELU在負區間會產生負的輸出,有助于使激活的均值更接近0,有助緩解梯度消失問題。當輸入的是一個很大的負數的時候,ELU函數的輸出值無限逼近-\alpha。這個\alpha通常設置為1,能夠有很好的收斂效果。

縮放指數線性單元SELU

ELU_\alpha (x) =\lambda \begin{cases} \alpha (e^x-1) ,& x<0 \\x, & x \geqslant 0 \end{cases}??????????????????

該神經網絡通過自歸一化(各層的輸出在訓練過程中自動保持均值為0、方差為1的分布狀態)解決梯度消失和梯度爆炸問題。

自歸一化實現的條件:使用LeCun正態初始化、輸入特征需要標準化、不能使用批歸一化,只能用普通的MLP來保證自歸一化屬性、不能用正則化技術。

特性ELUSELU
全稱指數線性單元縮放指數線性單元
核心目標改善 ReLU 的缺點,提供平滑負輸出實現自歸一化,替代批歸一化
公式特點ELU(x) = \begin{cases} x &, x \geqslant 0 \\ \alpha (e^x - 1)&, x < 0 \end{cases}$\text{SELU}(x) = \lambda \cdot \text{ELU}(x, \alpha)$
參數$\alpha$ 通常為 1,可調\alpha \approx 1.6733,\lambda \approx 1.0507(固定)
優點緩解死亡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來決定,還應該考慮到輸入值在有多大的概率會被選中。其公式為:GELU(x) = x \cdot \Phi(x),它是處處平滑的,有利于梯度計算。在x很大的時候,函數的輸出值接近1;當 x 很小的時候函數輸出接近于0;對中間值的x,輸出x的一部分,這樣達到軟門控的效果。

Swish :看作是一個自門控的 Sigmoid 函數。門控信號來自輸入本身,通過一個Sigmoid函數產生一個介于0到1之間的軟門控值,然后用這個值來縮放原始輸入。和GELU一樣是處處平滑的。Sigmoid 函數像一個門控,根據 x?的值來決定讓多少信息通過。大的正值,門控接近1,全部通過;大的負值,門控接近0,完全抑制。有趣的是,在 x?為負的區間,函數值不是0,而是一個很小的負值,這有助于增加梯度流,緩解死神經元問題。

Mish:是在Swish的基礎上進一步改進的激活函數,在許多視覺任務中這個函數會表現的更好。它的設置目標是追求更好的平滑性和非單調性,比上邊兩個函數更加平滑,能夠有助于更好的梯度流動和信息深入網絡。同時,也采用了自門控的思想,使用$x \cdot \tanh(\ln(1 + e^x))$這個函數在負值區域具有更豐富的表現力。

特性GELUSwishMish
核心思想基于正態分布概率的門控基于Sigmoid的自門控基于tanh(softplus)的自門控
公式$x \cdot \Phi(x)$$\Phi(x)$是標準正態分布的累計分布函數$x \cdot \sigma(\beta x)$

$x \cdot \tanh(\ln(1 + e^x))$

平滑性平滑平滑極致平滑
單調性單調單調非單調(負區間有駝峰)
下界~0~0~-0.31
上界
主要應用領域NLP(Transformer)CV, NLPCV(目標檢測等)
計算成本較高(近似計算)中等(需計算sigmoid)較高(需計算exp、log、tanh)
keras使用activation="gelu"

activation=“swish”

activation=tf.keras.activations.swish

def swish(x):
return x * tf.sifmoid(x)
activation=swish

# 方法1:自定義
def mish(x):
return x * tf.math.tanh(tf.math.softplus(x))
activation=mish

# 方法2:使用TensorFlow Addons (需安裝)
# import tensorflow_addons as tfa
# activation=tfa.activations.mish

(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引入兩個可學習的參數?\gamma \text{ and } \beta?,對標準化后的數據進行縮放和平移。y_i = \gamma \hat{x_i} + \beta= \text{BN}{\gamma, \beta}(x_i)

特性描述
目的減少內部協變量偏移,加速訓練,穩定過程
位置通常置于全連接/卷積層之后,激活函數之前
操作1.?標準化:減去批次均值,除以批次標準差
2.?縮放平移:乘以$\gamma$,加上$\beta$(可學習參數)
訓練/推理訓練:使用當前批次的統計量
推理:使用全局(移動平均)統計量
優點加速收斂、允許高學習率、緩解梯度消失、有正則化效果、j降低對初始化的敏感度
局限依賴足夠大的Batch Size,在RNN中應用不便

批量歸一化算法的計算過程:

????????\mu_B = \frac{1}{m_B} \sum_{i=1}^{m_B} \mathbf{x}^{(i)}$$\\\\??\mu_B?是輸入均值的向量,在整個小批次B上評估(每個輸入包含一個均值),m_B是小批次中的實例數量

????????\sigma_B^2 = \frac{1}{m_B} \sum_{i=1}^{m_B} (\mathbf{x}^{(i)} - \mu_B)^2\\ \\?,\sigma _B是輸入標準差的向量,也在整個小批次上的評估(每個輸入一個標準差)

????????\hat{\mathbf{x}}^{(i)} = \frac{\mathbf{x}^{(i)} - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}\\\epsilon?是一個平滑項,用于避免除以0(是一個很小的值);

????????\mathbf{z}^{(i)} = \boldsymbol{\gamma} \otimes \hat{\mathbf{x}}^{(i)} + \boldsymbol{\beta}?,?$\boldsymbol{\gamma}$?是層的縮放參數向量(每個輸入一個縮放參數);$\boldsymbol{\beta}$是層的偏移參數向量;$\otimes$?表示逐元素懲罰(每個輸入乘以其相應的輸出縮放參數);$\mathbf{z}^{(i)}$是 BN 操作的輸出,將傳遞給下一層或激活函數。

在測試/推理時,我們常常需要處理單個實例或一個不可靠的小批量,但是無法像訓練時那樣計算出一個有統計意義的批次均值和方差。在理論上,可以在結束訓練后遍歷整個訓練集,之后為每個BN層計算均值和方差;在實際上是在訓練過程中,使用 指數移動平均(EMA) 來動態、平滑地估算整個訓練集地全局統計量。

每個BN層管理四個參數向量:\gamma?縮放向量,可學習參數;\beta偏移向量,可學習參數;\mu?均值向量,通過指數移動平均估算得到;\sigma標準差向量,通過指數移動平均估算到。

????????γ和 β:像普通的權重一樣,通過反向傳播和梯度下降進行學習和優化。μ 和 σ:在訓練過程中,每個批次都會計算當前的 μ_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)。完全沒有人工標注的標簽。監督信號來自數據自身(如上下文、數據變換)。
關系一個更廣泛的概念。無監督預訓練是它的一個子集,并且是

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/98160.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/98160.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/98160.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

(筆記)內存文件映射mmap

內存文件映射是一種將文件內容映射到進程的虛擬地址空間的技術&#xff0c;使得文件可以被視為內存的一部分&#xff0c;從而允許程序直接對這部分內存進行讀寫操作&#xff0c;而無需傳統的文件 I/O 調用。這種方法不僅簡化了文件操作&#xff0c;還提高了處理效率。 在Linux…

Golang中的NaN(Not a Number)

Golang中的NaN&#xff08;Not a Number&#xff09; 在Go語言中&#xff0c;NaN是浮點數&#xff08;特別是float32和float64&#xff09;中的一個特殊值&#xff0c;表示未定義或不可表示的數值。 go中&#xff0c;除數為0時并不會返回error或者nil&#xff0c;而是返回無窮大…

微軟圖引擎GraphEngine深度解析:分布式內存計算的技術革命

? "在大數據的汪洋中&#xff0c;圖引擎就像是一艘能夠高速穿越復雜關系網絡的超級快船" 引言&#xff1a;當內存遇上圖計算的火花 在這個數據爆炸的時代&#xff0c;傳統的關系型數據庫已經難以應對復雜關系數據的查詢挑戰。當Facebook的社交網絡擁有數十億用戶關…

catkin工程和CMakelist.txt的基本使用

catkin工程和CMakelist.txt的基本使用1.catkin工程和CMakelist.txt的基本使用1. 頂部基本信息2. 編譯選項 / C 標準3. 依賴查找&#xff08;catkin 包&#xff09;4. 第三方庫查找&#xff08;非 catkin&#xff09;5. 導出包信息&#xff08;catkin_package&#xff09;6. 頭文…

uniapp打包前端項目

打包前的準備工作確保項目開發已完成&#xff0c;并且已安裝最新版本的HBuilderX。檢查項目中所有依賴是否已正確安裝&#xff0c;配置文件如manifest.json已根據H5需求進行適配。在HBuilderX中打包在 HBuilderX 中&#xff0c;點擊頂部菜單欄的 “發行” -> “網站-H5手機版…

Dify + Bright Data MCP:從實時影音數據到可落地的智能體生產線

一、引言&#xff1a;AI 應用與實時影音數據的融合價值 內容生態近年的“視頻化、實時化、社交化”浪潮&#xff0c;將數據獲取鏈路推到了更靠前的位置。真正驅動業務的&#xff0c;不是某一幀漂亮的模型輸出&#xff0c;而是“數據—理解—動作”的持續閉環。無論是品牌內容策…

【Linux】make/Makefile工具篇

目錄一、自動化構建二、make/Makefile2.1 見識一個簡單的make/Makefile2.2 Makefile的基本語法2.3 Makefile的語法細節個人主頁<—請點擊 Linux專欄<—請點擊 一、自動化構建 自動化構建是指通過構建工具&#xff08;如make&#xff09;解析構建腳本&#xff08;如Make…

如何在企業微信上以 HTTPS 方式訪問內網 OA/ERP 等系統?

企業微信可以將 ZeroNews 平臺上添加的內網應用集成到企業微信的工作臺。這樣&#xff0c;用戶即使在外部網絡環境中&#xff0c;也可以通過企業微信訪問內網的 OA、ERP 等應用。以下是企業在 Linux 服務器上部署 OA 系統&#xff0c;并通過 ZeroNews 通過互聯網訪問 OA 系統的…

Windows 11 安裝使用 nvm,Node.js、npm多版本管理、切換

Windows 11 安裝使用 nvm&#xff0c;Node.js、npm多版本管理、切換 文章目錄Windows 11 安裝使用 nvm&#xff0c;Node.js、npm多版本管理、切換1. nvm 簡介2. 安裝、配置 nvm2.1. 卸載現有 Node.js&#xff08;非常重要&#xff01;&#xff09;2.2. 下載 nvm-windows 安裝包…

在LazyVim中配置Rust開發環境

要在LazyVim中配置Rust開發環境&#xff0c;包括代碼補全、格式化、調試等功能&#xff0c;可以按照以下步驟進行配置&#xff1a; 1. 確保基礎環境 首先確保你已經安裝了&#xff1a; Rust工具鏈 (rustup, rustc, cargo)LazyVim已正確安裝 # 安裝Rust工具鏈 curl --proto http…

LeetCode熱題100--114. 二叉樹展開為鏈表--中等

1. 題目 給你二叉樹的根結點 root &#xff0c;請你將它展開為一個單鏈表&#xff1a; 展開后的單鏈表應該同樣使用 TreeNode &#xff0c;其中 right 子指針指向鏈表中下一個結點&#xff0c;而左子指針始終為null 。展開后的單鏈表應該與二叉樹 先序遍歷 順序相同。 示例 …

REST API 設計最佳實踐指南 - 如何用 JavaScript、Node.js 和 Express.js 構建 REST API

過去幾年里&#xff0c;我創建并使用過很多 API。在此過程中&#xff0c;我遇到過各種好的和壞的實踐&#xff0c;也在開發和調用 API 時碰到過不少棘手的問題&#xff0c;但也有很多順利的時刻。 網上有很多介紹最佳實踐的文章&#xff0c;但在我看來&#xff0c;其中不少都缺…

MyCat

文章目錄18.1 MySQL 讀寫分離概述18.1.1 工作原理18.1.2 為什么要讀寫分離18.1.3 實現方式18.2 什么是 MyCat18.3 MyCat 安裝與配置1. 下載與解壓2. 創建用戶并修改權限3. 目錄說明4. Java 環境要求18.4 MyCat 啟動與配置1. 配置環境變量2. 配置 hosts&#xff08;多節點集群&a…

使用 Spring Boot 搭建和部署 Kafka 消息隊列系統

使用 Spring Boot 搭建和部署 Kafka 消息隊列系統 摘要 本文將引導您在 Kafka 上搭建一個消息隊列系統&#xff0c;并整合到您的 Spring Boot 項目中。我們將逐步實現這一方案&#xff0c;探討其中的關鍵原理&#xff0c;避開可能遇到的坑&#xff0c;并最終將其部署到 Kuberne…

daily notes[45]

文章目錄basic knowledgereferencesbasic knowledge the variable in Rust is not changed. let x5; x6;Rust language promotes the concept that immutable variables are safer than variables in other programming language such as python and and are in favour of th…

技術奇點爆發周:2025 年 9 月科技突破全景掃描

技術奇點爆發周&#xff1a;2025 年 9 月科技突破全景掃描當中國 "祖沖之三號" 量子計算機在特定任務上超越經典超級計算機一千萬億倍的算力新聞&#xff0c;與 OpenAI 宣布 100 億美元定制芯片量產協議的消息在同一周密集爆發時&#xff0c;我們真切感受到了技術革命…

分布式專題——10.3 ShardingSphere實現原理以及內核解析

1 ShardingSphere-JDBC 內核工作原理當往 ShardingSphere 提交一個邏輯SQL后&#xff0c;ShardingSphere 到底做了哪些事情呢&#xff1f;首先要從 ShardingSphere 官方提供的這張整體架構圖說起&#xff1a;1.1 配置管控在 SQL 進入 ShardingSphere 內核處理&#xff08;如解析…

移動語義的里里外外:從 std::move 的幻象到性能的現實

我們都已經聽過這樣的建議&#xff1a;“使用 std::move 來避免昂貴的拷貝&#xff0c;提升性能。” 這沒錯&#xff0c;但如果你對它的理解僅止于此&#xff0c;那么你可能正在黑暗中揮舞著一把利劍&#xff0c;既可能披荊斬棘&#xff0c;也可能傷及自身。 移動語義是 C11 帶…

selenium完整版一覽

selenium 庫驅動瀏覽器selenium庫是一種用于Web應用程序測試的工具,它可以驅動瀏覽器執行特定操作,自動按照腳本代碼做出單擊、輸入、打開、驗證等操作,支持的瀏覽器包括IE、Firefox、Safari、Chrome、Opera等。而在辦公領域中如果經常需要使用瀏覽器操作某些內容,就可以使用se…

[Linux]學習筆記系列 -- lib/kfifo.c 內核FIFO實現(Kernel FIFO Implementation) 高效的無鎖字節流緩沖區

文章目錄lib/kfifo.c 內核FIFO實現(Kernel FIFO Implementation) 高效的無鎖字節流緩沖區歷史與背景這項技術是為了解決什么特定問題而誕生的&#xff1f;它的發展經歷了哪些重要的里程碑或版本迭代&#xff1f;目前該技術的社區活躍度和主流應用情況如何&#xff1f;核心原理與…