NAVER 是一家韓國熱門搜索引擎公司,提供 Naver Place ,這是一項基于地理的服務,可提供有關韓國數百萬家企業和興趣點的詳細信息。用戶可以搜索不同的地點、發表評論,以及實時進行預訂或下單。
NAVER Place 垂直服務基于小語言模型 (SLMs) 來提高可用性,并專門針對 Place、Map 和 Travel。本文分享了 NVIDIA 和 NAVER 如何使用 NVIDIA TensorRT-LLM 優化 SLM 推理性能,從而在 NVIDIA Triton Inference Server 上實現基于 SLM 的垂直服務。如需詳細了解 NAVER 如何使用 AI,請參閱 NAVER Place AI 開發團隊簡介 。
適用于 NAVER Place 評測的小語言模型
與 大語言模型(LLMs) 相比,小語言模型(SLMs)是能夠以更少的參數理解自然語言的 AI 模型。眾所周知,當 SLMs 針對特定域任務進行適當微調時,它們可以在內存和計算能力較低的情況下正常工作。
NAVER Place 使用定制的小語言模型(SLMs)與其內部數據集結合使用,以提供摘要(根據 NAVER Place 用戶留下的評論創建)或微評論,解釋每個地點的特點。

使用 SLM Transformer 解碼器將參觀與景點匹配
NAVER Place 從其注冊地點收集收據和付款記錄,以顯示 NAVER Map 上每個地點的訪問和評論。為此,NAVER Place 提供了一個將參觀與興趣點 (POIs) 相匹配的系統。系統還會從博客文章中發現新的 POIs,或檢查重復的 POIs,以確保數據完整性并提高服務質量。

采用 NVIDIA TensorRT-LLM 實現卓越的推理性能
NVIDIA TensorRT-LLM 可加速并優化 NVIDIA GPU 上 LLM 的推理性能。它支持動態批處理以最大限度地提高吞吐量,并使用自回歸模型的內存優化方法 (例如分頁 KV 緩存和分塊上下文) 來提高內存效率。
NAVER Place 采用了 TensorRT-LLM,因為它在吞吐量、到達第一個令牌的時間 (TTFT) 和每個輸出令牌的時間 (TPOT) 方面優于其他 LLM 推理解決方案。TensorRT-LLM 在各種輸入長度和輸出令牌場景中始終如一地提供卓越性能。
圖 3 比較了使用 Qwen 模型 測量的熱門替代開源 LLM 推理庫和 TensorRT-LLM 在 NVIDIA A100 和 NVIDIA H100 GPU 上各種輸入和輸出令牌長度的吞吐量。

TensorRT-LLM 在所有解碼 – 預填充輕、預填充重、解碼重和解碼 – 預填充重操作模式下的表現均優于替代庫。其中,使用 SLM 的解碼重操作模式提供了最強的性能。此外,由于 TensorRT-LLM 提供針對最新 GPU 優化的內核,因此它在 NVIDIA Hopper 架構 上實現了特別高的性能。
要了解如何使用 TensorRT-LLM 評估性能,請參閱 NVIDIA/TensorRT-LLM GitHub repo 中提供的 性能概述 。如需詳細了解構建 TensorRT-LLM 引擎的基本調優技術,請參閱 調優 TensorRT-LLM 性能的最佳實踐 。
推理優化:在吞吐量和延遲之間做出權衡
本節將探討在批量大小和內存優化技術 (例如分頁 KV 緩存和動態批處理) 方面平衡 LLM 推理吞吐量和延遲的策略。
批量大小
LLM 推理服務器將請求批量處理,以更大限度地提高吞吐量。但是,這會導致高延遲。這種權衡意味著,雖然較大的批量大小可以提供更高的吞吐量,但也可能會增加響應時間,因此必須在效率和用戶體驗之間保持謹慎的平衡 (圖 4)。通過根據您的目標 TTFT 和 TPOT 調整批量大小,您可以優化系統的性能,以更好地滿足您的特定服務要求。

