謎題:深度本應有幫助,但當初卻沒有
現在你已經搭好了整台機器:一個做加權求和的人工神經元,把層堆疊成的多層感知機,把輸入變成預測的前向傳播,以及把誤差訊號送回去微調每一個權重的反向傳播。理論上,層數越多能力越強——通用逼近定理甚至承諾:只要網路足夠寬,就能擬合幾乎任何函式。所以配方看起來很明顯:想要更聰明的網路?多加幾層。
幾十年來,這個配方一直失敗。在整個 1990 與 2000 年代,研究者發現:層數超過幾層的網路訓練得很慢,甚至根本學不動——深層版本往往*還不如*淺層版本,即使在訓練資料上也是如此。這不是過擬合(死記訓練集);而是更詭異的東西。網路就是學不會。罪魁禍首原來就藏在反向傳播自己內部。
梯度消失與梯度爆炸
回想反向傳播是怎麼運作的:要算出某個靠前的權重該改變多少,鏈式法則會把這個權重與損失之間每一層的局部斜率連乘起來。網路越深,這條連乘鏈就越長。而把很多個數連乘有一個殘酷的性質:如果它們大多小於 1,乘積會飛速衝向零;如果它們大多大於 1,則會爆炸般衝向無窮。
這就是梯度消失問題(以及它邪惡的孿生兄弟:梯度爆炸)。經典的罪魁是 sigmoid 激活函式。它的斜率在中間最陡,但當輸入很大或很小時會壓平到幾乎為零——而且它的最大斜率也只有 0.25。把十個 sigmoid 串起來,到達第一層的梯度最多只有 0.25¹⁰ ≈ 原來的百萬分之一。最靠前的那些層——本應學習最基礎特徵的地方——幾乎得不到任何訊號,只能凍結在隨機的初始值上。
# gradient reaching layer 1 = product of per-layer slopes grad_L1 = slope_10 * slope_9 * ... * slope_2 * slope_1 # if every slope ~ 0.25 (sigmoid's best case): 0.25 ** 10 = 0.00000095 # vanished # if every slope ~ 1.5 (poorly scaled weights): 1.5 ** 10 = 57.7 # exploded
梯度爆炸則是鏡像情形:當乘積增大時,權重更新變得巨大而失控,損失跳成 `NaN`,訓練直接引爆。這兩種失敗有同一個根源——梯度的*大小*會隨深度被連乘放大或縮小,而我們必須讓這個累積乘積一路上下都保持在 1 附近,既不收縮也不膨脹。
修復一:從正確的尺度起步(權重初始化)
第一個槓桿是你從*哪裡*起步。每個網路都從隨機權重開始——但這種隨機的尺度極其關鍵。初始權重太大,訊號(和梯度)就會逐層放大、爆炸;太小,則會層層縮水、消失。把尺度調對,訊號就能一路保持大致恆定的大小。這個選擇叫做權重初始化,它正是那種看似無足輕重、卻決定一個深度網路到底能不能學起來的細節。
2010 年的想法(Xavier/Glorot 初始化)簡單得讓人意外:給隨機權重設定尺度,使訊號的*變異數*在每一層之後保持不變。粗略地說,就是除以輸入連接數的平方根,這樣一個彙總許多輸入的神經元就不會炸開。2015 年的改進(He 初始化)則針對會砍掉一半輸入的 ReLU 層調整了那個常數。沒有新的數學機器——只是把起始旋鈕調到合適的位置,讓那條連乘鏈一開始就是平衡的。
修復二:更好的激活函式,以及給梯度拴上韁繩
第二個槓桿是激活函式本身——這是最直接幹掉梯度消失的改動。把會飽和的 sigmoid 換成 ReLU(正數就原樣輸出、否則輸出零),它對每個正值的斜率恰好是 1。斜率為 1 時,梯度穿過它不會被縮小;串上一百個,訊號仍然存活。這個簡單到幾乎令人尷尬的改動,正是 2012 年深度學習突破得以發生的重要原因之一。
ReLU 並不完美——卡在負區的神經元會永遠輸出零(「ReLU 死亡」),這正是 leaky ReLU 等變體存在的原因。要誠實地說:這些都是務實的工程修復,而不是一套乾淨的理論。對於*爆炸*那一側,韁繩是梯度裁剪:如果梯度的整體長度超過閾值,就在更新前把它按比例縮回去。手法粗糙,卻能可靠地阻止損失引爆——尤其在循環網路裡,因為同一組權重被反覆施加、鏈條會變得極長。
修復三:歸一化訊號,並給梯度一條捷徑
良好的初始化只在訓練*開始*時設定好尺度,但隨著權重變化,訊號可能又漂回爆炸或消失。修復辦法是在訓練*過程中*、在每一層把激活值重新置中、重新縮放。這就是批次正規化及其表親層正規化背後的想法:讓每一層的輸出保持在健康的範圍內,這樣無論權重怎麼變,梯度都表現良好。下一階梯會完整介紹它們;現在只需知道,它們的存在是為了讓那條連乘鏈在整個訓練過程中、而不只是開頭,都保持在 1 附近。
最優雅的修復是殘差連接(2015),它是 100 多層網路背後的訣竅。與其逼著每個模組去變換訊號,不如讓它在輸入上*加*一個小的調整,同時讓原始訊號原封不動地穿過:`輸出 = 輸入 + 模組(輸入)`。這小小的 `+ 輸入` 給了梯度一條直通前面各層的高速公路,完全繞開了那條漫長的連乘鏈。一夜之間,更多的層真的可以意味著更好的結果——那個古老的配方終於奏效了。
這到底意味著什麼(以及不意味著什麼)
退一步,看看這個故事的形狀。深度學習在 2012 年騰飛,並不是因為有人發現了關於智慧的某種深奧新理論。它騰飛,是因為一批樸實無華的修復——ReLU、合理的初始化、正規化、殘差連接,再加上快得多的 GPU 和更大的資料集——合在一起,讓梯度下降在深度網路上*真正能用了*。反向傳播的數學從未改變。我們只是學會了如何讓它的訊號穿越許多層而不死掉。
有兩個迷思值得抵制。第一,「越深越好」是錯的——超過某個點,多加的層只會帶來成本和不穩定卻毫無收益,而且深度永遠替代不了好資料。第二,這些技巧在一定程度上是*經驗性*的:殘差連接和批次正規化顯然有幫助,但學界至今仍在爭論*究竟為什麼*。這份誠實很重要。明白今天的深度網路靠的是一把精心設計的妙招、而非一套完成的理論,正是這條階梯其餘部分賴以建立的那種清醒認知。
- 診斷:堆疊許多層後,梯度作為各層斜率的長連乘,要麼消失趨近於零,要麼爆炸趨於無窮。
- 起步要對:給隨機權重設定尺度(Xavier/He),讓訊號變異數逐層保持不變。
- 使用不飽和的激活函式(ReLU),讓接近 1 的斜率不縮小梯度;當它有爆炸之虞時進行裁剪。
- 在訓練過程中用正規化穩住陣線,並用殘差連接給梯度一條回家的捷徑。