LLM生成延遲降低50%!DeepSpeed團隊發(fā)布FastGen:動態(tài)SplitFuse技術(shù),提升2.3倍有效吞吐量
GPT-4和LLaMA這樣的大型語言模型(LLMs)已在各個層次上成為了集成AI 的主流服務(wù)應用。從常規(guī)聊天模型到文檔摘要,從自動駕駛到各個軟件中的Copilot功能,這些模型的部署和服務(wù)需求正在迅速增加。
像DeepSpeed、PyTorch和其他幾個框架可以在LLM訓練期間實現(xiàn)良好的硬件利用率,但它們在與用戶互動及處理開放式文本生成等任務(wù)時,受限于這些操作的計算密集度相對較低,現(xiàn)有系統(tǒng)往往在推理吞吐量上遇到瓶頸。
為了解決這一問題,使用類似vLLM這樣由PagedAttention驅(qū)動的框架或是Orca系統(tǒng)可以顯著提高LLM推理的性能。
然而,這些系統(tǒng)在面對長提示的工作負載時,依舊難以提供良好的服務(wù)質(zhì)量。隨著越來越多的模型(例如MPT-StoryWriter)和系統(tǒng)(例如DeepSpeed Ulysses)支持延伸到數(shù)萬個token的上下文窗口,這些長提示工作負載變得越來越重要。
為了更好地理解問題,微軟DeepSpeed的研究人員最近發(fā)表了一篇博文,詳細介紹了LLM的文本生成,以及DeepSpeed-FastGen框架是如何在「提示處理」和「生成」的這兩個階段中運行的。
DeepSpeed-FastGen
當系統(tǒng)將「提示處理」和「生成」視為不同的階段時,生成階段將被提示處理所搶占,可能會破壞服務(wù)級別協(xié)議(SLAs)。
通過采用動態(tài)SplitFuse技術(shù),DeepSpeed-FastGen框架能夠提供比vLLM等先進系統(tǒng)高出多達2.3倍的有效吞吐量。
DeepSpeed-FastGen是DeepSpeed-MII和DeepSpeed-Inference的結(jié)合,提供了一個易于使用的服務(wù)系統(tǒng)。
快速開始:要使用DeepSpeed-FastGen只需安裝最新的DeepSpeed-MII發(fā)行版:
pip install deepspeed-mii
要使用簡單的非持久性管道部署并生成文本,請運行以下代碼。
from mii import pipeline
pipe = pipeline("mistralai/Mistral-7B-v0.1")
output = pipe(["Hello, my name is", "DeepSpeed is"], max_new_tokens=128)
print(output)
現(xiàn)有LLM服務(wù)技術(shù)
單個序列的文本生成工作負載包含兩個階段:
1. 提示處理,此階段系統(tǒng)處理用戶輸入的文本,將其轉(zhuǎn)換成一系列token并構(gòu)建用于注意力機制的鍵值(KV)緩存;
2. 生成token,即向緩存中添加單個token并產(chǎn)生新的token。
在生成文本序列的過程中,系統(tǒng)將對模型進行多次前向調(diào)用以生成完整的文本序列,現(xiàn)有文獻和系統(tǒng)中已經(jīng)提出了兩種主要技術(shù),解決了這些階段中可能出現(xiàn)的各種限制和瓶頸。
分塊KV緩存
vLLM識別出大型單體KV緩存導致的內(nèi)存碎片化顯著降低了大型語言模型服務(wù)系統(tǒng)的并發(fā)性,并提出了「分頁注意力」(Paged Attention)機制來實現(xiàn)非連續(xù)KV緩存,并增加整個系統(tǒng)的總吞吐量。
此技術(shù)采用分頁緩存機制,從而提升了系統(tǒng)的整體吞吐量。不同于之前分配各個不同大小的連續(xù)內(nèi)存塊的做法,分塊KV緩存中的底層存儲是固定大小的塊(也稱為頁面)。
分塊KV緩存通過消除KV緩存引起的內(nèi)存碎片化,增加了潛在的序列并發(fā)量,從而增加了系統(tǒng)吞吐量。非連續(xù)KV緩存也被HuggingFace TGI和NVIDIA TensorRT-LLM等框架所實現(xiàn)。
連續(xù)批處理
過去,動態(tài)批處理(服務(wù)器等待多個請求以同步處理)被用來提高GPU利用率。然而,這種方法有缺點,因為它通常需要將輸入填充到相同長度或使系統(tǒng)等待以構(gòu)建更大的批次(batch)。
近期大型語言模型(LLM)推理和服務(wù)的優(yōu)化一直專注于細粒度調(diào)度和優(yōu)化內(nèi)存效率。例如,Orca提出了迭代級調(diào)度(也稱為連續(xù)批處理),它在模型的每次前向傳遞時作出獨特的調(diào)度決策。
這允許請求根據(jù)需要加入/離開批次,從而消除了填充請求的需要,提高了總體吞吐量。除了Orca,NVIDIA TRT-LLM、HuggingFace TGI和vLLM也實現(xiàn)了連續(xù)批處理。
在當前系統(tǒng)中,有兩種主要方法來實現(xiàn)連續(xù)批處理。
- 在TGI和vLLM中,生成階段被搶占以執(zhí)行提示處理(在TGI中稱為填充)然后繼續(xù)生成。
- 在Orca中,這些階段不被區(qū)分;相反,只要總序列數(shù)沒有達到固定限制,Orca就會將提示加入正在運行的批次中。這兩種方法都在不同程度上需要暫停生成以處理長提示。
為了解決這些缺點,我們提出了一種新穎的提示和生成組合策略,動態(tài) SplitFuse。
動態(tài)SplitFuse:一種新穎的提示和生成組合策略
類似于現(xiàn)有的框架如TRT-LLM、TGI和vLLM,DeepSpeed-FastGen的目標是利用連續(xù)批處理和非連續(xù)KV緩存技術(shù),以提升數(shù)據(jù)中心服務(wù)大型語言模型(LLM)的硬件利用率和響應速度。
為了實現(xiàn)更高的性能,DeepSpeed-FastGen提出了SplitFuse技術(shù),它利用動態(tài)提示和生成分解,統(tǒng)一來進一步改善連續(xù)批處理和系統(tǒng)吞吐量。
A. 三個性能見解
在描述動態(tài)SplitFuse之前,我們回答三個關(guān)鍵的性能問題,這些問題解釋了SplitFuse背后的邏輯。
1. 哪些因素影響單個LLM的前向傳遞?
為了有效地調(diào)度,我們必須首先了解調(diào)度過程中應考慮的獨立變量有哪些。
我們觀察到,在前向傳遞中序列的組成(序列中的批次大小)對性能的影響可以忽略不計。
這意味著我們可以圍繞單一變量——即前向傳遞中的token數(shù)量——構(gòu)建一個高效的調(diào)度器。
2. 模型的吞吐量與前向傳遞中token數(shù)量的關(guān)系如何?
一個LLM有兩個關(guān)鍵的運行區(qū)間,并且過渡相對陡峭。
當token數(shù)量較少時,GPU的瓶頸是從內(nèi)存中讀取模型,因此吞吐量會隨著token數(shù)量的增加而上升,而當token數(shù)量很多時,模型的吞吐量受GPU計算能力限制,吞吐量近乎恒定。
因此如果我們能將所有前向傳遞都保持在吞吐量飽和區(qū)間,則模型運行效率最高。
3. 如何在多個前向傳遞中調(diào)度一組token?
我們在上圖中觀察到,對于對齊良好的輸入,token吞吐量曲線是凹的,這意味著第二導數(shù)必定小于或等于0。
設(shè)f(x)為給定模型的延遲至吞吐量的凹函數(shù)。則對于凹函數(shù)f(x),以下關(guān)系成立:
這表明,對于給定的2x個總token來說,最大化吞吐量的方式是將它們均勻分割到兩個批次之間。
更一般地說,在一個系統(tǒng)中,如果要在F個前向傳遞中處理P個token,最理想的分區(qū)方案是均勻分配它們。
B. 動態(tài)分割融合(Dynamic SplitFuse)
動態(tài)分割融合是一種用于提示處理和token生成的新型token組成策略。
DeepSpeed-FastGen利用動態(tài)分割融合策略,通過從提示中取出部分token并與生成過程相結(jié)合,使得模型可以保持一致的前向傳遞大?。╢orward size)。
具體來說,動態(tài)分割融合執(zhí)行兩個關(guān)鍵行為:
將長提示分解成更小的塊,并在多個前向傳遞(迭代)中進行調(diào)度,只有在最后一個傳遞中才執(zhí)行生成。短提示將被組合以精確填滿目標token預算。
即使是短提示也可能被分解,以確保預算被精確滿足,前向大?。╢orward sizes)保持良好對齊。
動態(tài)分割融合(Dynamic SplitFuse)提升了以下性能指標:
- 更好的響應性:
由于長提示不再需要極長的前向傳遞來處理,模型將提供更低的客戶端延遲。在同一時間窗口內(nèi)執(zhí)行的前向傳遞更多。
- 更高的效率:
短提示的融合到更大的token預算使模型能夠持續(xù)運行在高吞吐量狀態(tài)。
- 更低的波動和更好的一致性:
由于前向傳遞的大小一致,且前向傳遞大小是性能的主要決定因素,每個前向傳遞的延遲比其他系統(tǒng)更加一致。
生成頻率也是如此,因為DeepSpeed-FastGen不需要像其他先前的系統(tǒng)那樣搶占或長時間運行提示,因此延遲會更低。
因此,與現(xiàn)有最先進的服務(wù)系統(tǒng)相比,DeepSpeed-FastGen將以允許快速、持續(xù)生成的速率消耗來自提示的token,同時向系統(tǒng)添加token,提高系統(tǒng)利用率,提供更低的延遲和更高的吞吐量流式生成給所有客戶端。
圖 1:連續(xù)批處理策略的示意圖。每個塊顯示一個前向傳遞的執(zhí)行。箭頭表示前向傳遞有一或多個token生成。vLLM在一個前向傳遞中要么生成token要么處理提示;token生成搶占提示處理。Orca在生成過程中以完整長度處理提示。DeepSpeed-FastGen動態(tài)分割融合則執(zhí)行固定大小批次的動態(tài)組合,包括生成和提示token
性能評估
DeepSpeed-FastGen利用分塊KV緩存和動態(tài)分割融合連續(xù)批處理,提供了最先進的LLM服務(wù)性能。
我們以下述的基準測試方法對DeepSpeed-FastGen和vLLM在一系列模型和硬件配置上進行評估。
A. 基準測試方法論
我們采用兩種主要的定量方法來衡量性能。
吞吐量-延遲曲線:生產(chǎn)環(huán)境的兩個關(guān)鍵指標是吞吐量(以每秒請求計)和延遲(每個請求的響應性)。
為了衡量這一點,我們模擬了多個客戶端(數(shù)量從1到32不等)同時向服務(wù)器發(fā)送請求(總計512個)的情況。每個請求的結(jié)果延遲在端點測量,吞吐量通過完成實驗的端到端時間來測量。
有效吞吐量:諸如聊天應用程序之類的交互式應用程序可能有比上述指標(如端到端延遲)更嚴格和復雜的要求。
以越來越受歡迎的聊天應用為例:
用戶通過發(fā)送提示(輸入)來開始對話。系統(tǒng)處理提示并返回第一個token。隨著生成的進行,后續(xù)token被流式傳輸給用戶。
在這個過程的每個階段,系統(tǒng)都有可能提供不利的用戶體驗;例如,第一個token到達得太慢;或生成似乎停止了一段時間。
我們提出了一個考慮這兩個維度的SLA框架。
由于提示和生成文本的長度差異很大,影響計算成本,因此設(shè)定同一個SLA值對于吞吐量和延遲是不切實際的。
因此,我們將提示延遲的SLA定義為「|提示中的token|/512」秒(=512 token/秒)。
此外,考慮到人類的閱讀速度,我們將生成延遲的SLA設(shè)置在指數(shù)移動平均(EMA)上為2、4或6 token/秒。能夠達到這些SLA的請求被認為是成功的,這些成功請求的吞吐量被稱為有效吞吐量。
我們通過在NVIDIA A100、H100和A6000上運行Llama-2 7B、Llama-2 13B和Llama-2 70B對vLLM和DeepSpeed-FastGen進行了評估。
B. 吞吐量-延遲分析
在這個實驗中,DeepSpeed-FastGen在吞吐量和延遲方面都優(yōu)于vLLM,在相同的延遲下DeepSpeed-FastGen的吞吐量更大;在相同的吞吐量下DeepSpeed-FastGen的響應延遲更小。
如圖2所示,在Llama-2 70B運行于4個A100-80GB的情況下,DeepSpeed-FastGen展示了高達2倍的吞吐量(1.36 rps對比0.67 rps)在相同的延遲(9 秒)下;或高達50%的延遲減少(7秒對比14秒)同時實現(xiàn)相同的吞吐量(1.2 rps)。
圖 2:使用Llama 2 70B進行文本生成的吞吐量和延遲(使用4個A100-80GB GPU的張量并行)。提示和生成長度遵循正態(tài)分布,平均值分別為1200/2600和128/60,方差為30%
評估Llama-2 13B時DeepSpeed-FastGen也呈現(xiàn)了這些趨勢,如圖3所示。
圖 3:使用Llama 2 13B進行文本生成的吞吐量和延遲(A100-80GB GPU,無張量并行)。提示和生成長度遵循正態(tài)分布,平均值分別為1200/2600和60/128,并且有30%的方差
C. 有效吞吐量分析
在考慮了首個token的延遲和生成速率的有效吞吐量分析下,DeepSpeed-FastGen提供的吞吐量比vLLM高出多達2.3倍。
圖4展示了DeepSpeed-FastGen和vLLM的有效吞吐量的比較分析。每個繪制的點表示從特定數(shù)量的客戶端得出的有效吞吐量。
圖 4:DeepSpeed-FastGen和vLLM的有效吞吐量(Llama 2 70B/A100-80GB使用張量并行在4個A100-80GB GPU上。提示和生成長度遵循正態(tài)分布,平均值分別為2600和60,并且有30%的方差)
當我們擴大客戶端數(shù)量時,我們最初觀察到有效吞吐量的增加。然而,當客戶端數(shù)量接近系統(tǒng)容量時,延遲也顯著增加,導致許多請求未能滿足SLA。
因此,有效吞吐量將在某個點上飽和或減少。從可用性角度來看,達到最大有效吞吐量所需的客戶端數(shù)量并不特別重要;線條的最高點是最優(yōu)的服務(wù)點。
當vLLM搶占正在進行的先前請求的生成時,生成延遲會明顯增加。這導致vLLM的有效吞吐量看起來低于其直接測量的吞吐量。
在vLLM的峰值時,有效吞吐量為0.63查詢/秒,大約28%的請求未能滿足4 token/秒的SLA。在相同的SLA下,DeepSpeed-FastGen達到了1.42查詢/秒(不到1%的請求未能滿足SLA),這是vLLM的2.3倍。
D. token級時間分析
圖5顯示了生成過程的P50、P90和P95延遲。vLLM和DeepSpeed-FastGen展示了類似的P50延遲,但vLLM的P90和P95延遲顯著更高。
這種差異是由于vLLM在搶占正在進行的生成以處理新提示時,生成延遲出現(xiàn)顯著增加所導致的。
相比之下,DeepSpeed-FastGen通常會同時處理之前請求的提示和生成,導致生成延遲更加一致。
圖 5:使用張量并行在4個A100-80GB GPU上的Llama 2 70B/A100-80GB的每token生成延遲,16客戶端。提示和生成長度遵循正態(tài)分布,平均值分別為2600和128,并且有30%的方差。
E. 使用負載均衡的可擴展性
DeepSpeed-FastGen提供了副本級負載均衡,可以將請求均勻分布在多個服務(wù)器上,讓您輕松擴展應用程序。
圖6展示了DeepSpeed-FastGen在使用負載均衡器和最多16個副本時的可擴展性。請注意,我們使用了4個A100 GPU來計算每個Llama 2 70B模型。
圖 6:使用負載均衡功能的可擴展性。提示和生成長度遵循正態(tài)分布,平均值分別為2600和60,并且有30%的方差
結(jié)果展示了DeepSpeed-FastGen幾乎完美的可擴展性。
單個副本時DeepSpeed-FastGen的吞吐量為1.46查詢/秒,而16個副本的吞吐量達到了23.7查詢/秒,與單個副本相比標志著線性的16倍增長。
F. 其他硬件平臺
除了對A100的深入分析,我們還提供了H100和A6000的基準測試結(jié)果。在A6000和H100上觀察到的性能趨勢與A100相同。
圖 7:使用8個H100 GPU的Llama 2 70B的吞吐量-延遲曲線和有效吞吐量。提示和生成長度遵循正態(tài)分布,平均值分別為2600和60,并且有30%的方差
圖 8:使用A6000的Llama 2 7B的吞吐量-延遲曲線和有效吞吐量。提示和生成長度遵循正態(tài)分布,平均值分別為2600和60,并且有30%的方差
軟件實現(xiàn)與使用指南
DeepSpeed-FastGen是DeepSpeed-MII和DeepSpeed-Inference的協(xié)同組合,如下圖所示。
兩個軟件包共同提供了系統(tǒng)的各個組成部分,包括前端API、用于使用動態(tài)SplitFuse調(diào)度批次的主機和設(shè)備基礎(chǔ)設(shè)施、優(yōu)化的內(nèi)核實現(xiàn),以及構(gòu)建新模型實現(xiàn)的工具。
alpha版DeepSpeed-FastGen最快的入門方式是:pip install deepspeed-mii
A. 支持的模型
在DeepSpeed-FastGen的當前alpha版本中,我們目前支持以下模型架構(gòu):LLaMA和LLaMA-2MistralOPT
所有當前模型都利用了后端的HuggingFace API來提供模型權(quán)重和模型對應的分詞器。
我們計劃在最初發(fā)布后的幾周和幾個月內(nèi)添加更多模型。如果您希望支持特定的模型架構(gòu),請?zhí)峤粏栴}來讓我們知道。
B. 部署選項
以下所有示例均可在DeepSpeedExamples中運行。安裝后,您有兩種部署方式:交互式非持久管道或持久化服務(wù)部署:
非持久管道
非持久管道部署是快速入門的好方法,只需幾行代碼即可完成。非持久模型只在您運行的python腳本期間存在,適用于臨時交互式會話。
from mii import pipeline
pipe = pipeline("mistralai/Mistral-7B-v0.1")
output = pipe(["Hello, my name is", "DeepSpeed is"], max_new_tokens=128)
print(output)
持久部署
持久部署非常適合用于長時間運行和生產(chǎn)的應用。持久部署使用了輕量級的GRPC服務(wù)器,可以使用以下兩行代碼創(chuàng)建:
import mii
mii.serve("mistralai/Mistral-7B-v0.1")
上述服務(wù)器可以同時被多個客戶端查詢,這要歸功于DeepSpeed-MII內(nèi)置的負載平衡器。創(chuàng)建客戶端也只需要兩行代碼:
client = mii.client("mistralai/Mistral-7B-v0.1")
output = client.generate("Deepspeed is", max_new_tokens=128)
print(output)
持久部署可以在不再需要時終止:
client.terminate_server()
C. 高級安裝方式
為了使用方便并顯著減少許多其他框架所需的冗長編譯時間,我們通過名為DeepSpeed-Kernels的新庫分發(fā)了覆蓋我們大部分自定義內(nèi)核的預編譯 Python wheel。
我們發(fā)現(xiàn)這個庫在環(huán)境中非常便攜,只要這些環(huán)境具有NVIDIA GPU計算能力 8.0+(Ampere+)、CUDA 11.6+和Ubuntu 20+。
在大多數(shù)情況下,您甚至不需要知道這個庫的存在,因為它是DeepSpeed-MII的依賴項,并將自動與之一起安裝。然而,如果您因任何原因需要手動編譯我們的內(nèi)核,請參閱我們的高級安裝文檔。
轉(zhuǎn)載自微軟DeepSpeed組官方知乎賬號:zhihu.com/people/deepspeed