Paged KV 緩存和 in-flight batching
TensorRT-LLM 包括默認啟用的 分頁 KV 緩存 選項,可提高內存效率并增加批量大小上限,以適應需要低延遲和高吞吐量的任務。此默認設置可確保模型能夠平滑擴展,以處理延遲敏感的實時請求和需要更高吞吐量的批量處理場景,從而提供更靈活、更可靠的解決方案。
TensorRT-LLM 也默認啟用 In-flight batching ,這可以提高吞吐量。對于大多數任務,NAVER 團隊默認使用這兩個選項。
一個例外是,服務需要在較小的模型和較舊的 GPU 上實現極低的延遲。NAVER Place 在特定情況下需要極低的延遲,當關閉兩個選項時,性能表現更好。例如,POI 匹配是指實時處理請求,需要極低延遲的情況。由于模型相對較小,只有 1.3 億個,并且 NVIDIA T4 GPU 架構相對較舊,因此該服務需要將批量大小設為 1 以實現最低延遲,并關閉批處理選項。
此外,使用小模型大小為 1.3 億,批量大小為 1,與計算開銷相比,分頁開銷更高,從而導致延遲增加和 QPS 降低。為了解決這個問題,團隊采用了連續的 KV 緩存,而不是分頁 KV 緩存,因為在給定條件下,內存開銷不太重要。這種選擇使我們能夠滿足 POI 匹配等用例的嚴格實時要求。
精度 | 分頁 KV 緩存 | 緩存塊 | 輸入/輸出 | 最大 batch_size | QPS | 延遲 (以秒為單位) |
FP16 | 打開 | 7110 | 500/5 | 1 | 6.49 | 0.154 |
FP16 | 關閉 | 7110 | 500/5 | 1 | 8.39 | 0.119 |
雖然 POI 匹配對實時服務的延遲要求極低,但它也需要高吞吐量才能進行背景匹配。因此,我們目前對每種版本使用不同的構建選項。
"build_config": { "max_input_len": 512, "max_output_len": 32, "max_batch_size": 1, "max_beam_width": 1, "max_num_tokens": 4096, ... "plugin_config": { ... "paged_kv_cache": false, ... } } |
"build_config": { "max_input_len": 512, "max_output_len": 32, "max_batch_size": 8, "max_beam_width": 1, "max_num_tokens": 4096, ... "plugin_config": { ... "paged_kv_cache": true, ... } } |
推理優化:下游緩存
本節將探討利用緩存技術來簡化下游推理任務的優化策略。我們研究了前綴和響應緩存如何幫助減少冗余計算并提高整體效率。
前綴緩存
由于下游任務生成的提示詞具有通用前綴,因此計算每個請求的整個預填充會浪費資源。為了避免這種情況,TensorRT-LLM 提供了前綴緩存,這可以顯著減少內存使用量和計算負載。有關更多詳細信息,請參閱 如何在 NVIDIA/TensorRT-LLM GitHub repo 中啟用 KV 緩存重用 。
這種方法可以顯著增強 TTFT,并且對于具有長輸入長度、共享系統提示和短輸出長度的任務很有幫助。它特別適用于微評論,因為生成一個微評論平均需要 40 個多步驟推理,并且每個步驟共享前綴。
但是,對于涉及高度多樣化系統提示的任務,前綴緩存可能無法高效運行,同時降低緩存性能并增加管理開銷,因為緩存基于最近使用最少(LRU)策略。
響應緩存
響應緩存是 NVIDIA Triton Inference Server 的一項功能,有助于避免低效的冗余推理。Triton 會使用推理請求哈希來訪問響應緩存,其中包括模型名稱、模型版本和模型輸入。響應緩存非常有效,但有意要求重新引用的情況除外,例如多項采樣解碼。在實時提供的 POI 匹配中,每秒發生 4 到 5 次緩存命中,這意味著計算負載減少了 17%。有關更多詳細信息,請參閱 Triton Response Cache 文檔 。

使用 Triton 服務 TensorRT-LLM
使用 TensorRT-LLM 構建的 SLM 引擎可在 Triton Inference Server 上提供。Triton 提供了諸如 ensemble models 和 Business Logic Scripting (BLS) 等功能,用于組成標記化、后處理或多步驟推理等工作流。例如,NAVER Place 選擇使用 BLS,是因為它為特定用例提供了所需的靈活性。本節將介紹 NAVER Place 如何最大限度地提高 Triton BLS 的優勢和可用性。
通過定義明確的請求/響應模式提高可用性
Triton 模型以 pb_tensor
格式交換數據。為提高通信效率和優化 LLM 推理而選擇的 BLS 結構包含預處理和后處理代碼,這需要將數據類型從 pb_tensor
轉換為 NumPy 數組,然后再轉換回 pb_tensor
。
此過程存在兩個困難。首先,如果每個模型的 IO 數據未經過驗證,則調試很困難,因為在運行時發現了任何無效的數據格式或缺少必填字段。其次,由于將預處理和后處理合并到 BLS 中,代碼變得更加復雜,如果模型之間存在調用依賴項,則擴展和維護變得更加困難。
這些挑戰強調了需要一個定義明確的請求/響應模式,以減少運行時錯誤并簡化代碼管理,尤其是在必須將多個模型鏈接在一起的情況下。此外,在整個工作流中保持一致的數據格式可顯著緩解調試困難,并確保更流暢的集成。例如,POI 匹配會經歷復雜的工作流,如圖 6 所示。

