一片由錯誤堆成的曲面
在上一篇裡你認識了損失函數:一個數字,告訴你模型當前在訓練資料上錯得有多離譜。現在把模型每一個可調的參數——每一個權重和偏置——都想像成一個你能擰的旋鈕。把這些旋鈕在它們所有的取值裡掃一遍,對每一種組合都量一下損失。這就給了你一片地貌:模型錯的地方它隆起、對的地方它凹陷。這就是損失曲面,而梯度下降說穿了,不過是在它上面往下坡走的一種方法。
誠實的版本更難想像,但值得說出來。一個真實的網路有數百萬乃至數十億個旋鈕,所以這片地貌不是三維空間裡的一座小山——它是一個數百萬維空間裡的曲面。沒有人能看見它。但是*局部*的下坡走法,在百萬維裡和在山坡上是一模一樣的:就在你站著的地方感覺一下哪邊是下坡,然後朝那個方向邁一步。
哪邊是下坡?梯度告訴你
站在霧裡的山坡上,你看不見山谷——但你仍然能感覺到腳下的坡度。這種感覺的數學版本,就是梯度。對每一個旋鈕,我們都問一個偏導數:如果我把*這一個*旋鈕往上擰一絲絲、其餘旋鈕都按住不動,損失是漲還是落,又有多陡?把每個旋鈕的這些答案收進一支大箭頭裡,你就得到了梯度——它指向*最陡的上坡*方向。想下坡,你只要朝相反方向邁步就行。
我們究竟怎樣才能得到所有這些偏導數,而不必為了每個旋鈕把模型重跑一百萬遍?這正是反向傳播的活兒,你早先已經見過它:它在一次向後的掃掠中,逐層套用鏈式法則,就把*每一個*權重的梯度都算了出來。梯度下降是策略——逆著梯度邁步;反向傳播則是那台高效的機器,把梯度遞給它好讓它邁步。
# one step of gradient descent
grad = backprop(loss, params) # arrow pointing uphill
for each p in params:
p = p - learning_rate * grad[p] # step the opposite way
# repeat until the loss stops dropping步子邁多大?學習率說了算
梯度告訴你該往哪個方向邁,但沒告訴你邁多遠。這個距離由一個單一卻極其重要的旋鈕決定:學習率。它是一個超參數——一個由*你*在訓練前選定、而不是由模型學出來的設置。把梯度乘上學習率,這個乘積就是你這一步的大小。調對了,下降又快又穩;調錯了,整件事會以兩種截然相反的方式翻車。
太小,你就下山下得畏畏縮縮,訓練慢得沒有盡頭——還可能遠沒到谷底就卡在一塊平台上。太大,你就會衝過頭:一躍就橫跨整個山谷,落到一個*比出發點還高*的地方,接著又朝另一邊衝過頭,越彈越寬,直到損失炸到無窮大。最佳點是這樣一步:大膽到足以取得真正的進展,又溫柔到不至於一躍跳過山谷。找到它多半靠反覆試錯——這也正是為什麼人們要盯著一條損失隨時間變化的學習曲線,一眼就能看出自己正陷在哪一種翻車裡。
踩著樣本走,而不是踩著整張地圖
這裡有個現實的麻煩。要算出*真正*的梯度,你得先在整個資料集上量一遍損失,才能邁出一步。當例子有上百萬條時,這一步慢得讓人痛苦。所以在實踐裡我們會作弊——而且作得很划算。隨機梯度下降每次只用少數幾個例子、也就是一個小批量來估計坡度,然後踩著這個估計邁步。每一步都帶點雜訊,像隔著霧去讀坡度,但在邁出一個真正步子的時間裡,你能邁出成千上萬步。
把全部訓練資料完整走一遍,叫做一個輪次;訓練通常要跑很多輪,每一輪裡都邁出許多帶雜訊的小批量步子。出乎意料的是,這點雜訊往往是*特性*而非缺陷:那隨機的抖動能把行走者從一些淺坑裡顛出來,否則它本會卡在裡頭。現代最佳化器把這一套又做了精進——動量讓步子在持續的下坡方向上攢起速度,而Adam最佳化器會自動為每個旋鈕調整步長——但它們說到底,仍然都是這同一趟下坡之走。
它何時停下——又停在哪裡?
當你接近谷底,地面漸漸變平,梯度隨之變小,於是你的步子自然就短了下來。當損失不再有任何實質性的下降時,我們就說訓練達到了收斂。實踐中沒人會等梯度精確歸零;進展停滯時你就停手,或者更早——早停會在模型在留出資料上的表現不再提升的那一刻喊停,這同時也防住了過擬合(這一階後面有一篇專講它)。
可它*停在哪裡*呢?這裡有個老教科書曾反覆念叨的誠實陷阱。一趟下坡之走,只能找到*出發點附近*的一個低點——一個局部最小值——而無法保證那座山谷就是整片地貌裡最深的那個(全域最小值)。更糟的是,訓練可能在一個鞍點上慢到近乎停滯:那是個在某些方向往下、在另一些方向往上的地方,活像馬鞍的座面,那裡梯度幾乎是平的,行走者便磨蹭起來。這些險情都歸在局部最小值與鞍點名下。
接下來是真正出人意料的地方,也是低維直覺會把人帶偏的地方。在大網路那數百萬維的地貌裡,被困在一個*糟糕*的局部最小值中,結果是很罕見的:要讓一個點成為真正的最小值,地面必須在*每一個*方向上同時向上彎曲,而當方向有數百萬個時,這簡直不可能湊齊。大多數平坦處其實是鞍點,動量能把它滾過去;而大多數走得到的山谷,深淺其實都差不多。這正是為什麼梯度下降在實踐中遠比當年那套憂心忡忡的理論所預言的要好用——不是因為危險消失了,而是因為高維幾何比一座三維小山所暗示的要仁慈得多。
梯度下降到底承諾了什麼
剝去那層神祕感,這個方法其實很謙卑:它是一個倒過來跑的爬山者,沒有地圖,也不記得更遠處的地形,只是朝此刻感覺最下坡的方向,邁出一小步。它無法保證最好的模型,只能保證一個局部不錯的模型——而且它需要損失曲面是可微的,這樣你才總能讀出一個坡度來。這是個實打實的限制,卻是個出了名地好用的限制。幾乎每一個現代模型,從線性迴歸到一個大語言模型,都是用這同一趟下坡之走的某種變體訓練出來的。
所以下次有人說一個模型在「學習」,你現在就能精確地想像出這個詞底下究竟在發生什麼了。那裡沒有理解,沒有洞見——只有一個叫損失的數字、一個叫梯度的坡度,以及數百萬個朝下坡邁出的微小步子。叫人稱奇的不是每一步有多聰明;而是這麼多笨拙卻小心、朝對的方向邁出的步子,累加起來竟能做出會翻譯語言、會認出人臉的東西。這一階後面的幾篇,會展開那些為這些步子掌舵的最佳化器,以及懲罰走得太遠的過擬合。