JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

光譜:CPU、GPU、FPGA、ASIC

硬體活在一條彈性與效率的光譜上,從什麼都能做的 CPU,到只做一件事的 ASIC。本篇沿著這條光譜走一遍,提煉出領域專用的設計守則,並以 TPU 的脈動陣列當作招牌範例——同時誠實面對:唯有當工作負載夠大、夠穩定、又夠平行,加速器才划得來。

從一個旋鈕到四個落點

上一篇說明了為什麼現在專用化划得來:Dennard 縮放已經終結、摩爾定律步履蹣跚,你不能再只是等一個更快的時脈,於是改用「把矽片裁剪成貼合工作」的方式來換取效率。但「專用化」不是一個開關——它是一個旋鈕。往一邊轉,你保有完整彈性卻浪費能量;往另一邊轉,你換來驚人的效率卻失去執行其他東西的能力。每一類重要的晶片,都只是這同一個旋鈕的不同刻度,也就是彈性對效率的光譜

這個旋鈕上有四個地標。CPU 最有彈性:它能跑任何為其指令集架構而寫的程式,分支與判斷都便宜,是那位什麼都會、但一次只能做幾件事的天才。GPU 拿一部分彈性換取純粹的吞吐量——上千條簡單的車道做著相同的算術。FPGA現場可程式邏輯閘陣列)讓你在製造之後還能接出客製硬體,重新塑形晶片本身。ASIC特定應用積體電路)則把一個固定功能燒進永久的矽片。由左到右,你用「什麼都能跑」換取「一件事跑得無比出色」。

走過旋鈕:每個落點的得與失

從 CPU 開始。它的彈性並非免費:它能量中很大一部分不是花在你的算術上,而是花在「身為通用機器」的額外開銷上——取指令、解碼、預測分支、重新命名暫存器、為亂序執行而重排。對於一個充滿判斷、序列且多分支的程式,那些開銷正是你要的,CPU 輕鬆獲勝。但對於一整面相同的乘加運算,同一套機構就是純粹的浪費——晶片把大部分功率燒在「決定下一步做什麼」,而不是真正去做。

滑到 GPU,那份浪費就縮小了。GPU 把一次取指令攤提給整個齊步執行(SIMT)的warp車道,於是解碼開銷是「為三十二個算術結果付一次」,而不是一個。代價是上一篇就點出的那句誠實話,這裡講得更尖銳:GPU 不是更快的 CPU。餵它序列、多分支發散的程式,車道就會分歧、大多數閒置,於是它爬行。它只在寬而規律的資料層級平行上發光——成千上萬個元素走同一條路。

再往前推,你抵達 FPGA 與 ASIC,它們乾脆完全拋棄了指令。它們不去取「導引固定資料路徑」的命令,而是把運算直接接成硬體——資料流經為這個問題量身排好的閘。FPGA 用一張可重新配置的織物做到這件事,你能在數秒內重新接線,所以它可重新編程,但比客製矽片慢且大。ASIC 把同樣的想法凍進光罩,達到所有選項裡最佳的速度與能耗——代價是數百萬美元、數個月的設計時間,以及做好後零彈性。旋鈕的盡頭極致地高效,也極致地不彈性。

領域專用的設計守則

當架構師打造一個領域專用架構——一個瞄準單一工作負載的加速器——他們會一再地祭出同樣的四招。每一招都把矽片花在通用 CPU 花在別處的地方。合起來,它們就是把一個已知工作負載變成高效硬體的劇本。

  1. 使用專屬、由軟體管理的記憶體。用編譯器明確掌控的暫存記憶體(scratchpad)取代 CPU 的自動快取階層。加速器事先就知道自己的存取樣式,於是能把資料完美擺位、略過快取的標籤比對與猜測——沒有快取未命中要承受,因為什麼都不靠運氣。
  2. 把省下的面積花在更多算術單元上。既然取指令/解碼/分支的機構都拿掉了,就把那些矽片倒進數百到數千個乘加單元,全都讓它們忙起來。現在晶片主要由純算術構成,而不是控制。
  3. 善用該領域特有的平行性。讓硬體的形狀貼合問題的形狀——用一格網的單元對應一格網的資料——而不是靠一個通用排程器在執行期去尋找平行性。
  4. 降低精度。如果工作負載容許,就用較窄的數(降低精度,例如 8 位元整數或 16 位元浮點)取代 32 或 64 位元。較窄的資料代表較小的乘法器、較少的記憶體流量,以及每焦耳更多的結果——當應用能吸收掉那些被捨去的位元時,這是個極大的槓桿。

