作為圖片屆的“Twitter”,Pinterest首頁展示給用戶的圖片也離不開背后的推薦模型。近期,其工程團隊通過將機器學習服務(wù)從CPU轉(zhuǎn)移到GPU上,使得Pinterest可以上線比之前大100倍的推薦模型。上線大模型給模型質(zhì)量帶來了階躍式的提升,最終將Pinterest首頁feed流的用戶活躍度提高了16%。
【資料圖】
在本文中,他們分享了如何只經(jīng)過微小的投入和延遲的成本實現(xiàn)這一優(yōu)化目標,這包括優(yōu)化特定算子,整合內(nèi)存?zhèn)鬏?,通過CUDA Graph技術(shù)在設(shè)備上執(zhí)行靜態(tài)圖,以及分布式系統(tǒng)的重新設(shè)置。他們的實踐證明,要想提高模型效果,模型參數(shù)就得變大,而使用GPU服務(wù)方案的經(jīng)濟效益遠超CPU服務(wù)方案。
來源|Pinterest Engineering
翻譯|鄭澤康
Pinterest的使命是給每個人帶來創(chuàng)造他們所熱愛生活的靈感。為了實現(xiàn)這一使命,我們所有產(chǎn)品中都包含的一個關(guān)鍵組件就是各式各樣的推薦模型,它們負責在合適的時間給合適的人展示合適的內(nèi)容。我們的推薦模型是通過高級算法進行訓(xùn)練的一系列機器學習模型,用于理解用戶在Pinterest上花費時間時的行為,這些推薦模型是通過定制的機器學習模型服務(wù)器(Scorpion Model Server, 即SMS)來運行的。
SMS 上需要面對十分艱巨的技術(shù)挑戰(zhàn),基于3000多億個Pin的語料庫,它必須在毫秒內(nèi)為4億多個用戶提供相關(guān)推薦。之前,SMS在CPU上進行模型推理,其內(nèi)核經(jīng)過了多年的優(yōu)化以滿足我們對延遲和基礎(chǔ)設(shè)施成本的嚴格要求,但即使最新一代的CPU也幾乎達到了SMS服務(wù)的極限。我們必須非常審慎地確保,每次因模型變化而帶來的延遲和基礎(chǔ)設(shè)施成本的增加都是合情合理的。
機器學習領(lǐng)域里模型參數(shù)和計算量增加的趨勢讓問題變得更加嚴峻。在推薦系統(tǒng)中,具有1000億參數(shù)量的模型已經(jīng)很常見,并在業(yè)內(nèi)常被提及。
在Pinterest,我們采用了稍微不同的方式,通過使用諸如Transformer的現(xiàn)代模型架構(gòu)來擴大模型。在更大模型下,我們立即觀測到模型準確率發(fā)生的質(zhì)變——其大幅提升了Pinner(譯注:Pinterest用戶)的參與度。但是,在CPU服務(wù)器上運行這些現(xiàn)代模型架構(gòu)幾乎讓成本和延遲都提升了40倍,這一代價難以承受。因此,我們轉(zhuǎn)而尋求使用GPU來加速模型推理,從而可以使用合理的成本來運行這些模型。
1
優(yōu)化
當我們嘗試那些開箱即用的GPU服務(wù)時,很快意識到在經(jīng)濟高效地利用GPU運行推薦模型服務(wù)之前需要對其優(yōu)化。我們首先使用分析工具來分析在模型推理過程中發(fā)生了什么,在仔細觀察分析結(jié)果時,我們注意到時間線上有大量的小CUDA Kernel在執(zhí)行。
這是推薦系統(tǒng)模型的預(yù)期行為,其中數(shù)百個特征在模型后期階段進行特征拼接之前需要單獨處理。然而,對于大量的小算子,啟動CUDA Kernel帶來的開銷比計算開銷還要昂貴。與訓(xùn)練時的batchsize相比,模型服務(wù)時的batchsize相對更小,進而加劇了這一問題。
上圖分別是模型優(yōu)化前和優(yōu)化后的分析結(jié)果。CUDA Kernel時間線(用紅框突出顯示)表明,Kernel的啟動開銷(藍色塊之間的間隙)顯著減少,因此GPU得到了更好得利用,它將大部分時間花費在Kernel執(zhí)行中。
2
減少小op的數(shù)量
我們采取的第一個方法是找出減少小op數(shù)量的機會。我們尋找常被使用的模型組件,并盡可能對其優(yōu)化。其中一個例子是Embedding的查表模塊,它包含兩個計算步驟:原始ID到索引的查找,索引到Embedding的查找。由于我們有大量特征,這兩步操作會被重復(fù)數(shù)百次。通過使用cuCollections?(https://github.com/NVIDIA/cuCollections)?以支持GPU上原始ID的哈希表,并實現(xiàn)了自定義的Embedding查找模塊以合并多個查找操作,我們顯著地減少了op的數(shù)量。在執(zhí)行一些優(yōu)化后,馬上看到了更優(yōu)的性能表現(xiàn)。
3
合并內(nèi)存拷貝
同樣,當我們在主機和GPU顯存之間搬運Tensor時,也存在整合數(shù)據(jù)傳輸?shù)臋C會。通用推薦模型里的一個候選樣例通常會使用數(shù)百個特征作為輸入,對于每一次推理,各個特征作為一個單獨的tensor被拷貝到GPU顯存中。雖然在主機和GPU顯存之間搬運數(shù)據(jù)非???,但是為每個請求調(diào)度數(shù)百個cudaMemcpy()函數(shù)調(diào)用的開銷很快成為瓶頸。
從主機單獨拷貝Tensor到 GPU?vs?一次拷貝整個內(nèi)存緩沖區(qū)
為了解決這個問題,我們應(yīng)用了一個簡單的優(yōu)化將cudaMemcpy()調(diào)用次數(shù)從幾百次減少到一次:不再使用Torch框架將Tensor單獨移動到GPU上,而是先將所有Tensor的數(shù)據(jù)放置到一塊預(yù)先分配好的連續(xù)內(nèi)存緩沖區(qū)中,并一次性將緩沖區(qū)內(nèi)容拷貝到GPU里,最終通過指向GPU顯存緩沖區(qū)的不同偏移量來重構(gòu)得到GPU上的所有張量。
該優(yōu)化帶來的代價是要顯式管理預(yù)先分配的內(nèi)存緩沖區(qū)的生命周期,以及需要對不同數(shù)據(jù)類型手動處理GPU顯存對齊。但作為結(jié)果,P50數(shù)據(jù)拷貝延遲從10ms 降低到1ms以下,這證明了該優(yōu)化帶來的復(fù)雜性是可以接受的。
4
利用CUDA Graph
為了進一步優(yōu)化模型推理過程,我們使用CUDA Graph(https://pytorch.org/blog/accelerating-pytorch-with-cuda-graphs/)來完全消除剩余小op的開銷。CUDA Graph允許我們將模型推理過程捕捉為靜態(tài)圖,而不是單獨調(diào)度。它可以讓整個計算作為一個單元進行執(zhí)行,而不產(chǎn)生任何Kernel啟動開銷。我們支持將CUDA Graph作為模型服務(wù)的一個新后端。一開始加載模型時,模型服務(wù)執(zhí)行一次模型推理以構(gòu)建圖實例,該實例可以針對實時流量重復(fù)執(zhí)行。
CUDA Graph在一個批處理內(nèi)(下圖)執(zhí)行Kernel,而不是在一個序列中逐個執(zhí)行(上圖),這減少了Kernel之間CPU啟動帶來的開銷。圖表來自:https://pytorch.org/blog/accelerating-pytorch-with-cuda-graphs/
CUDA Graph自身的一些限制給我們的模型服務(wù)帶來了額外的復(fù)雜性。其中最大的限制是CUDA Graph要求所有Tensor都具有靜態(tài)形狀和布局,這對動態(tài)大小批次和不規(guī)則的變長Tensor帶來了挑戰(zhàn)。然而,我們相信為了獲得更好性能進行的權(quán)衡是值得的,并且我們可以將輸入Tensor補齊到精心挑選的靜態(tài)形狀。
5
使用更大的batchsize
最后,我們重新研究了SMS為模型推理執(zhí)行的批處理策略。SMS支持動態(tài)批處理,可以讓多個請求合并成更大的批次。它通常能帶來更好的吞吐量,但代價是需要較短的時間以等待請求序列收集足夠多的項(item)。對于CPU上的ML推斷,我們通常想要將請求分成小批量來提高并行度以減小延時。然而對于GPU,其延時對batchsize并不敏感,使用更大的batchsize對GPU提升工作負載效率更重要。
這種batchsize的需求使我們重新思考了SMS里的分布式系統(tǒng)設(shè)置。對于CPU上的ML推斷,我們使用scatter-gather結(jié)構(gòu)將原始請求拆分,并在多個葉子結(jié)點上并行執(zhí)行,以獲得更小的延時。
此外,該架構(gòu)允許我們?yōu)槊總€葉子結(jié)點分配一個固定的數(shù)據(jù)切片,以優(yōu)化特征提取期間的緩存命中率。然而,由于GPU傾向使用大batchsize,因此刪除root layer直接在原始請求中使用大batchsize更有意義。最終我們使用了CacheLib的混合緩存,它用DRAM和SSD來補償與scatter-gather 架構(gòu)設(shè)置相比的緩存容量損失。
6
結(jié)果
我們首先測量了模型單次推理的延時。我們使用c5.18x AWS實例提供CPU服務(wù),g5.4 AWS實例提供GPU服務(wù)。
CPU延時隨著batchsize線性增長,在較小的batchsize下,GPU延時幾乎相同,此時Kernel啟動開銷占延時主導(dǎo)因素。然而隨著batchsize增加,實際計算時間主導(dǎo)了延時,GPU延時以亞線性形式增長。在實踐中,GPU效率提升的亮點在于SMS可以使用更大的batch工作。結(jié)合了所有優(yōu)化之后,我們獲得了驚人的結(jié)果,相比 CPU 服務(wù),GPU服務(wù)在較大batchsize下的每批次的延遲提升了100倍以上。
我們的服務(wù)指標也展示了令人印象深刻的結(jié)果。通過優(yōu)化模型操作,重新設(shè)置分布式系統(tǒng)以及優(yōu)化數(shù)據(jù)傳輸并使用CUDA Graph,我們以30%的更低延時上線了77倍大的模型,并以適當成本增加了20%的吞吐量。
最后,兩個數(shù)量級效率提升開啟了Pinterest最先進的推薦模型架構(gòu)??梢钥吹?,模型質(zhì)量顯著地提升直接轉(zhuǎn)化為更高的用戶參與度。在過去的一年,我們以適當?shù)幕A(chǔ)設(shè)施成本將一個主要產(chǎn)品的用戶參與度提升了16%。很快,我們將推出比我們的CPU模型大100倍的最大模型。
7
結(jié)論
將基于CPU模型服務(wù)轉(zhuǎn)換成基于GPU服務(wù)的過程很復(fù)雜,但這是我們在Pinterest使用最先進推薦模型的一個必要步驟。我們能夠以適當?shù)某杀咎峁┐?00倍的推薦模型,這為我們的機器學習工程師給Pinner解鎖更相關(guān)和響應(yīng)更迅速的推薦內(nèi)容提供了基礎(chǔ)。
(本文經(jīng)授權(quán)后編譯發(fā)布,原文:
https://medium.com/pinterest-engineering/gpu-accelerated-ml-inference-at-pinterest-ad1b6a03a16d)
其他人都在看
OneFlow v0.8.0正式發(fā)布
18張圖,直觀理解神經(jīng)網(wǎng)絡(luò)、流形和拓撲
Geoffrey Hinton:深度學習的下一個大事件
分布式深度學習編程新范式:Global Tensor
LLVM之父:為什么我們要重建AI基礎(chǔ)設(shè)施軟件
OneFlow源碼解析:算子指令在虛擬機中的執(zhí)行
大模型訓(xùn)練難?效率超群、易用的“李白”模型庫來了
歡迎體驗OneFlow v0.8.0:GitHub - Oneflow-Inc/oneflow: OneFlow is a deep learning framework designed to be user-friendly, scalable and efficient.OneFlow is a deep learning framework designed to be user-friendly, scalable and efficient. - GitHub - Oneflow-Inc/oneflow: OneFlow is a deep learning framework designed to be user-friendly, scalable and efficient.https://github.com/Oneflow-Inc/oneflow/
關(guān)鍵詞: