上圖將近年的深度學(xué)習(xí)框架粗略分為三代。一個趨勢是在上層的用戶API層面,這些框架在變得越來越靈活,靈活性變強的同時也為底層性能問題提出了更大的挑戰(zhàn)。初代深度學(xué)習(xí)框架類似 Caffe 用 sequence of layer 的方式描述神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu),第二代類似 TensorFlow 用更細(xì)粒度的 graph of operators 描述計算圖,到第三代類似 PyTorch,TensorFlow Eager Mode 的動態(tài)圖。我們可以看到框架越來越靈活,描述能力越來越強,帶來的問題是優(yōu)化底層性能變得越來越困難。業(yè)務(wù)團(tuán)隊也經(jīng)常需要補充完成所需要的手工優(yōu)化,這些工作依賴于特定業(yè)務(wù)和對底層硬件的理解,耗費人力且難以泛化。而深度學(xué)習(xí)編譯器則是結(jié)合編譯時圖層的優(yōu)化以及自動或者半自動的代碼生成,將手工優(yōu)化的原理做泛化性的沉淀,以替代純手工優(yōu)化帶來的各種問題,去解決深度學(xué)習(xí)框架的靈活性和性能之間的矛盾。
AI框架在硬件泛化性方面的需求
表面上看近些年AI發(fā)展的有目共睹、方興未艾,而后臺的硬件算力數(shù)十年的發(fā)展才是催化AI繁榮的核心動力。隨著晶體管微縮面臨的各種物理挑戰(zhàn)越來越大,芯片算力的增加越來越難,摩爾定律面臨失效,創(chuàng)新體系結(jié)構(gòu)的各種DSA芯片迎來了一波熱潮,傳統(tǒng)的x86、ARM等都在不同的領(lǐng)域強化著自己的競爭力。硬件的百花齊放也為AI框架的發(fā)展帶來了新的挑戰(zhàn)。
而硬件的創(chuàng)新是一個問題,如何能把硬件的算力在真實的業(yè)務(wù)場景中發(fā)揮出來則是另外一個問題。新的AI硬件廠商不得不面臨除了要在硬件上創(chuàng)新,還要在軟件棧上做重度人力投入的問題。向下如何兼容硬件,成為了如今深度學(xué)習(xí)框架的核心難點之一,而兼容硬件這件事,則需要由編譯器來解決。
AI系統(tǒng)平臺對前端AI框架泛化性方面的需求
當(dāng)今主流的深度學(xué)習(xí)框架包括Tensoflow、Pytorch、Keras、JAX等等,幾個框架都有各自的優(yōu)缺點,在上層對用戶的接口方面風(fēng)格各異,卻同樣面臨硬件適配以及充分發(fā)揮硬件算力的問題。不同的團(tuán)隊常根據(jù)自己的建模場景和使用習(xí)慣來選擇不同的框架,而云廠商或者平臺方的性能優(yōu)化工具和硬件適配方案則需要同時考慮不同的前端框架,甚至未來框架演進(jìn)的需求。Google利用XLA同時支持TensorFlow和JAX,同時其它開源社區(qū)還演進(jìn)出了Torch_XLA,Torch-MLIR這樣的接入方案,這些接入方案目前雖然在易用性和成熟程度等方面還存在一些問題,卻反應(yīng)出AI系統(tǒng)層的工作對前端AI框架泛化性方面的需求和技術(shù)趨勢。
什么是深度學(xué)習(xí)編譯器
傳統(tǒng)編譯器是以高層語言作為輸入,避免用戶直接去寫機(jī)器碼,而用相對靈活高效的語言來工作,并在編譯的過程中引入優(yōu)化來解決高層語言引入的性能問題,平衡開發(fā)效率與性能之間的矛盾。而深度學(xué)習(xí)編譯器的作用相仿,其輸入是比較靈活的,具備較高抽象度的計算圖描述,輸出包括CPU、GPU及其他異構(gòu)硬件平臺上的底層機(jī)器碼及執(zhí)行引擎。
傳統(tǒng)編譯器的使命之一是減輕編程者的壓力。作為編譯器的輸入的高級語言往往更多地是描述一個邏輯,為了便利編程者,高級語言的描述會更加抽象和靈活,至于這個邏輯在機(jī)器上是否能夠高效的執(zhí)行,往往是考驗編譯器的一個重要指標(biāo)。深度學(xué)習(xí)作為一個近幾年發(fā)展異??焖俚膽?yīng)用領(lǐng)域,它的性能優(yōu)化至關(guān)重要,并且同樣存在高層描述的靈活性和抽象性與底層計算性能之間的矛盾,因此專門針對深度學(xué)習(xí)的編譯器出現(xiàn)了。而傳統(tǒng)編譯器的另外一個重要使命是,需要保證編程者輸入的高層語言能夠執(zhí)行在不同體系結(jié)構(gòu)和指令集的硬件計算單元上,這一點也同樣反應(yīng)在深度學(xué)習(xí)編譯器上。面對一個新的硬件設(shè)備,人工的話不太可能有精力對那么多目標(biāo)硬件重新手寫一個框架所需要的全部算子實現(xiàn),深度學(xué)習(xí)編譯器提供中間層的IR,將頂層框架的模型流圖轉(zhuǎn)化成中間層表示IR,在中間層IR上進(jìn)行通用的圖層優(yōu)化,而在后端將優(yōu)化后的IR通用性的生成各個目標(biāo)平臺的機(jī)器碼。
深度學(xué)習(xí)編譯器的目標(biāo)是針對AI計算任務(wù),以通用編譯器的方式完成性能優(yōu)化和硬件適配。讓用戶可以專注于上層模型開發(fā),降低用戶手工優(yōu)化性能的人力開發(fā)成本,進(jìn)一步壓榨硬件性能空間。
距離大規(guī)模應(yīng)用面臨的瓶頸問題
深度學(xué)習(xí)編譯器發(fā)展到今天,雖然在目標(biāo)和技術(shù)架構(gòu)方面與傳統(tǒng)編譯器有頗多相似之處,且在技術(shù)方向上表現(xiàn)出了良好的潛力,然而目前的實際應(yīng)用范圍卻仍然距離傳統(tǒng)編譯器有一定的差距,主要難點包括:
易用性
深度學(xué)習(xí)編譯器的初衷是希望簡化手工優(yōu)化性能和適配硬件的人力成本。然而在現(xiàn)階段,大規(guī)模部署應(yīng)用深度學(xué)習(xí)編譯器的挑戰(zhàn)仍然較大,能夠?qū)⒕幾g器用好的門檻較高,造成這個現(xiàn)象的主要原因包括:
魯棒性
目前主流的幾個AI編譯器項目大多數(shù)都還處于偏實驗性質(zhì)的產(chǎn)品,但產(chǎn)品的成熟度距離工業(yè)級應(yīng)用有較大的差距。這里的魯棒性包含是否能夠順利完成輸入計算圖的編譯,計算結(jié)果的正確性,以及性能上避免coner case下的極端badcase等。
性能問題
編譯器的優(yōu)化本質(zhì)上是將人工的優(yōu)化方法,或者人力不易探究到的優(yōu)化方法通過泛化性的沉淀和抽象,以有限的編譯開銷來替代手工優(yōu)化的人力成本。然而如何沉淀和抽象的方法學(xué)是整個鏈路內(nèi)最為本質(zhì)也是最難的問題。深度學(xué)習(xí)編譯器只有在性能上真正能夠代替或者超過人工優(yōu)化,或者真正能夠起到大幅度降低人力成本作用的情況下才能真正發(fā)揮它的價值。
然而達(dá)到這一目標(biāo)卻并非易事,深度學(xué)習(xí)任務(wù)大都是tensor級別的計算,對于并行任務(wù)的拆分方式有很高的要求,但如何將手工的優(yōu)化泛化性的沉淀在編譯器技術(shù)內(nèi),避免編譯開銷爆炸以及分層之后不同層級之間優(yōu)化的聯(lián)動,仍然有更多的未知需要去探索和挖掘。這也成為以MLIR框架為代表的下一代深度學(xué)習(xí)編譯器需要著重思考和解決的問題。
BladeDISC的主要技術(shù)特點
項目最早啟動的初衷是為了解決XLA和TVM當(dāng)前版本的靜態(tài)shape限制,內(nèi)部命名為 DISC (DynamIc Shape Compiler),希望打造一款能夠在實際業(yè)務(wù)中使用的完備支持動態(tài)shape語義的深度學(xué)習(xí)編譯器。
從團(tuán)隊四年前啟動深度學(xué)習(xí)編譯器方向的工作以來,動態(tài)shape問題一直是阻礙實際業(yè)務(wù)落地的嚴(yán)重問題之一。彼時,包括XLA在內(nèi)的主流深度學(xué)習(xí)框架,都是基于靜態(tài)shape語義的編譯器框架。典型的方案是需要用戶指定輸入的shape,或是由編譯器在運行時捕捉待編譯子圖的實際輸入shape組合,并且為每一個輸入shape組合生成一份編譯結(jié)果。
靜態(tài)shape編譯器的優(yōu)勢顯而易見,編譯期完全已知靜態(tài)shape信息的情況下,Compiler可以作出更好的優(yōu)化決策并得到更好的CodeGen性能,同時也能夠得到更好的顯存/內(nèi)存優(yōu)化plan和調(diào)度執(zhí)行plan。然而,其缺點也十分明顯,具體包括:
在2020年夏天,DISC完成了僅支持TensorFlow前端以及Nvidia GPU后端的初版,并且正式在阿里內(nèi)部上線投入實際應(yīng)用。最早在幾個受困于動態(tài)shape問題已久的業(yè)務(wù)場景上投入使用,并且得到了預(yù)期中的效果。即在一次編譯且不需要用戶對計算圖做特殊處理的情況下,完備支持動態(tài)shape語義,且性能幾乎與靜態(tài)shape編譯器持平。對比TensorRT等基于手工算子庫為主的優(yōu)化框架,DISC基于編譯器自動codegen的技術(shù)架構(gòu)在經(jīng)常為非標(biāo)準(zhǔn)開源模型的實際業(yè)務(wù)上獲得了明顯的性能和易用性優(yōu)勢。
從2020年第二季度開始至今,DISC持續(xù)投入研發(fā)力量,針對前文提到的從云端平臺方視角看到的深度學(xué)習(xí)編譯器距離大規(guī)模部署和應(yīng)用的幾個瓶頸問題,在性能、算子覆蓋率和魯棒性、CPU及新硬件支持、前端框架支持等方面逐漸完善。目前在場景覆蓋能力和性能等方面,已經(jīng)逐漸替換掉團(tuán)隊過往基于XLA和TVM等靜態(tài)shape框架上的工作,成為PAI-Blade支持阿里內(nèi)部及阿里云外部業(yè)務(wù)的主要優(yōu)化手段。2021年后,DISC在CPU及GPGPU體系結(jié)構(gòu)的后端硬件上的性能有了顯著的提升,同時在新硬件的支持上面投入了更多的技術(shù)力量。2021年底,為了吸引更多的技術(shù)交流和合作共建需要,以及更大范圍的用戶反饋,正式更名為BladeDISC并完成了初版開源。
關(guān)鍵技術(shù)
BladeDISC的整體架構(gòu),及其在阿里云相關(guān)產(chǎn)品中的上下文關(guān)系如下圖所示:
MLIR基礎(chǔ)架構(gòu)
MLIR是由Google在2019年發(fā)起的項目,MLIR 的核心是一套靈活的多層IR基礎(chǔ)設(shè)施和編譯器實用工具庫,深受 LLVM 的影響,并重用其許多優(yōu)秀理念。這里我們選擇基于MLIR的主要原因包括其比較豐富的基礎(chǔ)設(shè)施支持,方便擴(kuò)展的模塊化設(shè)計架構(gòu)以及MLIR較強的膠水能力。
動態(tài)shape編譯
上圖為BladeDISC的主體Pass Pipeline設(shè)計。對比目前主流的深度學(xué)習(xí)編譯器項目,主要技術(shù)特點如下:
圖層IR設(shè)計
BladeDISC選擇基于HLO作為核心圖層IR來接入不同的前端框架,但是HLO是原本為XLA設(shè)計的純靜態(tài)shape語義的IR。靜態(tài)場景下,HLO IR中的shape表達(dá)會被靜態(tài)化,所有的shape計算會被固化為編譯時常量保留在編譯結(jié)果中;而在動態(tài)shape場景下,IR本身需要有足夠的能力表達(dá)shape計算和動態(tài)shape信息的傳遞。BladeDISC從項目建立開始一直與MHLO社區(qū)保持緊密的合作,在XLA的HLO IR基礎(chǔ)上,擴(kuò)展了一套具有完備動態(tài)shape表達(dá)能力的IR,并增加了相應(yīng)的基礎(chǔ)設(shè)施以及前端框架的算子轉(zhuǎn)換邏輯。這部分實現(xiàn)目前已經(jīng)完整upstream至MHLO社區(qū),確保后續(xù)其它MHLO相關(guān)項目中IR的一致性。
運行時Shape計算、存儲管理和Kernel調(diào)度
動態(tài)shape編譯的主要挑戰(zhàn)來自于需要在靜態(tài)的編譯過程中能夠處理動態(tài)的計算圖語義。為完備支持動態(tài)shape,編譯結(jié)果需要能夠在運行時做實時的shape推導(dǎo)計算,不僅要為數(shù)據(jù)計算,同時也需要為shape計算做代碼生成。計算后的shape信息用于做內(nèi)存/顯存管理,以及kernel調(diào)度時的參數(shù)選擇等等。BladeDISC的pass pipeline的設(shè)計充分考慮了上述動態(tài)shape語義支持的需求,采用了host-device聯(lián)合codegen的方案。以GPU Backend為例,包括shape計算、內(nèi)存/顯存申請釋放、硬件管理、kernel launch運行時流程全部為自動代碼生成,以期得到完備的動態(tài)shape端到端支持方案和更為極致的整體性能。
動態(tài)shape下的性能問題
在shape未知或者部分未知的情況下,深度學(xué)習(xí)編譯器在性能上面臨的挑戰(zhàn)被進(jìn)一步放大。在大多數(shù)主流硬件backend上,BladeDISC采用區(qū)分計算密集型部分和訪存密集型部分的策略,以期在性能與復(fù)雜性和編譯開銷之間獲取更好的平衡。
對于計算密集型部分,不同的shape要求更加精細(xì)的schedule實現(xiàn)來獲得更好的性能,pass pipeline在設(shè)計上的主要考慮是需要支持在運行時根據(jù)不同的具體shape選擇合適的算子庫實現(xiàn),以及處理動態(tài)shape語義下的layout問題。
而訪存密集型部分的自動算子融合作為深度學(xué)習(xí)編譯器主要的性能收益來源之一,同樣面臨shape未知情況下在性能上的挑戰(zhàn)。許多靜態(tài)shape語義下比較確定性的問題,例如指令層的向量化,codegen模版選擇,是否需要implicit broadcast等等在動態(tài)shape場景下都會面臨更大的復(fù)雜性。針對這些方面的問題,BladeDISC選擇將部分的優(yōu)化決策從編譯時下沉到運行時。即在編譯期根據(jù)一定的規(guī)則生成多個版本的kernel實現(xiàn),在運行時根據(jù)實際shape自動選擇最優(yōu)的實現(xiàn)。這一機(jī)制被稱作speculation,在BladeDISC內(nèi)基于host-device的聯(lián)合代碼生成來實現(xiàn)。此外,在編譯期沒有具體shape數(shù)值的情況下,會很容易在各個層級丟失掉大量的優(yōu)化機(jī)會,從圖層的線性代數(shù)簡化、fusion決策到指令層級的CSE、常數(shù)折疊等。BladeDISC在IR及pass pipeline的設(shè)計過程中著重設(shè)計了shape constraint在IR中的抽象和在pass pipeline中的使用,例如編譯期未知的不同dimension size之間的約束關(guān)系等。在優(yōu)化整體性能方面起到了比較明顯的作用,保證能夠足夠接近甚至超過靜態(tài)shape編譯器的性能結(jié)果。
大顆粒度算子融合
團(tuán)隊在開啟BladeDISC項目之前,曾經(jīng)基于靜態(tài)shape編譯器在大顆粒度算子融合及自動代碼生成方面有過若干探索[3][4],其基本思想可以概括為借助于GPU硬件中低訪存開銷的shared memory或CPU中低訪存開銷的Memory Cache,將不同schedule的計算子圖縫合進(jìn)同一個kernel內(nèi),實現(xiàn)多個parallel loop復(fù)合,這種codegen方法稱之為fusion-stitching。這種訪存密集型子圖的自動代碼生成打破了常規(guī)的loop fusion,input/output fusion對fusion顆粒度的限制。在保證代碼生成質(zhì)量的同時,大幅增加fusion顆粒度,同時避免復(fù)雜性及編譯開銷爆炸。且整個過程完全對用戶透明,無需人工指定schedule描述。
在動態(tài)shape語義下實現(xiàn)fusion-stitching對比靜態(tài)shape語義下同樣需要處理更大的復(fù)雜性,動態(tài)shape語義下的shape constraint抽象一定程度上簡化了這一復(fù)雜性,使整體性能進(jìn)一步接近甚至超過手工算子實現(xiàn)。
多前端框架支持
AICompiler框架在設(shè)計時也包含了擴(kuò)展支持不同前端框架的考慮。PyTorch側(cè)通過實現(xiàn)一個輕量的Converter將TorchScript轉(zhuǎn)換為DHLO IR實現(xiàn)了對PyTorch推理作業(yè)的覆蓋。MLIR相對完備的IR基礎(chǔ)設(shè)施也為Converter的實現(xiàn)提供了便利。BladeDISC包含Compiler以及適配不同前端框架的Bridge側(cè)兩部分。其中Bridge進(jìn)一步分為宿主框架內(nèi)的圖層pass以及運行時Op兩部分,以插件的方式接入宿主框架。這種工作方式使BladeDISC可以透明化的支持前端計算圖,可以適配用戶各種版本的宿主框架。
運行時環(huán)境適配
為將編譯的結(jié)果能夠配合TensorFlow/PyTorch等宿主在各自的運行環(huán)境中執(zhí)行起來,以及管理運行時IR層不易表達(dá)的狀態(tài)信息等等,我們?yōu)椴煌倪\行時環(huán)境實現(xiàn)了一套統(tǒng)一的Compiler架構(gòu),并引入了運行時抽象層,即RAL(Runtime Abstraction Layer)層。
RAL實現(xiàn)了多種運行環(huán)境的適配支持,用戶可以根據(jù)需要進(jìn)行選擇,具體包括:
以上環(huán)境中在諸如資源管理,API語義等上存在差異,RAL通過抽象出一套最小集合的API ,并清晰的定義出它們的語義,將編譯器與運行時隔離開來,來達(dá)到在不同的環(huán)境中都能夠執(zhí)行編譯出來的結(jié)果的目的。此外RAL層實現(xiàn)了無狀態(tài)編譯,解決了計算圖的編譯之后,編譯的結(jié)果可能被多次執(zhí)行時的狀態(tài)信息處理問題。一方面簡化了代碼生成的復(fù)雜度,另一方面也更容易支持多線程并發(fā)執(zhí)行(比如推理)的場景,同時在錯誤處理,回滾方面也更加容易支持。
應(yīng)用場景
BladeDISC的典型應(yīng)用場景可以不太嚴(yán)格的分為兩類:其一是在主流的硬件平臺上(包括Nvidia GPU,x86 CPU等)上作為通用、透明的性能優(yōu)化工具,降低用戶部署AI作業(yè)的人力負(fù)擔(dān),提高模型迭代效率;另一個重要的應(yīng)用場景是幫助新硬件做AI場景的適配和接入支持。
目前BladeDISC已經(jīng)廣泛應(yīng)用在阿里內(nèi)部和阿里云上外部用戶的多個不同應(yīng)用場景下,覆蓋模型類型涉及NLP、機(jī)器翻譯、語音類ASR、語音TTS、圖像檢測、識別、AI for science等等多種典型AI應(yīng)用;覆蓋行業(yè)包括互聯(lián)網(wǎng)、電商、自動駕駛、安全行業(yè)、在線娛樂、醫(yī)療和生物等等。
在推理場景下,BladeDISC與TensorRT等廠商提供的推理優(yōu)化工具形成良好的技術(shù)互補,其主要差異性優(yōu)勢包括:
下圖為Nvidia T4硬件上幾個真實的業(yè)務(wù)例子的性能收益數(shù)字:
在新硬件支持方面,目前普遍的情況是除了積累比較深厚的Nvidia等頭部廠商之外,包括ROCM等其它GPGPU硬件普遍存在的情況是硬件的指標(biāo)已經(jīng)具備相當(dāng)?shù)母偁幜Γ珡S商受制于AI軟件棧上的積累相對較少,普遍存在硬件算力無法發(fā)揮出來導(dǎo)致硬件落地應(yīng)用困難的問題。如前文所述,基于編譯器的技術(shù)路徑下天然對于硬件的后端具備一定的泛化能力,且與硬件廠商的技術(shù)儲備形成比較強的互補。BladeDISC目前在GPGPU和通用CPU體系結(jié)構(gòu)上的儲備相對比較成熟。以GPGPU為例,在Nvidia GPU上的絕大部分技術(shù)??梢赃w移至海光DCU和AMD GPU等體系結(jié)構(gòu)相近的硬件上。BladeDISC較強的硬件泛化能力配合硬件本身較強的通用性,很好的解決了新硬件適配的性能和可用性問題。
下圖為海光DCU上幾個真實業(yè)務(wù)例子上的性能數(shù)字:
某識別類模型 | 推理 | 不同batchsize下 2.21X ~ 2.31X |
某檢測類模型A | 推理 | 不同batchsize下 1.73X ~ 2.1X |
某檢測類模型B | 推理 | 不同batchsize下 1.04X ~ 1.59X |
某分子動力學(xué)模型 | 訓(xùn)練 | 2.0X |
開源生態(tài)——構(gòu)想和未來
我們決定建設(shè)開源生態(tài)主要有如下的考慮:
后續(xù)我們計劃以兩個月為單位定期發(fā)布Release版本。BladeDISC近期的Roadmap如下:
此外,在中長期,我們在下面幾個探索性的方向上會持續(xù)投入精力,也歡迎各種維度的反饋和改進(jìn)建議以及技術(shù)討論,同時我們十分歡迎和期待對開源社區(qū)建設(shè)感興趣的同行一起參與共建。
歡迎加入BladeDISC用戶交流群:
參考文獻(xiàn)
本文作者: 朱凱