為什麼不直接用 CPU?
到現在你已經知道,一個神經網絡在底層其實是一長串矩陣乘法,由激活函數黏接而成。無論是前向傳播還是反向傳播,用算術的話說,都是同樣那麼幾種運算,在大片大片的數字網格上重複億萬次。普通 CPU 是出色的通才:少數幾個極快的核心,幾乎什麼都能做,一件複雜的事接著一件。這恰恰是這份工作所不需要的形狀。我們要的不是每一步多聰明,而是把*同一個簡單步驟*——相乘再相加——荒唐地重複無數次,而且同時進行。
GPU(圖形處理單元)生來就是為了一次畫出幾百萬個像素,所以它的造法恰恰相反:成千上萬個又小又簡單的核心,對不同的數據齊步執行*同一條*指令。這碰巧正是一次矩陣乘法的樣子。TPU(張量處理單元)走得更遠——這是谷歌專為深度學習的張量運算設計的晶片,其電路讓數字像水流一樣穿過一格格乘加單元,從而幾乎不必去記憶體裡慢吞吞地往返取數。兩者都屬於我們稱為 GPU 與 TPU 的家族,而它們之所以要緊,頭號原因是並行:不是每一步更快,而是在同一瞬間發生的步驟多得多。
當一塊晶片不夠用
單塊現代加速器已經非凡,可一個基礎模型或大語言模型會從兩個彼此獨立的方向把它撐爆,把這兩者分開來看很值得。第一是時間:哪怕是一塊快晶片,要啃完在數萬億 token 上的一次訓練,也得花上幾年。第二是記憶體:模型的參數,加上更新它們所需的梯度與優化器狀態,根本塞不進一塊晶片的記憶體。任何一個問題,都會把你逼上分散式訓練——把工作拆到許多晶片、往往是許多台機器上,用高速鏈路連成一體。
這裡有一個定義整個領域的要害:協同工作的晶片必須彼此*交談*,而交談相比計算是慢的。每當兩塊 GPU 要就一個數字達成一致,位元組就得沿電纜奔走一趟,而那根電纜遠比晶片內部的運算慢得多。所以分散式訓練從來不是乾淨俐落的提速——加上第二台機器,從來都湊不滿雙倍的吞吐。全部的本事,就在於把工作安排得讓晶片把時間花在*計算*上,把*等待通信*的時間壓到最低。請記住這股張力;它解釋了接下來的每一個設計抉擇。
拆分工作的三種方式
對於「我們到底拆什麼?」這個問題,有三種誠實的回答,而真實系統會把三者糅合在一起。它們統稱為數據、模型與流水線並行。最簡單的是數據並行:每塊晶片都持有模型的*一份完整副本*,但看到的是小批量的*不同切片*。各自在自己的切片上算出梯度,然後所有晶片把梯度平均到一起,好讓每一份副本保持完全一致。這很好理解、擴展性也好——直到模型本身大到一塊晶片放不下,那時把它複製到處處便成了不可能。
當模型放不下,你就轉而拆*模型*。模型(或張量)並行把單獨一個巨大的層切到多塊晶片上——A 晶片持有一個權重矩陣的左半,B 晶片持有右半——於是一次矩陣乘法由它們合力算出,晶片在運算中途交換部分結果。流水線並行則把*不同的層*放到不同晶片上,像裝配線上的工位:1 號晶片做最前面幾層,把輸出交給 2 號晶片,依此類推。這裡的危險是「氣泡」——2 號晶片在等 1 號的第一份輸出時只能空閒——所以工程師會一次餵進許多微批量,讓每個工位都不停工,就像真正的裝配線絕不會卡在第一個工人那裡。
DATA PARALLEL each chip = full model, different data slice chip0 [MODEL] <- batch[0:8] \ chip1 [MODEL] <- batch[8:16] > average gradients --> sync chip2 [MODEL] <- batch[16:24] / MODEL PARALLEL one big layer split across chips chip0 [layer L: left half ] chip1 [layer L: right half] exchange partials mid-multiply PIPELINE PARALLEL different layers on different chips chip0 [layers 1-8] -> chip1 [layers 9-16] -> chip2 [layers 17-24]
混合精度:一半的位元,幾乎全部的精度
還有第二根槓桿,與拆分工作彼此獨立,幾乎是白送地換來速度與記憶體。預設情況下,網絡裡的每個數字都用 32 位元浮點儲存——精度慷慨,卻在記憶體和搬運它的能耗上都昂貴。[[mixed-precision-training|混合精度訓練]]改用 16 位元(甚至 8 位元)浮點來做大部分運算,這大致把記憶體用量減半,也讓晶片的專用單元跑得更快,同時為那些真正需要多幾位的部分保留一份 32 位元的權重主副本。令人意外的是精度損失之小:在帶雜訊的數據上訓練出來的網絡足夠穩健,把大多數運算的精度削掉一點,幾乎不會動搖最終結果。
算力的真實代價
這一切硬體的昂貴,遠不止租用帳單那麼簡單。有錢的代價——訓練一個前沿模型,可能要花掉數百萬美元的晶片小時。有電力以及訓練的環境代價——大型訓練動輒消耗數兆瓦,數據中心的用水與碳足跡都是實打實的。還有一種更隱蔽的代價:工程師的時間,因為一個本該連跑幾週的集群,會遇上晶片故障、網絡打嗝、運行停滯,總得有人守著它。把兩種狀態分開看會有幫助。訓練是一次性的、殘酷的開銷;之後為模型提供服務——它的推理成本——單次請求很小,卻要永遠付下去,落在每個用戶的每一次查詢上。
這種成本結構,也正是為什麼「慘痛的教訓」——即把更多算力和數據砸向通用方法,往往勝過手工雕琢的小聰明——既是真的、卻又容易被誤讀。「直接擴大規模」只有在你掏得起帳單、管得住工程、並接受收益遞減時才行得通。研究者測出的縮放定律是真實而平滑的,但它們是*冪律*:每新增一截能力,所花的算力都不成比例地多於上一截。擴展是一種策略,而不是通往愈來愈強能力的免費扶梯——更絕不是通向通用智能的自動通道。誠實的框架是工程經濟學:你在以陡升的價格,買入一份數額已知的改進。
而這正是本篇令人振奮的收尾:硬體是一根槓桿,不是一種宿命。後面幾級台階,大體都在講*怎麼少花錢*——把模型縮小,讓它服務起來更便宜;把請求成批處理,讓每塊晶片幹更多活;並盯住延遲與吞吐之間的權衡。你不需要一千塊 GPU 才能做出出色的工作。你需要的是搞懂硬體擅長什麼、成本藏在哪裡,以及什麼時候該擴大規模、什麼時候該把規模用得*更聰明*。