優(yōu)與部署關(guān)鍵實(shí)踐:從指標(biāo)到實(shí)戰(zhàn))
1. 先搞清楚推理性能調(diào)優(yōu)到底在調(diào)什么做AI模型部署的同學(xué)應(yīng)該都有同感模型訓(xùn)練完了只是第一步真正讓人頭疼的是后面那句“上線(xiàn)跑一下”。訓(xùn)練時(shí)你關(guān)心loss降沒(méi)降、收斂快不快可一旦進(jìn)入推理階段畫(huà)風(fēng)就全變了——延遲、吞吐、顯存占用、首token耗時(shí)、并發(fā)能力每一個(gè)指標(biāo)都有可能成為壓垮線(xiàn)上服務(wù)的最后一根稻草。我見(jiàn)過(guò)不少團(tuán)隊(duì)把大量精力花在訓(xùn)練調(diào)參上結(jié)果模型一到推理階段就各種翻車(chē)GPU利用率上不去、請(qǐng)求一多就超時(shí)、顯存莫名其妙OOM?;仡^復(fù)盤(pán)問(wèn)題往往出在“不知道推理性能的瓶頸到底在哪”這件事上。所以這篇文章想認(rèn)真聊一聊AI模型推理性能調(diào)優(yōu)與部署建議把我在實(shí)際項(xiàng)目中踩過(guò)的坑、驗(yàn)證過(guò)的方法、以及一些可以直接抄作業(yè)的配置方案分享出來(lái)。先給這篇文章定個(gè)位如果你正準(zhǔn)備把訓(xùn)練好的模型部署成線(xiàn)上服務(wù)或者已經(jīng)在部署但性能不理想這篇文章值得你從頭看到尾。內(nèi)容覆蓋推理性能指標(biāo)拆解、常見(jiàn)瓶頸定位、模型優(yōu)化手段、部署架構(gòu)選擇、運(yùn)行時(shí)參數(shù)配置、實(shí)測(cè)調(diào)優(yōu)過(guò)程以及高頻故障的排查思路。我會(huì)盡量用實(shí)際場(chǎng)景說(shuō)話(huà)而不是堆理論。注意文中的所有測(cè)試數(shù)據(jù)和配置參數(shù)都來(lái)自我本人在某公司內(nèi)部搭建的模擬項(xiàng)目X中的實(shí)操記錄硬件環(huán)境為單卡和雙卡兩種方案結(jié)論在同類(lèi)GPU上具備一定的參考價(jià)值但不同架構(gòu)、不同驅(qū)動(dòng)版本下結(jié)果會(huì)有差異建議以實(shí)測(cè)為準(zhǔn)。2. 推理性能的核心指標(biāo)與瓶頸拆解2.1 別只看單次延遲這些指標(biāo)同樣重要很多剛接觸部署的同學(xué)習(xí)慣拿“單次推理耗時(shí)”來(lái)衡量模型快不快但真實(shí)線(xiàn)上場(chǎng)景里單次推理耗時(shí)只是表象。舉個(gè)很簡(jiǎn)單的例子一個(gè)接口單次推理只要10ms但只能同時(shí)處理1個(gè)請(qǐng)求另一個(gè)接口單次推理要30ms卻能同時(shí)處理32個(gè)請(qǐng)求。在業(yè)務(wù)并發(fā)較高的時(shí)候后者的整體吞吐反而是前者的好幾倍用戶(hù)體驗(yàn)也好得多。推理性能調(diào)優(yōu)時(shí)我一般會(huì)同時(shí)盯住下面幾個(gè)核心指標(biāo)延遲Latency從請(qǐng)求發(fā)出到拿到完整響應(yīng)的時(shí)間細(xì)分下來(lái)還包括首token時(shí)間TTFT和每token生成時(shí)間TPOT。在線(xiàn)業(yè)務(wù)對(duì)延遲特別敏感比如對(duì)話(huà)類(lèi)場(chǎng)景首token超過(guò)3秒用戶(hù)基本就會(huì)覺(jué)得“卡了”。吞吐量Throughput單位時(shí)間內(nèi)能處理的請(qǐng)求數(shù)或token數(shù)。離線(xiàn)批處理場(chǎng)景更看重吞吐比如批量文檔解析、離線(xiàn)生成。GPU利用率這塊很多人會(huì)忽略。GPU利用率低往往意味著算子沒(méi)有充分利用硬件或者數(shù)據(jù)加載/預(yù)處理成了瓶頸。顯存占用模型權(quán)重、KV Cache、中間激活值、CUDA context加起來(lái)分分鐘能把顯存吃滿(mǎn)。并發(fā)能力服務(wù)在同一時(shí)刻能支撐的請(qǐng)求連接數(shù)直接決定你能扛多大的業(yè)務(wù)流量。表格整理一下方便對(duì)照?qǐng)鼍斑x指標(biāo)指標(biāo)適用場(chǎng)景主要瓶頸來(lái)源延遲含TTFT/TPOT在線(xiàn)對(duì)話(huà)、實(shí)時(shí)交互模型規(guī)模、解碼方式、算子效率吞吐量離線(xiàn)批處理、數(shù)據(jù)生產(chǎn)batch size、并發(fā)數(shù)、顯存帶寬GPU利用率所有場(chǎng)景數(shù)據(jù)加載、CPU預(yù)處理、算子調(diào)度顯存占用所有場(chǎng)景模型權(quán)重、KV Cache、中間激活并發(fā)能力高并發(fā)API服務(wù)框架線(xiàn)程模型、顯存容量、顯存管理策略2.2 推理瓶頸往往不在模型本身我做過(guò)的幾個(gè)調(diào)優(yōu)案例里印象最深刻的一個(gè)是模型本身算力占用不大但接口整體延遲高得離譜。排查到最后發(fā)現(xiàn)問(wèn)題出在輸入數(shù)據(jù)的預(yù)處理環(huán)節(jié)——每來(lái)一個(gè)請(qǐng)求服務(wù)端都要做一次圖像解碼、縮放、歸一化而這一步跑在CPU上且是串行執(zhí)行的。GPU在那閑著等數(shù)據(jù)CPU成了瓶頸整個(gè)鏈路就被拖慢了。這個(gè)案例很有代表性。推理性能調(diào)優(yōu)的第一步永遠(yuǎn)是先定位瓶頸而不是盲目上優(yōu)化手段。一般來(lái)說(shuō)瓶頸可能出現(xiàn)在以下幾個(gè)位置數(shù)據(jù)預(yù)處理/后處理CPU密集操作、編解碼耗時(shí)、數(shù)據(jù)格式轉(zhuǎn)換經(jīng)常被忽視。CPU與GPU之間的數(shù)據(jù)傳輸小批量請(qǐng)求頻繁拷貝數(shù)據(jù)PCIe傳輸耗時(shí)占比會(huì)非常高。模型計(jì)算本身算子實(shí)現(xiàn)低效、內(nèi)存訪(fǎng)問(wèn)模式不佳、圖優(yōu)化未開(kāi)啟。推理框架與調(diào)度線(xiàn)程數(shù)配置不當(dāng)、顯存分配策略不合理、動(dòng)態(tài)shape引起的重編譯。服務(wù)端網(wǎng)絡(luò)與IO請(qǐng)求排隊(duì)、連接池耗盡、序列化/反序列化開(kāi)銷(xiāo)。定位瓶頸有一個(gè)很樸素但有效的方法先把模型單獨(dú)拿出來(lái)做一條龍壓測(cè)逐步拆解每一段的耗時(shí)占比。比如你用profile工具看一遍時(shí)間線(xiàn)如果發(fā)現(xiàn)GPU kernel執(zhí)行只占了20%時(shí)間其余都在數(shù)據(jù)搬運(yùn)和CPU處理那砸再多GPU算力也白搭。2.3 用哪個(gè)指標(biāo)判斷優(yōu)化效果調(diào)優(yōu)過(guò)程中一定要先定好基準(zhǔn)。我推薦的做法是固定同一份測(cè)試數(shù)據(jù)集包含不同長(zhǎng)度的輸入固定batch size和并發(fā)數(shù)跑足夠多輪取p50/p99延遲同時(shí)記錄吞吐量。調(diào)優(yōu)前后對(duì)比這些數(shù)據(jù)而不是看單次運(yùn)氣好的結(jié)果。我自己做調(diào)優(yōu)時(shí)第一件事是在服務(wù)里埋好日志記錄每次請(qǐng)求的預(yù)處理耗時(shí)、排隊(duì)耗時(shí)、GPU kernel耗時(shí)、后處理耗時(shí)。后面所有的優(yōu)化動(dòng)作都能用數(shù)據(jù)說(shuō)話(huà)哪段耗時(shí)長(zhǎng)就去優(yōu)化哪段避免憑感覺(jué)調(diào)參。3. 模型層面的優(yōu)化從權(quán)重到算子的瘦身術(shù)3.1 模型量化性?xún)r(jià)比最高的第一刀模型量化是推理性能調(diào)優(yōu)里回報(bào)率最高的手段之一。原理很簡(jiǎn)單訓(xùn)練時(shí)模型權(quán)重通常用FP32或FP16存儲(chǔ)推理時(shí)其實(shí)沒(méi)必要保持這么高的精度把權(quán)重從FP32壓到FP16能直接減半顯存占用從FP16壓到INT8還能再減一半。代價(jià)是部分任務(wù)精度會(huì)有輕微下降。實(shí)際項(xiàng)目中大模型的KV Cache同樣會(huì)消耗大量顯存。KV Cache量化比如從FP16壓到INT8甚至INT4可以顯著提升并發(fā)能力因?yàn)橥瑯拥娘@存可以塞下更多請(qǐng)求的KV緩存。以我在模擬項(xiàng)目X里的一個(gè)7B模型為例權(quán)重從FP16切到INT8后單卡能處理的并發(fā)數(shù)從16提升到了28顯存占用降低了約45%。量化落地時(shí)有兩點(diǎn)值得特別注意不是所有算子都適合INT8量化。像LayerNorm、Softmax這類(lèi)對(duì)精度敏感的算子通常保持高精度量化主要集中在矩陣乘法和Embedding層。量化后的模型一定要做精度驗(yàn)證。用一小部分測(cè)試集對(duì)比量化前后輸出差異超過(guò)可接受閾值就需要回退部分層或者改用混合精度方案。表不同量化精度對(duì)顯存和速度的影響7B模型實(shí)測(cè)精度方案顯存占用相對(duì)吞吐提升精度損失FP32100%基準(zhǔn)1x無(wú)FP16/BF16約50%1.6x可忽略INT8約25%2.1x低需驗(yàn)證INT4約12.5%2.8x中需謹(jǐn)慎3.2 剪枝、蒸餾與模型結(jié)構(gòu)精簡(jiǎn)量化解決了存儲(chǔ)和計(jì)算強(qiáng)度的問(wèn)題但很多場(chǎng)景下還需要在結(jié)構(gòu)上做減法這就是模型剪枝和蒸餾的用武之地。模型剪枝的做法是去掉神經(jīng)網(wǎng)絡(luò)中對(duì)最終輸出貢獻(xiàn)較小的權(quán)重連接或甚至整個(gè)通道。當(dāng)前很多開(kāi)源模型本身就存在參數(shù)冗余剪掉一部分權(quán)重后精度下降有限但計(jì)算量會(huì)明顯減少。實(shí)際操作中結(jié)構(gòu)化剪枝比非結(jié)構(gòu)化剪枝更適合推理加速因?yàn)榉墙Y(jié)構(gòu)化剪枝產(chǎn)生的稀疏矩陣在GPU上不太好發(fā)揮除非硬件專(zhuān)門(mén)支持稀疏計(jì)算。模型蒸餾則是用一個(gè)大的教師模型去指導(dǎo)一個(gè)小學(xué)生模型學(xué)習(xí)讓小學(xué)生模型在參數(shù)量小很多的情況下盡量逼近教師模型的輸出。蒸餾后的模型精度可能略低但推理成本下降得非常明顯。我見(jiàn)過(guò)一個(gè)團(tuán)隊(duì)把BERT-base蒸餾成三層的小模型在線(xiàn)問(wèn)答場(chǎng)景延遲從80ms降到了20ms效果還能接受。選擇哪種手段要看業(yè)務(wù)容忍度毫秒級(jí)延遲敏感場(chǎng)景優(yōu)先上蒸餾和小規(guī)模模型別硬扛大模型。離線(xiàn)高吞吐場(chǎng)景可以用量化大批次的方案不用太在意單次延遲。精度要求極高場(chǎng)景盡量保留高精度權(quán)重只在KV Cache和激活值上做溫和量化。3.3 算子融合與計(jì)算圖優(yōu)化模型推理時(shí)計(jì)算圖里有很多細(xì)碎的算子頻繁在GPU上啟動(dòng)內(nèi)核kernel。每個(gè)kernel啟動(dòng)都有固定開(kāi)銷(xiāo)雖然單次只有幾十微秒但模型里有幾百上千個(gè)算子累積起來(lái)非??捎^(guān)。算子融合就是把相鄰的幾個(gè)算子合并成一個(gè)減少kernel啟動(dòng)次數(shù)同時(shí)減少中間結(jié)果的讀寫(xiě)。最經(jīng)典的融合案例是把“矩陣乘法偏置激活函數(shù)”融合成一個(gè)算子。比如Transformer里的Attention計(jì)算把QKV映射、縮放、Softmax、輸出映射等步驟盡量融合能省掉不少中間顯存讀寫(xiě)。PyTorch的torch.compile、TensorRT的圖優(yōu)化、ONNX Runtime的graph optimization都在做類(lèi)似的事。我用torch.compile試過(guò)一個(gè)12層的Transformer模型在A(yíng)100上推理延遲直接降了18%且無(wú)需改任何業(yè)務(wù)代碼。但要注意torch.compile首次運(yùn)行會(huì)有較長(zhǎng)的編譯時(shí)間服務(wù)上線(xiàn)時(shí)需要預(yù)熱的機(jī)制否則第一個(gè)請(qǐng)求會(huì)特別慢。4. 推理引擎與服務(wù)架構(gòu)的選型邏輯4.1 主流推理引擎橫向?qū)Ρ冗x推理引擎是部署中繞不開(kāi)的決策點(diǎn)。我用過(guò)的方案包括PyTorch原生、ONNX Runtime、TensorRT、以及專(zhuān)門(mén)的大模型推理框架如vLLM、TGI、SGLang。各有各的優(yōu)劣勢(shì)不存在萬(wàn)能選擇。引擎優(yōu)勢(shì)劣勢(shì)適用場(chǎng)景PyTorch原生上手快、兼容好、生態(tài)全性能一般、顯存占用高原型驗(yàn)證、快速迭代ONNX Runtime跨平臺(tái)、優(yōu)化好、部署輕部分算子轉(zhuǎn)換有坑通用模型上云、端側(cè)部署TensorRTGPU上性能極致構(gòu)建時(shí)間長(zhǎng)、硬件綁定生產(chǎn)環(huán)境、固定shape場(chǎng)景vLLM/TGI大模型專(zhuān)用、吞吐極高依賴(lài)特定GPU架構(gòu)對(duì)話(huà)、生成、大規(guī)模并發(fā)我比較推薦的生產(chǎn)路徑是先用PyTorch做功能和正確性驗(yàn)證再導(dǎo)出ONNX或直接用TensorRT做性能優(yōu)化。如果模型真的很小或者對(duì)上線(xiàn)速度要求極快PyTorch torch.compile也能撐一段時(shí)間但后續(xù)擴(kuò)容時(shí)大概率還得換引擎。4.2 單機(jī)多卡部署時(shí)的切分策略模型大到單卡放不下就得考慮多卡部署。常見(jiàn)的有張量并行、流水線(xiàn)并行和數(shù)據(jù)并行三者解決的問(wèn)題完全不同。張量并行把一層里的矩陣運(yùn)算切分到多張卡適合單層計(jì)算量極大、顯存放不下的場(chǎng)景。缺點(diǎn)是卡間通信頻繁對(duì)NVLink帶寬要求很高。流水線(xiàn)并行把模型按層切分成多段每張卡負(fù)責(zé)若干層數(shù)據(jù)按順序流過(guò)各卡。適合層數(shù)很深的模型但會(huì)出現(xiàn)流水線(xiàn)氣泡利用率不一定理想。數(shù)據(jù)并行每張卡都放完整模型各自處理不同batch的數(shù)據(jù)最后同步梯度或結(jié)果。推理時(shí)基本不涉及梯度同步所以擴(kuò)展性很好。實(shí)際部署中這些策略往往組合使用。大模型推理通常先用張量并行解決單卡放不下的問(wèn)題再用數(shù)據(jù)并行提升整體吞吐。通信開(kāi)銷(xiāo)是必須重點(diǎn)關(guān)注的如果卡間通信瓶頸嚴(yán)重多卡跑的收益可能還不如單卡。我做過(guò)一個(gè)對(duì)比7B模型在單卡上能跑但并發(fā)很低切成兩卡張量并行后單次延遲反而增加了約10%因?yàn)橥ㄐ砰_(kāi)銷(xiāo)抵消了算力收益。但對(duì)于更大規(guī)模的模型比如70B級(jí)不多卡部署根本跑不起來(lái)通信開(kāi)銷(xiāo)屬于必須付出的代價(jià)。4.3 動(dòng)態(tài)batch與Continuous Batching傳統(tǒng)的靜態(tài)batching是等一批請(qǐng)求湊夠數(shù)量再統(tǒng)一推理缺點(diǎn)是等待時(shí)間不可控而且batch里長(zhǎng)短不一的序列會(huì)互相拖累——都得按照最長(zhǎng)序列來(lái)算浪費(fèi)嚴(yán)重。大模型推理框架普遍引入了Continuous Batching連續(xù)批處理本質(zhì)是不再要求一個(gè)batch內(nèi)的請(qǐng)求同進(jìn)同出。某個(gè)請(qǐng)求生成完一個(gè)token就退出新請(qǐng)求隨時(shí)可以插入GPU始終在處理有效計(jì)算。這個(gè)機(jī)制對(duì)吞吐的提升非常明顯。以vLLM為例在同等資源下相同并發(fā)壓測(cè)中吞吐往往是Naive PyTorch實(shí)現(xiàn)的數(shù)倍。部署時(shí)如果想用上Continuous Batching就別自己造輪子了直接選vLLM或TGI這類(lèi)成熟框架內(nèi)部已經(jīng)實(shí)現(xiàn)了顯存管理和調(diào)度邏輯比手寫(xiě)高效得多。5. 運(yùn)行時(shí)參數(shù)調(diào)優(yōu)與關(guān)鍵配置5.1 顯存管理與緩存策略顯存是推理性能最大的物理約束之一。做大模型推理時(shí)顯存主要消耗在三塊模型權(quán)重、KV Cache、臨時(shí)激活值。模型權(quán)重基本固定臨時(shí)激活值隨batch和序列長(zhǎng)度波動(dòng)KV Cache則是優(yōu)化空間最大的部分。幾個(gè)實(shí)用的顯存優(yōu)化思路盡量復(fù)用顯存框架層面做好內(nèi)存池避免每次請(qǐng)求都重新分配。vLLM就是通過(guò)PagedAttention把KV Cache分塊管理大幅減少了碎片和浪費(fèi)。調(diào)整KV Cache策略將KV Cache從FP16降到INT8或INT4或者限制最大序列長(zhǎng)度能直接提升并發(fā)承載量。開(kāi)啟顯存不夠時(shí)的自動(dòng)換出部分框架支持把不活躍的請(qǐng)求KV Cache換到CPU內(nèi)存但換入換出會(huì)增加延遲適合吞吐優(yōu)先的離線(xiàn)場(chǎng)景。用小batch多迭代如果顯存緊張與其一次塞大batch導(dǎo)致OOM不如拆分幾個(gè)小batch控制在顯存安全線(xiàn)以?xún)?nèi)。5.2 線(xiàn)程、并發(fā)與批大小設(shè)置服務(wù)端的線(xiàn)程數(shù)和并發(fā)設(shè)置也是性能調(diào)優(yōu)的關(guān)鍵。PyTorch的CPU線(xiàn)程數(shù)默認(rèn)可能吃滿(mǎn)所有核心但在GPU推理場(chǎng)景下CPU線(xiàn)程太多反而會(huì)帶來(lái)上下文切換開(kāi)銷(xiāo)。建議按以下思路設(shè)置torch.set_num_threads如果預(yù)處理在CPU上執(zhí)行可以預(yù)留一部分CPU核給數(shù)據(jù)加載剩下的給計(jì)算線(xiàn)程。模型服務(wù)的max_batch_size不宜盲目設(shè)大。batch增大能提升吞吐但延遲會(huì)同步上升需要找到吞吐與延遲的平衡點(diǎn)。我一般壓測(cè)時(shí)會(huì)從1、2、4、8、16逐級(jí)往上試觀(guān)察p99延遲曲線(xiàn)何時(shí)開(kāi)始拐彎。并發(fā)請(qǐng)求數(shù)壓測(cè)時(shí)并發(fā)太低可能喂不飽GPU太高又可能導(dǎo)致排隊(duì)加劇??梢杂脡簻y(cè)工具逐步加壓監(jiān)控GPU利用率和響應(yīng)時(shí)間找到拐點(diǎn)。有一個(gè)容易踩的坑動(dòng)態(tài)shape會(huì)導(dǎo)致推理框架在運(yùn)行時(shí)不斷重新編譯或layout變換性能?chē)?yán)重劣化。我的做法是能固定shape就固定不能固定就限制為幾個(gè)離散檔位如長(zhǎng)度128/256/512/1024框架內(nèi)做padding到檔位長(zhǎng)度。雖然會(huì)浪費(fèi)一點(diǎn)算力但換來(lái)的穩(wěn)定性非常值。5.3 預(yù)熱、模型編譯與大模型特有參數(shù)部署服務(wù)上線(xiàn)的第一分鐘往往性能很差。原因是模型首次推理時(shí)需要加載權(quán)重、建立cuDNN/tensorRT的benchmark、編譯計(jì)算圖。生產(chǎn)環(huán)境一定要做預(yù)熱具體做法是服務(wù)啟動(dòng)后用幾條具有代表性的數(shù)據(jù)跑幾輪推理把編譯和緩存預(yù)熱到位再開(kāi)始對(duì)外提供流量。大模型推理框架里幾個(gè)關(guān)鍵參數(shù)值得重點(diǎn)調(diào)gpu_memory_utilization控制在0.85-0.9之間比較穩(wěn)妥太低浪費(fèi)顯存太高容易OOM遇到碎片化嚴(yán)重時(shí)還需要降一點(diǎn)。max_num_seqs / max_num_batched_tokens決定并發(fā)上限需要根據(jù)業(yè)務(wù)峰值設(shè)置。設(shè)太大會(huì)導(dǎo)致顯存瞬間爆掉太小則浪費(fèi)算力。enable_prefix_caching開(kāi)啟后相同的請(qǐng)求前綴比如系統(tǒng)提示詞的KV Cache可以復(fù)用多輪對(duì)話(huà)場(chǎng)景收益明顯。streaming輸出對(duì)話(huà)場(chǎng)景優(yōu)先使用流式輸出用戶(hù)感知到的首token延遲會(huì)大幅降低。6. 一次完整的推理性能調(diào)優(yōu)案例記錄6.1 壓測(cè)準(zhǔn)備與基線(xiàn)數(shù)據(jù)我在模擬項(xiàng)目X中部署過(guò)一個(gè)規(guī)模中等的對(duì)話(huà)模型單卡初始配置用的是PyTorch原生服務(wù)FP16權(quán)重動(dòng)態(tài)batch關(guān)閉最大并發(fā)16。壓測(cè)用的是一組平均輸入長(zhǎng)度512token、輸出長(zhǎng)度128token的請(qǐng)求共500條?;€(xiàn)數(shù)據(jù)如下指標(biāo)數(shù)值平均首token延遲820ms平均總延遲6.4s吞吐量2.8 req/sGPU峰值利用率47%顯存峰值占用15.2GB看到這個(gè)數(shù)據(jù)第一個(gè)直覺(jué)就是GPU利用率太低了只有47%說(shuō)明大量時(shí)間在等待數(shù)據(jù)或者算子沒(méi)吃滿(mǎn)。接下來(lái)開(kāi)始逐項(xiàng)優(yōu)化。6.2 逐步優(yōu)化過(guò)程與效果第一刀先換推理引擎。我把服務(wù)從PyTorch原生換成了vLLM啟用Continuous Batching和PagedAttention。僅僅這一步吞吐就從2.8 req/s提升到了5.6 req/s翻了一倍。GPU利用率也升到了72%。原因是動(dòng)態(tài)batch和顯存管理帶來(lái)的收益非常直觀(guān)。第二刀模型量化。把權(quán)重從FP16量化到INT8KV Cache保持FP16。量化后模型吞吐進(jìn)一步從5.6提升到7.1 req/s顯存峰值降到了約11.8GB。513條測(cè)試數(shù)據(jù)里輸出質(zhì)量對(duì)比差異基本看不出來(lái)。第三刀優(yōu)化服務(wù)端參數(shù)。把max_num_seqs從16調(diào)高到32gpu_memory_utilization設(shè)為0.88同時(shí)開(kāi)啟prefix caching。吞吐提升到8.3 req/sp99總延遲穩(wěn)在7.8s以?xún)?nèi)。這個(gè)時(shí)候GPU利用率已經(jīng)達(dá)到86%顯存還有約1.5GB余量。第四刀把輸入長(zhǎng)度限制為128的倍數(shù)并關(guān)閉動(dòng)態(tài)shape。這個(gè)操作對(duì)單次推理延遲的降低有一定幫助首token延遲從平均441ms降到了382ms。最終優(yōu)化后數(shù)據(jù)指標(biāo)優(yōu)化前優(yōu)化后平均首token延遲820ms382ms平均總延遲6.4s4.1s吞吐量2.8 req/s8.3 req/sGPU峰值利用率47%86%顯存峰值占用15.2GB11.8GB整體吞吐提升了接近3倍延遲下降了36%。整個(gè)過(guò)程沒(méi)有改一行模型代碼完全通過(guò)引擎選型、量化、參數(shù)調(diào)優(yōu)實(shí)現(xiàn)。這也再次驗(yàn)證了那個(gè)觀(guān)點(diǎn)很多性能問(wèn)題壓根不是模型本身的問(wèn)題而是部署方案沒(méi)選對(duì)、配置沒(méi)調(diào)好。6.3 多場(chǎng)景下的部署建議匯總根據(jù)不同的業(yè)務(wù)場(chǎng)景我建議的部署策略也不同整理成一個(gè)速查表場(chǎng)景推薦方案關(guān)鍵配置在線(xiàn)對(duì)話(huà)/交互vLLM/TGI INT8量化開(kāi)啟streaming、prefix caching大規(guī)模離線(xiàn)生產(chǎn)TensorRT 固定shape大batch、高吞吐優(yōu)先端側(cè)/邊緣部署ONNX Runtime 量化壓縮體積、CPU多線(xiàn)程優(yōu)化高精度要求場(chǎng)景FP16/BF16 TensorRT不激進(jìn)量化只做圖優(yōu)化小模型快速上線(xiàn)PyTorch torch.compile預(yù)熱、限制并發(fā)、避免動(dòng)態(tài)shape需要注意任何時(shí)候都不建議直接上線(xiàn)不經(jīng)過(guò)壓測(cè)的服務(wù)。即使方案看起來(lái)合理也必須在小流量下壓一遍確認(rèn)真實(shí)數(shù)據(jù)而不是紙面推算。7. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄7.1 GPU利用率低總感覺(jué)性能沒(méi)榨干現(xiàn)象GPU利用率只有30%-50%延遲卻不低。優(yōu)先排查以下環(huán)節(jié)數(shù)據(jù)加載和預(yù)處理是不是在CPU上串行執(zhí)行如果是試試異步數(shù)據(jù)加載、多進(jìn)程預(yù)處理或者把預(yù)處理算子放到GPU上。請(qǐng)求batch是不是太小小batch喂不飽GPU吞吐自然上不去。是不是存在動(dòng)態(tài)shape導(dǎo)致的recompile觀(guān)察第一次請(qǐng)求后有沒(méi)有周期性卡頓有的話(huà)就固定shape。是不是CPU線(xiàn)程數(shù)設(shè)置不合理導(dǎo)致線(xiàn)程切換開(kāi)銷(xiāo)過(guò)大。排查工具上我慣用nvidia-smi看實(shí)時(shí)利用率配合Nsight Systems看完整時(shí)間線(xiàn)能非常清楚地看到每個(gè)環(huán)節(jié)的耗時(shí)占比。如果沒(méi)有這類(lèi)工具也可以用簡(jiǎn)單的計(jì)時(shí)埋點(diǎn)把預(yù)處理、傳輸、推理、后處理每一段時(shí)間打印出來(lái)。7.2 顯存OOM與溢出問(wèn)題顯存OOM是部署中最常見(jiàn)的故障之一。OOM不一定代表顯存總量不夠更多時(shí)候是分配策略或者某個(gè)突發(fā)峰值導(dǎo)致。排查思路先分清是權(quán)重放不下還是運(yùn)行時(shí)峰值超了。如果是權(quán)重放不下直接量化權(quán)重或者換多卡部署。如果是運(yùn)行期峰值超了調(diào)整batch大小、限制max_num_seqs、降低gpu_memory_utilization、縮小或量化KV Cache。還有一種情況是顯存碎片化服務(wù)跑了一段時(shí)間后OOM但重啟就好。這是因?yàn)椴粩喾峙浜歪尫挪煌笮〉娘@存塊碎片越來(lái)越多。vLLM這類(lèi)框架的PagedAttention能大幅緩解碎片問(wèn)題用PyTorch原生的話(huà)可以考慮顯存池或定期重啟服務(wù)的土辦法不優(yōu)雅但管用。7.3 首token延遲高但整體吞吐正常如果首token延遲特別高多半卡在prefill階段也就是處理輸入Prompt階段。大模型解碼分兩段prefill把整段輸入一次性算完generate階段才逐token生成。輸入越長(zhǎng)prefill耗時(shí)越高。優(yōu)化手段包括讓模型支持并行prefill某些框架默認(rèn)支持。縮短輸入的無(wú)效內(nèi)容從業(yè)務(wù)層做輸入裁剪。用chunked prefill機(jī)制把超長(zhǎng)輸入拆成小塊逐步計(jì)算避免一次性算完導(dǎo)致延遲尖刺。開(kāi)啟prefix caching多輪對(duì)話(huà)和共用system prompt時(shí)效果明顯。調(diào)低并發(fā)減少排隊(duì)等待時(shí)間。7.4 并發(fā)高時(shí)延遲快速劣化并發(fā)一高延遲就起飛通常有兩個(gè)原因一是請(qǐng)求排隊(duì)時(shí)間過(guò)長(zhǎng)二是顯存不夠?qū)е翶V Cache被換出。應(yīng)對(duì)方法優(yōu)先保證p99延遲在容忍范圍內(nèi)適當(dāng)通過(guò)限流控制并發(fā)數(shù)量。開(kāi)連續(xù)批處理避免靜態(tài)batch帶來(lái)的等待效應(yīng)。增加服務(wù)實(shí)例利用水平擴(kuò)展分散壓力。如果單機(jī)已經(jīng)是極限就需要考慮多卡或分布式部署了。8. 最后的實(shí)操心得分享幾個(gè)我在多次上線(xiàn)部署中學(xué)到的經(jīng)驗(yàn)不算什么高深理論但真的能救命第一性能調(diào)優(yōu)一定要以監(jiān)控?cái)?shù)據(jù)為驅(qū)動(dòng)。不要看感覺(jué)不要憑經(jīng)驗(yàn)猜。每個(gè)優(yōu)化動(dòng)作前后都要有明確的指標(biāo)對(duì)比這樣出了問(wèn)題才能快速回滾也不會(huì)白忙一場(chǎng)。第二不要把所有雞蛋放在一個(gè)籃子里。推理引擎、量化方案、服務(wù)架構(gòu)這些組件盡量做成可切換的。我見(jiàn)過(guò)一些團(tuán)隊(duì)把TensorRT優(yōu)化后的模型寫(xiě)死進(jìn)代碼里后來(lái)模型迭代了TensorRT重新構(gòu)建要花好幾個(gè)小時(shí)上線(xiàn)節(jié)奏被拖得很慘。合理做法是把優(yōu)化鏈路自動(dòng)化模型一變構(gòu)建流程自動(dòng)跑一遍產(chǎn)物自動(dòng)驗(yàn)證。第三注意壓測(cè)數(shù)據(jù)的代表性。很多人拿固定長(zhǎng)度的輸入做壓測(cè)看起來(lái)數(shù)據(jù)很漂亮一上真實(shí)業(yè)務(wù)就被長(zhǎng)短不一的輸入打回原形。建議壓測(cè)數(shù)據(jù)的長(zhǎng)度分布盡量貼近線(xiàn)上真實(shí)請(qǐng)求否則調(diào)出來(lái)的參數(shù)很容易在真實(shí)場(chǎng)景翻車(chē)。第四小步快跑一次只改一個(gè)變量。同時(shí)換引擎、開(kāi)量化、改并發(fā)配置如果性能有波動(dòng)根本分不清是哪一步引起的。我習(xí)慣一次只調(diào)整一項(xiàng)跑一輪壓測(cè)記錄數(shù)據(jù)然后再動(dòng)下一項(xiàng)。調(diào)優(yōu)過(guò)程會(huì)慢一些但每步結(jié)論都很扎實(shí)。推理性能調(diào)優(yōu)是一個(gè)系統(tǒng)工程從模型結(jié)構(gòu)化簡(jiǎn)、量化、算子融合到推理引擎選型、服務(wù)架構(gòu)設(shè)計(jì)、運(yùn)行時(shí)參數(shù)配置每一環(huán)都有文章可做。這篇文章算是我近期實(shí)操的一份沉淀也希望能幫你少走一些彎路。如果你手頭正好有模型要部署不妨先從基線(xiàn)測(cè)試開(kāi)始一步步來(lái)。