作為一家由多位前Google TPU開發者組建的芯片公司,Groq一經成立便備受關注。2016年底,曾領導研發Google張量處理單元(TPU,用于加速機器學習而定制的芯片)的Jonathon Ross離職創辦了Groq,他們希望能為AI和HPC工作負載提供毫不妥協的低延遲和高性能。
不同于傳統的CPU和GPU架構,Groq從頭設計了一個張量流處理器 (TSP) 架構,?以加速人工智能、機器學習和高性能計算中的復雜工作負載。這個架構不是開發小型可編程內核并對其進行數百次復制,而是容納一個具有數百個功能單元的單個處理器。?
Groq的軟件將深度學習模型編譯成指令流,所有這些都是預編排的。他們用“軟件定義硬件”的思路,將芯片中的控制和調度操作都交給軟件完成,從而減少相應的硬件開銷,壓榨更多的性能。
目前,Groq主要面向云端推理領域。2021年4月,Groq宣布獲得3億美元新融資,用于開拓自動駕駛和數據中心行業市場。
近期,Groq首席架構師Dennis Abts完整介紹了Grop公司研發的軟件定義橫向擴展的張量流式多處理器(Tensor Streaming Processor,簡稱TSP)架構,主要包括搭建TSP架構的背景及構成,并說明了TSP的工作負載性能。
01?TSP的設計理念
Groq將軟件定義(software-defined)的方法引入到多處理器中軟硬件接口的設置問題。具體來說,靜態和動態(static-dynamic)界面來區分什么應該在編譯時做,什么應該在運行時執行;軟硬件接口由通過指令集架構(ISA, instruction set architecture )來實現,僅僅向編譯器暴露必要的體系結構內部狀態。?
我們將更多的控制權交給軟件,并將那些應該硬件做的事交給芯片,而對于能在軟件中完成的事情,則更多的放在軟件堆棧中去做(在軟件堆棧中這些任務也能完成得更好)。?
面向確定性的設計(designing for determinism )要求我們在設計時作出選擇,并對該設計理念一以貫之。我們必須確保硬件可以完全由編譯器來控制,這不是要抽象掉硬件的細節,而是要顯式地控制底層硬件。并且編譯器能夠清楚地了解硬件在任何給定周期內的工作情況。
傳統的系統和CPU通常采用亂序執行(out-of-order execution)和推測執行(speculative execution)等技術在內存層次結構中暴露出附加的指令級并行(instruction level parallelism)和內存并發性(memory concurrency)。
而Groq則采取了不同方式,只在一個220兆字節的scratchpad內存中顯式分配tensor,以便編譯器知道tensor的位置以及它們如何在芯片上移動。編譯器還可以利用大量的內存并發性,我們通過分區的全局地址空間來對此進行描述,并使其可以在整個系統中訪問。
由于系統中的處理單元會達到數以萬計(這些元素通常由異構組件組成,例如CPU、GPU、SmartNICs、FPGAs,所有這些組件都具有不同的故障特征和性能概況),系統層面的復雜性通常也會不斷增加。
結果,系統的性能會發生變化,同時響應時間也會延長,這些變化也會相應地降低其他互聯網應用程序的運行速度,所有需要機器各部分協作完成的事情最終都會受到這種延時的影響。
因此,我們盡量避免在系統層面出現這種資源浪費和濫用行為,同時引入新技術來幫助平衡系統負載,而無需在網絡層面使用自適應路由和其他激進技術。
02?TSP微架構:
軟件定義硬件意味著什么
接下來讓我們介紹微架構。首先是從傳統的同構眾核開始,每個核心都包含計算單元、整數單元、浮點單元、加載存儲單元和網絡接口。我們將這些功能單元分解并重新組織成SIMD功能單元,并將它們彼此相鄰放置,便于控制并利用其空間局部性。這看起來與傳統CPU有點不同,但執行方式卻與傳統CPU一樣將較大的指令分解為微指令。同樣,我們將深度學習操作分解為更小的微操作,并將它們作為一個整體執行,共同實現更大的目標。
因此,如果我們只看芯片架構,會發現芯片是按照空間方向(spatial orientation)排列的,功能單元彼此相鄰布置。它們通過在彼此之間傳遞操作數和結果來相互協作,這種有效運作方式稱作“鏈條化(chaining)”,可以將一個功能單元的輸出鏈接到相鄰下游功能單元的輸入。
在芯片上的大型MXM模塊是TSP架構的主力,該模塊是矩陣單元,包含409,600個乘加器。換言之,我們可以通過芯片上的數據并行來利用大量權重參數,這使得我們能提供巨大的計算密度,每平方毫米硅面積超過1 TeraOps。?
現在往回看,來看看GroqChip的抽象構造。芯片上有多個不同的功能單元,這些單元組成了簡單的構建塊,長度為320個元素(本處所指的是SIMD單元),每個SIMD單元由指令調度單元(位于芯片底部)控制。
這些功能單元彼此相鄰,正如軟件的不同分類一樣,這些不同的功能單元都有各自的用途,包括矩陣單元MXM,用于逐點運算的vector單元,用于數據重塑的SXM單元(開關執行模塊),以及一個用于處理片上存儲的存儲器單元。
它們在布局上彼此相鄰,以此來利用空間定向的優勢。所以我們可以在芯片上采取東西向流式傳輸數據,充分利用其空間局部性。從某種意義上說,它正在捕獲數據流的局部性,這在機器學習模型中很常見。
這種架構使得ISA能夠賦能我們的軟件堆棧。我們顯式地將控制權移交給軟件,特別是編譯器,以便它可以從第一性原理的角度推斷硬件上的正確性和調度指令。?
具體來說,我們有144個片上指令控制單元,每個指令控制單元控制著與其相關聯的功能單元的調度。這使我們能夠將調度的硬件開銷保持在非常低的水平,僅僅不到3%的區域用于指令解碼和調度,同時將大部分芯片區域用于執行功能模型。?
這使得編譯器能非常簡單地進行提取,即每個功能單元與一組流寄存器文件(SRF,stream register files)交互。通過SRF提供的管道(conduit),數據輸入和數據結果被傳送到其他功能單元。
可以把SRF看作是連接不同功能單元的tensor裝配線,這些流寄存器是非常簡單的模型,編譯器可以推斷每個流寄存器之間只有單周期跳(one-cycle hop)。在加載存儲或網絡引用中沒有仲裁節點,沒有提示,也沒有重新排序。因此,編譯器確實擁有預言性信息,以此推斷其生成的每個程序的正確性。?
該功能的核心是指令集,它是用于在機器學習模型上運行的特定領域指令集。具體來說,我們采用conv.2d之類的機器學習操作,并將它們分解為一組微指令,這些指令在每個不同功能單元的芯片上執行。它們協作產生更高級別的指令,如conv.2d或max pooling操作,并且根據每個功能單元將指令分解為不同的指令集。?
硬件本身支持的數據類型是INT8、UINT8以及FLOAT16,處理逐點元素的向量處理器支持包括FP32在內的超集。
所以如果只看TSP的功能單元,每個功能單元都有一定數量必備指令,即取指、無操作(No-Op)和同步。這些是協調執行所必需的基本指令。?
芯片的核心是矩陣乘法單元。矩陣引擎通過具有320個元素的向量進行操作,每個矩陣中有320個特征,提供320x320整數運算。對于浮點運算,我們可以做320x160,可以同時處理整數和浮點數。浮點有點獨特,因為一對字節平面(byte planes)協作產生一個FP16的輸出。?
芯片的中間是矢量執行模塊(VXM,vector execution module),它是機器學習模型中常見的向量逐點運算,例如GELU或ReLU,并且向量單元中存在其他超越函數(transcendental functions)以利用逐點操作。
每個矢量通道支持16個ALU(網絡算術邏輯單元,Arithmetic Logic Unit),并且通過內存功能單元(memory functional unit)連接到在SRAM(靜態隨機存取存儲器,Static Random-Access Memory)中的片上內存。內存功能單元在芯片上有88個切片,每個切片每次可讀取一次。所以原則上內存系統最多支持176路并發執行,這是大量可利用的內存并發。?
最后,SXM(switch execution module)是一個開關執行模塊。SXM就像是一把瑞士軍刀,來處理數據操作、數據重塑、片上數據搬運和片外數據搬運。如上圖所示,C2C IO、PCIE也由這個SXM單元處理。
03?系統概覽:
封裝、拓撲、路由和流控
接下來如何將這些組件封裝,進而組建成一個系統?首先是將GroqChip與散熱器封裝在一張卡上,然后將八張這種卡集合成一個GroqNode,最后再將八個GroqNode加一個備用包打包到一個GroqRack中,并使其在云端也可訪問。
這種橫向擴展排列方式非常獨特。第一,它利用封裝層次來制作低直徑網絡,這利用了蜻蜓拓撲(dragonfly topology),而蜻蜓拓撲又利用了封裝局部性(packaging locality)。它創建了所謂的軟件調度的直連網絡(software-scheduled direct network),支持每個TSP上的16個直接相連的芯片到芯片鏈路進行通信。?
橫向擴展組織利用較小的網絡直徑將多達8個芯片打包到一個節點中,這8個芯片使用28根電線連接到它們的7個中轉點,這些電線被放置在每個節點底層,使我們能夠豐富地連接單個節點內的8個TSP,以再次利用封裝的局部性。這些節點使用電線連接,較長的電線將在機架到機架網絡(rack-to-rack network)之間使用光纜。?
蜻蜓拓撲是分層拓撲。它首先通過識別這8個TSP構建成一個組,每個TSP都公開四個全局端口,所以8×4是32個端口。這32個虛擬端口用于連接全局系統,使能夠連接多達30到32個單個系統中共計264個TSP的對等節點。
我們可以實現這個想法,并將這個機架作為本地組,如此一來,我們將能夠在系統中連接多達145個機架,從而實現超過10000 TSP的總可擴展性。?
Groq的橫向擴展拓撲使用蜻蜓拓撲來完全連接機架內的八個全局節點集,如下圖所示。
該結構提供了一個備用節點作為熱備用(hot spare),并利用網絡的邊緣和節點對稱性來提供n+1冗余,由此提高系統彈性。
04?全局同步網絡
這個系統組織的核心是全局同步網絡。當然,目前這個網絡并不是真正同步的,因為系統中的每個節點都還沒有統一的全局時鐘。我們提供了同步行為的假象,還特別使用了一系列硬件和軟件技術、硬件對齊計數器和軟件對齊計數器,幫助檢測何時發生漂移并補償漂移。
全局同步網絡由多同步鏈路組成,這意味著它們大部分是同步的,在驅動每個鏈接的時鐘晶體的容差范圍內是同步的。正是對于這一點的利用,使得我們能夠檢測到漂移何時發生,并通過硬件和軟件技術對其進行補償。
再次強調,在這個部分必須啟用ISA支持,以便能夠對這些芯片間的鏈接進行糾偏(我們有特定的指令支持糾偏)。
此外,這些鏈接不是硬件流控制,而是軟件流控制。軟件控制鏈接的運行節奏,以確保它們永遠不會溢出或下溢。該鏈接的核心是前向糾錯,這樣就可以在每個網絡鏈路上都有一個固定的延遲,讓編譯器能夠推斷出需要消息傳遞的時間。
從概念上講,這些計數器在機器剛復位時相互獨立,然后將它們放入鎖步(lock step),可能會隨著時間的推移略有漂移,但我們會消除偏移并將它們重新放入鎖步。這就是我們如何在分布式系統中保持同步行為的方法。
不同于傳統網絡依賴硬件判優機制來動態競爭一組輸出端口,我們讓編譯器可以調度所有物理網絡端口,使它可以像調度ALU或矩陣一樣調度網絡鏈接。傳統方法只會對網絡中的擁塞做出反應,而不是對擁塞做出反應后進行自適應路由,以試圖改善因競爭而導致的熱點(hot spots)問題。?
相反,我們的首要原則是完全避免競爭,并將流量模式分散到網絡上的可用路徑多樣性中,以顯現和利用額外的對分帶寬。
我們將tensor視為消息,換句話說,我們將tensor作為數據包進行路由,這些連續的向量流在時間上背對背出現,形成一個tensor。這使我們能將消息構建為向量序列,能夠非常有效地在網絡上對消息進行編碼,而編碼開銷僅為2.5%。
05?確定性的負載平衡
同時,利用最小和非最小路由是我們這個想法的核心。系統中的每個TSP在每個源目標對之間都有一個最小路徑,但是也有很多非最小路徑。在這種情況下,編譯器可以查看張量的大小,并決定在其上傳播多少條路徑,以最大限度地減少在網絡傳輸時的序列化延遲。
這使我們能夠進行所謂的確定性負載平衡,而不必使用更傳統的自適應路由方法去適應或響應網絡中的擁塞。傳統的方法有其自身的問題,因為只能看到一小部分網絡,只能查看輸出端口的擁塞狀態,這可能導致做出錯誤的決定,選擇一條可能比目前路徑更擁擠的糟糕路徑。
我們的方法做出了更好的權衡,它允許編譯器對所有物理鏈路進行負載平衡,就像我們對芯片上的任何其他功能單元進行負載平衡一樣。
Groq芯片間鏈路的核心是簡化的通信協議和流量控制。流量控制是由軟件明確驅動的,沒有硬件流量控制,所以軟件必須確保它們不會溢出或下溢,我們設計的就是保證確定性成為首要原則,這也是設計的基石。
如果看一下傳統的RDMA類型的請求,我們向目標發出讀取請求,并且該讀取將造成內存事務(memory transaction),然后將這個回復回流到網絡,以便以后使用。?
更簡單的方法是讓編譯器知道正在讀取的地址,并且數據只在需要時通過網絡推送,以便在源頭使用。這使得我們能夠以更少的網絡消息和更少的開銷來實現更高效的網絡傳輸。
06?可靠性
我們在整個系統中利用了TSP和網絡內的冗余。例如制造良率的問題,芯片實際上是由21條超級通道構成的,而我們只使用了20條,因此可以允許出現一條無效的超級通道。這意味著我們可以在編譯器中隱藏備用的超級鏈接,實際上也確實將硬件細節隱藏在其中。
這使我們能夠使用一個全優的芯片,其能夠包容目前領域可能存在的一些缺陷。
此外,每個架構內的冗余電源和冗余節點提供了額外的冗余。不僅如此,確定性還簡化和改進了ASIC的設計過程,設計和驗證可以通過硬件和軟件需要確保的一些假設來表達,并保證硬件和軟件需要確保彼此進行驗證。例如,硬件制造的任何保證需要作為軟件假設進行驗證。
軟件堆棧對可靠性和冗余性起著重要作用,特別是在運行時層面處理異常處理時。這就是為什么所有鏈路都需要前向糾錯,如果遇到錯誤,則需要軟件重演(software replay),并且通過運行時處理。
為了保護所有片上數據結構,我們使用單糾錯和雙檢測(SECDED)來保護所有數據路徑、所有流寄存器、所有指令緩沖區和芯片上的指令提示。我們稱這種方法為無處不在的ECC。
既然開銷很容易計算,那么我們可以利用這一點。在這個問題上偏執一點是值得的,因為確實有過無記載數據損壞,我的谷歌前同事在他們的論文《cores that don't count(不算數的內核)》中聲明了這一點。重要的是,我們要成為客戶數據的好管家。
因此,我們需要保護所有關鍵的硬件結構,在這個圖中,每一個被編號的灰色框都是流寄存器,SECDED保護著它們的安全,當張量在芯片流動時,我們可以對它再次保護。
此外,我們希望提供異常處理來避免常見問題,例如算術異常,算術溢出或下溢,可以通過提前決定異常語義來處理先驗,例如編譯器可以通過使用飽和指令來避免任何算術溢出,比如加減飽和或乘以飽和。這讓我們可以避免值溢出,并將溢出位精度精確到一個很小的值。
07?負載評估
因此,如果查看我們獨特的工作負載,會發現它們往往都與線性代數有關,因為這是機器學習以及許多HPC代碼的主力。舉個例子,看一下喬里斯基分解(Cholesky Factorization),它使用塊循環將這個三角形元素擴展到多個芯片。
我們在TSP上實現了BERT和BERT Large的最先進的結果,并展示了如何真正有效地完成一般矩陣乘法。最后,當我們準備進行通信時,就能體會到所有上述優點,即使我們的引腳帶寬比競品芯片少,也能夠更好地利用該引腳帶寬,并采取細粒度通信的優勢,換句話說,小張量在這個網絡上可以非常有效。
08?總結
簡單總結一下。首先,所有這些內容都是為了使編譯器更高效且更輕量級,從編譯器取得的快速進展就可以看出,我們已經能夠更廣泛地編譯各種不同類型操作的模型。因此,從更廣泛的角度來看,我們試圖實現的是可預測和可重復性的性能,以在整個系統中提供低延遲和高吞吐量,以及支持軟件定義的硬件方法。
我們不是要通過抽象去掉細節,而是要控制底層的硬件。我們希望公開一組正確的架構可見狀態,將其交給編譯器,它可以從第一性原理推斷正確性,使軟件和異常處理分別在編譯時和運行時處理。
最后,我們啟用了同步通信模型,該模型使得在非常大的系統中進行無鎖通信,這是我們希望能夠幫助到你的超級力量。
審核編輯:劉清
評論
查看更多