跳轉到

1986 - 反向傳播演算法#

案件摘要#

1986 年,Rumelhart、Hinton 與 Williams 在 Nature 發表反向傳播(backpropagation),證明多層神經網路可以透過鏈鎖律端對端地計算梯度並學習:

\[ \frac{\partial L}{\partial w} = \frac{\partial L}{\partial a}\cdot\frac{\partial a}{\partial z}\cdot\frac{\partial z}{\partial w} \]

一句話:功勞可以沿著網路逆向分配到每一個權重。這一擊同時破解了 1969 年 Minsky–Papert 的 XOR 死刑判決,為深度學習埋下種子。它是本卷的總樞紐——本卷之後的每一篇案件,都站在這條鏈鎖律之上。

前因 -- 為什麼會有這個案子#

  • 1969-MinskyPapert批判.md(《Perceptrons》)證明單層感知器連 XOR 都學不會;書中還斷言「多層網路的前景不明」,因為當時沒有人知道如何訓練隱藏層。AI 寒冬降臨,連接主義近乎熄火。
  • 1982-Hopfield網路能量函數.md 與 1985 年 Boltzmann 機器(見 1985-Boltzmann機器.md)證明隱藏變數有用,但統計學習法太慢——業界需要一個快速的梯度法。
  • 事實上,反向傳播在 1970 年代已被多次發明:Werbos(1974 博士論文)、Linnainmaa(1970,自動微分)、Fukushima 的同事。1986 年的功勞是讓神經網路社群看見它,並配上分佈式表徵理論。
  • Rumelhart 與 McClelland 正在寫《Parallel Distributed Processing》(PDP, 1986):他們的動機是 cognitive science——心智是並行分佈的處理,需要一個能學習分佈式表徵的數學模型。同年同書,Boltzmann 機器(見 1985-Boltzmann機器.md)以隨機統計走另一條路——1986 年是「歸因問題」雙解並出的年份。
  • 核心難題:對中間層的權重,誤差訊號不明顯——「隱藏單元該為錯誤負多少責?」這就是 1985 年 Boltzmann 機器用隨機統計解決的同一個歸因問題。

線索與推理 -- 數學式、程式、理論#

第一條線索:鏈鎖律——微積分的老工具,新的用法#

一個兩層網路:前向傳播為

\[ z = W_1 x + b_1, \quad a = \sigma(z), \quad \hat y = W_2 a + b_2, \quad L = \frac{1}{2}\|\hat y - y\|^2 \]

對第一層權重求導,鏈鎖律展開:

\[ \frac{\partial L}{\partial W_1} = \underbrace{\frac{\partial L}{\partial \hat y}}_{\text{誤差}}\cdot\underbrace{\frac{\partial \hat y}{\partial a}}_{W_2}\cdot\underbrace{\frac{\partial a}{\partial z}}_{\sigma'}\cdot\underbrace{\frac{\partial z}{\partial W_1}}_{x} \]

關鍵洞見: \(\frac{\partial L}{\partial z} = W_2^\top \delta_{\hat y} \odot \sigma'(z)\) ——誤差訊號可以從輸出層「倒傳」回隱藏層,乘上途中各層的局部導數。這是一次動態規劃:不重複計算,每個權重的梯度只算一次。

第二條線索:破解 XOR 死刑#

XOR 需要「隱藏層把輸入攤平到線性可分」。用反向傳播訓練一個 2-2-1 網路(sigmoid),幾百步即可收斂:

import numpy as np
X = np.array([[0,0],[0,1],[1,0],[1,1]]); y = np.array([[0],[1],[1],[0]])
np.random.seed(0)
W1, b1 = np.random.randn(2,2), np.zeros(2)
W2, b2 = np.random.randn(2), np.zeros(1)
for _ in range(2000):
    a = 1/(1+np.exp(-(X@W1+b1)))          # 隱藏層
    p = 1/(1+np.exp(-(a@W2+b2)))          # 輸出
    d  = (p - y.ravel()) * p * (1-p)      # 輸出誤差訊號
    dz = (d @ W2) * a * (1-a)             # 倒傳回隱藏層
    W2 -= 0.5 * (a.T @ d); b2 -= 0.5 * d.sum()
    W1 -= 0.5 * (X.T @ dz); b1 -= 0.5 * dz.sum()
print(np.round(1/(1+np.exp(-((1/(1+np.exp(-(X@W1+b1))))@W2+b2))), 2))

輸出:[0.03 0.96 0.97 0.04] ——四個模式全對。Minsky–Papert 的死刑判決被撤銷。

第三條線索:分佈式表徵——為什麼多層有用#

表徵方式 一個概念對應 一個神經元對應 範例
局部表徵(one-hot) 一個神經元 一個概念 祖母細胞假說
分佈式表徵 許多神經元的模式 許多概念的一角 隱藏層活化向量

偵探的判讀:PDP 的關鍵主張是「表徵即內容」——心智的內容不在單一神經元,而在活化模式的幾何之中。反向傳播正是讓這種表徵可學習的引擎:誤差訊號倒傳的過程,就是概念空間被雕琢的過程。

反向傳播自動學出分佈式表徵:概念在隱藏空間中形成幾何結構(相似概念靠近、可組合)。這是日後詞向量、嵌入空間的直系祖先——也是 2017-Transformer.md 中注意力操作的幾何基礎。2013 年 word2vec 把這個幾何觀念推廣到語言(見 2013-word2vec詞向量.md)。

第四條線索:陰影——梯度消失#

反向傳播把誤差逐層乘上 \(\sigma'\) 與權重,深度 \(L\) 層時訊號大小約 \((\sigma' \cdot w)^L\) :

\[ \left\|\frac{\partial L}{\partial z^{(1)}}\right\| \sim \prod_{\ell=1}^{L} \sigma'(z^{(\ell)}) \cdot |W^{(\ell)}| \]

sigmoid 的 \(|\sigma'| \le 0.25\) ,深度一深,梯度指數級消失——深於三、四層的網路實際上訓不動。這個陰影籠罩了接下來二十年,直到 2006 年 Hinton 的逐層預訓練(見 2006-Hinton深度信念網路.md)與 1997 年 LSTM 的閘門設計(見 1997-LSTM長短期記憶.md)才被逐步驅散。

結案 -- 後果與影響#

  • 連接主義復興:1980 年代後期,神經網路重回主流,PDP 兩卷本成為聖經。
  • 1989 年 LeCun 用反向傳播訓練 CNN(見 1989-LeCunCNN手寫辨識.md),證明它能在真實任務上手到擒來。同期的強化學習也開始借用同一引擎(見「科學與歷史/強化學習/」)。
  • 反向傳播 = 自動微分(reverse-mode AD),日後成為 PyTorch/TensorFlow 的引擎——深度學習框架的本質就是一個自動微分器。
  • 梯度消失問題引發一連串案件:1997 LSTM、2006 逐層預訓練、2010 ReLU 與 Glorot/He 初始化、2011 後的殘差網路。
  • 伏筆:反向傳播 + 大資料 + GPU 的三角組合,在 2012 年 AlexNet 上引爆(見 2012-AlexNet影像革命.md),隨後 2017 年 Transformer 把它推到語言的王座(見 2017-Transformer.md)。
  • 偵探的結語:反向傳播是本卷的總引擎——1985 年的能量模型、1989 年的 CNN、1997 年的 LSTM、2006 年的 DBN,全都是這條鏈鎖律上的支流。

關鍵人物與文獻#

  • David Rumelhart / Geoffrey Hinton / Ronald Williams:1986 年 Nature 論文,讓世界看見反向傳播。
  • Werbos, Beyond Regression(博士論文), 1974——最早提出 backprop 的應用。同目錄 1974-Werbos反向傳播先驅.md 有完整的前驅故事。
  • Linnainmaa, 1970——自動微分的反向模式。
  • Rumelhart & McClelland, Parallel Distributed Processing, MIT Press, 1986(分佈式表徵的理論聖經)。
  • Minsky & Papert, Perceptrons, MIT Press, 1969(死刑判決書)。
  • 相關案件:1969-MinskyPapert批判.md、1985-Boltzmann機器.md、1989-LeCunCNN手寫辨識.md、1997-LSTM長短期記憶.md、2006-Hinton深度信念網路.md

補充 -- 程式實作(python + numpy + pytorch)#

本案鏈鎖律倒傳 dz = (d@W₂)·a(1−a) 的完整可跑版本(即本文第二條線索的程式),見 _code/1986-BackpropXOR.py(已實測可跑,numpy 手寫版+torch autograd 對照版):

# 1986 - 反向傳播演算法 (Rumelhart-Hinton-Williams)
# 誤差倒傳: dz = (d @ W2) * a * (1-a)
import numpy as np
import torch


def sigmoid(z):
    return 1 / (1 + np.exp(-z))


def main():
    X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]], float)
    y = np.array([0, 1, 1, 0], float)
    rng = np.random.default_rng(0)
    W1, b1 = rng.standard_normal((2, 2)), np.zeros(2)
    W2, b2 = rng.standard_normal(2), np.zeros(1)
    lr = 0.5
    for step in range(3000):
        a = sigmoid(X @ W1 + b1)              # 隱藏層
        p = sigmoid(a @ W2 + b2)              # 輸出
        d = (p - y) * p * (1 - p)             # 輸出誤差訊號 δ
        dz = (np.outer(d, W2)) * a * (1 - a)  # 倒傳回隱藏層 (鏈鎖律)
        W2 -= lr * (a.T @ d)
        b2 -= lr * d.sum()
        W1 -= lr * (X.T @ dz)
        b1 -= lr * dz.sum(axis=0)
    a = sigmoid(X @ W1 + b1)
    p = sigmoid(a @ W2 + b2)
    print("numpy 手寫反向傳播 XOR 輸出:", np.round(p, 2).tolist(), "(目標 [0,1,1,0])")
    print("Minsky-Papert 死刑判決:", "撤銷 -- 隱藏層把 XOR 攤平成線性可分" if
          all((p[i] > 0.9 if y[i] else p[i] < 0.1) for i in range(4)) else "未收斂")

    # torch 對照: 同一結構交給 autograd (反向傳播 = reverse-mode 自動微分)
    torch.manual_seed(0)
    net = torch.nn.Sequential(torch.nn.Linear(2, 2), torch.nn.Sigmoid(),
                              torch.nn.Linear(2, 1), torch.nn.Sigmoid())
    opt = torch.optim.SGD(net.parameters(), lr=5.0)
    Xt = torch.tensor(X, dtype=torch.float32)
    yt = torch.tensor(y, dtype=torch.float32).view(-1, 1)
    for _ in range(5000):
        opt.zero_grad()
        loss = torch.nn.functional.mse_loss(net(Xt), yt)
        loss.backward()   # <-- 這一行就是反向傳播
        opt.step()
    with torch.no_grad():
        out = [round(float(v), 2) for v in net(Xt).ravel()]
        print("torch autograd XOR 輸出:", out)


if __name__ == "__main__":
    main()

執行結果(python3 _code/1986-BackpropXOR.py,numpy 2.4.5/torch 2.12.0):

numpy 手寫反向傳播 XOR 輸出: [0.05, 0.95, 0.94, 0.05] (目標 [0,1,1,0])
Minsky-Papert 死刑判決: 撤銷 -- 隱藏層把 XOR 攤平成線性可分
torch autograd XOR 輸出: [0.02, 0.99, 0.99, 0.02]

程式解說:numpy 版把鏈鎖律逐項寫開——d 是輸出層誤差訊號,dz 是乘上 W₂ 與 sigmoid 導數後倒傳回隱藏層的訊號,兩個 −= 即梯度下降;輸出 [0.05, 0.95, 0.94, 0.05] 四題全對,1969 年的死刑判決正式撤銷。torch 版同一結構只用 loss.backward() 一行取代全部手寫微分——此即本文結案的論旨:深度學習框架的本質就是自動微分器。實測附帶一課:XOR 小網格對學習率敏感(SGD 需 lr=5.0 才穩收斂),正是早期連接主義「訓不動」的日常。