Adam有了mini版:記憶體佔用少一半,吞吐量提升50%

机器之心發表於2024-07-08
在訓練大型語言模型(LLM)時,Adam(W) 基本上已經成為了人們預設使用的最佳化器

Adam 儘管效能優異,但使用成本很高。具體來說,Adam 需要記憶體來儲存其最佳化器狀態:一階動量 m 和二階動量 v^2。這總共需要模型大小至少 2 倍的記憶體。這樣的記憶體消耗已經成為了 LLM 訓練的一大主要負擔。

舉個例子,要訓練一個 7B 模型,只是 Adam 就需要每張卡有大約 56 GB 來儲存 m 和 v;而如果再加上梯度,則總共需要 86 GB。即使使用最先進的 A100-80GB,成本也過高了。

為了支援這樣的高記憶體演算法,實踐中必須要使用 CPU 解除安裝與分片,但這又會增加延遲,減慢訓練速度。在訓練 PaLM (有 5400 億引數)這樣的更大型模型時,情況還會更糟。在這種情況下,Adam 自身就要佔用超過 50 GB,並且這也是預訓練階段的一大主要開銷。

因此,人們希望設計出記憶體需求更少又有效的最佳化器。首先,減少記憶體可以減輕 CPU 解除安裝的負擔並能減輕對模型引數執行分片的需求。這些都能減少 GPU 和 CPU 之間的通訊量,並進一步提升訓練過程的吞吐量和速度。其次,這允許實踐者使用更少的 GPU 來訓練所需大小的模型,從而極大地節省成本和能源。第三,這能降低訓練 LLM 的門檻並鼓勵更多 GPU 資源有限的研究者參與進來。

但是,修改 Adam 但不影響其效能的難度非常大。其中一個主要原因是我們仍然不太理解 Adam 的 m 和 v 的作用。我們還不清楚 Adam 的哪些元件對其卓越效能而言必不可少,也就更不知道可以重新設計和改進哪些元件了。

Adafactor 是一個頗受歡迎的嘗試,其能降低在 v 上低秩分解所用的記憶體。但是,很多研究發現 Adafactor 訓練 LLM 的效能不佳。可能的原因有兩個。第一,當前 Adam 中的 v 可能對有效性來說非常關鍵,已經沒有縮減空間。第二,v 是有可能縮減的,只是 Adafactor 使用的方法並不是最合適的:矩陣分解是一種可以廣泛應用的通用方法,但它沒有利用太多特定於問題的結構,因此它在特定的神經網路任務上效果不佳。

近日,香港中文大學(深圳)、深圳市大資料研究院、杜克大學和史丹佛大學的一個聯合研究團隊發現:可以透過一個簡單技巧來降低 v 的使用量。

目前而言,Adam 的 v 會為每個引數單獨分配一個學習率,即第 i 個引數獲得的學習率圖片,,其中 v_i 是 v 的第 i 個元件。對於十億引數量的模型,Adam 就要設計十億個學習率

該團隊認為這些學習率資源可以大幅降低,同時還不會影響模型效能,甚至能讓模型獲得更優效能。該團隊注意到,Transformer 的 Hessian 有一種接近塊對角線的結構,其由不同大小的密集子塊構成。他們發現,對於每一個這樣的密集子塊,都存在效能優於 Adam 的單個高質量學習率——只要有足夠的資源將其搜尋出來。由於密集子塊的數量遠少於引數數量,這個發現表明使用遠遠更少的學習率是有可能取得優良效能的。剩下的問題如何高效地找到它們。

為了找到效能足以比肩甚至優於 Adam 的優良學習率,該團隊提出了一種低成本的簡單方法 Adam-mini。另外,該團隊也釋出了 Adam-mini 的一種實現。
圖片
  • 論文標題:Adam-mini: Use Fewer Learning Rates To Gain More
  • 論文地址:https://arxiv.org/pdf/2406.16793
  • 實現程式碼:https://github.com/zyushun/Adam-mini

在實驗中,Adam-mini 的表現非常優秀。如圖 1 所示, 在預訓練 Llama2-7B 時,Adam-mini 的記憶體佔用可以大幅降低,同時吞吐量也有明顯提升。在保證效能與 Adam 相當的同時,其能帶來 33% 的速度提升。

圖片

圖 2 展示了 Adam-mini 的大致圖示和學習率使用情況。可以看到,Adam-mini 是根據 Hessian 結構來分配學習率,因此其使用的學習率比 SGD 多,但遠少於 Adam。

圖片

本研究的通訊作者,香港中文大學(深圳)資料科學學院副教授孫若愚(Ruoyu Sun)表示:「如果你喜歡 Adam(W),那 Adam-mini 就是你的不二之選!」

方法

動機和觀察