注意這四招的共通點:它們都用通用性換取一個保證。CPU 之所以做快取,是因為它無法預測你的存取;加速器之所以略過快取,是因為它能預測。CPU 保留 64 位元精度,是因為它必須服務所有人;加速器降到 8 位元,是因為它服務的那個工作負載已證明撐得住。這套劇本只有在領域夠窄、讓這些保證成立時才管用——而這正是我們在結尾要回到的那條誠實的界線。

招牌範例:TPU 的脈動陣列

要看這套劇本實際運作,最清楚的地方就是深度學習加速器,而其中最有名的是 Google 的張量處理單元(TPU)。事實證明,深度學習被一種運算主宰:矩陣乘法,而它本身就是一大堆乘加運算。如果你能造出一個把稠密矩陣乘法做得驚人地快又便宜的硬體,你就加速了整個領域。這正是 TPU 下的賭注。

它的引擎是一個脈動陣列——一格由微小乘加單元組成的方陣,在最初的 TPU 裡是 256 乘 256 的網格。名字源自心臟:資料像血液一樣有節奏地脈動穿過格網。權重先被載入各單元;接著輸入值從左邊流進、部分和從上面流下。每一個時脈滴答,每個單元把流經它的值乘上自己存的權重、加上從上方抵達的部分和,再把兩者往下游傳。當資料行進穿過格網,一次完整的矩陣乘法就自然落出——每個時脈數萬次乘加,而幾乎沒有指令開銷。

systolic array: a value, once read, is reused as it walks the grid

  inputs ->  [x]->[x]->[x]->[x]      each [x] = one multiply-add cell
             [x]->[x]->[x]->[x]      weights sit inside the cells
             [x]->[x]->[x]->[x]      partial sums flow DOWN
             [x]->[x]->[x]->[x]      input data flows RIGHT
                |    |    |    |
                v    v    v    v
              column results (accumulated dot products)

  key trick: read each operand from memory ONCE, then let it
  do useful work in every cell it passes through on its way across.
  fewer trips to memory  ==  the win.
脈動陣列為何取勝:每個值只讀一次記憶體,之後就被重複使用很多次,直擊真正的瓶頸——資料搬移,而非算術。

兩招劇本讓它起飛。第一,降低精度:TPU 用 8 位元整數(int8)或 16 位元浮點(bfloat16,保留浮點寬廣的指數範圍、卻丟掉訓練不需要的精度位元)來做乘法。較小的乘法器讓格網塞得更密、能耗大砍。第二——這是最深的一點——這種機器的瓶頸不是算術,而是資料搬移:把資料餵進陣列。脈動設計之所以聰明,正因為一個值一旦從記憶體讀出,就在它經過的每個單元裡被重複使用,於是一次記憶體讀取做了很多次乘法。把上記憶體的次數降到最低,而不是加更多乘法器,才是真正的勝負手。

超越機器學習,以及那條誠實的界線

深度學習加速器是最大聲的例子,但只要你願意看,這條光譜無處不在。數位訊號處理器(DSP)為濾波音訊與無線電的乘加運算而調校。每支手機裡的視訊編解碼器是一個固定功能區塊,用 CPU 所需功率的一小部分就解出一條串流。加密引擎用專屬硬體做 AES 與雜湊。SmartNIC 或 DPU把網路封包處理從主 CPU 卸載出去。每一個都是同一個想法:把一個熱門、穩定的工作負載從通用核心拿走,給它客製矽片。

這就是為什麼系統單晶片主宰了現代裝置:一顆手機 SoC 是一座由專用區塊組成的城市——CPU 叢集、一顆 GPU、一個 ML 加速器、一顆 DSP、編解碼器、一個加密引擎——共用一片晶粒與一份記憶體。而它逼出一種紀律,叫做軟硬體協同設計:你不再分開設計晶片與軟體。加速器的形狀、資料的排列、以及驅動它的程式是一起設計的,彼此互相遷就,因為一個被「沒排好的資料」餓著的完美陣列,只是昂貴的閒置矽片。