大模型有什么用,從技術(shù)上看
目前為止,大模型主要是以NLP為主,因為NLP拋棄了RNN序列依賴的問題,采用了Attention is All you need的Transformer結(jié)構(gòu),使得NLP能夠演變出更多大模型。圖像領(lǐng)域也不甘示弱,CNN大模型也開始陸續(xù)涌現(xiàn)。
模型碎片化,大模型提供預(yù)訓(xùn)練方案。目前AI面對行業(yè)、業(yè)務(wù)場景很多,人工智能需求正呈現(xiàn)出碎片化、多樣化的特點。從開發(fā)、調(diào)參、優(yōu)化、迭代到應(yīng)用,AI模型研發(fā)成本極高,且難以滿足市場定制化需求,所以網(wǎng)上有的人會說現(xiàn)階段的AI模型研發(fā)處于手工作坊式?;旧弦粋€公司想要用AI賦能自身的業(yè)務(wù),多多少少也得招聘懂AI的研發(fā)人員。為了解決手工作坊式走向工廠模式,大模型提供了一種可行方案,也就是“預(yù)訓(xùn)練大模型+下游任務(wù)微調(diào)”的方式。大規(guī)模預(yù)訓(xùn)練可以有效地從大量標(biāo)記和未標(biāo)記的數(shù)據(jù)中捕獲知識,通過將知識存儲到大量的參數(shù)中并對特定任務(wù)進行微調(diào),極大地擴展了模型的泛化能力。例如,在NLP領(lǐng)域,預(yù)訓(xùn)練大模型共享了預(yù)訓(xùn)任務(wù)和部分下游任務(wù)的參數(shù),在一定程度上解決了通用性的難題,可以被應(yīng)用于翻譯,問答,文本生成等自然語言任務(wù)。PS:手工作坊式 ==> 工廠模式,一個大模型替代之前幾十個專門小模型。
大模型具備自監(jiān)督學(xué)習(xí)功能,降低訓(xùn)練研發(fā)成本。大模型的自監(jiān)督學(xué)習(xí)方法,可以減少數(shù)據(jù)標(biāo)注,在一定程度上解決了人工標(biāo)注成本高、周期長、準(zhǔn)確度不高的問題。
大模型有望進一步突破現(xiàn)有模型結(jié)構(gòu)的精度局限。從深度學(xué)習(xí)發(fā)展前10年的歷程來看,模型精度提升,主要依賴網(wǎng)絡(luò)在結(jié)構(gòu)上的變革。例如,從AlexNet到ResNet50,再到NAS搜索出來的EfficientNet,ImageNet Top-1 精度從58提升到了84。但是,隨著神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)設(shè)計技術(shù),逐漸成熟并趨于收斂,想要通過優(yōu)化神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)從而打破精度局限非常困難。近年來,隨著數(shù)據(jù)規(guī)模和模型規(guī)模的不斷增大,模型精度也得到了進一步提升,研究實驗表明,模型和數(shù)據(jù)規(guī)模的增大確實能突破現(xiàn)有精度的一個局限。
二、什么是大模型
TensorFlow在推薦系統(tǒng)中的分布式訓(xùn)練優(yōu)化實踐隨著美團業(yè)務(wù)的發(fā)展,推薦系統(tǒng)模型的規(guī)模和復(fù)雜度也在快速增長,具體表現(xiàn)如下:
訓(xùn)練數(shù)據(jù):訓(xùn)練樣本從到百億增長到千億,增長了近10倍。
稀疏參數(shù):個數(shù)從幾百到幾千,也增長了近10倍;總參數(shù)量(也就是tf.Variable)從幾億增長到百億,增長了10~20倍。
模型復(fù)雜度:越來越復(fù)雜,模型單步計算時間增長10倍以上。對于大流量業(yè)務(wù),一次訓(xùn)練實驗,從幾個小時增長到了幾天,而此場景一次實驗保持在1天之內(nèi)是基本的需求。
深度學(xué)習(xí)分布式訓(xùn)練的現(xiàn)狀及未來大模型主要分為兩類:
搜索、推薦、廣告類任務(wù),它的特點是海量樣本及大規(guī)模稀疏參數(shù)(sparse embeddings),適合使用 CPU/GPU 參數(shù)服務(wù)器模式(PS);參數(shù)服務(wù)器模式從第一代 Alex Smola 在 2010 年提出的 LDA(文本挖掘領(lǐng)域的隱狄利克雷分配模型),到第二代 Jeff Dean 提出的 DistBelief,接著到第三代李沐提出的相對成熟的現(xiàn)代 Parameter Server 架構(gòu),再到后來的百花齊放:Uber 的 Horvod,阿里的 XDL、PAI,Meta 的 DLRM,字節(jié)的 BytePs、美團基于 Tensorlow 做的各種適配等等。參數(shù)服務(wù)器的功能日趨完善,性能也越來越強,有純 CPU、純 GPU,也有異構(gòu)模式。
CV、NLP 任務(wù),它的特點是常規(guī)樣本數(shù)據(jù)及大規(guī)模稠密參數(shù),它適合用純 GPU 集合通信模式(Collective)?;诩?GPU 的集合通信模式的分布式訓(xùn)練框架,伴隨著 Nvidia 的技術(shù)迭代,特別是 GPU 通信技術(shù)(GPU Direct RDMA)的進步,性能也變得愈來愈強。
廣告推薦中大規(guī)模分布式模型 為啥一兩百類的特征,我們卻總是聽說大規(guī)模特征?舉個例子,用戶 userid 這一維特征,比如系統(tǒng)中用戶有1億個,那么每個 id 實際上也可以當(dāng)做一個獨立的特征對待。這樣一算,特征規(guī)模就上去了。這里就要重新理解 embedding 的概念了。對于模型而言,id 查了embedding表后得到向量,輸入進來進行計算,是對數(shù)據(jù)進行抽特征。如果類比到圖像分類,抽取 rgb 特征來分類 (一個值變成 3個255)
參數(shù)量卷到一百萬億!華人團隊開源史上最大的推薦訓(xùn)練系統(tǒng)Persia 一般來說,推薦系統(tǒng)模型首先需要將不同的ID特征(如用戶ID和session ID)映射到一個固定長度的低維向量,而系統(tǒng)中的用戶ID、交叉特征數(shù)量都特別多,就需要更大規(guī)模的模型來捕獲特征和映射。但更大規(guī)模的embedding layer也需要更大的內(nèi)存來載入,不得不說大模型太費錢了!
有了embedding后,剩下的工作就簡單了,設(shè)計后續(xù)layer來適配不同的任務(wù)。通常只占據(jù)整個模型的0.1%,無需大內(nèi)存,主要是一些計算密集型的工作。
在實現(xiàn)上
推理服務(wù)在運行時 也會訪問ps (distributed inference),根據(jù) ID feature 查詢對應(yīng)的 embedding 向量。當(dāng)然,有的框架直接將 ps 組件的功能內(nèi)嵌到各個worker 上了。
針對 大模型 包含 embedding layer的場景,input 層和 embedding 層之間不是全連接的,而是一個 embedding_lookup 的Op
常規(guī)的dense 模型,input是一個一維向量。針對多個id feature,為了 確保與模型的input 層對齊,input 實際變成了一個 map<string,tensor>,key 為id feature 名字,value 為id feature 值對應(yīng)的 tensor。
內(nèi)存墻。在計算過程中,神經(jīng)網(wǎng)絡(luò)模型每一層的卷積或者全連接計算,都會把權(quán)重W_m長期保存下來,用作網(wǎng)絡(luò)的權(quán)重參數(shù)更新(靜態(tài)內(nèi)存)。另外針對諸如ADAM的優(yōu)化器,會存儲優(yōu)化器的動量等信息,用于優(yōu)化器計算(動態(tài)內(nèi)存)。一塊有16G顯存的AI芯片,最大能塞滿20+億參數(shù)的模型,但是這時候已經(jīng)沒有額外空間,留給動態(tài)內(nèi)存進行分配啦。靜態(tài)內(nèi)存和動態(tài)內(nèi)存都可能造成內(nèi)存墻的問題。
通訊墻。大模型通過模型并行、流水線并行切分到AI集群后,通訊便成了主要的性能瓶頸。隨著機器規(guī)模的擴大,基于同步的All Reduce通訊聚合方式,會因為大量的AI芯片和服務(wù)器之間頻繁進行同步,出現(xiàn)水桶效應(yīng),也就是最慢的一路通訊,將會決定整個AI集群的通訊的高度。如果采用目前比較流行的Ring-AllReduce的通信聚合方式,當(dāng)通訊的環(huán)越大,通訊的延長將會不斷地被擴大。另外網(wǎng)絡(luò)協(xié)議的多次握手的方式,諸如此類的開銷會導(dǎo)致訓(xùn)練無法有效利用帶寬。
性能墻。性能墻呢主要是指計算資源利用率的問題。隨著大模型的提出,對算力需求更加迫切,理論上在4K的集群上每塊卡快1分鐘,總體就快了68個小時。大模型會增加對算力的需求,但是隨著大模型引入各項分布式并行技術(shù)的同時,會降低計算資源的利用率。
算子層(Operator Level):小算子過多,可以通過算子融合進行優(yōu)化;子實現(xiàn)不夠高效,類似于卷積CONV算子針對2x2和3x3 Kernel大小的使用Winograd算法代替;內(nèi)存局部性差,對算子和內(nèi)存的開銷進行分析,可以對計算時算子輸出有相同的shape進行復(fù)用。
圖層(Graph Level):如何搜索和切分處計算效率更高的子圖,分配到不同的機器上進行計算;數(shù)據(jù)在通訊和內(nèi)存之間如何增加overlay重疊部分,提高單卡整體的計算率。
任務(wù)層(Task Level):在任務(wù)層級,性能的瓶頸從計算轉(zhuǎn)移到了通信,如何降低通信量,縮減通信域規(guī)模,盡可能把通信時延隱藏在計算中,是大規(guī)模訓(xùn)練的核心關(guān)注點。
調(diào)優(yōu)墻。所以在數(shù)千節(jié)點的集群上,需要考慮到提升算法工程師分布式調(diào)試調(diào)優(yōu)的效率,另外還要考慮降低工程師對大模型進行并行切分的難度。除了對人的考慮,還要對硬件集群的管理,需要保證計算的正確性、性能、可用性。要是有一臺機器壞了,如何快速恢復(fù)訓(xùn)練中的參數(shù)。
淺談工業(yè)界分布式訓(xùn)練(一) 除了上述的數(shù)據(jù)量級大,不同場景下分布式訓(xùn)練的痛點 對CV和NLP場景
CV和NLP場景模型復(fù)雜,單機性能要求高,比如卷積的計算時間在CPU上和 GPU上相差十倍到幾十倍。==> 業(yè)界主要使用高性能的GPU進行計算,并采用All-reduce的通信拓?fù)溥M行參數(shù)的同步更新。
模型大(DenseNet部分),比如NLP領(lǐng)域,GPT-3這樣的模型高達1750億參數(shù),顯存占用高達2.8 TB,單機內(nèi)存無法容納。而Bert-Large雖然只有3.4億參數(shù)規(guī)模,但由于各種內(nèi)存占用,在16G V100上,訓(xùn)練也僅能使用batch Size=8。==> 當(dāng)面對GPT-3這種DenseNet部分大的模型,Allreduce 單卡內(nèi)存無法容納,我們需要采用模型并行(model parallelism)的方式將計算圖劃分到不同的設(shè)備上構(gòu)建有向無環(huán)圖(DAG)進行分布式訓(xùn)練,其中Gpipe, Megatron, Oneflow和Whale都提出模型并行的相關(guān)解決方案。相比于數(shù)據(jù)并行每個worker只有一部分?jǐn)?shù)據(jù),模型并行下每個node使用所有數(shù)據(jù).
Intra-layer parallelism(Tensor Parallelism) 。主要是將一層Layer中的矩陣計算分別拆分到不同的機器上進行運算,比如簡單的Y_1=W_1 X_1這一次矩陣乘法中,我們將模型參數(shù)W_1或者輸入數(shù)據(jù)X_1,按某個維度分別拆分到不同設(shè)備上計算,比如1D Megatron。
Inter-layer parallelism(Pipeline Parallelism)。而Inter-Layer Parallism會將模型的layers拆分到不同的機器上,則一次forward就需要跨過不同的機器串行地進行運算,而流行并行通過將batch size切分為更小的mirco batch,減少數(shù)據(jù)依賴,從而將整個計算過程異步起來,最大化資源利用率。舉例來說,在一個簡單的三層MLP中(的Y_i = W_i X_i, i=1,2,3)會存在三次矩陣乘法 W_i X_i,流水線并行會把W_i X_i分別分配到三臺機器上進行運算。
AI for Science的出現(xiàn),讓高性能計算與AI融合成為剛需:
數(shù)據(jù)并行。假如整個模型設(shè)兩個節(jié)點,一個模型節(jié)點0、另一個模型做的節(jié)點1,整個模型都做了數(shù)據(jù)并行,數(shù)據(jù)各一半要拿去訓(xùn)練學(xué)習(xí),但是要注意訓(xùn)練完了以后不是最終的結(jié)果,因為只輸入了一半的數(shù)據(jù)。因此這中間要AII-Reduce
模型并行。將整個模型切成一半,一半模型節(jié)點0,一半模型節(jié)點1,數(shù)據(jù)是整個拿去訓(xùn)練。訓(xùn)練完了以后出來的結(jié)果也不是最終結(jié)果,因為只訓(xùn)練了一半的模型,出來還有AII-Gather,也是做通信的。 究竟用哪種并行方法呢?實際上這跟計算機結(jié)構(gòu)有關(guān)。如果每臺計算機之間通信都非???,那么用數(shù)據(jù)并行就可以;如果你的通信比較慢,就要考慮模型并行。因此,這些模型如何跟數(shù)據(jù)、機器實際情況匹配?這就涉及到軟硬件協(xié)
基于tensorflow做擴展支持大模型的做法
在模型比較小的時候,比如100G以下,模型還有可能單機存儲。這個時候的方案是tensorflow分布式訓(xùn)練+savedmodel,分布式訓(xùn)練可以用多個ps(tensorflow自帶的),資源管理可以用yarn。用分布式是由于樣本數(shù)大,同時多ps也能異步加速訓(xùn)練。saved_model一般由chief worker保存,但存下來以后,會抹掉ps的痕跡,保存的模型跟單機訓(xùn)練的一模一樣。
當(dāng)模型比較大的時候,這個時候要求的樣本數(shù)也更大,訓(xùn)練完dump出來的模型會很大,一個單機放不下,尤其是embedding table。這個時候怎么辦?一個自然的思路就是,把訓(xùn)練時候的ps拷貝同步一份給serving ps,線上由該ps做serving。注意后面談到的serving ps,都是自己開發(fā)或者根據(jù)某個開源軟件修改而成(比如ps-lite)。如果是天級模型,可以用tensorflow原生的worker和train ps,但依然用saved model方式把模型存放到hdfs,然后從hdfs讀入另外一個serving ps。如果是實時訓(xùn)練,則serving ps還得跟訓(xùn)練ps進行實時的網(wǎng)絡(luò)連接,在內(nèi)存就解決掉weight同步的處理,這個時候就不能用tensorflow原生的ps了,因為原生的ps沒有實現(xiàn)同步接口。ps變了,worker也得跟著變,worker大多數(shù)都是基于tensorflow的c++底層接口開發(fā),底層用到tf的session接口。
針對上述的問題,各個大廠的訓(xùn)練框架進行很多相關(guān)優(yōu)化,目前總結(jié)下來,核心的兩點,一個在于分布式通信拓?fù)涞脑O(shè)計,還有一個在于Embedding Lookup的性能優(yōu)化。
只要單卡放的下,走數(shù)據(jù)并行,ps 或allreduce 都行,allreduce 通信成本小一些。若規(guī)模變大
稀疏模型,稀疏參數(shù)特殊處理
使用ps,加上一些稀疏tensor 的優(yōu)化,且將 embedding 存儲和更新 負(fù)擔(dān)轉(zhuǎn)嫁到 ps
稠密參數(shù)allreduce,想辦法解決 稀疏tensor 的存儲、通信成本。比如 HybridBackend架構(gòu)中參數(shù)放在 worker 上:稠密參數(shù) replication 存放,每個 worker 都有副本,梯度更新時進行 allreduce;稀疏參數(shù) partition 存放,每個 worker 只有部分分片,梯度更新時進行 alltoall。allreduce 和 alltoall 都會使用 nccl 進行同步通信,效率較高。hb 進行 alltoall 時,通信的是稀疏梯度,而不是完整的參數(shù),通信量上和 ps 是一致的,但是通信效率會更高。
稠密模型,單卡無論如何也放不下了,就只能采取模型并行 及附屬的一些優(yōu)化方案
知乎高贊回答——為什么說大模型訓(xùn)練很難?
算子拆分 單個矩陣乘法可以分到兩個device上計算 Y = WX = [W1,W2]X = [W1X,W2X]。我們在工程上要做的就是:將切分到兩個device上,將復(fù)制到兩個device上,然后兩個device分別做矩陣乘法即可。有的時候,切分會帶來額外的通信,比如矩陣乘法切到了reduction維度上,為了保持語義正確,就必須再緊跟一個AllReduce通信。這里復(fù)雜之處在于,你不能無腦地將所有算子全部做拆分,因為拆分可能會引入一些額外通信,降低總體吞吐。所以你得做些分析,決定哪些算子被拆分,現(xiàn)在大部分框架都不支持這種全自動化策略,要么是半自動或純手工,要么是針對某種模型把它的拆分方案寫死。所以只能造輪子解決這個事
流水并行 不切算子,而是將不同的Layer切分到不同的Device上,就可以形成Pipeline方案,GPipe就是這樣一種方案,提出了將一個batch拆分成若干個micro-batch,依次推入到Pipeline系統(tǒng)中,即可消除Bubble time。和算子拆分類似,全自動化方案工作量不小,比如Pipeline怎么切,才能讓通信量小,計算還能均勻,這需要一定的算法和工程量
搞定大模型訓(xùn)練
我們的模型可能會很大,或者數(shù)據(jù)量會很大。僅僅用一塊GPU卡可能連模型都放不下,或者batch size只能設(shè)置的很小,但是我們知道有些情況下大的batch size往往會提供更好的效果。
假設(shè)我們只有一個GPU,我們的模型一次只能輸入batch size為8的數(shù)據(jù),那么我們怎么樣實現(xiàn)batch size為32的更新呢?那就需要時間換空間了,即我們訓(xùn)練32/8=4步才去更新模型,也就是所謂的梯度累積。
Gradient-Checkpointing, 那么如果你的GPU連batch size為1都跑不了怎么辦?我們在訓(xùn)練深度學(xué)習(xí)模型的時候,需要先做前向傳播,然后將中間得到的激活值存儲在內(nèi)存中,然后反向傳播的時候再根據(jù)loss和激活值計算梯度。也就是說內(nèi)存消耗其實跟模型的層數(shù)線性相關(guān)。那么怎么減少這個內(nèi)存消耗呢?最簡單的想法就是我不存這些中間信息,計算梯度的時候,到了某一層我重新計算它的激活值,這個方法雖然可以讓內(nèi)存消耗是個常量,但是運行時間會是O(n^2),這是沒法接受的。那么就有一個折中的辦法,我不存全部的中間數(shù)據(jù),只存部分,那么我們在計算梯度的時候不需要從頭計算了,只需要從最近的checkpoint點計算就好。
我們訓(xùn)練模型一般都是用單精度(FP32)的參數(shù),但是其實我們還使用半精度(FP16)。半精度可以降低內(nèi)存消耗,從而訓(xùn)練更大的模型或者使用更大的batch size;同時運算時間受內(nèi)存和算術(shù)帶寬的限制,在有些gpu(Tensor cores)上可以為半精度提供更大的算術(shù)帶寬,從而提高訓(xùn)練效率,減少inference用時。
轉(zhuǎn)自知乎《大模型有什么用,從技術(shù)上看》
*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點,如有侵權(quán)請聯(lián)系工作人員刪除。