為了應對特徵值的異構性,Transformer 的每一引數塊都需要不同的學習率。Adam 的 v 可以提供這一點。

論文《Why Transformers Need Adam: A Hessian Perspective》發現:必須為每個塊使用不同的學習率。但是,Adam 所做的卻遠不止此:其並不只是為每個塊分配不同的學習率,而是為每個引數都分配不同的學習率。而引數量(可能超過數十億)要遠遠多於塊的數量(通常數百計)。那問題就來了:

有必要為每個引數都使用單獨的學習率嗎?如果沒必要,又能節省多少?

該團隊進行了一番探索,得到了如下發現:

圖片

  • 如圖 4 (a) 和 (b) 所示,Adam 的表現優於最優的單學習率方法。這符合預期。
  • 如圖 4 (c) 和 (d) 所示,這裡研究了其 Hessian 是 (a) 的一個密集子塊的新問題。該團隊探究了針對這個問題的最優單學習率方法,結果發現其表現優於 Adam,即使 Adam 分配的學習率要多得多。(a) 的所有三個子塊都有類似的現象。
  • 如果收集 (2) 中的那些最優學習率,並將其用於梯度下降的一個「逐塊」版本,那麼其在原始問題上的速度會比 Adam 快,見圖 4(b) 中的綠線。

也就是說,對於帶有塊對角 Hessian 的一般問題而言,許多學習率並不一定會帶來額外收益。

該團隊也在 Transformer 中觀察到了類似的現象。

圖片

總結起來,該團隊發現:對於 Transformer,有可能使用比 Adam 遠遠更少的學習率實現與之相當或更好的效能。剩下的問題就是在不使用網格搜尋的情況下如何找到這些學習率

新方法:Adam-mini

基於上述討論,該團隊提出了 Adam-mini,見演算法 1。Adam-mini 的目標是降低 Adam 中的學習率資源,而無需費力地對學習率執行網格搜尋。Adam-mini 包含兩個步驟。步驟 1 只在初始化時進行。

圖片

步驟 1-1:將模型引數切分為塊。對於 Transformer,該團隊選擇的策略是「Partition for Transformers」,即根據頭來切分所有的 Query 和 Key,並使用 PyTorch 來切分其餘部分。對於其它網路,則使用預設的 PyTorch 切分即可,他們將其稱之為「Partition for non-Transformers」。

步驟 1-2:使用 embd_blocks。對於 Transformer,其包含嵌入層和輸出層。對於其它網路,不選擇任何引數

步驟 2:對於每個位於 embd_blocks 之外的引數塊,都使用單個學習率。為了高效地為每個塊選擇合適的學習率,Adam-mini 的做法是直接將原始 Adam 中的 g◦g 替換成其均值。Adam-mini 像 Adam 一樣在這些均值上使用了移動平均值。

一個簡單示例。為了說明 Adam-mini 的關鍵設計,該團隊在論文中給出了一個簡單的示例。假設有一個問題,其有 5 個引數 w ∈ ℝ^5,Adam 和 Adam-mini 都會執行 w = w − u ◦ m,其中 m 是一階動量,而 u 有不同的形式,如下所示:

  • 對於 Adam:

圖片

  • 對於 Adam-mini:假設分片方式為 (1, 2, 3) 和 (4, 5),則

圖片

請注意,有效元素 u_mini 的數量就等於塊的數量,這遠遠小於 u_Adam,其等於引數數量。結果表明,這能讓 LLM 的 v 中的元素數量減少 90% 以上。

分片策略的原則

現在討論如何為 Adam-mini 選擇引數分片。該團隊基於前述分析得出了一個廣義原則:

原則 1:應當將引數切分成不同的引數塊,使得每個引數塊都關聯了 Hessian 中最小的密集子塊。

圖片

由於引數的塊對角結構,PyTorch 的預設分片方法是一個合理的候選項。實際上,這種分片確實能很好地用於非 Transformer 任務,比如 ResNet、擴散模型和圖模型。演算法 3 Partition for non-Transformers 展示了該策略。

但不幸的是,該團隊發現,預設的 PyTorch 切片並不總是能很好地應對 Transformer。比如他們發現 Adam-mini 在 1B 模型上會出現訓練不穩定問題(見圖 6(d))。

圖片

他們猜測這是因為 PyTorch 切片無法完整地理解 Hessian結構。經過一番探索後,他們發現 Hessian 子模組分為兩類:

第一類:類似於 Hessian 整體,這種 Hessian 子塊本身也有進一步的塊對角結構,由更小的密集矩陣構成。這一類包含 Query 和 Key。他們透過實驗發現,小型密集子塊的數量就等於多頭注意力中頭的數量。

