斜率不過是「變化有多快」
先把「微積分」這個詞放一邊。想像你在徒步,低頭看腳下:地面是平的、緩緩上升的,還是陡峭攀升的?那種感覺——再往前邁一步,你的高度變化多少——就是斜率。導數不過就是這個斜率,在曲線上某一個點處測出來的值。如果一個函數 f 把輸入 x 變成輸出,它的導數告訴你:把 x 輕輕推動一點點,輸出會移動多少、朝哪個方向?
讓導數成為「某一點的斜率」而不是「某一段的斜率」,靠的是把步子縮到幾乎消失。在曲線上取相鄰的兩點,畫出它們之間的直線,讀出它的傾斜:上升量除以前進量。現在把第二個點不斷地往第一個點靠近。這條直線就不再是粗略的平均,而變成精確的切線——也就是曲線在那一點的斜率。那個極限處的傾斜,就是導數。
把符號和大小當成儀表盤來讀。導數為正,意味著你向右移動時曲線在上升;為負則在下降;為零則是平的——一個山峰、一個山谷,或者一段暫時的平台。數值大表示陡,數值小表示幾乎水平。這就是導數全部的「情緒內容」:朝哪個方向、有多用力。
從一個旋鈕到許多個:梯度
單個導數回答的是一個輸入的問題。但真正的模型有成千上萬、甚至上億個可調的數字——它的權重和參數。想像一台調音台,上面是一大排推子,還有一個你想往下壓的輸出表(誤差)。對每一個推子,你都能問同一個小問題:如果我只推動這一個,表會往哪邊動、動多少?做這件事時,把其他所有推子都按住不動——這種一次只動一個推子的斜率,就是偏導數。
現在把所有這些「一次一個」的斜率收集成一張清單——每個推子對應一個數字。這張清單就是梯度。因為它不過是一摞帶著長度和方向的數字,所以它是一個向量,正是你在前面向量那篇裡見過的那種對象;正是這種向量視角,讓我們能一次性談論所有旋鈕,而不必一個一個地折騰。
這裡有一個值得記住的事實:梯度指向上升最陡的方向。在霧裡站在山坡上,梯度就是那根指南針,告訴你「此刻沿這個確切的方向走,爬得最快」。它的長度告訴你這條最快上坡有多陡。而相反的方向——負梯度——指向最快*下山*的路。那個朝下的箭頭,正是梯度對學習重要的全部原因。
鏈式法則:相乘的斜率
真正的模型不是單個函數;它們是函數套在函數裡面。原始輸入餵給一層,那一層的輸出餵給下一層,最後的輸出再餵給誤差。要學習,我們需要那個最終誤差對深埋其中某個旋鈕的斜率。鏈式法則正是讓我們拿到它的規則,而它的想法簡單得幾乎令人尷尬:當變化沿著一條鏈條傳遞時,它們的斜率會相乘。
想像一組齒輪。如果大齒輪每轉 1 圈,中齒輪轉 2 圈;中齒輪每轉 1 圈,小齒輪轉 3 圈,那麼大齒輪每轉 1 圈,小齒輪就轉 3 × 2 = 6 圈。你是通過把鏈條上各處的局部比率相乘,得到了整體比率。鏈式法則對斜率說的正是這件事:末端對起點的敏感度,等於每一環對它前一環敏感度的乘積。
這種相乘也解釋了為什麼深層網路會很嬌氣。如果許多環節各自的斜率都小於 1,那麼隨著鏈條變長,乘積會朝零收縮,最早的那些層幾乎感受不到誤差——這就是著名的梯度消失問題。如果環節大於 1,乘積反而可能爆炸。鏈式法則對這兩種情況都很誠實:它只如實報告相乘的結果,哪怕答案小得或大得令人頭疼。
對於一個真實的網路,你幾乎永遠不會用手去套鏈式法則。軟體會為每一個運算建立一張計算圖,再倒著走一遍,自動把局部斜率相乘——這種技術叫自動微分,也是反向傳播背後的引擎。你的任務不是手搖代數,而是信任它算出的結果;並且在訓練卡住時,能認出背後悄悄作祟的,正是這條相乘斜率的鏈條。
為什麼梯度驅動學習
現在一切都對上了。「學習」意味著調節旋鈕,讓模型的錯誤變小。我們用一個損失函數來度量這些錯誤——它是一個數字,模型對的時候低,錯的時候高。全部權重合在一起,定義出一片廣闊、起伏的曲面,叫做損失地形,其中海拔就是損失。訓練就是在那片曲面上尋找一處低谷,而梯度是我們唯一用來判斷哪邊是下坡的感官。
這個配方簡單得近乎可笑。算出梯度(哪邊是上坡),把它反過來朝下,邁一小步,然後重複。這個循環就是梯度下降,幾乎訓練每一個現代模型的主力。每步的大小由一個叫學習率的旋鈕決定:太小,學習就爬行;太大,你就一步跨過山谷,來回亂彈。大多數網路用的是一個廉價、帶雜訊的版本,每次只用少量樣本來邁步——隨機梯度下降——它更快,而且很奇妙地,往往泛化得更好。
# one step of learning, in four honest lines loss = compute_loss(model, batch) # how wrong are we? grad = gradient(loss, model.weights) # which way is uphill? model.weights -= learning_rate * grad # step the opposite way # ...repeat thousands of times until loss stops dropping
對它能帶來什麼,要誠實。梯度下降可靠地找到的是一處*低*點,而不是*最低*點——這片地形裡佈滿了局部極小與鞍點,那裡斜率是平的,但你並不在谷底。對於較簡單模型那種碗形的、凸的損失,這沒問題;但對於深層網路,根本談不上保證,我們歪打正著掉進去的那些谷底通常夠用,這是實踐中的一點小小奇蹟(而非定理)。
帶著往後走的東西
要讀懂這條階梯後面的內容,你一個導數都不用手算。你需要的是那幅畫面:導數是曲線在一點處的斜率,梯度把許多旋鈕的這些斜率收集起來並指向上坡,鏈式法則把斜率穿過層層套疊的函數相乘,而學習不過是反著梯度一次次往下坡邁步。記住這四句話,後面那些笨重的機器,就會像一位你早已認識的朋友。
- 導數 = 一點處的斜率:當你推動一個輸入時,輸出朝哪個方向、以多陡的程度移動。
- 梯度 = 一個偏導數向量,每個旋鈕一項;它指向上升最陡的方向,所以它的相反方向指向下坡。
- 鏈式法則 = 斜率沿著函數鏈相乘;這正是反向傳播所自動化的事。
- 學習 = 沿著負梯度一小步一小步地走,直到損失不再下降——並接受它落入的是一處不錯的谷底,而非完美的那個。
最後一句對炒作的提醒:梯度裡沒有魔法。它給模型的是一種方向感,而不是理解。梯度無法告訴你資料是否有偏、損失是否在度量正確的東西,也無法告訴你更低的誤差是否意味著真正的智能。它是一個絕妙而簡單的指南針——而指南針的好壞,取決於你拿它對著的那張地圖。保留這份懷疑;在這條階梯上方的每一級,它都會幫到你。