本文聚焦 NVIDIA FP8 訓練與推理的實踐應用。
FP8 訓練利用 E5M2/E4M3 格式,具備與 FP16 相當的動態范圍,適用于反向傳播與前向傳播。FP8 訓練在相同加速平臺上的峰值性能顯著超越 FP16/BF16,并且模型參數越大,訓練加速效果越好,且其與 16-bits 訓練在收斂性和下游任務表現上無顯著差異。FP8 訓練通過 NVIDIA Transformer Engine 實現,僅需少量代碼改動,并且支持 FlashAttention、混合精度訓練遷移等。支持 FP8 的框架包括 NVIDIA Megatron-LM、NeMo、DeepSpeed、飛槳 PaddlePaddle、Colossal AI、HuggingFace 等。
FP8 推理通過 NVIDIA TensorRT-LLM 實現,權重輸入先轉換為 FP8,并融合操作以提高內存吞吐,但部分輸出仍需 FP16 進行 reduction。NVIDIA 技術團隊正研究直接 FP8 reduction 以實現端到端的加速優化。
FP8 基本原理、采用理由和收益
圖 1. 四種數據類型
首先詳解 FP8 的概念,圖 1 展示了 FP8、FP16、FP32 與 BF16 四種數據類型。業界曾長期依賴 FP16 與 FP32 訓練,直至 GPT 橫空出世,BF16 因能避免計算過程中的數值溢出問題而受到青睞。
近年來,NVIDIA 技術團隊在 FP8 領域持續投入,發布了多篇論文,并在歷屆 GTC 大會也分享了 FP8 在計算機視覺 (CV)、自然語言處理 (NLP) 以及大模型訓練中的實際效果。
圖 2. E4M3 與 E5M2 兩種數據格式
圖 2 表格展示了 E4M3 與 E5M2 兩種數據格式。其中可以看到,FP8 精度的 E5M2 數據格式的數部分,與 FP16 的保持一致。這意味著 FP8 精度的 E5M2 數據格式具備與 FP16 相當的動態范圍,因此該數據格式常被用在訓練的反向傳播階段。而 E4M3 是在前向傳播中采用的 FP8 格式。圖 2 詳盡展示了 FP8 格式下各類特殊數值的表示方式。
當我們考慮浮點數的數據精度會不會損失的時候,這個浮點數往往會落入圖 2 下半部分里粉色的 subnormal 區間。圖 2 下半部分是以 FP32 舉例的,讀者可根據圖 2 表格看到 FP8 的 subnormal 區間,因此我們在訓練模型時可進行理論分析,探究數值精度是否影響模型效果。
表 1. 援引的測試數據[1]僅供技術參考和討論
表 1 旨在闡述采用 FP8 的原因,以在 NVIDIA H100 Tensor Core GPU 上為例,單位是 TFLOPS,相較 FP16 和 BF16,FP8 的峰值性能能夠實現翻倍。并且此表展示的基準測試數據是在 2023 年采集的,當前性能提升更為顯著。
圖 3. 測試數據僅供技術參考和討論
圖 3 左側圖表對比了不同參數規模的 GPT-3 模型在 H100 上做 FP8 訓練,以及在 NVIDIA A100 Tensor Core GPU 上做 FP16/BF16 訓練的吞吐加速比。這個加速效果隨模型規模正向變化,比如參數規模為 5B 至 40B,它的加速效果約為 2 到 3 倍。
右側表格則進一步對比了不同參數規模的模型同在 H100 GPU 上,使用 FP8 訓練相對 BF16 的性能加速比。就 126M 至 175B 參數的模型而言,除了個別特殊任務外,FP8 訓練的加速效果同樣隨模型規模增大而提升。換言之,模型規模越大,采用 FP8 訓練的收益越大。
圖 4. 援引的測試數據[2]僅供技術參考和討論
圖 4 援引的是行業測試數據。左側圖表顯示的是對 GEMM 單一計算任務的加速對比。在 H100 GPU 上 FP8 訓練相對于 A100 GPU 上 BF16 訓練的峰值性能加速比約為 6 倍,而在 GEMM 任務測試中接近 5 倍。并且鑒于底層 CUDA 內核持續優化,未來性能將進一步提升。
右側表格則展示了在不同規模的 GPT 模型做 FP8 訓練的實際加速效果,模型參數規模分別為 1B、3B、7B 和 30B。該圖表分別對比了在 H100 GPU 與 A100 GPU 上做 BF16 和 FP8 訓練的加速效果。可以看到 BF16 訓練對 1B、3B 模型的加速比約為 2.2 倍,而 FP8 訓練的加速比分別達 2.7 倍、2.8 倍,對 7B、30B 模型加速比則達到 3 倍和 3.3 倍,說明 FP8 訓練的性能優化效果更加顯著。
FP8 的訓練性能和收斂性
圖 5. 測試數據僅供技術參考和討論
圖 5 展示了 FP8 訓練的性能與收斂性。右圖顯示在不同規模的 GPT 模型上使用 BF16 與 FP8 進行訓練的 loss (損失值)曲線,并以困惑度 PPL(Perplexity) 為度量指標。同色曲線代表相同模型規模,實線代表 BF16,虛線為 FP8。觀察 PPL 曲線走勢,可見隨著訓練進程,FP8 與 BF16 的曲線幾乎完全吻合,表明兩者收斂性并無顯著差異。
左側表格則匯總了歷屆 GTC 大會中分享的下游任務數據,包括 PPL 指標及 FP8 與 16-bits 訓練的對比,涵蓋 NLP 模型和 CV 模型。結果顯示,使用 FP8 訓練的模型與 16-bits 訓練的模型在各項指標上的數值差異甚微,證實了 FP8 訓練能達到同等效果。
圖 6. 援引的測試數據[3]僅供技術參考和討論
圖 6 展示了我們在本地測試的一個 1.3B 參數模型的實際訓練結果,共進行了約 2.5 萬步訓練。結果顯示,該模型的 loss 曲線與預期基本相符,僅有微小(零點零幾)的差異。
這里列舉在 FP8 訓練中實際采用的配置。可以看到使用 FP8 訓練時對代碼的改動極少,只需添加幾行代碼即可,后文將詳細解釋這些代碼的具體含義。
--fp8-hybrid
--transformer-impl transformer_engine
--fp8-amax-history-len 1024
--fp8-amax-compute-algo max
此外,我們在實際訓練中的常見問題解答如下:
目前廣泛采用 BF16 進行混合訓練,轉用 FP8 是否需要自行編譯 kernel 或進行復雜的數據類型轉換? 答案是否,建議使用 NVIDIA Transformer Engine 預置的多種 FP8 kernel(Linear、MLP、LayerNorm 等基礎算子及基于這些算子的fused kernel),無需開發,直接調用即可。
如果沒使用 NVIDIA Megatron 或 DeepSpeed 框架,而是采用自定義框架,可以無縫使用 Transformer Engine 進行 FP8 訓練嗎? 答案是可以。只需在 PyTorch 上使用 Transformer Engine 提供的 fp8_autocast 包裝器(wrapper),即可在原生 PyTorch 環境中開展 FP8 訓練。此 wrapper 主要用于提供一系列 FP8-safe 的算子,自動將高精度的輸入數據轉換為 FP8,簡化了低精度訓練的實現過程。在上述過程中,需要對每個 tensor 更新其縮放因子 (scale),為此我們引入 amax(maximums of absolute value)的概念,fp8_autocast wrapper 會更新 amax 值。此外,根據 amax 值,該 wrapper 還會自動計算每個 tensor 的實際 scale 值。
Transformer Engine 除提供 FP8 layer-wise 模塊和自動數據類型轉換外,還有什么功能? 答案是它還支持 FlashAttention 機制。這意味著 Transformer Engine 也能夠提升傳統 BF16、FP16 訓練的性能。
對于已使用 BF16 訓練的存量模型,能夠使用 FP8 做繼續訓練嗎? 答案是可以。實踐證明,BF16 格式的 checkpoint 可以直接導入進行 FP8 繼續訓練;反之亦然,即在預訓練階段使用了 FP8,那么在 SFT(supervised Fine-Tuning) 階段,出于對模型精度或數據健壯性的考慮,仍舊可以從 FP8 無縫切換到 BF16 做繼續訓練。Transformer Engine 全面支持此類精度遷移的操作。
圖 7. 解讀 FP8 訓練中新增的五行代碼
圖 7 旨在解讀前文提及的 FP8 訓練中新增的五行代碼,代碼的功能是用于計算當前 tensor 的 scale 值。我們采用名為 delayed scaling 策略,即當前 tensor 的 scale 值并非基于實時計算得出,而是依據其歷史數據,例如基于前幾個迭代周期的值計算得出。計算方法可選擇取 max 值,也可采用最近時間的值。
以該圖展示的 amax history 說明,針對當前 tensor,系統可存儲 1,024 個 amax 值,并從中選取最大值作為當前 tensor 的 amax 值。隨后,根據一個簡化的 recipe 算法即可計算出 scale 值。
實際應用中,Hopper GPU 上 FP8 訓練相較于 BF16 的加速效果為 30%-40%,低于 FP8 在單一 GEMM 計算任務中理論可達的 5 倍加速比。為解釋此現象,本文借助圖 8 進行闡述。
使用 Transformer Engine 訓練 FP8 LLM
圖 8. FP8 訓練在 Transformer Engine 上的完整流程
圖 8 顯示了訓練中前向與反向計算的精度差異:紅線表示高精度(BF16、FP32),綠線為 FP8。在整個訓練期間,圖片上半部分的權重(weight)及下半部分的梯度(gradient)始終以高精度存儲。僅在執行 linear 操作時,才對當前 tensor 進行數據格式轉換(cast),轉為 FP8 精度計算,但 linear 輸出仍為高精度。因此,后續 bias 計算等均在高精度上進行。
圖示表明,實際訓練中僅 GEMM 計算采用 FP8,其余計算保持高精度。盡管業界存在對非線性操作也采用 FP8 計算和存儲的激進策略,并在部分下游任務中表現良好,但主流方案依然遵循上述精細化的精度分配原則。
目前支持 FP8 訓練的分布式訓練框架與工具包括 NVIDIA Megatron-LM、NeMo 框架,DeepSpeed、飛槳 PaddlePaddle、Colossal AI、HuggingFace 等,也就是說這些框架均已集成了 Transformer Engine,可選用上述任一框架進行大模型 FP8 訓練。
圖 9. 不同數據精度
集合Transformer Engine 的訓練測試結果對比
圖 9 總結了上述重點,通過對比三類測試情況:綠線代表僅使用 BF16 訓練,橘線表示 BF16 訓練結合 Transformer Engine(即在啟用 FlashAttention 的同時,使用 Transformer Engine 內置的 fused kernel),藍線為 FP8 訓練結合 Transformer Engine。
綠線顯示,僅用 BF16 訓練時,模型在單 GPU 卡上即遭遇內存不足(OOM),而在啟用 Transformer Engine 后,依舊采用 BF16,模型也能順利完成訓練。若進一步轉為 FP8,單次迭代時間可提升約 34.56%。
中間的圖表展示了各類測試的顯存占用情況。如前文所述,權重、梯度及優化器(optimizer)的數據均以高精度存儲,此外,FP8 訓練因需在 checkpoint 中保存額外值,訓練時顯存占用比 FP16 略高約 5% 以內。須注意,推理階段的顯存占用與訓練階段是完全不同的。
圖 10. Llama2-7B 模型做 FP8/BF16
繼續訓練的 loss 曲線高度一致
圖 10 展示了對 Llama2-7B 模型做 FP8 繼續訓練的效果。本測試并未進行長時間的訓練,目的是在為了提供概念驗證 (PoC, Proof of Concept)。圖中共有四條曲線:灰色曲線代表全程使用 BF16 訓練,其余三條線分別表示以 BF16 進行預訓練,保存 checkpoint 后,再分別以 BF16 與 FP8 繼續訓練。從繼續訓練的兩條曲線來看,loss 曲線高度一致,且與灰色曲線的趨勢也保持一致。
圖 11. Llama2-7B 模型 1.3 萬步內
全程 FP8/BF16 訓練的 loss 曲線基本一致
圖 11 展示的是對 Llama2-7B 在 1.3 萬迭代步內做全程 FP8 訓練,可以看到它和全程 BF16 訓練的 loss 曲線也幾乎一致。
FP8 推理流程
本章節分享使用 TensorRT-LLM 進行 FP8 推理。前文圖 8 展示的 FP8 訓練在 Transformer Engine 上的完整流程,而在進入推理階段,圖 8 下半部分如梯度等訓練特有部分可去除,僅保留上半部份即可。
訓練時為確保梯度計算準確,權重通常維持為高精度(如 BF16 或 FP32),這是由于訓練時需更新參數,而在推理時,權重已固定,故可在模型加載或預處理階段提前將權重轉換為 FP8,確保模型加載即為 FP8 格式。此外,推理階段應盡量進行操作融合,如將 LayerNorm 與后續數據格式轉換操作整合,確保 kernel 輸入輸出盡可能維持 FP8,從而能夠有效提升 GPU 內存吞吐。同樣,GeLU (Gaussian Error Linear Unit) 激活函數也要力求融合。
目前少量輸出仍會保持為 FP16,原因是 NVIDIA NCCL 僅支持高精度規約操作 (reduction),所以現在仍然需采用 FP16 進行 reduction,完成后再轉化為 FP8。
圖 12. FP8 推理流程
經過上述融合后,推理流程就簡化為圖 12 所示。綠線代表 FP8 的輸入輸出(I/O),紅線表示高精度 I/O。圖中可見,最前端的 LayerNorm 輸出與權重均為 FP8,矩陣輸出暫時保持 FP16,與前文描述一致。并且經過測試驗證可得,雖然矩陣輸出精度對整體性能影響較小,但與輸入問題的規模相關;且因其計算密集特性,對輸出形態影響微弱。
在完成 MHA(Multi-Head Attention)后,需要將結果轉換為 FP8 以進行后續矩陣計算,Reduction 是以 FP16 執行后再轉換到 FP8 的。對于 MLP1 和 MLP2,兩者邏輯相似,但不同之處在于:MLP1 的輸出可保持在 FP8,因為它已經把 GeLU 加 Bias 等操作直接融合到 MLP1 的 kernel。
由此引發的關鍵問題是,能否將剩余紅線(高精度 I/O)全部轉為綠線(FP8 I/O),實現進一步的加速優化?這正是 NVIDIA 持續進行的方向。以 reduction 為例,NVIDIA 正研究直接實現 FP8 reduction,盡管中間累加仍需高精度,但在數據傳輸階段可采用 FP8。與現有 reduction 不同的是,FP8 reduction 內部需引入反量化(de-quantization)與量化 (quantization)操作,故需定制開發 reduction kernel。
最佳實踐:使用 TensorRT-LLM 實現 FP8 推理
TensorRT-LLM 是基于 NVIDIA TensorRT 構建,其 FP8 能力也主要是通過 TensorRT 提供。自 TensorRT 9.0 版本起,官方就已經開始支持 FP8 推理。要在 TensorRT 中啟用 FP8 推理,需完成以下幾步:
設置 FP8 標志:通過調用 config.set_flag (trt.BuilderFlag.FP8) 在 TensorRT 配置中啟用 FP8 支持。類似 INT8、BF16、FP16,FP8 也是類似的啟用方式。
添加 GEMM 縮放因子(scale):主要針對輸入和權重,需在 weight.py (TensorRT-LLM 中的文件)中額外加載這些縮放因子。這是 FP8 推理中不可或缺的步驟。
編寫 FP8模型:現階段我們需要明確編寫需要 FP8 支持的模型。具體做法如下:將原始 FP16 輸入量化至 FP8,隨后進行反量化;權重同樣進行量化與反量化操作。如此編寫的模型,TensorRT 會自動將量化與反量化操作盡可能與前一個 kernel 融合,以及將反量化操作與 matmul kernel 融合。最終生成的計算圖表現為量化后的 X 與 W 直接進行 FP8 計算,輸出也為 FP8 結果。
為了簡化 FP8 在 TensorRT-LLM 中的應用,TensorRT-LLM 已對其進行封裝,提供了 FP8 linear 函數和 FP8 row linear 函數來實現。對于使用直接線性層(linear layer),則無需重新編寫代碼,直接調用函數即可。
圖 13. FP8 推理計算流程
本文用圖 13 總結上述內容。首先權重以 FP8 精度存儲的,在進行計算前,權重先經歷一次反量化。注意,在此之前,權重的量化已在輸入前完成了,此處僅需進行反量化操作。這意味著,在進行矩陣內部計算時,實際上是使用反量化后的數據,通常是 FP16 或甚至 FP32 來進行運算的。
矩陣層盡管以 FP8 表示,但累加是采用 FP32 完成,累加后再乘以 scale 的相關參數,形成如圖所示的計算流程。最終得到的結果具備較高精度。由于累加器(accumulator)需要采用高精度的數值,因此,要獲得最終 FP8 的輸出結果,模型還需經過一個量化節點 (quantitation node)。
回顧整個流程,輸入經歷了量化與反量化操作。其中,量化 kernel 發生在反量化 kernel 之前,而 TensorRT 則會智能地融合這些 kernel,確保計算的高效和準確。
使用 Tensor-LLM 實現 FP8 推理的性能
表 2 測試數據僅供技術參考和討論
表 2 對比第一列不同的 batch size,其中 max 值指的是在設定輸入為 1,024,輸出為 256,模型為 GPT-J 6B,所能使用的最大 batch size。
列表顯示,FP16 的 max 值為 75,而 FP8 的 max 值則提升至 85。原因是 FP8 僅節省了權重部分的內存,部分 tensor 以及 KV cache 仍保持在 FP16。表格最后一列展示了使用 FP8 KV cache 的情況,此時能夠看到其 max 值相比 FP16 的 max 值超出 2 倍。
在性能方面,單純啟用 FP8 會由于 batch size 提升有限,以及 KV cache 的影響,導致性能提升并不顯著。然而,一旦將 KV cache 也轉換至 FP8,通過減半其內存消耗,模型吞吐量可以相較 FP16 提升約兩倍左右,這是一個相當理想的性能提升幅度。
-
NVIDIA
+關注
關注
14文章
4940瀏覽量
102815 -
計算機視覺
+關注
關注
8文章
1696瀏覽量
45927 -
GPT
+關注
關注
0文章
351瀏覽量
15314
原文標題:NVIDIA GPU 架構下的 FP8 訓練與推理
文章出處:【微信號:NVIDIA-Enterprise,微信公眾號:NVIDIA英偉達企業解決方案】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論