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