?揭秘NVIDIA大模型推理框架:TensorRT-LLM
一、TensorRT-LLM 的產(chǎn)品定位
TensorRT-LLM 是 NVIDIA 用于做 LLM(Large Language Model)的可擴(kuò)展推理方案。該方案是基于 TensorRT 深度學(xué)習(xí)編譯框架來構(gòu)建、編譯并執(zhí)行計(jì)算圖,并借鑒了許多 FastTransformer 中高效的 Kernels 實(shí)現(xiàn),然后利用 NCCL 完成設(shè)備之間的通訊。考慮到技術(shù)的發(fā)展和需求的差異,開發(fā)者還可以定制算子來滿足定制需求,比如基于 cutlass 開發(fā)定制 GEMM。TensorRT-LLM 是一款致力于提供高性能并不斷完善其實(shí)用性的 NVIDIA 官方推理方案。

TensorRT-LLM 已經(jīng)在 GitHub 上開源,主要分為兩個(gè)分支,即 Release branch 和 Dev branch。其中 Release branch 每個(gè)月更新一次,而在 Dev branch 中則會(huì)較為頻繁地更新來自官方或社區(qū)中的功能,方便開發(fā)者體驗(yàn)、評(píng)估最新功能。下圖展示了 TensorRT-LLM 的框架結(jié)構(gòu),其中除了綠色 TensorRT 編譯部分和一些涉及硬件信息的 kernels 外,其他部分都是開源的。

TensorRT-LLM 還提供了類似于 Pytorch 的 API 來降低開發(fā)者的學(xué)習(xí)成本,并提供了許多預(yù)定義好的模型供用戶使用。

考慮到大語言模型比較大,有可能單卡放不下,需要多卡甚至多機(jī)推理,因此 TensorRT-LLM 還提供了 Tensor Parallelism 和 Pipeline Parallelism 兩種并行機(jī)制來支持多卡或多機(jī)推理。

二、TensorRT-LLM 的重要特性
TensorRT-LLM 的重要特性之一就是豐富的模型支持。TensorRT-LLM 對(duì)主流大語言模型都提供了支持,比如 Qwen(千問)就是由開發(fā)者完成的模型適配,并已經(jīng)納入官方支持。用戶可以很容易地基于這些預(yù)定義的模型做擴(kuò)展或定制。其二就是低精度推理,TensorRT-LLM 默認(rèn)采用 FP16/BF16 的精度推理,并且可以利用業(yè)界的量化方法,使用硬件吞吐更高的低精度推理進(jìn)一步推升推理性能。

另外一個(gè)特性就是 FMHA(fused multi-head attention) kernel 的實(shí)現(xiàn)。由于 Transformer 中最為耗時(shí)的部分是 self-attention 的計(jì)算,因此官方設(shè)計(jì)了 FMHA 來優(yōu)化 self-attention 的計(jì)算,并提供了累加器分別為 fp16 和 fp32 不同的版本。另外,除了速度上的提升外,對(duì)內(nèi)存的占用也大大降低。我們還提供了基于 flash attention 的實(shí)現(xiàn),可以將 sequence-length 擴(kuò)展到任意長(zhǎng)度。

如下為 FMHA 的詳細(xì)信息,其中 MQA 為 Multi Query Attention,GQA 為 Group Query Attention。

另外一個(gè) Kernel 是 MMHA(Masked Multi-Head Attention)。FMHA 主要用在 context phase 階段的計(jì)算,而 MMHA 主要提供 generation phase 階段 attention 的加速,并提供了 Volta 和之后架構(gòu)的支持。相比 FastTransformer 的實(shí)現(xiàn),TensorRT-LLM 有進(jìn)一步優(yōu)化,性能提升高達(dá) 2x。

另外一個(gè)重要特性是量化技術(shù),以更低精度的方式實(shí)現(xiàn)推理加速。常用量化方式主要分為 PTQ(Post Training Quantization)和 QAT(Quantization-aware Training),對(duì)于 TensorRT-LLM 而言,這兩種量化方式的推理邏輯是相同的。對(duì)于 LLM 量化技術(shù),一個(gè)重要的特點(diǎn)是算法設(shè)計(jì)和工程實(shí)現(xiàn)的 co-design,即對(duì)應(yīng)量化方法設(shè)計(jì)之初,就要考慮硬件的特性。否則,有可能達(dá)不到預(yù)期的推理速度提升。

TensorRT 中 PTQ 量化步驟一般分為如下幾步,首先對(duì)模型做量化,然后對(duì)權(quán)重和模型轉(zhuǎn)化成 TensorRT-LLM 的表示。對(duì)于一些定制化的操作,還需要用戶自己編寫 kernels。常用的 PTQ 量化方法包括 INT8 weight-only、SmoothQuant、GPTQ 和 AWQ,這些方法都是典型的 co-design 的方法。

INT8 weight-only 直接把權(quán)重量化到 INT8,但是激活值還是保持為 FP16。該方法的好處就是模型存儲(chǔ)2x減小,加載 weights 的存儲(chǔ)帶寬減半,達(dá)到了提升推理性能的目的。這種方式業(yè)界稱作 W8A16,即權(quán)重為 INT8,激活值為 FP16/BF16——以 INT8 精度存儲(chǔ),以 FP16/BF16 格式計(jì)算。該方法直觀,不改變 weights,容易實(shí)現(xiàn),具有較好的泛化性能。

第二個(gè)量化方法是 SmoothQuant,該方法是 NVIDIA 和社區(qū)聯(lián)合設(shè)計(jì)的。它觀察到權(quán)重通常服從高斯分布,容易量化,但是激活值存在離群點(diǎn),量化比特位利用不高。

SmoothQuant 通過先對(duì)激活值做平滑操作即除以一個(gè)scale將對(duì)應(yīng)分布進(jìn)行壓縮,同時(shí)為了保證等價(jià)性,需要對(duì)權(quán)重乘以相同的 scale。之后,權(quán)重和激活都可以量化。對(duì)應(yīng)的存儲(chǔ)和計(jì)算精度都可以是 INT8 或者 FP8,可以利用 INT8 或者 FP8 的 TensorCore 進(jìn)行計(jì)算。在實(shí)現(xiàn)細(xì)節(jié)上,權(quán)重支持 Per-tensor 和 Per-channel 的量化,激活值支持 Per-tensor 和 Per-token 的量化。

第三個(gè)量化方法是 GPTQ,一種逐層量化的方法,通過最小化重構(gòu)損失來實(shí)現(xiàn)。GPTQ 屬于 weight-only 的方式,計(jì)算采用 FP16 的數(shù)據(jù)格式。該方法用在量化大模型時(shí),由于量化本身開銷就比較大,所以作者設(shè)計(jì)了一些 trick 來降低量化本身的開銷,比如 Lazy batch-updates 和以相同順序量化所有行的權(quán)重。GPTQ 還可以與其他方法結(jié)合使用如 grouping 策略。并且,針對(duì)不同的情況,TensorRT-LLM 提供了不同的實(shí)現(xiàn)優(yōu)化性能。具體地,對(duì) batch size 較小的情況,用 cuda core 實(shí)現(xiàn);相對(duì)地,batch size 較大時(shí),采用 tensor core 實(shí)現(xiàn)。

第四種量化方式是 AWQ。該方法認(rèn)為不是所有權(quán)重都是同等重要的,其中只有 0.1%-1% 的權(quán)重(salient weights)對(duì)模型精度貢獻(xiàn)更大,并且這些權(quán)重取決于激活值分布而不是權(quán)重分布。該方法的量化過程類似于 SmoothQuant,差異主要在于 scale 是基于激活值分布計(jì)算得到的。


除了量化方式之外,TensorRT-LLM 另外一個(gè)提升性能的方式是利用多機(jī)多卡推理。在一些場(chǎng)景中,大模型過大無法放在單個(gè) GPU 上推理,或者可以放下但是影響了計(jì)算效率,都需要多卡或者多機(jī)進(jìn)行推理。

TensorRT-LLM 目前提供了兩種并行策略,Tensor Parallelism 和 Pipeline Parallelism。TP 是垂直地分割模型然后將各個(gè)部分置于不同的設(shè)備上,這樣會(huì)引入設(shè)備之間頻繁的數(shù)據(jù)通訊,一般用于設(shè)備之間有高度互聯(lián)的場(chǎng)景,如 NVLINK。另一種分割方式是橫向切分,此時(shí)只有一個(gè)橫前面,對(duì)應(yīng)通信方式是點(diǎn)對(duì)點(diǎn)的通信,適合于設(shè)備通信帶寬較弱的場(chǎng)景。

