「萬字干貨」深度對話Quentin Anthony:GPU不足,如何優(yōu)雅地訓(xùn)練大模型?
在初創(chuàng)公司甚至VC都在瘋狂囤積GPU的狂熱年代,干一件事比囤GPU更有價值——搞明白如何高效地使用它們。
(資料圖片)
直到Eleuther AI的出現(xiàn)。
四月,Eleuther AI團隊發(fā)布博文《Transformers Math 101》,介紹如何運用簡單算式估計大模型的算力成本,大大消除了該領(lǐng)域的信息不對稱,在圈內(nèi)圈外廣泛傳播,成為該領(lǐng)域最具權(quán)威性的博文之一。公式如下:
C = τT?≈?6PD
其中:C表示Transformer需要的計算量,單位是FLOP;P表示Transformer模型包含的參數(shù)量;D表示訓(xùn)練數(shù)據(jù)規(guī)模,以Token數(shù)量為單位;τ表示吞吐量,單位為FLOP 表示訓(xùn)練時間;
該公式的原理如下:
C=Cforward+Cbackward:表示訓(xùn)練過程中的前后向傳播;?Cforward?≈?2PD:前向傳播計算成本約等于兩倍的參數(shù)量乘以數(shù)據(jù)規(guī)模;Cbackrward?≈?4PD:反向傳播計算成本約等于四倍的參數(shù)量乘以數(shù)據(jù)規(guī)模;
C是一個量化計算成本的單位,通常用FLOP表示,亦可用一些新的單位來表示,如FLOP/s-s:表示每秒浮點運算數(shù)/秒;PetaFLOP/s-days:表示實際情況下每秒浮點運算數(shù)/天。
8月17日,Eleuther AI首席工程師、《Transformers Math 101》的主要作者Quentin Anthony博士,同風(fēng)險投資公司Decibel Partners 的合伙人兼首席技術(shù)官Alessio、Latent Space主理人Swyx進行了一場深度交流,
雙方圍繞Transformer模型算力評估、混合精度訓(xùn)練、3D并行、INT8量化、分布式挑戰(zhàn)等NLP前沿話題展開了深度討論,文章干貨很足,相信對想了解Transformer成本、大模型優(yōu)化技術(shù)等方面的朋友一定大有裨益。
以下為全文內(nèi)容,大家enjoy~???
(由ChatGPT翻譯,經(jīng)略微修改)
●?發(fā)文動機
●?GPU并非越多越好
●?估計GPT-3訓(xùn)練的計算量
●?AMD GPU:可用,但效率不高
●?模型精度(FP32、FP16、BF16等)對內(nèi)存的影響
●?深度學(xué)習(xí)模型量化的好處
●?如何計算優(yōu)化器的內(nèi)存使用
●?訓(xùn)練內(nèi)存的各個組成部分
● 并行訓(xùn)練
●?高級3D并行技術(shù)
●?異構(gòu)集群分布的挑戰(zhàn)
01 發(fā)文動機
Quentin:
聊到撰寫《Transformer Math 101》一文的動機,就不得不提到我經(jīng)常會在深度學(xué)習(xí)訓(xùn)練領(lǐng)域看到一些推特帖子,比如Hugging Face的Stas Bekman,他會發(fā)布一些推文,說什么他們剛剛發(fā)現(xiàn)了一個神奇數(shù)字,一切都變得快了20%等等。
他們非常興奮,但實際上并不真正了解發(fā)生了什么。對我們來說,我們經(jīng)常發(fā)現(xiàn)很多人可能了解AI訓(xùn)練或推理的理論或基本原理,但沒有人真正了解像在自己的機器上如何正確運行分布在兩個GPU上的推理之類的細節(jié)。
而我們,在Eleuther內(nèi)部積累了很多筆記,并在工程師之間共享,我們認為,這可能會幫助很多其他人。
這可能不適合寫論文,但對于博客文章或技術(shù)報告來說,這可能確實能夠從已有的硬件中擠出更多性能。
因此,我們在Eleuther有很多經(jīng)驗,我們試圖以一種大公司們不會采取的方式將其與人們分享。
Swyx:
是的,這是很少有人會真正干的事情。首先,寫下來需要額外的工作。其次,這是一種商業(yè)機密,因此很少有人這樣做。
因此,通常了解這些內(nèi)容的唯一方法就是實際在大型模型實驗室中工作。而你們,做了很多特別的事情。我唯一能想到的其他另一個情況是Facebook的OPT。還有什么類似的項目,可以共享交流經(jīng)驗,但不是正式的研究知識呢?
Quentin:
我會說是Bloom。比如Hugging Face的Bloom項目在大科學(xué)領(lǐng)域等方面,這種開放程度非常高。
我覺得,OPT和Bloom的級別相同,甚至更詳細。
除此之外,我想微軟有一個有關(guān)他們的Turing NLG的文檔。他們的文章讀起來非常輕松,也確實談到了工作中的一些挑戰(zhàn)。除了OPT, Bloom和我們,我想不出其他的了。這是一個新事物。
Swyx:
重要的是,你們正追求足夠好的經(jīng)驗法則。我認為,很多人試圖追求精確,但過于精確實際上并不有幫助。
Quentin:
是的,你會在博客文章中看到一些類似表述。你知道,我們不會進一步詳細討論每個小的內(nèi)存部分,錙銖必較的話可能需要額外的一個月。但是,得到足夠好的結(jié)果對人們?nèi)匀挥袔椭?/p>02 最少GPU數(shù)量,是最佳方案
Alessio:
聊回您在《Transformer Math 101》一文中給出的估計方程,這里的核心方程式不是計算成本,而是轉(zhuǎn)化Transformer模型所需的計算,大約等于τ乘以T,其中τ是吞吐量,單位為FLOPT表示訓(xùn)練時間,然后T是花費的時間。
我認為人們可以很容易地想象這一點?;旧鲜悄阌卸嗌賯€GPU,你讓它們運行多長時間。
之前在Chinchilla論文和OpenAI的規(guī)模定律中,有類似的內(nèi)容,你在博文中也提到了這一點。
現(xiàn)在,人們在構(gòu)建模型時應(yīng)該如何考慮這個問題?當(dāng)他們開始考慮訓(xùn)練自己的基于Transformer 的模型時,他們應(yīng)該從哪里找到這個方程?
Quentin:
人們通常從數(shù)據(jù)集開始,你有一些數(shù)據(jù)集,然后你想在基于此訓(xùn)練一個模型。
讓我們開始逐步思考,一開始,從6PD的角度來看,每個參數(shù)大約有6個令牌與之對應(yīng)。因此,這決定了我的模型大小,以此為Chinchilla Optimal。
從那時起,我們發(fā)現(xiàn)為了獲得良好的質(zhì)量模型,需要更多的令牌,可能會超過20個。
但從系統(tǒng)的角度來看,你們應(yīng)該考慮的下一個問題是,這個模型需要多長時間來訓(xùn)練?我應(yīng)該有什么樣的預(yù)算?
假設(shè)我需要一些云實例,持續(xù)一段時間,每個實例都有一個附加的價格。這就是吞吐量的用武之地。
現(xiàn)在,你有了這個模型,這個參數(shù)數(shù)量,你應(yīng)該將它映射到一個Transformer架構(gòu),并在該模型類型的軟件棧上基準測試你的吞吐量,接著你可以在單個GPU上實現(xiàn)每秒的FLOPS。
然后根據(jù)并行性方案(我相信我們會詳細討論的,例如數(shù)據(jù)并行性或張量并行性等),這個FLOPS數(shù)將如何擴展到不同數(shù)量的GPU?
從這里,你將得到一個時間。進而,得到了時間,就能算出成本。
簡而言之,這就是答案。
Alessio:
我注意到另一件事,你提到一些這些定律,只在1個小時內(nèi)使用1000 GPU的成本與1個GPU運行1000小時的成本相同才成立。
考慮目前我們?nèi)狈Υ罅縂PU的實際情況,在這方面,對于人們?nèi)绾蝺?yōu)先考慮這一點,你有什么想法嗎?
我會說,首先應(yīng)該找出剛好能容納你的模型的最小GPU數(shù)量。
如果您在訓(xùn)練一個相當(dāng)大的模型,內(nèi)存瓶頸是你最大的問題。如果只在訓(xùn)練一個小模型,那沒人會在意。
大多數(shù)人關(guān)心的模型,都需要分配到多個GPU上。因此,找到適合你的模型的一個實例的最小gpu數(shù)量,然后計算需要多長時間。如果是時間合理,那么你完成了。如果時間太長,那么你就需要開始考慮使用多個模型實例。
我總是覺得,人們應(yīng)該選擇最小數(shù)量的GPU。你擁有的GPU數(shù)量越多,出現(xiàn)問題的可能性就越大。
所以我會說,只要找出什么時間對你來說是合理的,然后將gpu的數(shù)量與之匹配,而不需更多。
人們往往會變得貪婪,他們會說,如果我有兩倍的GPU,我可以在半個時間內(nèi)完成這項工作。但事實上,最終可能花了三倍時間,因為每天都會出現(xiàn)各種問題。那時,可能需要痛苦地在午夜時分起床,加班加點搶修你的模型。
Swyx:
你們會不會有一個類似的開源框架,來幫助gpu線性擴展?還是說,這么想過于簡單化了?
Quentin:
Mosaic和我們都有一種可以理論上良好擴展的軟件堆棧配置,一會我會詳細討論。
Mosaic完全基于優(yōu)化器分片。它基于ZeRO。因此,你完全將模型優(yōu)化器、參數(shù)和梯度分布在所有不同的GPU上。你的聚合內(nèi)存就是參數(shù)數(shù)目除以GPU數(shù)目。優(yōu)化器和其他內(nèi)容也是一樣。
而我們在Eleuther使用了Megatron DeepSpeed的庫,會更加復(fù)雜。因此,效率可能會更高,但也更容易出現(xiàn)故障。
在這兩種情況下,回到實際情況,通過增加更多的GPU應(yīng)該能夠獲得線性加速。但問題是會出現(xiàn)硬件故障。
如果有太多的GPU,你可能會有問題,例如損失會溢出,或者一個GPU掛掉,你就可能碰到軟件問題、同步問題等。
這就是我為什么說,實際上你應(yīng)該選取你擁有的最小GPU數(shù)量,因為這些情況更容易調(diào)試。
Alessio:
另一件事情是,電腦就像在前向和后向傳遞,前向是2PD,后向是4PD。為什么兩者之間的比率是如此?你能解釋一下嗎?為什么是兩倍的數(shù)量?
Quentin:
簡單來說,對于前向傳播,您只是在移動,您正在通過該層向前傳播輸入。
而在后向傳播中,你要做的事情比這更復(fù)雜一些。你正在做反向傳播。我認為我無法足夠直觀地解釋它,需要數(shù)字上進一步深入探討。
Swyx:
實際上,反向傳播的速度很低。老實說,這是我喜歡深度學(xué)習(xí)數(shù)學(xué)的最基本的原因之一,與大學(xué)微積分中遇到的其他數(shù)值方法相比,深度學(xué)習(xí)的數(shù)學(xué)令人驚訝地高效。
Alessio:
我認為另一件事是,事情聽起來很簡單,你知道,當(dāng)人們在Twitter上說,哦,20是最優(yōu)的比率,然后就是,好吧,為什么是那個數(shù)字呢?
答案通常要困難得多,就像我們現(xiàn)在看到的。所以我認為這是一個很好的提醒,數(shù)字聽起來簡單,就像所有最好和最受歡迎的數(shù)學(xué)方程一樣,非常優(yōu)雅。不過,顯然,背后的證明并不那么容易。
02 估計GPT-3訓(xùn)練的計算量
Swyx:
我想稍微測試一下這個方程。我們可以從GPT-3的角度或GPT-NeoX的角度來做。你有實際浮點運算和理論浮點運算之間的區(qū)別。
很多時候,當(dāng)人們報告訓(xùn)練一個模型所需的浮點運算量時,就像我們剛剛在Lama 2中看到的那樣,估算的數(shù)值就是浮點運算量。
比如,GPT-3需要3.14 x 10的23次浮點運算。這是理論浮點運算。我想弄清楚一個數(shù)值是否經(jīng)得起推敲。
我想知道如何做到這一點,因為我應(yīng)該能夠?qū)⑦@個方程代入其中,對吧?我知道GPT-3是基于3000億tokens進行訓(xùn)練的。
我知道模型的參數(shù)大小是175。是不是只要計算一下6 x 175 x 300就行了?
Quentin:
理論浮點運算通常是根據(jù)給定的硬件配置得出的,這是你預(yù)計硬件可以實現(xiàn)的。
但問題在于,實際上,我們通常會有一些閑置時間,例如等待從GPU到CPU的數(shù)據(jù)傳輸,或者等待跨不同GPU之間的同步。所以訓(xùn)練時候你會花掉很多空閑時間。
Swyx:
聞起來怎么樣。(注:效果如何?)
Quentin:
我不確定我是否有一個自己的"聞起來怎么樣"的標準,
坦白說,也許我會查看像在A100上期望的一些浮點運算量。
事實上,在某種程度上,對于給定的GPU類型,每個人都知道可以期望多少浮點運算量。
例如,對于A100來說,這個數(shù)值大約在100到180之間。對于較舊的GPU類型V100,這個數(shù)值可能在30到40之間。
人們通常會根據(jù)運行深度學(xué)習(xí)的內(nèi)核來確定應(yīng)該期望的浮點運算量。然后,將這個與人們報告的理論浮點運算量進行比較,看是否與你的預(yù)期相符。
03 A100 基線標準:115+ TeraFLOPS/sec
Alessio:
在文章中,你提到對于A100來說,如果你的浮點運算量低于115 TeraFLOPS/秒,那么你的模型或硬件有問題。
你是怎么得出這個115的?是不是根據(jù)實際觀察和經(jīng)驗,你在過去的幾個月里見到的平均水平?你是怎么得出這些數(shù)字的?
Quentin:
對于這個數(shù)字,基本上,我們比較了很多不同的框架。就像我之前提到的,Mosaic有他們自己的框架,我們也有自己的框架。它們都有自己的浮點運算計數(shù)器。
我們看到,在許多不同的硬件配置上,如果你正確調(diào)整設(shè)置,你應(yīng)該在幾乎所有情況下都能得到超過115的浮點運算量。
所以,如果某個數(shù)值低于115,那么你的軟件肯定有問題。但這實際上就是比較不同的軟件堆棧和硬件系統(tǒng)。
04 AMD GPU:可用,但效率不高
Alessio:
不同的GPU有什么不同嗎?
上周,我們邀請了George Hotz,他談到了AMD顯卡,以及理論上他們的浮點運算要比一些Nvidia顯卡好得多,但實際上,CUDA運行時會彌補這一差距。
人們應(yīng)該如何考慮這一點?你知道,像A100的浮點運算量達到115 TeraFLOPS。我是否應(yīng)該堅持使用它?
Quentin:
這涉及到開發(fā)者的時間,哪個更昂貴,歸根結(jié)底,AMD和Rockham的軟件堆棧還有很長的路要走。
我會說,大多數(shù)東西都可以在那里運行,但效率不高,而且你可能會遇到以前沒有遇到過的奇怪錯誤。
選擇使用Nvidia和PyTorch的軟件堆棧的一個重要優(yōu)點是,有成千上萬個GitHub問題與你面臨的相同問題,而且,以開源方式快速解決這些問題,這可能是目前選擇Nvidia軟件堆棧的最大優(yōu)勢。
AMD的硬件與Nvidia相當(dāng),但軟件不太一樣,而且他們在開源領(lǐng)域的勢頭還沒有完全發(fā)展起來。
例如,像Flash Attention這樣的功能在更多Nvidia GPU類型上的應(yīng)用要比在AMD上的應(yīng)用要多。等待這些最新的功能在AMD上實現(xiàn),對很多人來說是一個障礙,但它正在發(fā)展壯大。
我現(xiàn)在正在AMD上運行很多實驗,因為它已經(jīng)進入了政府實驗室的超級計算機。所以很多實驗現(xiàn)在都在那里進行,而且我預(yù)計它會在幾年內(nèi)趕上來。
05 模型精度(FP32、FP16、BF16等)對內(nèi)存的影響
(注:一般情況下,計算機在進行浮點運算時所采用的是FP32(單精度),其中8位用于存儲整數(shù)部分,23位存儲小數(shù)部分,因此其可以存儲高精度浮點數(shù)。
因此,在顯存優(yōu)化場景下,犧牲浮點運算的精度可以降低存儲量。)
Alessio:
我們可以輪流討論一下,有很多內(nèi)容需要涵蓋,但或許我們可以從模型權(quán)重開始。
過去,我們在過去的許多討論中經(jīng)常涉及的一個主題就是精度和量化,這顯然是內(nèi)存的主要因素之一。
你在文章中提到,大多數(shù)Transformer都是混合精度,如FP16加FP32或BF16 FP32,它們可以進行轉(zhuǎn)換,而且可以進行高達INT8的量化,而不會對性能造成太大的影響。也許,我們可以解釋一下一些數(shù)學(xué)和不同精度之間的字節(jié)參數(shù)比率?
Quentin:
當(dāng)我開始入行深度學(xué)習(xí)時,一切都是FP32。每個參數(shù)需要32位,即4個字節(jié)。事情相當(dāng)簡單。你不需要進行任何損失縮放。
但問題是,一旦NVIDIA切換到了V100并引入了Tensor核心,F(xiàn)P32就不能提供太多的浮點運算。Tensor核心在FP16精度下執(zhí)行所有計算。
因此,如果你在FP32下進行操作,你實際上浪費了所有這些。所以一旦硬件遷移到V100,軟件就會切換到混合精度,如APEX和AMP等?;旌暇鹊囊粋€讓人意想不到的部分是,實際上在訓(xùn)練時你需要更多的內(nèi)存,因為你需要一個FP16版本的權(quán)重副本和一個FP32版本的權(quán)重副本。
FP16是在Tensor核心上進行實際計算的地方。因此,你可能得到的吞吐量可能是FP32的兩倍。然后在每個步驟中,使用FP16更新FP32的副本,兩者都需要存儲在內(nèi)存中。
問題在于,F(xiàn)P16非常精確,但動態(tài)范圍不太大,
因此,如果從浮點的角度來看,你有一個非常大的尾數(shù),但沒有太多的指數(shù)。所以BF16將更多的位數(shù)從尾數(shù)移到指數(shù)中。也就是說,你有更大的范圍和較低的精度。
這消除了許多不穩(wěn)定性問題和損失縮放等問題,對于任何熟悉調(diào)試的人來說,都知道它有多么不穩(wěn)定,尤其是在大規(guī)模訓(xùn)練中。而BF16則減少了很多這種問題,但只在A100上受支持。所以你看到了硬件和軟件之間的來回變化。
每次NVIDIA引入一些新的Tensor核心或BF16支持之類的功能,軟件就會適應(yīng)并開始支持它,然后訓(xùn)練適應(yīng)。然后你現(xiàn)在提到了Ind8等。
現(xiàn)在,我們看到一些模型已經(jīng)在FP16、FP32或其他模式下訓(xùn)練,然后現(xiàn)在你想將該模型盡可能地量化為像Ind8這樣的更小的表示,同時又保持最小的損失和精度。
實際上,我們發(fā)現(xiàn),由于深度學(xué)習(xí)是一個如此具有隨機性的問題,許多這些最后的精度位實際上并不重要,我認為這種情況將會持續(xù)下去。
06 深度學(xué)習(xí)模型量化的好處
Alessio:
如果你有一個量化成八位的模型,你只需要一個字節(jié)來表示每個參數(shù)。例如,在一個80GB VRAM的A100上,你可以放下700億個參數(shù)的八位模型,而你無法放下一個FP32模型,因為你需要大約280GB的內(nèi)存。這會有多大影響?
你剛剛提到剛開始時都是FP32,如果有一個帶有1TB VRAM的GPU,人們會只將內(nèi)存加載為FP32權(quán)重嗎,還是他們?nèi)匀粫M麑⑺鼈兞炕允蛊涓痈咝??是的?/p>
Quentin:
我認為,即使你有無限的VRAM,你仍然會想要一個量化模型,只是一個更大的經(jīng)過量化的模型。
因為正如我剛剛提到的,在最后,深度學(xué)習(xí)是非常隨機的,很多時候,你可能擁有世界上所有的精度,但是當(dāng)你仍然非常依賴輸入時,這些精度實際上是沒有意義的。你在很大程度上依賴于輸入的微小變化,也許更多的訓(xùn)練數(shù)據(jù)樣本會更加重要。
在深度學(xué)習(xí)中,總體上,這些微小的精度并不是很重要的,重要的是整體的畫面。那個神經(jīng)元實際上在說什么?而不是它可能在想什么微小的細節(jié)。我還想提到,即使你擁有A100,實際模型的大小要比你提到的要小得多。
這是因為KV緩存。所以KV緩存在推理過程中,只在推理過程中起作用,想象一下,如果你在寫一段話,你想要在寫下一個詞之前記住之前寫過的每一個單詞。
所以什么是自回歸語言建模?它就是填充下一個詞、下一個標記。如果我說"the dog went to the",然后我需要寫下一個詞,我可能會寫"park"之類的。在我寫下一個詞之前,我的記憶會被清除,然后我必須重新閱讀整個句子。
這就是沒有KV緩存的情況。KV緩存則是說,在推理過程中,記住我之前生成的所有內(nèi)容,以及我之前生成內(nèi)容的所有上下文。但是KV緩存的內(nèi)存開銷通常與模型的內(nèi)存開銷相當(dāng),或在某些情況下甚至更大,特別是在上下文很長的情況下。
我認為具體的計算公式大致是,哦,是類似于兩倍的層數(shù)乘以頭數(shù)乘以每個頭的維度,然后有兩個這樣的部分,一個是K,一個是V。簡要來說,大概就是這樣。
Alessio:
我知道,這是Transformer中的數(shù)學(xué)概念,不過,關(guān)于RNNs,也有一些有趣的地方,比如遠離隨著序列長度增加而增加的KV緩存,而是使用固定的序列傳遞。
我知道,人們正在研究這些方面的內(nèi)容。
Quentin:
那么,如何在不增加Transformer所需的二次注意力開銷的情況下獲得Transformer質(zhì)量?這是有趣的,我建議人們閱讀這篇論文原文。
Swyx:
我們實際上已經(jīng)和RWKV的核心成員進行了一次未發(fā)布的訪談,他們稱之為軟注意力或輕量級注意力。我忘記他們具體叫什么了,但是可以近似地表示,使其線性化而不是二次方的方法。這很棒。
Quentin:
RWKV的人員經(jīng)常出現(xiàn)在Eleuther。
他們與我們密切合作。我的貢獻是,我們所有這些關(guān)于RNNs的實驗是由不同的人完成的,這些實驗與Transformer的關(guān)系以及我們?nèi)绾螌⑵滢D(zhuǎn)化為一篇論文,以便人們不必閱讀一年前的Discord日志就能理解發(fā)生了什么。
07 如何計算優(yōu)化器的內(nèi)存使用
Swyx:
很棒,現(xiàn)在,我想我們可能要花更多時間在優(yōu)化器狀態(tài)和Atom優(yōu)化器上。當(dāng)你處理這些優(yōu)化器時,你的想法是什么?在處理這些優(yōu)化器時,人們應(yīng)該記住什么?
Quentin:
我認為,Atom優(yōu)化器在其領(lǐng)域內(nèi)是出色的。這是一個比較寬泛的問題,所以讓我想一想。你有權(quán)重的副本,然后你有你的動量和方差。
用直觀的預(yù)言來解釋一下動量:比如說,你在一個峽谷,你想要到達底部。
如果你只是進行基本的隨機梯度下降,那么每一步都會是相同大小的。而如果你使用帶有動量項的Atom,那么你的步幅應(yīng)該會逐漸變大,因為你可以看到,一般的趨勢是我們正在迅速地向下前進。但是,由于Atom中有所有這些額外的項,你需要更多的內(nèi)存來存儲它。
例如,與SGD相比,通常需要三倍的內(nèi)存。如果你在你的優(yōu)化器狀態(tài)中花費了所有這些內(nèi)存,那么,你如何將它分布到GPU上?
你會發(fā)現(xiàn),在給定的GPU上,實際上比起裸計算、原始的計算能力,你更多地受限于并行性。這歸結(jié)為在將模型分割成需要在許多GPU上分割之前,你能夠?qū)⒍嗌倌P头旁趩蝹€GPU上。
然后,你會發(fā)現(xiàn)花費的時間更多地用于它們相互通信,而不是實際取得進展。所以,我們在博文中花費了很多時間來討論如何分布你的模型?所有這些不同的分布策略是什么樣的?哪些策略更有效?考慮到很多內(nèi)存都花費在了優(yōu)化器上,你如何有效地分布這個優(yōu)化器?
很多人在談?wù)摬⑿行詴r,他們談?wù)摰氖悄P筒⑿行裕磪?shù)本身。實際上,在訓(xùn)練時,相當(dāng)大一部分的內(nèi)存實際上是花費在優(yōu)化器狀態(tài)上的。所以你想要深入探討其中的哪個部分嗎?你想要深入探討零、分片優(yōu)化器之類的嗎?
Alessio:
Quentin,你在博文中提到"Atom是神奇的",實際上,即使對于像你這樣與底層很接近的人,有多少內(nèi)容是實際上的"神奇",有一些東西對你來說只是教義?有一些事情是你實際上在考慮在日常工作中進行改進的嗎?
Quentin:
所以我是一個系統(tǒng)工程師,很多這些事情對我來說是神奇的,Atom對我來說是神奇的。
我認為,這就是一個深度學(xué)習(xí)模型的訓(xùn)練方式。這就是下一步的計算方式。然后我說,好的,如何使其變得更快?
我會說我會看看如何通過使用第二階優(yōu)化器來改進它。因為有很多關(guān)于這方面的研究,因為它們很難分布。
但是對我來說,核心的貢獻總是來自于其他人已經(jīng)進行了一些深度學(xué)習(xí)的優(yōu)化,我需要使其運行得更快。所以我實際上無法談?wù)摓槭裁碅tom產(chǎn)生了,除非像我剛剛提到的,使用動量的一些簡單直觀的東西。
對我來說,Atom所占用的內(nèi)存比SGD要多三倍,這一點很重要。所有這些內(nèi)存都需要找個地方存放,它需要有效地分布。
Alessio:
所以,當(dāng)你把所有這些加在一起時,使用普通的Adam優(yōu)化器,每個參數(shù)需要12字節(jié)。
然后,你仍然需要在內(nèi)存中保存模型參數(shù),就像你提到的那樣,需要同時保存FB32、FB16混合量化的兩份副本,因此有不同的精度級別。所以每個參數(shù)需要6字節(jié),對吧?
Quentin:
再回顧一下,大多數(shù)人認為模型會變得很大,所以需要純粹的模型并行處理,比如張量并行處理。
但實際上,如果我們使用FB16,模型每個參數(shù)只需要2字節(jié)。而優(yōu)化器本身需要每個參數(shù)4字節(jié)的模型狀態(tài)、4字節(jié)的動量、4字節(jié)的方差。所以更重要的是如何高效地分割優(yōu)化器以及如何高效地存儲它。
像"bits and bytes"中的8位Adam優(yōu)化器,每個參數(shù)的優(yōu)化器狀態(tài)只需要1字節(jié),而不是4字節(jié)之類的。這會比將純FB16模型權(quán)重量化到int8之類的方式,更有效地降低模型訓(xùn)練所需的內(nèi)存開銷。
因此,對于訓(xùn)練來說,優(yōu)化器內(nèi)存占用非常重要,在大多數(shù)情況下最為重要。
Alessio:
在我們深入討論Zero之前,讓我們先總結(jié)一下稍后會對參數(shù)、優(yōu)化器狀態(tài)和梯度進行分片處理??梢院喴勔幌逻@個問題,然后我們可以討論如何在GPU上高效地加載它們。
Quentin:
所謂的參數(shù),是參數(shù)的FP32副本。
我們在優(yōu)化器討論中將它們包括在內(nèi)。有些人不這樣做,但只是為了清楚起見,優(yōu)化器狀態(tài)每個參數(shù)需要12字節(jié),其中有四個字節(jié)是用于FP32的權(quán)重副本。
四個字節(jié)是用于動量。我已經(jīng)解釋過為什么存儲動量很重要,但這也是每個參數(shù)。你需要存儲該參數(shù)未來的前進方向以及它在過去的前進方向。
你還需要知道,我們知道它往哪走,但是在這個峽谷上會有凹陷。
所以我們需要存儲它的方差。這些凹陷的頻率是多少?我們應(yīng)該更關(guān)注動量嗎?還是這個參數(shù)在到處跳來跳去?這些都是優(yōu)化器需要存儲的重要答案,它是每個參數(shù)的。
08 訓(xùn)練內(nèi)存的各個組成部分(模型內(nèi)存、優(yōu)化器內(nèi)存、梯度內(nèi)存、激活內(nèi)存)
Alessio:
我正在查看總訓(xùn)練內(nèi)存。您實際上有模型內(nèi)存、優(yōu)化器內(nèi)存、梯度內(nèi)存和激活內(nèi)存。我認為,這是我們討論的最后一個問題。
所以也許簡要地向人們介紹一下,,比方說活動內(nèi)存再計算、檢查點等。
Quentin:
在激活檢查點之前,可能會變得復(fù)雜,你有模型參數(shù),就像我之前提到的一樣,它們曾經(jīng)是FP32?,F(xiàn)在可能是BF16,或者如果是較舊的GPU,則可能是FP16。然后有優(yōu)化器。那是許多內(nèi)存所在的地方。
通常情況下,這是權(quán)重的高精度副本,通常是FP32。所以每個參數(shù)需要4字節(jié),然后你還有一些可選項,就像我們剛剛討論過的,比如動量或方差,或者根據(jù)你的優(yōu)化器而定的其他內(nèi)容。
接著是梯度,梯度是在模型前向傳遞后得到的梯度更新。這將是你低精度權(quán)重的副本,如果你使用FP16或BF16,每個參數(shù)需要兩個字節(jié)。
所有這些都是固定的。這個開銷在訓(xùn)練期間不會消失。在反向傳播梯度后,梯度可能會被清除,但優(yōu)化器狀態(tài)和模型狀態(tài)不會消失。
內(nèi)存開銷將一直存在。動態(tài)的是激活再計算和激活內(nèi)存。因此,有些人會遇到這樣的問題,模型在訓(xùn)練時加載得很好。但當(dāng)你實際運行第一次迭代,或者運行某個未來的迭代之類的時候,你會突然發(fā)現(xiàn)內(nèi)存不足。這是因為你實時計算的這些激活。
Alessio:
再計算是在什么時候發(fā)生的?它是如何在重新計算和存儲之間做出決策的?
Quentin:
有很多不同的方法,但我會說有幾種主要的方法。
首先,是一個非常簡單的方案。你重新計算所有的東西。你計算出的每一個激活都會被使用或拋棄,直到結(jié)束。所以在這種情況下,你非常關(guān)心內(nèi)存,但對計算關(guān)心不大。也許這會是一種情況,你必須在許多不同的GPU上分布,而且你的通信速度非常低。
然后可能是選擇性再計算。在選擇性再計算中,Megatron有一篇很好的論文,我認為我們博客文章中的圖表也是從那里來的。在這種情況下,你為每個激活做出加權(quán)決策。
對于非常大的激活張量,你決定,從內(nèi)存角度來看,是將其保存更昂貴,還是從計算角度來看,重新計算更昂貴?這是Megatron實施的智能方案。
他們使用了許多不同的啟發(fā)式方法。在這里可能沒有必要提到超長的方程式,但如果你對選擇性再計算感興趣,你應(yīng)該去閱讀那篇論文。然后大多數(shù)人使用的是一個相當(dāng)愚蠢的方案,包括NeoX,就是不使用所有這些啟發(fā)式方法,而是只是說,如果我的張量大于X,我就拋棄它。然后將X設(shè)置為某個固定的數(shù)字,就是這樣。
對于許多情況來說,這足夠了。
Swyx:
為什么足夠呢?
Quentin:
你不希望存儲超過X大小的張量。有些超過了這個限制,有些沒有。你不想擠壓。
你更關(guān)心的是讓某些張量盡可能地接近實際啟發(fā)式方法,而不是實際計算啟發(fā)式代碼,因為你不想花時間編寫那些啟發(fā)式代碼。
Swyx:
好的。我想這確實為我們帶來了內(nèi)存數(shù)學(xué)的一次大觀。在我們進入分布式處理、Zero等細節(jié)之前,還有什么高層次的要點嗎?
Quentin:
我想大概就是這樣了。
我要說的是,對于訓(xùn)練和推斷來說,情況會大不相同。人們常常說,BF16是最好的。然而,更正確的看法是,在訓(xùn)練期間,精度會更加重要。
因此,在訓(xùn)練中,BF16會比在推斷中使用更久一些,因為在推斷中,模型已經(jīng)基本成型,它絕對不需要一些精度的最后幾位,因此,對于推斷來說,更容易將精度降至int8,而不是訓(xùn)練。
所以,你在訓(xùn)練中學(xué)到的所有東西都必須在推斷中重新學(xué)習(xí),反之亦然。
Swyx:
還有第三類情況。你談到了訓(xùn)練與推斷之間的區(qū)別。這第三類情況與微調(diào)和可能的參數(shù)高效微調(diào)方法有關(guān)。
實現(xiàn)微調(diào)的樸素方法只是進行更多的訓(xùn)練。但我不知道你是否對微調(diào)有什么直覺,是否值得在這里插入。有什么直覺嗎?如果你要編寫微調(diào)的數(shù)學(xué)公式,會包含什么內(nèi)容?
Quentin:
我認為,關(guān)于微調(diào)還有很多問題沒有得到解答。
例如,我們知道訓(xùn)練的縮放規(guī)律。有些人已經(jīng)做了關(guān)于微調(diào)的縮放規(guī)律。但已經(jīng)在一個領(lǐng)域訓(xùn)練過的模型如何轉(zhuǎn)移到另一個領(lǐng)域進行微調(diào),就微調(diào)大小而言,我們不清楚。
對于微調(diào)數(shù)據(jù)集,每個參數(shù)應(yīng)該有多少個標記?也許我是無知的,但我覺得關(guān)于模型如何在原始訓(xùn)練數(shù)據(jù)集中沒有的新能力進行微調(diào)或理解的問題,肯定會包含在未來關(guān)于微調(diào)的博客文章中。
此外,數(shù)據(jù)集轉(zhuǎn)移、學(xué)習(xí)率轉(zhuǎn)移也是我們博客感興趣的內(nèi)容之一。
09 并行訓(xùn)練
Alessio:
您在這里首先提到的是ZeRO,它專注于分片優(yōu)化器。也許可以給人們解釋一下如何理解它。
Quentin:
ZeRO圍繞兩個通信操作展開。第一個是scatter。人們應(yīng)該看一下我們有的ZeRO圖表。
在我談?wù)撨@個問題時,論文中有一個包含參數(shù)、梯度和優(yōu)化器狀態(tài)的圖表。每個GPU將獲得自己等量的切片。
如果我們進行...有ZeRO的不同階段,但讓我們首先假設(shè)它是優(yōu)化器狀態(tài)、梯度和參數(shù)的等量切片。
在這種情況下,那將是零三,第三階段。我們通過scatter實現(xiàn)這一點。scatter的計算是,每個GPU分配1/結(jié)束的GPU數(shù)量,加上切片的偏移量,切片被分配給該GPU?,F(xiàn)在,所有的GPU都有一個相等的切片,按照其排名順序。
在每個訓(xùn)練步驟中,該GPU將等待所有其他切片進行通信,以便我們現(xiàn)在在該GPU上擁有整個數(shù)據(jù)。一旦我們有了整個數(shù)據(jù),我們對其進行正向傳遞。
然后,我們使用gather將該正向傳遞分發(fā)給所有其他GPU。所以,它是scatter,具體來說是減少scatter,然后是對所有其他GPU的gather。并且您每一步都這樣做。因此,它的要點是您正在將這些狀態(tài)分片到不同的GPU上。
通過不同的階段,您將在圖表中看到,優(yōu)化器狀態(tài)占據(jù)了最大的比例,這是因為我之前提到的。我們包括FP32副本并進行原子操作。所以我們需要每個參數(shù)的4個字節(jié),用于動量和方差。然后,零階段一,這是最常見的一個,僅為優(yōu)化器。
零階段二是優(yōu)化器加梯度。零階段三是優(yōu)化器梯度和模型參數(shù)。但歸根結(jié)底,所有這些都是圍繞著分片和來回聚合展開的。所以您從ZeRO中得到了很多通信開銷。但其中的正面部分是您可以將其中大部分的移動與計算重疊。
Alessio:
Quentin:
這更多地取決于您的互連是什么。放慢一步,所有這些GPU之間都需要同步,而且這些同步往往是累積的。
因此,如果您在速度較慢的互連上使用過多的GPU,那么您最終會花更多的時間在同步上。在哪個GPU上花費更多時間同步的這個魔法數(shù)字會因您的互連和GPU內(nèi)存的情況而異。每個GPU獲得多小的切片呢?
例如,對于Summit,我不能給出確切數(shù)字,但大約在200億參數(shù)左右。現(xiàn)在您有200億個參數(shù),那么對于那個數(shù)量的GPU,大約需要100到200個規(guī)模。
超過這個數(shù)量,您最終只會花費更多的時間在通信上。實際的FLOPS跌破您預(yù)先設(shè)定的某個數(shù)值,將取決于您最終確定的最佳選擇。
10 高級3D并行技術(shù)(數(shù)據(jù)、張量、流水線)
Alessio:
那么,對我來說,這部分內(nèi)容比較難理解,所以我很高興您能解釋一下3D并行。
Quentin:
好的,首先,讓我們來看一個非?;镜木S度,即數(shù)據(jù)并行。
數(shù)據(jù)并行是您有一個模型的副本。為簡單起見,假設(shè)一個副本恰好適合一個GPU。數(shù)據(jù)并行是,現(xiàn)在您有兩個GPU,所以GPU一上有一個副本,GPU二上有一個副本。兩者都執(zhí)行正向和反向傳遞,然后進行同步和平均梯度。然后這就是一個步驟。對于3D并行來說,數(shù)據(jù)并行實際上是零。所以,您正在將優(yōu)化器狀態(tài)分片到所有不同的GPU上。
而在流水線并行中,假設(shè)您的模型有四個層次,有四個GPU。您將一層放在每個GPU上,然后GPU一執(zhí)行前向傳遞,然后將其激活的輸出發(fā)送到GPU二。它執(zhí)行前向傳遞,將激活發(fā)送到三,您只是在沿著一條線移動。那是一個樸素的方案,所有其他GPU在單個GPU執(zhí)行其前向或后向傳遞時都處于空閑狀態(tài)。所以它被稱為流水線并行,因為您將小批次分成了微小批次。
但問題在于,您需要一個非常大的批次大小,以將其分成小批次和微小批次。因此,將這三者結(jié)合起來,您將得到一個3D網(wǎng)格,其中每個參數(shù)、優(yōu)化器狀態(tài)等都映射到每個GPU上。這就是3D并行。
進行此操作時是否需要所有GPU都相同?還是也可以使用不匹配的GPU?
有兩件事情很重要。如果兩種不同類型的GPU之間的VRAM有差異,那么您將受到VRAM較少的GPU的限制,因為它會耗盡內(nèi)存。然后您不能使用較大的GPU上剩余的部分。
問題在于,我之前提到的同步操作會讓您受限。因此,在這種情況下,您的移動速度將與您最慢或最小的GPU相同。
因此,每個節(jié)點都有一個不同的網(wǎng)絡(luò)交換機。所以,您最終會以最慢交換機的速度運行,并且調(diào)整一切,使其不比最慢交換機差,這是一個現(xiàn)實世界中可能會遇到的問題。
11 異構(gòu)集群分布的挑戰(zhàn)
Alessio:
就是分片優(yōu)化器和3D并行,將兩者結(jié)合在一起,采用這種網(wǎng)格策略。
我會說,很多主要的基于GPT的模型都使用了這種方案?,F(xiàn)在很多人更傾向于純粹的ZeRO方案。所以就是純粹的分片。
您只需對所有內(nèi)容進行分片。因為這樣非常容易,每個人都可以得到相等的切片。不再有流水線階段的問題。不再有哪個張量應(yīng)該放在哪個GPU上的問題。
我認為,3D并行給您最多的控制權(quán),也是犯錯的最多方式。具體是選擇哪種取決于您是擁有更多工程師還是更多GPU。
Swyx:
這也不算太難,對吧?
您基本上已經(jīng)概述了需要記住的五六個不同的數(shù)字。如果需要達到這種控制水平,您已經(jīng)為每個人提供了主要的控制杠桿。這很好。絕對的。
Quentin:
問題在于,比如說,好吧,GPT-4發(fā)布了?,F(xiàn)在我們有了VLLMs。
Swyx:
Virtual LLMs,就像Metro of Expert的東西嗎?不,是視覺的。
所以現(xiàn)在我們有了多模態(tài)模型之類的東西。我們?nèi)绾芜M行分布?我們將其分配到流水線階段嗎?我們只是將其分片嗎?將張量分割并進行張量并行嗎?
當(dāng)您具有這種3D并行方案時,要更改模型并添加新功能變得有點困難。我說困難,我的意思是將其調(diào)整和修改為適應(yīng)新功能會變得困難。
Alessio:
我很好奇,您是否仍然認為這些問題集中在訓(xùn)練、推理、數(shù)學(xué)優(yōu)化上,還是還有其他領(lǐng)域需要大家關(guān)注?
我認為在我研究的領(lǐng)域里,有兩個問題是我認為人們應(yīng)該非常關(guān)心的。
因此,如何將某些模型或某些GPU用于推理,而某些GPU用于訓(xùn)練?就像我之前提到的,你需要重新學(xué)習(xí)所有內(nèi)容,而且它們具有非常獨特的挑戰(zhàn)。
例如,在訓(xùn)練期間如何分割一個KV緩存?這些都是尚未得到充分研究的挑戰(zhàn)。
在多模態(tài)方面,你可能有一個視覺變換器和一個文本變換器。如何分割它們?你是否平均分配?將它們放在不同的GPU上,還是只是將一些視覺、一些文本參數(shù)放在一個GPU上?
然后,第二個問題是通信往往是一個瓶頸。所以我們談?wù)摿?D并行,但很多情況下,比如張量并行,你不能跨節(jié)點使用。你會在通信中受到限制。
讓人們在通信基礎(chǔ)設(shè)施上花費更少的金錢,而更多地用于GPU,這也是人們需要探索的領(lǐng)域。
關(guān)鍵詞: