JOVANA
Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

讓深度網路真正能訓練的那些技巧

按理說,多堆幾層應該更強——可多年來事實並非如此,直到三個不起眼的工程技巧改變了一切。我們來認識隨機失活、歸一化與殘差連接,並切實看清每一個為什麼能同時幫助深度模型「訓得動」又「學得穩」。

為什麼「更深」一度不再奏效

到現在為止,你已經見過這些積木:層層疊起的隱藏層在學一套分層的特徵,處理影像的卷積網路,處理序列的循環網路。下一步看起來很顯然——再多堆幾層。紙面上,更深的網路能表達更淺網路能表達的一切,還能更多。那麼,為什麼在 2010 年前後,許多團隊發現一味加層往往讓結果*更糟*而不是更好?

其實有兩個不同的問題被攪在了一起。第一個是最佳化問題:在反向傳播時,梯度逐層往回流,可能一路縮向零——這就是梯度消失——於是靠前的層幾乎學不到東西。第二個是泛化問題:一個動輒上百萬參數的龐大模型,可能乾脆把訓練集背下來,從而過擬合,而不是學到真正的規律。本篇的三個技巧,各自瞄準其中一個或兩個問題。

隨機失活:訓練的是一支合唱團,不是一位獨唱

[[dropout|隨機失活]]簡單得幾乎讓人意外。在每一步訓練裡,你隨機關掉一部分神經元——比如一半——把它們這一步的輸出置為零。下一步,又是另一批隨機的神經元熄滅。網路永遠沒法指望某個特定神經元總在場,因為它隨時可能缺席。

它為什麼幫的是*泛化*?因為它阻止神經元結成脆弱、過度專門化的小團伙——人們稱之為「共適應」:某個特徵只有在另外三個特定鄰居一起發火時才管用。被迫應對隨機缺席後,每個神經元都得多少獨立地學到點真正有用的東西。一個很美的理解角度是:隨機失活其實在偷偷訓練一個巨大的「瘦身網路」集成,它們共享權重,並在測試時被平均起來。靠冗餘換來的穩健。

一個常把新手絆倒的細節:隨機失活*只*在訓練時開啟。到推理時,你用的是每個神經元都在場的完整網路。為了讓數學保持一致,激活值會被縮放,使兩種模式下的「期望總訊號量」對得上。忘了這個縮放,模型一上線行為就變了樣。

歸一化:讓訊號保持「正常體溫」

訊號一層層往上傳,它的尺度可能漂移——數值要麼膨脹得巨大,要麼塌縮得極小——而這種漂移會讓損失曲面變得極難行走。[[batch-normalization|批歸一化]]這樣解決:在每一層,把激活值重新置中、重新縮放,使其大致均值為零、方差為一。關鍵在於,它是在當前這一小批量樣本上計算這個均值與方差的,再讓網路學習兩個參數對結果做縮放與平移,以免丟掉表達能力。

它換來什麼?主要是*最佳化*上的好處:損失曲面變得更平滑,於是你能用更大的學習率,訓練收斂快得多。它還帶有輕微的正則副作用,因為按批計算的統計量會注入一點雜訊。2015 年那篇原始論文把功勞歸於減少了「內部協變量偏移」——但後續研究表明,損失曲面更平滑才是更好的解釋。這也提醒我們:一個技巧可以效果驚人,哪怕它最初對「為什麼有效」的說法後來被證明並不完整。

批歸一化有個真實的弱點:它依賴於批。當批很小,或者在循環網路裡同一層要在變長序列上反覆運行時,那些按批統計量會變得嘈雜、不可靠。[[layer-normalization|層歸一化]]繞開了這點:它不是跨批、而是*在單個樣本內部*跨特徵去歸一化。它根本不需要任何批統計量——這正是它成為支撐當今語言系統的Transformer模型內部預設選擇的原因。

殘差連接:給梯度修一條捷徑

最大膽的修法恰恰也是最簡單的。[[residual-connection|殘差連接]](2015 年 ResNet 的核心)把一層的*輸入*直接加到它的*輸出*上:與其要一個模組算出完整答案 H(x),不如只讓它算出那點*變化量* F(x),再把 x 加回來。這個模組學的是一個殘差——對已經傳到的訊號做一點修正——而不是從頭重造整個訊號。

# a plain block:        y = F(x)
# a residual block:     y = F(x) + x
#
# in backprop, the gradient through 'y' splits:
#   dL/dx = dL/dy * (dF/dx + 1)
#                              ^ the +1 is the shortcut:
#                                gradient flows even if dF/dx -> 0
那個「+ x」意味著一部分梯度原封不動地抵達更早的層——正是這個「+1」擊敗了梯度消失。

看看程式片段裡的數學:因為加了 x,往回流的梯度多出一個乾淨的「+1」項。哪怕這個模組自身的導數縮向零,那個 +1 也能讓一股健康的訊號繼續流向下面的層。這就直接擊敗了梯度消失,也正因如此,殘差讓研究者得以訓練幾百層深的網路——這種深度在過去根本無法訓練。

還有第二個、更溫和的好處。如果某個模組沒什麼有用的東西可加,它最容易學到的就是輸出接近零,於是 y ≈ x——一個恆等映射。所以殘差網路實際上能*自己挑選深度*,只用它需要的那些層,悄悄跳過其餘的。額外的深度不再是負擔,而變成模型可取可捨的一種選項。

它們如何協同(以及它們修不了什麼)

在一個現代深度網路裡,這些技巧不是對手,它們是疊在一起用的。一個典型模組會先對輸入做歸一化,跑一個帶非線性ReLU激活的變換,加一點隨機失活,再把整塊用殘差連接包起來。每個技巧治不同的病——殘差管梯度流動,歸一化管損失曲面更平滑,隨機失活管過擬合——所以合在一起,就能訓練出十年前根本沒指望的模型。

  1. 隨機失活——訓練時隨機丟棄神經元;靠強制冗餘對抗過擬合。推理時關閉。
  2. 歸一化——把激活值重新置中、縮放;讓損失曲面更平滑,使訓練更快更穩。批歸一化跨批計算,層歸一化在單個樣本內計算。
  3. 殘差連接——把輸入加回到輸出上;給梯度一條捷徑,讓極深的網路仍然訓得動。

現在說點誠實的話,因為這個領域充斥著誇大其詞。這些技巧沒有一個能增添知識,也沒有一個能讓模型「理解」任何東西——它們只是讓最佳化得以成功的管道工程。它們救不了一個有缺陷的資料集、一個錯誤的目標,或一個對著錯誤問題發力的模型;垃圾進,依舊垃圾出。而且「我們現在訓得動了」並不等於「它學到了對的東西」——一個 200 層的殘差網路照樣會過擬合,照樣會抓住虛假的捷徑,照樣會在訓練分布之外無法泛化

儘管如此,它們的歷史影響怎麼說都不算誇張。這三個毫不起眼的點子——丟掉一些、歸一化一些、加一條捷徑——基本上就是把「深度」從一個夢想變成日常工具的關鍵。帶著它們繼續走:當你在下一階遇到 Transformer 時,會發現每一個模組外面都裹著殘差連接和層歸一化。你在這裡學到的管道從未消失——它只是被放大了。