為了克服這些困難,NAVER Place 團隊提出了以下方法。
標準化 IO 模式管理
基于 NVIDIA 的 Python 數據類,我們使用 Pydantic 定義了 IO 模式,這使得數據驗證變得更容易。這有助于確保所有 Triton 模型的請求和響應之間的結構一致性,并增強數據驗證。通過在此階段采用定義明確的模式,開發者可以盡早檢測到數據問題,并在整個推理工作流中維護一致的數據結構,最終減少調試用度并提高整體可靠性。
例如,我們定義了一個名為 BlsRequest
的類,用于管理 Triton 請求的輸入數據格式并執行數據驗證,如以下代碼示例所示:
# NOTE: Because Triton uses pb_tensor and Numpy objects, # it is required to declaratively manage the fields that are not defined as Python default types. # For this, we added tTe json_schema_extra field of Pydantic to explicitly manage data types. class BlsRequest(TritonFieldModel): name: Optional[ str ] = Field( None , json_schema_extra = { 'data_type' : "TYPE_STRING" }) subname: Optional[ str ] = Field( None , json_schema_extra = { 'data_type' : "TYPE_STRING" }) biznum: Optional[ str ] = Field( None , json_schema_extra = { 'data_type' : "TYPE_STRING" }) address: Optional[ List [ str ]] = Field( None , json_schema_extra = { 'data_type' : "TYPE_STRING" }) tel: Optional[ List [ str ]] = Field( None , json_schema_extra = { 'data_type' : "TYPE_STRING" }) @root_validator (pre = True ) def check_all_fields_empty( cls , values): if not any ( bool (v) for v in values.values()): raise ValidationError( "All fields cannot be empty" , model = cls .__name__) |
按模型實現 IO 類型轉換的模塊化
我們為每個模型封裝了 IO 數據轉換過程,并為 pb_tensor
和 Pydantic 之間的轉換創建了一個通用函數,使其適合基礎 Triton Python 模型。這有助于以一致的方式調用模型,而無需擔心內部數據轉換過程。
以下代碼示例是一個函數,該函數接收 Pydantic Request 對象,將其轉換為 Triton pb_tensor
,然后將模型推理的結果作為 Pydantic Response 對象返回:
def _infer_model( self , request_model, response_model_cls, model_name, request_model, * * infer_kwargs): # Converts Pydantic Request to Triton pb_tensors. pb_tensors = self .convert_pydantic_to_pb_tensors(request_model, batch_inference) # Runs model inference. infer_request = pb_utils.InferenceRequest( model_name = model_name, inputs = pb_tensors, requested_output_names = response_model_cls.get_field_names(), * * infer_kwargs, ) infer_response = infer_request. exec () # Converts Triton Response(pb_tensors) to Pydantic Response. return self .convert_pb_tensors_to_pydantic(response, response_model_cls) |
以下代碼示例使用 _infer_model
調用模型。只需聲明 GeneratorRequest
和 GeneratorResponse
類,而忽略了復雜的數據轉換或模型調用過程。
def infer_generator( self , request, text_input, max_tokens): response_model_cls = schema.GeneratorResponse request_model = schema.GeneratorRequest(text_input = text_input, max_tokens = max_tokens) return self ._infer_model( request = request, model_name = "generator_bls" , request_model = request_model, response_model_cls = response_model_cls, ) |
模塊化 BLS 業務邏輯并增強可測試性
NAVER 團隊通過以下方式模塊化了業務邏輯,并在 BLS 中預處理和后處理代碼,以實現低耦合。這有助于降低代碼的復雜性,并提高可測試性和可維護性。
- 模塊化預處理和后處理,并引入單元測試 將模型訓練、預處理和后處理代碼的業務邏輯模塊化,使其可重復使用。 將測試代碼設計為在 Python 運行時中獨立運行,即使沒有 Triton 運行時,也能驗證每個模型的預處理和后處理。
- 重新定義 BLS 的角色 BLS 僅負責模型調用和端到端測試。這可以確保系統保持可擴展性,即使添加了新要求,也能最大限度地減少對 BLS 代碼的影響。
- CI 簡介 為業務邏輯以及預處理和后處理代碼創建了 CI 測試管道。這有助于快速驗證模型訓練過程中所做的更改,確保它們不會影響服務。將這些測試集成到 CI 管道中可實現更早的問題檢測和快速解決,在不中斷服務流程的情況下確保穩定的更新。
使用這種方法,我們有效地實現了增強數據驗證、代碼可維護性和開發生產力的目標,從而提高了基于 Triton 的 LLM 服務開發的生產力。
總結
NAVER Place 已成功使用 NVIDIA TensorRT-LLM 優化 LLM 引擎,并提高了 NVIDIA Triton Inference Server 的可用性。通過這種優化,該團隊還最大限度地提高了 GPU 利用率,進一步提高了整體系統效率。整個流程有助于優化多個基于 SLM 的垂直服務,使 NAVER Place 更加用戶友好。基于這些經驗,我們將繼續開發其他垂直模型,并將其應用于我們的服務。
開始使用 NVIDIA TensorRT-LLM 和 NVIDIA Triton Inference Server 。
?
?