最后一個(gè)要強(qiáng)調(diào)的特性是 In-flight batching。Batching 是提高推理性能一個(gè)比較常用的做法,但在 LLM 推理場(chǎng)景中,一個(gè) batch 中每個(gè) sample/request 的輸出長(zhǎng)度是無法預(yù)測(cè)的。如果按照靜態(tài)batching的方法,一個(gè)batch的時(shí)延取決于 sample/request 中輸出最長(zhǎng)的那個(gè)。因此,雖然輸出較短的 sample/request 已經(jīng)結(jié)束,但是并未釋放計(jì)算資源,其時(shí)延與輸出最長(zhǎng)的那個(gè) sample/request 時(shí)延相同。In-flight batching 的做法是在已經(jīng)結(jié)束的 sample/request 處插入新的 sample/request。這樣,不但減少了單個(gè) sample/request 的延時(shí),避免了資源浪費(fèi)問題,同時(shí)也提升了整個(gè)系統(tǒng)的吞吐。

三、TensorRT-LLM 的使用流程
TensorRT-LLM 與 TensorRT的 使用方法類似,首先需要獲得一個(gè)預(yù)訓(xùn)練好的模型,然后利用 TensorRT-LLM 提供的 API 對(duì)模型計(jì)算圖進(jìn)行改寫和重建,接著用 TensorRT 進(jìn)行編譯優(yōu)化,然后保存為序列化的 engine 進(jìn)行推理部署。

以 Llama 為例,首先安裝 TensorRT-LLM,然后下載預(yù)訓(xùn)練模型,接著利用 TensorRT-LLM 對(duì)模型進(jìn)行編譯,最后進(jìn)行推理。

對(duì)于模型推理的調(diào)試,TensorRT-LLM 的調(diào)試方式與 TensorRT 一致。由于深度學(xué)習(xí)編譯器,即 TensorRT,提供的優(yōu)化之一是 layer 融合。因此,如果要輸出某層的結(jié)果,就需要將對(duì)應(yīng)層標(biāo)記為輸出層,以防止被編譯器優(yōu)化掉,然后與 baseline 進(jìn)行對(duì)比分析。同時(shí),每標(biāo)記一個(gè)新的輸出層,都要重新編譯 TensorRT 的 engine。

對(duì)于自定義的層,TensorRT-LLM 提供了許多 Pytorch-like 算子幫助用戶實(shí)現(xiàn)功能而不必自己編寫 kernel。如樣例所示,利用 TensorRT-LLM 提供的 API 實(shí)現(xiàn)了 rms norm 的邏輯,TensorRT 會(huì)自動(dòng)生成 GPU 上對(duì)應(yīng)的執(zhí)行代碼。

如果用戶有更高的性能需求或者 TensorRT-LLM 并未提供實(shí)現(xiàn)相應(yīng)功能的 building blocks,此時(shí)需要用戶自定義 kernel,并封裝為 plugin 供 TensorRT-LLM 使用。示例代碼是將 SmoothQuant 定制 GEMM 實(shí)現(xiàn)并封裝成 plugin 后,供 TensorRT-LLM 調(diào)用的示例代碼。

四、TensorRT-LLM 的推理性能
關(guān)于性能、配置等細(xì)節(jié)都可以在官網(wǎng)看到,在此不做詳細(xì)介紹。該產(chǎn)品從立項(xiàng)開始一直與國(guó)內(nèi)很多大廠都有合作。通過反饋,一般情況下,TensorRT-LLM 從性能角度來說是當(dāng)前最好的方案。由于技術(shù)迭代、優(yōu)化手段、系統(tǒng)優(yōu)化等眾多因素會(huì)影響性能,并且變化非???,這里就不詳細(xì)展開介紹 TensorRT-LLM 的性能數(shù)據(jù)。大家如果有興趣,可以去官方了解細(xì)節(jié),這些性能都是可復(fù)現(xiàn)的。




值得一提的是,TensorRT-LLM 跟自己之前的版本比,性能有持續(xù)地提升。如上圖所示,在 FP16 基礎(chǔ)上,采用了 KVQuant 后,速度一致的情況下降低了顯存的使用量。使用 INT8,可以看到明顯的吞吐的提升,同時(shí)顯存用量進(jìn)一步降低??梢?,隨著 TensorRT-LLM 優(yōu)化技術(shù)的持續(xù)演進(jìn),性能會(huì)有持續(xù)地提升。這個(gè)趨勢(shì)會(huì)持續(xù)保持。
五、TensorRT-LLM 的未來展望
LLM 是一個(gè)推理成本很高、成本敏感的場(chǎng)景。我們認(rèn)為,為了實(shí)現(xiàn)下一個(gè)百倍的加速效果,需要算法和硬件的共同迭代,通過軟硬件之間 co-design 來達(dá)到這個(gè)目標(biāo)。硬件提供更低精度的量化,而軟件角度則利用優(yōu)化量化、網(wǎng)絡(luò)剪枝等算法,來進(jìn)一步提升性能。

