传统编译器与神经网络编译器
傳統(tǒng)編譯器與神經(jīng)網(wǎng)絡(luò)編譯器
傳統(tǒng)編譯器
以LLVM(low level virtual machine)為例,輸入是高級編程語言源碼,輸出是機(jī)器碼,由一系列模塊化的編譯器組件和工具鏈組成。
LLVM通過模塊分為前端,中端(優(yōu)化)和后端三部分。每當(dāng)出現(xiàn)新的編程語言,只需要開發(fā)相應(yīng)的前端,將編程語言轉(zhuǎn)換成LLVM的中間表示;類似地,出現(xiàn)新的硬件架構(gòu),只需要開發(fā)相應(yīng)的后端,對接上LLVM的中間表示。
模塊化的劃分,避免了因編程語言和CPU架構(gòu)的翻新,而引發(fā)的編譯器適配性問題,大大簡化了編譯器的開發(fā)工作。
神經(jīng)網(wǎng)絡(luò)編譯器
輸入是深度學(xué)習(xí)訓(xùn)練框架,訓(xùn)練出來的模型定義文件,輸出是能夠在不同硬件高效執(zhí)行的代碼。
從上至下由四個(gè)層級組成:
- 最上層對接各個(gè)深度學(xué)習(xí)訓(xùn)練框架,訓(xùn)練出來的算法模型(Tensorflow, Caffe, Pytorch, Mxnet等)。
- 圖層級(High-level IR):神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)可以表示成計(jì)算圖,圖層級的操作,對計(jì)算圖進(jìn)行一些和具體硬件和框架無關(guān)的操作,比如算子融合,內(nèi)存分配優(yōu)化,數(shù)據(jù)類型和數(shù)據(jù)維度的推導(dǎo)等。
可通過算子融合的方式,避免中間數(shù)據(jù)頻繁的在寄存器和內(nèi)存直接來回讀寫,從而提升整體推理性能。
Nividia通過把conv, bn, relu這三個(gè)算子融合成一個(gè)算子 fuse- CBR,實(shí)現(xiàn)了三倍的推理性能提升。
3. 算子層級(operator level/kernel level)算子層級,主要是張量計(jì)算。為了實(shí)現(xiàn)這些計(jì)算在硬件上高效實(shí)現(xiàn),發(fā)揮芯片的性能,通常硬件芯片配有專門優(yōu)化的算子計(jì)算庫,如Intel的MKL, Nvidia的CuDNN, TensorRT。這個(gè)層級需要支持每個(gè)硬件后端的算子實(shí)現(xiàn)。
4. 各硬件后端:GPU, ARM CPU, X86 CPU, NPU等。
自深度學(xué)習(xí)編譯器的概念提出以來,各類編譯器變層出不窮的出現(xiàn)。
TVM的前世今生
在編譯器快速發(fā)展的浪潮中,較為突出的便是TVM(Tensor Virtual Machine)。
TVM最早提出是2017年,深度學(xué)習(xí)系統(tǒng)的編譯器堆棧。
第一代TVM的設(shè)計(jì),借鑒了借鑒傳統(tǒng)編譯器框架LLVM的設(shè)計(jì)思路,設(shè)計(jì)抽象出中間表示層,不同的模型,只需要開發(fā)相應(yīng)的前端接口,不同的后端,只需要開發(fā)相應(yīng)的后端接口。
TVM全稱為Tensor Virtual Machine,屬于算子層級,主要用于張量計(jì)算,提供獨(dú)立于硬件的底層計(jì)算中間表示,采用各種方式(循環(huán)分塊,緩存優(yōu)化等)對相應(yīng)的計(jì)算進(jìn)行優(yōu)化。第一代的圖層級表示叫NNVM(Neural Network Virtual Machine)。NNVM的設(shè)計(jì)目標(biāo)是:將來自不通深度學(xué)習(xí)框架的計(jì)算圖,轉(zhuǎn)換為統(tǒng)一的計(jì)算圖中間表示(IR),對之進(jìn)行優(yōu)化。
第一代的靜態(tài)圖存在一定的缺陷:
- 不能較好支持控制流,如分支跳轉(zhuǎn),循環(huán)等。
- 不能支持計(jì)算圖輸入形狀,取決于輸入tensor大小的模型,比如word2vec等。
雖然Tensorflow有如tf.cond.Tf.while_loop的控制接口,在某種程度上解決第一個(gè)問題,tf.fold來解決第二個(gè)問題,但是這些方式對剛剛接觸深度學(xué)習(xí)框架的人來說門檻過高。
后面出現(xiàn)的動態(tài)圖,摒棄了傳統(tǒng)的計(jì)算圖先定義,后執(zhí)行的方式,采用了計(jì)算圖在運(yùn)行時(shí)定義的模式,這種計(jì)算圖就稱為動態(tài)圖。
第二代TVM的圖計(jì)算層,變?yōu)镽elay VM,Relay和第一代的圖計(jì)算表示NNVM的最主要區(qū)別,Relay IR除了支持dataflow(靜態(tài)圖), 能夠更好地解決control flow(動態(tài)圖)。不僅是一種計(jì)算圖的中間表示,也支持自動微分。
總結(jié)一下,目前TVM的架構(gòu)是:
- 最高層級支持主流的深度學(xué)習(xí)前端框架,包括TensorFlow,MXNet,Pytorch等。
- Relay IR支持可微分,該層級進(jìn)行圖融合,數(shù)據(jù)重排等圖優(yōu)化操作。
- 基于tensor張量化計(jì)算圖,并根據(jù)后端進(jìn)行硬件原語級優(yōu)化,autoTVM根據(jù)優(yōu)化目標(biāo)探索搜索空間,找到最優(yōu)解。
- 后端支持ARM、CUDA/Metal/OpenCL、加速器VTA(Versatile Tensor Accelerator)。
Halide
Algorithm部分主要是算法描述和計(jì)算的數(shù)學(xué)表達(dá)式。
Halide于2012年提出,主要用于自動優(yōu)化。其嵌入到C++中,MIT研究人員專門為圖像處理設(shè)計(jì)的一種程序語言。Halide語言易于編寫,語法簡單,數(shù)據(jù)結(jié)構(gòu)清晰,自動對代碼進(jìn)行優(yōu)化,使得程序獲得更好的執(zhí)行效率。
設(shè)計(jì)的核心思想是把算法和調(diào)度分離。這樣做的好處,在給定算法的情況下,只需要去調(diào)整Schedule 調(diào)度選擇,不用重寫算法實(shí)現(xiàn)不同的Schedule。當(dāng)調(diào)整Schedule、探索設(shè)計(jì)空間時(shí),也不會擔(dān)心因?yàn)橹貙懰惴?#xff0c;而導(dǎo)致計(jì)算的正確性會發(fā)生變化。
Algorithm部分主要是算法描述和計(jì)算的數(shù)學(xué)表達(dá)式。
Schedule部分,告訴機(jī)器什么時(shí)候分配內(nèi)存,如何計(jì)算(分塊計(jì)算還是順序計(jì)算)——目前已經(jīng)提供了一些調(diào)度策略。
不同調(diào)度策略,考慮重復(fù)冗余計(jì)算和局部性(locality)的權(quán)衡。
AutoKernel
深度學(xué)習(xí)模型能否成功在終端落地應(yīng)用,滿足產(chǎn)品需求,一個(gè)關(guān)鍵的指標(biāo)就是神經(jīng)網(wǎng)絡(luò)模型的推理性能。
目前的高性能算子計(jì)算庫,主要是由高性能計(jì)算優(yōu)化工程師,進(jìn)行手工開發(fā)。然而新的算法/硬件的不斷涌現(xiàn),導(dǎo)致了算子層級的優(yōu)化開發(fā)工作量巨大。同時(shí)優(yōu)化代碼的工作,并不是一件簡單的事,要求工程師,既要精通計(jì)算機(jī)體系架構(gòu),又要熟悉算子的計(jì)算流程。
人才少,需求多,技術(shù)門檻高,算子優(yōu)化自動化是未來的大趨勢。而提出AutoKernel的初衷,便是希望能把這個(gè)過程自動化,從小處入手,在算子層級的優(yōu)化,實(shí)現(xiàn)優(yōu)化代碼的自動生成。
AutoKernel的輸入是算子的計(jì)算描述(如Conv、Poll、Fc),輸出是經(jīng)過優(yōu)化的加速源碼。
這一工具的開發(fā),旨在降低優(yōu)化工作的門檻,不需要有底層匯編的知識門檻,不用手寫優(yōu)化匯編。可通過直接調(diào)用開發(fā)的工具包,可生成匯編代碼。同時(shí)還提供了包含CPU、GPU的docker環(huán)境,無需部署開發(fā)環(huán)境,只需使用docker便可。還可通過提供的插件——plugin,可以把自動生成的算子,一鍵集成到推理框架中——Tengine。
對應(yīng)地,算子層級的AutoKernel,主要分為三個(gè)模塊,
- Op Generator:算子生成器,采用了開源的Hallide。
- AutoSearch:目前還在開發(fā)中,目標(biāo)是通過機(jī)器學(xué)習(xí)、強(qiáng)化學(xué)習(xí)常用算法自動搜索出優(yōu)化策略。
- AutoKernel Plugin:把生成的自動算子以插件的形式,插入到Tengine中,和人工定制互為補(bǔ)充。
Tengine對象層對接了不同的神經(jīng)網(wǎng)絡(luò)模型,圖層級的NNIR包含了模型解析、圖層優(yōu)化,算子層級包括高性能計(jì)算庫(HCL lib)。
AutoKernel Plugin主要分為生成和部署兩部分,生成部分用Hallid填寫算法描述和調(diào)度策略,執(zhí)行時(shí)指定后端類型(基本覆蓋目前的主流后端)。
部署部分則封裝為Tengine的庫,直接調(diào)用。
參考鏈接:
https://www.163.com/dy/article/G583KIQD0511DPVD.html
總結(jié)
以上是生活随笔為你收集整理的传统编译器与神经网络编译器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Apple苹果公司组织架构
- 下一篇: 北汽蓝谷极狐阿尔法S与T