即使半導體晶片還是能隨著摩爾定律(Moore’s Law)的腳步改進製程,能在同樣的面積裡塞進更多的半導體元件,但是因為現代硬體製造技術的限制,單一元件的耗電量難以下降,傳統的通用型處理器例如中央處理器(CPU)、圖形處理器(GPU),在不增加供電的前提下,透過製程進步能獲得的效率提昇相當有限。現在的電腦系統也因此從早期追求頻率更高的處理器的設計,轉為提供更多為特定應用設計(application-specific)的硬體加速器(hardware accelerators)。例如Google在雲端伺服器上加入的張量處理器(Tensor Processing Units, TPUs)、Pixel手機上的邊緣張量處理器(Edge TPUs)、Apple的類神經引擎(Neural Engines)、NVIDIA的張量核心(Tensor Cores),都是為了人工智慧(AI)、機器學習(ML)以及類神經網路(NN)而設計的特殊功能加速器。而為了在遊戲及電影達到更好的光影效果,NVIDIA的GPU上也加入為了光影追蹤(Ray Tracing)而打造的RT Cores。就連Intel最新一代的處理器上,也多了所謂的高斯類神經加速器(Gaussian & Neural Accelerators)。
距今約20年前,所謂的GPU,也就真的只是單純的圖學加速器,專門為了加速遊戲畫面成像或是影像創作需求而打造的。而今,在各種程式開發環境、工具、系統軟體的加持以及GPU本身硬體架構的改進下,GPU已經成為了能廣泛支援各式各樣需要大量平行計算應用程式的向量處理器(Vector Processors)了。也因為在GPU上實現「通用計算」(GPGPU)的可能性,直接導致了近代類神經網路的復興。
回想GPU的故事,再看看當今百家爭鳴的硬體加速器,不禁讓人好奇,當中是不是有哪種能夠重演GPU成為通用型處理器的輝煌歷史呢?
勝投候選人
目前已經有不少研究著手於利用這些加速器的功能來改善原本用途以外的應用程式的效能。而在已經商用化的加速器當中,又以TPU、Tensor Cores、RT Cores最受注目。
TPUs
TPU是Google推出專為AI/ML/NN的應用打造的加速器,自從2016年之後開始在Google Cloud大量應用,其主要的核心設計則首見於他們在ISCA 2017所發表的論文。由於這是Google的祕密武器,目前Cloud TPU只能透過Google的雲端服務使用。除了雲端版本的Cloud TPU,Google另外也推出了所謂的邊緣計算用TPU(Edge TPUs)。Edge TPUs有給嵌入式系統用的單晶片版本、也有USB、M.2加速器的版本、也有整合在Pixel 6的處理器中的版本,可應用的平台跟範圍更是廣泛、也更容易取得。然而不論是Cloud TPU或是Edge TPU,他們都是以一次能夠直接對矩陣(Matrix)計算的目標而設計。而能夠對矩陣所做的運算功能,則是以AI/ML/NN應用所倚賴的卷積(convolution)、完全連接(fully connected)這類的計算為主。
儘管TPU只提供這些高度為AI/ML/NN所設計的運算功能,許多研究者以及Google自家的工程師們,也開始利用TPU加速像是資料庫查詢的連接(Join)功能、快速傅立葉轉換[Lu ISBI’21, Lu HPEC’20]、以及蒙地卡羅物理模擬[Morningstar, Pederson]。而筆者自家的lab,也在GPTPU這篇論文中,展現了利用Edge TPU加速一般的矩陣乘法、高斯消去法、LU分解等常用的矩陣代數計算。
Tensor Cores
Tensor Cores是NVIDIA拿來與Google相庭抗禮的AI/ML/NN解決方案。雖然同樣都以直接處理矩陣資料為主軸,Tensor Cores支援的運算只有矩陣相乘一種。但是相較於Google TPU系列相當不透明的低階硬體介面,NVIDIA至少大方地提供了WMMA介面以及一堆像是cuBLAS這樣的函式庫(library)。同時更因為矩陣相乘的應用廣泛,利用Tensor Cores加速非AI/ML/NN應用程式的例子也不在少見。例如加速資料庫處理[Dakkak ICS’19, TCUDB]、快速傅立葉轉換[tcFFT, Durrani PACT’21],甚至是加解密演算法。
光影追蹤加速器(RT Cores)
RT Cores也是NVIDIA在最新幾代GPU上提供的加速器。RT Cores著眼於遊戲、特效中讓場景更逼真的Ray Tracing演算法。相較於傳統著色演算法的高度規律性,光的行為充滿了各種不確定性,也讓這類演算法至今仍是傳統GPU核心相當苦手的項目。RT Cores的出現,至少相當程度地加速了Ray Tracing演算法中判斷光與物體相交與否這段的計算過程。也因為光追演算法本身就是以模擬光的物理行為為出發點,所以也很自然地可以運用在像蒙地卡羅模擬(Monte Carlo simulations)這樣的程式當中,此外,也有人利用RT Cores加速nearest neighbor search的問題以及機器人在3D空間移動的路線決策問題。
挑戰
儘管不少人成功地利用這些加速器在其本身設計目的以外的場合,但是其實這樣的嘗試一點都不簡單啊!尤其當我們的目的不僅僅是「用」,而是希望能達到「加速」的效果的時候。而把這些加速器運用在其他方面之所以難,有以下幾點原因。
功能性的限制
別忘了,這些加速器的初衷就只是加速特定應用程式,為了降低製造成本跟運作時的耗電量,不必要的功能自然能省則省。也因此,想利用這些加速器上有限的功能,只能想辦法「魔改」原本的演算法了。例如,在我們做GPTPU Project的時候、還有Google本身用TPU加速FFT的這些專案裡,都必須重新排列資料的順序,才能使用TPU最有效率的卷積運算。
沒有白吃的午餐-使用加速器的產生的多餘工作量
此外,天下沒有白吃的午餐。由於輸出入介面的不同、加速器的架構以及在系統中的位置,使用加速器往往伴隨著一定的副作用。首先,傳統上記憶體、儲存裝置的資料都是線性的定址,所以我們在記憶體、儲存裝置中,早早就把高維度的資料變成了線性的資料,原本的維度早就不存在了。而當我們使用這些矩陣處理器的時候,就得把資料重新整理回高維度的樣子。這個過程往往造成記憶體存取時頻寬的浪費、也會需要CPU的資源計算正確的位置。就算資料已經是高維度的形狀了,但是像卷積這類的運算,資料的排列還是跟矩陣乘法要的順序不同。而且這些加速器本身可能還有一些對資料編碼的額外要求。像Edge TPU的其中一組輸入,就必須是TFLite的模型(model),所以一個矩陣必須重新掃描過資料的分佈、再量化,才能拿來計算。
精準度
基於「能省則省」的哲學,這些加速器在精準度上也是拿捏的「恰到好處」。所以當我們想把加速器拿來用在需要更高精準度的程式上的時候,這些原本剛剛好的設計,就成了絆腳石。傳統的CPU或GPU,都能好好地支援64-bit的精準度,但是TPU、Tensor Cores,頂多做到16-bit的輸入、32-bit的輸出。假設我們真的想把這些處理器用在更高精準度的程式上時,為了補償失去的精準度而付出的代價,很可能就超過快速計算帶來的好處了。
謎樣的加速器設計
最後,也是最讓調校效能的工程師頭痛的事情,莫過於這些加速器猶如黑盒子一樣的內部設計跟沒有原始碼的函式庫。像Cloud TPU,除了TensorFlow的interface之外,其在Google Cloud上的後端程式是完全不公開的,所以呼叫了函式之後的效能只能巴望著Google的工程師下次更新版本的時候幫你升級。至於像我們想把Cloud TPU用在一些其他的領域,除了自己想著怎麼把TensorFlow的那些API發揮創意組合之外,恐怕是沒辦法期待Google工程師們專門為你寫一個你想要的API了。而我們在做GPTPU Project的時候,則是費盡心思地逆向工程分析Edge TPU Compiler產生出來的models,才有辦法自己兜出一個能夠對任意矩陣產生model的程式。
未來的展望
儘管有著相當的挑戰,不過現階段研究還是為把這些加速器「通用化」點出了一條康莊大道以及當中我們可以努力的方向。
更多的程式
除了現階段的嘗試之外,還有很多我們這些電腦科學家所不知道、沒想到的應用,這也是為什麼我想寫這篇文章想請大家集思廣益的原因。除了把現有的演算法改成能用矩陣之外,更有趣的,或許是思考有沒有一些傳統上認為因為複雜度較高而被捨棄的方法,能夠利用新的加速器而有效率的運算。別忘了,之前類神經網路之所以被捨棄,也就是因為需要的計算時間太久罷了。假設我們能加速一些傳統比較複雜的方法,是不是有像類神經網路這種能再次掀起革命的方法出現呢?
更多的加速器功能
我們先前提過,加速器本身的架構理論上可以擔當很多功能,但是因為「加速器」的任務限制,我們只提供了「必要」的功能。實際上,很多演算法的過程跟原理非常相近,可能只需要小小的修改,就能讓加速器更有用。像是大家很愛的動態規劃(Dynamic Programming, DP)演算法,其實跟矩陣乘法的過程基本上是一樣的-只要你把矩陣乘法的相乘變成了相加、累加換成了取最大或是取最小,兩者的運算程序是相同的。RT Cores如果能把那些Bounding Boxes的形狀什麼的更加自由的修改,就可以廣泛地運用在各種圖論的問題上。在精準度的部份,我們則已經見到一些研究像是EGEMM-TC或硬體製造商本身開始逐步提昇能支援的資料格式了。
程式開發環境以及軟硬體介面
其實這才是最令人頭痛的部份。以前的年代,不管是CPU或是GPU也好,至少硬體製造商跟程式開發環境之間,有著「指令集」(Instruction Set Architecture, ISA)這樣的「共識」、「合約」,所以只要遵循著這個共識(?),大家可以各自發展、共榮共存(不要想太多!)。寫程式的人不用為了硬體升級一直改程式,而做硬體的人,也就專心讓運算本身更快速就好。
但是到了加速器的時代,API還有所謂的領域特定語言(Domain Specific Language, DSL)變成了加速器跟軟體溝通的介面。硬體直接跳過compiler,直接跟寫程式的人面對面。結果就是每當硬體升級、架構改變,寫程式的人就得改變習慣、學習新的開發環境。如同先前一篇Computer Architecture Today的文章所說,我們是應該思考到了加速器的時代,什麼樣的軟硬體介面、語言,才能最符合軟硬體開發的需要,讓大家不用疲於整天改程式。
記憶體的介面
加速器的使用,不僅讓電腦內部的計算方式變得白花齊放,更讓資料本身得在不同的處理模式下,有著不同維度、精準度的展現。像CPU是以處理一對對的64-bit數值為基礎設計、GPU則是為了處理一對對32-bit的向量(Vector)而設計、TPU或是Tensor Cores則是以16-bit甚至是8-bit的矩陣作為運算的輸出入。一組矩陣資料,面對這些處理器的時候,往往得不停地轉換。如果想要避免這些多餘的轉換,我們真的需要一些創新的記憶體定址、儲存方法,也許像是先前GS-DRAM, RC-NVM還有NDS這類論文裡面所提到的方法吧!
結語
身處於計算機結構的革命性新時代,我們有幸見到這麼多不同的加速器的誕生。除了發展新的加速器之外,我們也應該看看除了自身關注的這些程式、問題之外,是不是有著更多其他的問題,可以受惠於這些加速器喔!