TensorRT-LLM,將來 NVIDIA 會(huì)持續(xù)致力于提升 TensorRT-LLM 的性能。同時(shí)通過開源,收集反饋和意見,提高它的易用性。另外,圍繞易用性,會(huì)開發(fā)、開源更多應(yīng)用工具,如 Model zone 或者量化工具等,完善與主流框架的兼容性,提供從訓(xùn)練到推理和部署端到端的解決方案。

六、問答環(huán)節(jié)
Q1:是否每一次計(jì)算輸出都要反量化?做量化出現(xiàn)精度溢出怎么辦?
A1:目前 TensorRT-LLM 提供了兩類方法,即 FP8 和剛才提到的 INT4/INT8 量化方法。低精度如果 INT8 做 GEMM 時(shí),累加器會(huì)采用高精度數(shù)據(jù)類型,如 fp16,甚至 fp32 以防止 overflow。關(guān)于反量化,以 fp8 量化為例,TensorRT-LLM 優(yōu)化計(jì)算圖時(shí),可能動(dòng)自動(dòng)移動(dòng)反量化結(jié)點(diǎn),合并到其它的操作中達(dá)到優(yōu)化目的。但對(duì)于前面介紹的 GPTQ 和 QAT,目前是通過硬編碼寫在 kernel 中,沒有統(tǒng)一量化或反量化節(jié)點(diǎn)的處理。
Q2:目前是針對(duì)具體模型專門做反量化嗎?
A2:目前的量化的確是這樣,針對(duì)不同的模型做支持。我們有計(jì)劃做一個(gè)更干凈的api或者通過配置項(xiàng)的方式來統(tǒng)一支持模型的量化。
Q3:針對(duì)最佳實(shí)踐,是直接使用 TensorRT-LLM 還是與 Triton Inference Server 結(jié)合在一起使用?如果結(jié)合使用是否會(huì)有特性上的缺失?
A3:因?yàn)橐恍┕δ芪撮_源,如果是自己的 serving 需要做適配工作,如果是 triton 則是一套完整的方案。
Q4:對(duì)于量化校準(zhǔn)有幾種量化方法,加速比如何?這幾種量化方案效果損失有幾個(gè)點(diǎn)?In-flight branching 中每個(gè) example 的輸出長(zhǎng)度是不知道的,如何做動(dòng)態(tài)的 batching?
A4:關(guān)于量化性能可以私下聊,關(guān)于效果,我們只做了基本的驗(yàn)證,確保實(shí)現(xiàn)的 kernel 沒問題,并不能保證所有量化算法在實(shí)際業(yè)務(wù)中的結(jié)果,因?yàn)檫€有些無法控制的因素,比如量化用到的數(shù)據(jù)集及影響。關(guān)于 in-flight batching,是指在 runtime 的時(shí)候去檢測(cè)、判斷某個(gè) sample/request 的輸出是否結(jié)束。如果是,再將其它到達(dá)的 requests 插進(jìn)來,TensorRT-LLM 不會(huì)也不能預(yù)告預(yù)測(cè)輸出的長(zhǎng)度。
Q5:In-flight branching 的 C++ 接口和 python 接口是否會(huì)保持一致?TensorRT-LLM 安裝成本高,今后是否有改進(jìn)計(jì)劃?TensorRT-LLM 會(huì)和 VLLM 發(fā)展角度有不同嗎?
A5:我們會(huì)盡量提供 c++ runtime 和 python runtime 一致的接口,已經(jīng)在規(guī)劃當(dāng)中。之前團(tuán)隊(duì)的重點(diǎn)在提升性能、完善功能上,以后在易用性方面也會(huì)不斷改善。這里不好直接跟 vllm 的比較,但是 NVIDIA 會(huì)持續(xù)加大在 TensorRT-LLM 開發(fā)、社區(qū)和客戶支持的投入,為業(yè)界提供最好的 LLM 推理方案。





