第二類:這種 Hessian 子塊有密集的結構,無法進一步分成更小的塊。這一類包含 Value、注意力投射和 MLP 層。請注意 Value 的 Hessian 結構不同於 Query 和 Key 的 Hessian 結構,但它們全都由 4 個頭組成。這是因為 Value 位於自注意力設計的 softmax 運算元之外,而 Query 和 Key 卻不是。

基於上述發現,該團隊發現預設的 PyTorch 分片確實不是最適合 Transformer 的。可以根據頭將 Query 和 Key 進一步切分成不同的塊。根據原則 1,不同的頭應當屬於不同的塊。根據直覺就能知道,不同的頭在理解 token 時的作用也不同,因此它們需要不同的學習率就很合理了。

由此,該團隊得到了演算法 2:Partition for Transformers,其可根據頭來切分 Query 和 Key。該過程遵循基於最小 Hessian 子塊的原則如圖 6 (d) 所示。該策略確實能穩定訓練過程並提升效能。

Adam-mini 的一些特點

減少記憶體用量

根據設計,Adam-mini 可為 Transformer 減少學習率的數量——從引數總數減少到嵌入層的大小、輸出層的大小和其它層中塊的數量的總和。因此,減少的記憶體比例取決於模型中非嵌入引數的比例。

圖片

在 Llama2-7B 上,這個比例是 96.2%。對於主流的語言模型,這個比例通常 ≥ 90%。請注意,如果層數更多,這個比例也會更加接近 100%;比如對於 Llama3-70B,這個比例為 99.25%。因此,Adam-mini 可將 v 減少至少 90%,由此可為 Adam 帶來 45% 到 50% 的記憶體節省。

吞吐量更高

Adam-mini 可取得比 AdamW 更高的吞吐量,尤其是當硬體資源有限時。

圖片

基於此,Adam-mini 可以減少預訓練的總時間。如表 2 所示。當在 2 臺 A800-80GB 上預訓練 Llama2-7B 時,Adam-mini 的吞吐量比 AdamW 高 49.6%。召回吞吐量 (↑) 指的是每秒處理的 token 數量,因此在預訓練時,Adam-mini 處理相同數量的 token 可節省 33.1% 的時間。

實驗

預訓練

設定

該團隊預訓練了一些開源 LLM,包括 GPT2 系列和 LLM 系列。他們在主流英語語料庫上從頭開始訓練了這些模型。

具體來說,他們在 Openwebtext 上訓練了 GPT2 系列,在 CommonCrawl 上訓練了 TinyLlama-1B 和 Llama2-7B。他們使用 2B、3B 和 25B token 訓練了模型。模型配置(比如上下文長度)是根據標準協議選擇的。

該團隊將 Adam-mini 與 AdamW 以及 Adafactor、CAME 和 SM3 等常用記憶體高效型方法進行了比較。對於 Adafactor 和 SM3,為了確保與其它方法進行公平的比較,這裡整合了 β_1 = 0.9 的動量。他們在同樣的預算內對所有方法的學習率進行了調節,並報告了最佳效能。

Llama 系列

圖片

圖 7 (a) 展示了預訓練 TinyLlama-1B 的驗證損失曲線。Llama2-7B 的訓練曲線已經在圖 1(c) 中給出。對於 TinyLlama-1B 和 Llama2-7B,可以發現 Adam-mini 使用更少的記憶體便能達到與 AdamW 相近的效果。

GPT2 系列

圖 7 (b) 展現了 GPT2-125M 的驗證損失曲線,圖 8 展示了大小從 330M 到 1.5B 的 GPT2 的驗證損失曲線。可以看到,Adam-mini 使用更少的記憶體就能取得與 AdamW 相當的優良效能,而其它方法的表現要更差一些。

圖片

敏感度分析

該團隊在 GPT2-125M 預訓練任務上測試了 Adam-mini 對超引數的敏感度。這裡報告了使用 2.5B token 訓練之後的驗證損失。如圖 7 所示,Adam-mini 看起來對超引數並不敏感。

監督式微調和 RLHF

該團隊評估了 Adam-mini 對下游微調任務的有效性。

具體來說,他們考慮了兩種有代表性的任務:監督式微調(SFT)和根據人類反饋的強化學習(RLHF)。這裡使用的預訓練模型是 Llama-2-7B。

圖片

結果見表 3,可以看到 Adam-mini 的表現優於 AdamW,即便 Adam-mini 使用了單個學習率並且記憶體效率更高。

非 LLM 任務

該團隊也在非 LLM 任務評估了 Adam-mini。表 4 給出了在 ImageNet 上訓練 ResNet18、在 CelebA 上訓練擴散模型、在 OGB-arxiv 上訓練圖卷積網路(GCN)和圖注意力網路(GAT)的結果。結果發現 Adam-mini 使用更少的記憶體便能取得與 AdamW 相當或更好的效能。

圖片

相關文章