為什麼序列與眾不同
在上一篇指南中,你認識了卷積網路,它把影像當作一個凍結的網格,在每個位置滑動同一個濾波器。這種做法很出色,因為角落裡的貓仍然是貓。但現在考慮一個句子。詞是按順序到達的,而順序本身就是含義:「狗咬人」和「人咬狗」用的是完全相同的字,卻描述了相反的事件。一個只看到凍結快照的網路無法尊重這種順序。
序列無處不在:句子中的詞、旋律中的音符、逐日的價格、影片中的影格、感測器的讀數。對於標準前饋網路而言,它們有兩個棘手的共同特徵。第一,它們沒有固定長度——一則推文和一部小說都是文字。第二,先出現的內容應當影響我們對後來內容的解讀。我們需要一種架構,其連線本身就能把資訊沿時間向前傳遞。
那個循環:一張被反覆重寫的便籤
循環神經網路(RNN)一次一步地讀取序列,並在每一步保持一份不斷更新的記憶,稱為隱藏狀態。想像你朗讀時手裡拿著一張便籤。你讀第一個詞,記下一個簡短的概要;讀下一個詞時,你重寫便籤,把剛學到的內容融進去;如此直到結尾。便籤從不變大——它每一步都被覆寫——但讀到最後一個詞時,它已攜帶了此前一切的壓縮痕跡。
關鍵的細節在於:每一步應用的是*同一個*更新規則。網路只有一小組權重,它在第一個詞、第二個詞、第三千個詞上都重複使用這同一組。這種循環複用正是「循環」的含義,也是為什麼一個小小的網路就能處理任意長度的序列。新的隱藏狀態由上一個隱藏狀態和當前輸入算出,再經一個像 tanh 這樣的激活函數壓縮。
h = zeros() # the sticky note starts blank
for x in sequence: # read one step at a time
h = tanh(W_h @ h + W_x @ x + b) # rewrite the note
y = output(h) # optional: emit something each step
# same W_h, W_x, b reused at EVERY step訓練依靠一個叫做時間反向傳播的思路。你在腦中把循環「展開」成一條長鏈——每一步一份網路副本——然後沿著它執行普通的反向傳播,把每個權重在它被使用的所有步驟上的貢獻加總起來。從概念上說,這就是你已經熟悉的鏈式法則,只是沿時間被拉長了。
記憶難題
這就是幾乎扼殺 RNN 的頑固弱點。由於記憶在每一步被擠壓並重寫,早期詞語的影響往往會消退。更糟的是,訓練時誤差信號必須沿著同一條長鏈回傳,每一步都被乘上一個數。如果這些數小於一——而 tanh 平坦的尾部很容易導致這一點——把許多這樣的數相乘會讓信號以指數速度趨向零。這就是你在深層網路那一級見過的梯度消失問題,如今從層間被拉長到了時間之上。
在實踐中,這意味著普通 RNN 難以連接相距很遠的內容。設想:「今天早上,在那場漫長而混亂的會議之前,我落在廚房桌上的鑰匙……不見了。」當網路讀到「不見了」時,主語「鑰匙」已在許多步之前,而消退的記憶或許已不記得它是複數。長程依賴——代詞與它十句話之前所指的名詞——正是普通 RNN 無法把握的。
還有一個鏡像的危險:如果那些逐步的數大於一,信號反而會爆炸——梯度爆炸——訓練便會失穩為劇烈的震盪。常見的補救是梯度裁剪:每當梯度增長過大就限制它的大小。裁剪能馴服爆炸,卻對消退方向無能為力。消失問題需要更深層的解決方案。
閘控:LSTM 與 GRU
突破在於:不再每一步都覆寫整份記憶。LSTM(長短期記憶)保留一條受保護的記憶線,稱為細胞狀態——想像一條輸送帶筆直穿過整個序列,只有在被指示時才裝卸貨物。資訊可以幾乎原封不動地從第三個詞一路乘到第三百個詞。而正因為它能原封不動地乘行,誤差信號也能沿它回流而不消退,繞開了梯度消失的陷阱。
負責「指示」的,是一組叫做閘的小閥門——一個個微小的、可學習的控制器,每個透過 sigmoid 輸出一個介於 0(完全關閉)與 1(完全打開)之間的數。遺忘閘決定抹去哪些舊記憶;輸入閘決定哪些新資訊值得儲存;輸出閘決定此刻揭示多少記憶。因為這些閘可以選擇不去觸碰細胞狀態,早期學到的事實便能存活下來。
GRU(閘控循環單元)是一個精簡的近親,用更少的部件追求同樣的目標。它只用兩個閘——一個更新閘,在「保留我已知的」和「接納剛到來的」之間調和;一個重置閘,決定忽略多少過去——並把細胞狀態和隱藏狀態合併為一。在實踐中,GRU 與 LSTM 表現相近;兩者都不是普遍更優,所以人們常常都試一試。GRU 更輕、訓練略快,這在較小資料集或較緊的硬體上有幫助。
RNN 造就了什麼——以及為何 Transformer 取而代之
從 1990 年代末到 2017 年前後,閘控 RNN 一直是序列學習的主力。它們驅動了第一波真正出色的機器翻譯、語音辨識、手寫辨識,以及你手機上的輸入預測。它們催生的一個關鍵模式是編碼器—解碼器結構:一個 RNN 讀入整段輸入並壓縮成一個概要,第二個 RNN 則以該概要及自己已生成的內容為條件,一次一個詞元地生成輸出。
那個配方有一個瓶頸:把整句話壓進一個概要向量,在長輸入上會卡住。解決辦法是讓解碼器按需回看輸入的任意部分——這就是注意力機制。注意力最初是作為輔助件被加裝到 RNN 上的。隨後在 2017 年,人們意識到可以徹底丟掉循環,只保留注意力:這便是 Transformer。
Transformer 為何取勝?不是因為注意力是魔法,而是因為一個實際的工程事實:RNN 必須一次一步地讀取,因此無法在序列維度上並行化,且在長輸入上很慢。Transformer 一次性讀取整個序列,這恰好契合現代 GPU 的並行硬體。這使得在海量得多的資料上訓練成為可能——而在今日大語言模型的規模下,規模才是最要緊的。