在昨日舉行的 “2022 百度云智峰會(huì)·智算峰會(huì)” 上,百度智能云發(fā)布國(guó)內(nèi)首個(gè)全棧自研的 AI 基礎(chǔ)設(shè)施 “百度 AI 大底座”,引發(fā)行業(yè)的廣泛關(guān)注。其中,百度百舸·AI 異構(gòu)計(jì)算平臺(tái)作為 AI IaaS 層的重要構(gòu)成,是 AI 大底座堅(jiān)實(shí)的基礎(chǔ)設(shè)施。百度百舸·AI 異構(gòu)計(jì)算平臺(tái)整合了百度自研的 AI 芯片 “昆侖芯”,在 AI 計(jì)算、存儲(chǔ)、加速、容器方面進(jìn)行系統(tǒng)優(yōu)化,發(fā)揮算力的最佳性能和效率。
在本次峰會(huì)上,NVIDIA GPU 計(jì)算專家陳庾分享了以 “視覺(jué)大模型訓(xùn)練與推理優(yōu)化” 為題的演講,以 Swin Transformer 模型為例,介紹了 NVIDIA 在視覺(jué)大模型訓(xùn)練與推理優(yōu)化上的探索和實(shí)踐經(jīng)驗(yàn),包括在 Swin Transformer 的訓(xùn)練和推理上采用到的加速技巧以及對(duì)應(yīng)的加速效果。這些加速方法目前已經(jīng)應(yīng)用到百度百舸·AI 異構(gòu)計(jì)算平臺(tái)的 AIAK 加速功能中,助力各行業(yè)客戶的 AI 業(yè)務(wù)加速落地。
以下為演講內(nèi)容概要。
視覺(jué)大模型簡(jiǎn)介:Swim Transformer
在介紹 Swin Transformer 之前,我們可以先回顧一下 Vision Transformer (ViT) 的模型結(jié)構(gòu)。如左圖所示,ViT 會(huì)將一個(gè)圖像分割成一系列的圖像塊(patch),然后通過(guò)基于 Transformer 的編碼器對(duì)這一系列圖像塊進(jìn)行編碼,最后得到可用于分類等任務(wù)的特征。
而 Swin Transformer,它引入了 window attention 的概念,不同于 ViT 對(duì)整個(gè)圖像進(jìn)行注意力計(jì)算(attention)。Swin Transformer 會(huì)先將圖像劃分成若干個(gè)窗口(window),然后僅對(duì)窗口內(nèi)部的圖像塊進(jìn)行對(duì)應(yīng)的注意力計(jì)算,從而減少計(jì)算量。為了彌補(bǔ)窗口帶來(lái)的邊界問(wèn)題,Swin Transformer 進(jìn)一步引入 window shift 的操作。同時(shí)為了使得模型有更豐富的位置信息,Swin Transformer 還在注意力計(jì)算時(shí)引入了 relative position bias。
在 Swin Transformer 的網(wǎng)絡(luò)結(jié)構(gòu)中,我們也可以看到, Swin Transformer 被劃分為多個(gè)階段(stage),其中每個(gè)階段的分辨率是不一樣的,從而形成了一個(gè)分辨率金字塔,這樣也使得每個(gè)階段的計(jì)算復(fù)雜程度也逐漸降低。每個(gè)階段中對(duì)應(yīng)若干個(gè) transformer block。
接下來(lái),我們從具體操作的角度來(lái)對(duì) Swin Transformer 進(jìn)行算子的劃分。可以看到,一個(gè) transformer block 中涉及到三大部分,第一部分是如 window shift、partition、reverse 的一些窗口相關(guān)的操作,第二部分是注意力計(jì)算,第三部分是 FFN 計(jì)算。而 attention 和 FFN 部分又可以進(jìn)一步細(xì)分為若個(gè)算子,最終如圖所示,我們可以將整個(gè)模型細(xì)分為幾十個(gè)算子的組合。這樣的算子劃分,對(duì)于我們進(jìn)行性能分析,定位性能瓶頸以及開(kāi)展加速優(yōu)化而言,都是非常重要的。
視覺(jué)大模型 Swim Transformer 的訓(xùn)練加速
接下來(lái),介紹 NVIDIA 在 Swim Transformer 模型訓(xùn)練加速上進(jìn)行的優(yōu)化工作。對(duì)于 Swin Transformer 而言,我們一般采用數(shù)據(jù)并行的方式進(jìn)行多 GPU 訓(xùn)練,我們發(fā)現(xiàn)卡間通訊的開(kāi)銷占比會(huì)相對(duì)較少,所以在這里,我們優(yōu)先對(duì)單 GPU 上的計(jì)算瓶頸進(jìn)行優(yōu)化。
首先,我們通過(guò) nsight system 性能分析工具來(lái)看一下整個(gè) baseline 的性能表現(xiàn)。左圖所示的是 FP32 的 baseline,可以看到它的 GPU 利用率是很高的,而其中占比最高的是矩陣乘法相關(guān)的 kernel。
那么對(duì)于矩陣乘法而言,我們的一個(gè)優(yōu)化手段,就是充分利用 tensor core 進(jìn)行加速,可以考慮直接采用 tf32 tensor core 或者在混合精度下采用 fp16 tensor core。在這里,我們采用了混合精度的方案,可以看到右圖中,矩陣乘法的 kernel 由于采用了 fp16 tensor core,其耗時(shí)占比有了明顯下降。此外,采用混合精度的方式,我們也可以在 kernel io 上取得一定的收益。整體而言,在 Swin-Large 模型上,通過(guò)混合精度的方式,我們可以取得了 1.63 倍的吞吐提升。
下一個(gè)優(yōu)化方案是算子融合。算子融合一般而言可以為我們帶來(lái)兩個(gè)好處:一個(gè)是減少 kernel launch 的開(kāi)銷。如左圖所示,兩個(gè) cuda kernel 的執(zhí)行需要兩次 launch,那樣可能會(huì)導(dǎo)致 kernel 之間存在一定的空隙,使得 GPU 空閑。
如果我們將兩個(gè) cuda kernel 融合成一個(gè) cuda kernel,一方面節(jié)省了一次 launch,同時(shí)也可以避免 gap 的產(chǎn)生。另外一個(gè)好處是減少了 global memory 的訪問(wèn),因?yàn)?global memory 的訪問(wèn)是非常耗時(shí)的。而兩個(gè)獨(dú)立的 cuda kernel 之間要進(jìn)行結(jié)果傳遞,都需要通過(guò) global memory,將兩個(gè) cuda kernel 融合成一個(gè) kernel,我們就可以在寄存器或者 shared memory 上進(jìn)行結(jié)果傳遞,從而避免了一次 global memory 寫和讀,從而提升性能。
對(duì)于算子融合,我們第一步,是采用現(xiàn)成的 apex 庫(kù)來(lái)進(jìn)行 Layernorm 和 Adam 中操作的融合??梢钥赐ㄟ^(guò)簡(jiǎn)單的指令替換,我們可以使能 apex 的 fused layernorm 和 fused Adam,從而使得加速效果從 1.63 倍提升至 2.11 倍。
除了利用現(xiàn)有的 apex 庫(kù),NVIDIA 也進(jìn)行了手工的融合算子開(kāi)發(fā)。這里展示的是,我們針對(duì) Swin Transformer 特有的 window 相關(guān)操作,如 window partition、shift、merge 等進(jìn)行的融合算子開(kāi)發(fā)。可以看到,通過(guò)引入我們的定制化融合算子,可以將加速比進(jìn)一步提升至 2.19 倍。
接下來(lái)展示的是,NVIDIA 對(duì) mha 部分的融合工作。Mha 部分是 transformer 模型中一個(gè)占比很大的模塊,因此對(duì)它的優(yōu)化往往可以帶來(lái)較大的加速效果。從圖中可以看到,在沒(méi)有進(jìn)行算子融合之前,mha 部分的操作占比為 37.69%,其中包括了不少 elementwise 的 kernel。我們通過(guò)將相關(guān)操作融合成一個(gè)獨(dú)立的 fmha kernel,從而將加速比進(jìn)一步提升 2.85 倍。
上述是我們?cè)趩慰ㄉ先〉玫挠?xùn)練加速效果。我們?cè)賮?lái)看一下單機(jī) 8 卡的訓(xùn)練情況,可以看到,通過(guò)上述優(yōu)化,我們可以將訓(xùn)練吞吐從 1,612 提升至 3,733,取得 2.32 倍的加速。
視覺(jué)大模型 Swim Transformer 的推理加速
接下來(lái),介紹 NVIDIA 在 Swim Transformer 模型推理加速上進(jìn)行的優(yōu)化工作。
跟訓(xùn)練一樣,推理的加速離不開(kāi)算子融合這一方案。不過(guò)相對(duì)于訓(xùn)練而言,在推理上進(jìn)行算子融合有兩個(gè)好處:一,推理上的算子融合不需要考慮反向,所以 kernel 開(kāi)發(fā)過(guò)程中不需要考慮保存計(jì)算梯度所需要的中間結(jié)果;二,推理過(guò)程允許預(yù)處理,我們可以對(duì)一些只需要一次計(jì)算便可重復(fù)使用的操作,提前算好,保留結(jié)果,每次推理時(shí)直接調(diào)用從而避免重復(fù)計(jì)算。
在推理側(cè),NVIDIA 進(jìn)行了不少算子融合,在這里挑選了兩個(gè)加速效果比較明顯的算子進(jìn)行介紹。
首先是 mha 部分的算子融合,我們將 position bias lookup 這一操作提前到預(yù)處理部分,從而避免每次推理時(shí)都進(jìn)行 lookup,然后將 batch gemm、softmax、batch gemm 融合成一個(gè)獨(dú)立的 fmha kernel??梢钥吹?,融合后,該部分取得了 10 倍的加速,而端到端也取得了 1.58 倍的加速。
另一個(gè)算子融合是 QKV gemm + bias 的融合,gemm 和 bias 的融合是一個(gè)十分常見(jiàn)的融合手段。在這里為了配合我們前面提到的 fmha kernel,我們需要對(duì) weight 和 bias 提前進(jìn)行格式上的變換,這種提前變換也體現(xiàn)了上文提到的,推理上進(jìn)行算子融合的靈活性。最后,通過(guò) QKV gemm+bias 的融合,我們可以進(jìn)一步取得 1.1 倍的端到端加速。
除算子融合以外,我們使用了矩陣乘法 padding 的優(yōu)化手段。在 Swin Transformer 的計(jì)算中,有時(shí)候我們會(huì)遇到主維為奇數(shù)的矩陣乘法,這時(shí)候并不利于我們的矩陣乘法 kernel 進(jìn)行向量化讀寫,從而使得 kernel 的運(yùn)行效率變低。這時(shí)候我們可以考慮對(duì)參與運(yùn)算的矩陣主維進(jìn)行 padding 操作,使其變?yōu)?8 的倍數(shù),這樣一來(lái),矩陣乘法 kernel 就可以以 alignment=8,一次讀寫 8 個(gè)元素的方式來(lái)進(jìn)行向量化讀寫,提升性能。
如下表所示,我們將 n 從 49 padding 到 56 后,矩陣乘法的 latency 從 60.54us(微秒) 下降為 40.38us,取得了 1.5 倍的加速比。
下一個(gè)優(yōu)化手段,是巧用 half2 或者 char4 這樣的數(shù)據(jù)類型。
以 half2 為例,可以帶來(lái)以下三個(gè)好處:
一,向量化讀寫可以提升顯存的帶寬利用率并降低訪存指令數(shù)。如右圖所示,通過(guò) half2 的使用,訪存指令減少了一半,同時(shí) memory 的 SOL 也有顯著提升。
二, 結(jié)合 half2 專有的高吞吐的數(shù)學(xué)指令,可以減低 kernel 的時(shí)延。
三,在進(jìn)行 reduction 時(shí),采用 half2 數(shù)據(jù)類型意味著一個(gè) cuda 線程同時(shí)處理兩個(gè)元素,可以有效減少空閑的線程數(shù)。最終通過(guò)使用 half2,我們可以觀察到圖示的 addBiasResidual 這一個(gè) kernel,latency 從 20.96us 下降為 10.78us,加速 1.94 倍。
下一個(gè)優(yōu)化手段,是巧用寄存器數(shù)組。在我們進(jìn)行 layernorm 或者 softmax 等 Transformer 模型常見(jiàn)的算子優(yōu)化時(shí),我們經(jīng)常需要在一個(gè) kernel 中多次使用同一個(gè)輸入數(shù)據(jù),那么相對(duì)于每次都從 global memory 讀取,我們可以采用寄存器數(shù)組來(lái)緩存數(shù)據(jù),從而避免重復(fù)讀取 global memory。
由于寄存器是每個(gè) cuda 線程獨(dú)占的,所以在進(jìn)行 kernel 設(shè)計(jì)時(shí),我們需要提前設(shè)定好每個(gè) cuda 線程所需要緩存的元素個(gè)數(shù),從而開(kāi)辟對(duì)應(yīng)大小的寄存器數(shù)組,并且在分配每個(gè) cuda 線程所負(fù)責(zé)元素時(shí),需要確保我們可以做到合并訪問(wèn)。
如右圖所示,當(dāng)我們有 8 個(gè)線程時(shí),0 號(hào)線程可以處理 0 號(hào)元素,當(dāng)我們有 4 個(gè)線程是,0 號(hào)線程則處理 0 號(hào)和 4 號(hào)元素,如此類推。我們一般建議可以采用模板函數(shù)的方式,通過(guò)模板參數(shù)來(lái)控制每個(gè) cuda 線程的寄存器數(shù)組大小。
此外,在使用寄存器數(shù)組時(shí),需要保證我們的下標(biāo)是常量,如果是循環(huán)變量作為下標(biāo),我們應(yīng)該盡量保證可以進(jìn)行循環(huán)展開(kāi),這樣可以避免編譯器將數(shù)據(jù)放到了時(shí)延很高的 local memory 中,如圖所示,我們?cè)谘h(huán)條件中添加限制,通過(guò) ncu 報(bào)告可以看到,避免了 local memory 的使用。
最后一個(gè)我想介紹優(yōu)化手段是 INT8 量化。INT8 量化是推理加速非常重要的加速手段,對(duì)于 Transformer based 的模型而言,INT8 量化往往可以帶來(lái)不錯(cuò)的加速效果。
而對(duì)于 Swin Transformer 來(lái)說(shuō),通過(guò)結(jié)合合適的 PTQ 或 QAT 量化方案,可以在取得良好加速效果的同時(shí),保證量化精度。通過(guò) QAT,我們可以保證精度損失在千分之 5 以內(nèi)。
而在 PTQ 那一列,我們可以看到 swin large 的掉點(diǎn)比較嚴(yán)重。我們可以通過(guò)禁用 FC2 和 PatchMerge 中的部分量化結(jié)點(diǎn),來(lái)進(jìn)一步提升量化精度,這其實(shí)就是一個(gè)性能和精度的 tr 平衡了。
接下來(lái)介紹 NVIDIA 在推理側(cè)取得的加速效果。
左上圖優(yōu)化后 跟 pytorch 的時(shí)延對(duì)比,右下圖為優(yōu)化后 FP16 下跟 pytorch 以及 INT8 優(yōu)化跟 FP16 優(yōu)化的加速比??梢钥吹?,通過(guò)優(yōu)化,在 FP16 精度上,我們可以取得,相對(duì)于 pytorch 2.82x~7.34x 的加速,結(jié)合 INT8 量化,我們可以在此基礎(chǔ)上進(jìn)一步取得 1.2x~1.5x 的加速。
總結(jié):視覺(jué)大模型 Swim Transformer 訓(xùn)練與推理加速技巧
本次分享中我們介紹了一系列訓(xùn)練與推理加速技巧,其中包括 :
一,混合精度訓(xùn)練、低精度推理,使用更高性能的 Tensor Core 進(jìn)行計(jì)算矩陣乘法或卷積計(jì)算;
二、算子融合;
三、cuda kernel 優(yōu)化技巧 :如矩陣補(bǔ)零,向量化讀寫,巧用寄存器數(shù)組等。
結(jié)合上述優(yōu)化技巧,加速效果:
在訓(xùn)練上,以 Swin-Large 模型為例,取得了單卡 ~2.85x 的加速比,8 卡 2.32x 的加速比;
在推理上,以 Swin-tiny 模型為例,在 FP16 精度下取得了 2.82x - 7.34x 的加速比,結(jié)合 INT8 量化,進(jìn)一步取得 1.2x - 1.5x 的加速比。
上述介紹的視覺(jué)大模型訓(xùn)練與推理的加速方法,已經(jīng)在百度百舸·AI 異構(gòu)計(jì)算平臺(tái)的 AIAK 加速功能中實(shí)現(xiàn)。
原文標(biāo)題:百度智算峰會(huì)精彩回顧:視覺(jué)大模型訓(xùn)練與推理優(yōu)化
文章出處:【微信公眾號(hào):NVIDIA英偉達(dá)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
英偉達(dá)
+關(guān)注
關(guān)注
22文章
3829瀏覽量
91626 -
大模型
+關(guān)注
關(guān)注
2文章
2523瀏覽量
2977
原文標(biāo)題:百度智算峰會(huì)精彩回顧:視覺(jué)大模型訓(xùn)練與推理優(yōu)化
文章出處:【微信號(hào):NVIDIA_China,微信公眾號(hào):NVIDIA英偉達(dá)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論