在32核CPU、無GPU的服務器上,使用Python后端和ONNX后端部署嵌入模型,并實現并行調用和性能優化策略。
方案一:使用Python后端部署Embedding模型
Python后端提供了極大的靈活性,可以直接在Triton中運行您熟悉的sentence-transformers
代碼。但其性能開銷相對較高,需要精細配置以充分利用CPU資源。
1. 拉取Triton Docker鏡像
首先,拉取包含Python后端的Triton Server官方鏡像。
# 將<xx.yy>替換為最新或您需要的版本,例如 24.06
docker pull nvcr.io/nvidia/tritonserver:<xx.yy>-py3
2. 準備模型倉庫
您需要創建一個模型目錄,其中包含一個model.py
腳本(用于加載和運行模型)和一個config.pbtxt
配置文件(用于定義模型行為和優化)。
-
創建目錄結構:
mkdir -p model_repository/embedding_py/1
-
創建
model.py
腳本:
此腳本的核心是在initialize
方法中加載模型(只執行一次),并在execute
方法中處理推理請求。# 保存為 model_repository/embedding_py/1/model.py import json import numpy as np import torch from sentence_transformers import SentenceTransformer import triton_python_backend_utils as pb_utilsclass TritonPythonModel:def initialize(self, args):"""在模型加載時調用一次。"""# 關鍵性能優化:當Triton實例數(count) > 1時,限制每個實例的PyTorch線程數# 可以避免實例間的線程競爭,讓Triton來調度并行。torch.set_num_threads(1)# 從模型目錄加載模型,使用CPUself.model = SentenceTransformer(args['model_repository'], device='cpu')print('SentenceTransformer model loaded on CPU.')def execute(self, requests):"""處理每一批推理請求。"""responses =for request in requests:# 1. 從請求中獲取輸入張量 (文本字符串)# as_numpy()會返回一個包含字節串的NumPy數組in_str = pb_utils.get_input_tensor_by_name(request, "TEXT")sentences = [s.decode('utf-8') for s in in_str.as_numpy()]# 2. 使用模型進行推理embeddings = self.model.encode(sentences, convert_to_numpy=True)# 3. 創建輸出張量out_tensor = pb_utils.Tensor("EMBEDDING", embeddings.astype(np.float32))# 4. 創建并添加響應inference_response = pb_utils.InferenceResponse(output_tensors=[out_tensor])responses.append(inference_response)return responsesdef finalize(self):"""在模型卸載時調用。"""self.model = Noneprint('Cleaned up model.')
-
創建
config.pbtxt
配置文件:
這是CPU性能優化的關鍵。我們將創建多個模型實例(instance_group
)以利用全部32個核心。# 保存為 model_repository/embedding_py/config.pbtxt name: "embedding_py" backend: "python" max_batch_size: 64 # 允許服務器對請求進行批處理input # 可變長度的字符串輸入} ]output # 假設嵌入維度為768} ]# --- 性能優化配置 --- # 為CPU創建多個模型實例以實現并行處理 instance_group# 動態批處理:在CPU上依然有用,可以分攤請求開銷 dynamic_batching {max_queue_delay_microseconds: 10000 # 10毫秒延遲換取更大批次preferred_batch_size: }
3. 啟動Triton服務器 (CPU模式)
使用docker run
命令啟動服務器,注意不使用--gpus
標志。
docker run --rm -p 8000:8000 -p 8001:8001 -p 8002:8002 \
-v $(pwd)/model_repository:/models \
nvcr.io/nvidia/tritonserver:<xx.yy>-py3 \
tritonserver --model-repository=/models
服務器啟動后,您會看到日志顯示embedding_py
模型已經READY
。
4. 并行推理客戶端
為了充分利用服務器端配置的16個實例,客戶端必須能夠并行地發送請求。使用asyncio
和aiohttp
是實現高并發客戶端的有效方式。
# client_py.py
import asyncio
import numpy as np
import tritonclient.http.aio as aiohttpclientSERVER_URL = "localhost:8000"
MODEL_NAME = "embedding_py"async def send_request(client, text_list):# 準備輸入數據text_array = np.array([[s.encode('utf-8')] for s in text_list], dtype=np.object_)inputs =inputs.set_data_from_numpy(text_array, binary_data=True)# 準備輸出outputs =# 發送請求response = await client.infer(MODEL_NAME, inputs, outputs=outputs)embedding = response.as_numpy("EMBEDDING")return embeddingasync def main():# 模擬大量并發任務tasks =# 創建一個可以并行發送請求的客戶端async with aiohttpclient.InferenceServerClient(SERVER_URL) as client:# 假設我們要并行處理100個請求,每個請求包含4個句子for i in range(100):task_texts =tasks.append(send_request(client, task_texts))# 等待所有并發請求完成results = await asyncio.gather(*tasks)print(f"成功完成 {len(results)} 個并行任務。")print(f"第一個任務的嵌入向量形狀: {results.shape}")if __name__ == "__main__":asyncio.run(main())
5. Python后端性能優化策略總結
- 核心策略:增加實例數 (
instance_group
):這是在多核CPU上實現吞吐量擴展的最重要手段。將count
設置為接近CPU核心數(例如16, 24, 32),讓Triton的多個模型實例并行處理請求。 - 限制實例內線程 (
torch.set_num_threads(1)
):當count
> 1時,這是至關重要的優化。它避免了多個PyTorch實例爭搶CPU資源,將并行化的任務完全交給Triton調度,從而減少了線程切換的開銷。 - 動態批處理 (
dynamic_batching
):雖然在CPU上的收益不如GPU明顯,但它仍然可以通過將小請求聚合成大批次,來分攤Python解釋器和請求處理的固定開銷,從而提升吞吐量。
方案二:使用ONNX后端部署Embedding模型
ONNX (Open Neural Network Exchange) 是一種為機器學習模型設計的開放格式。使用ONNX后端通常比Python后端性能更高,因為它繞過了Python解釋器,直接由高度優化的C++運行時(ONNX Runtime)執行。
1. 轉換模型為ONNX格式
首先,您需要將sentence-transformers
模型導出為ONNX格式。使用optimum
庫是最簡單的方式。
pip install optimum[exporters]
# 將 BAAI/bge-base-en-v1.5 替換為您想使用的模型
optimum-cli export onnx --model BAAI/bge-base-en-v1.5 --task feature-extraction./embedding_onnx_model
執行后,./embedding_onnx_model
目錄下會生成model.onnx
文件。
2. 準備模型倉庫
-
創建目錄結構并移動模型:
mkdir -p model_repository/embedding_onnx/1 mv./embedding_onnx_model/model.onnx model_repository/embedding_onnx/1/
-
創建
config.pbtxt
配置文件:
此配置將指向ONNX模型,并同樣通過instance_group
進行CPU優化。# 保存為 model_repository/embedding_onnx/config.pbtxt name: "embedding_onnx" backend: "onnxruntime" # 或 platform: "onnxruntime_onnx" max_batch_size: 128input # 動態批處理, 動態序列長度},{name: "attention_mask"data_type: TYPE_INT64dims: [ -1, -1 ]} ]output # 假設嵌入維度為768} ]# --- 性能優化配置 --- instance_groupdynamic_batching {max_queue_delay_microseconds: 5000 # 5毫秒延遲preferred_batch_size: }
3. 啟動Triton服務器 (CPU模式)
啟動命令與Python后端完全相同,Triton會自動發現并加載embedding_onnx
模型。
docker run --rm -p 8000:8000 -p 8001:8001 -p 8002:8002 \
-v $(pwd)/model_repository:/models \
nvcr.io/nvidia/tritonserver:<xx.yy>-py3 \
tritonserver --model-repository=/models
4. 并行推理客戶端
ONNX模型的客戶端需要一個額外的步驟:文本分詞(Tokenization)。這個過程需要在客戶端完成,因為預處理邏輯沒有像Python后端那樣被部署在服務器上。
# client_onnx.py
import asyncio
import numpy as np
import tritonclient.http.aio as aiohttpclient
from transformers import AutoTokenizerSERVER_URL = "localhost:8000"
MODEL_NAME = "embedding_onnx"
# 使用與導出ONNX時相同的模型名稱來加載分詞器
TOKENIZER_NAME = "BAAI/bge-base-en-v1.5" # 在全局加載分詞器
tokenizer = AutoTokenizer.from_pretrained(TOKENIZER_NAME)def mean_pooling(model_output, attention_mask):# 從ONNX輸出中提取嵌入向量token_embeddings = model_outputinput_mask_expanded = np.expand_dims(attention_mask, -1).repeat(token_embeddings.shape[-1], -1)sum_embeddings = np.sum(token_embeddings * input_mask_expanded, 1)sum_mask = np.clip(input_mask_expanded.sum(1), a_min=1e-9, a_max=None)return sum_embeddings / sum_maskasync def send_request(client, text_list):# 1. 客戶端分詞encoded_input = tokenizer(text_list, padding=True, truncation=True, return_tensors='np')# 2. 準備輸入張量inputs = [aiohttpclient.InferInput("input_ids", encoded_input['input_ids'].shape, "INT64"),aiohttpclient.InferInput("attention_mask", encoded_input['attention_mask'].shape, "INT64")]inputs.set_data_from_numpy(encoded_input['input_ids'])inputs.[1]set_data_from_numpy(encoded_input['attention_mask'])# 3. 準備輸出outputs =# 4. 發送請求response = await client.infer(MODEL_NAME, inputs, outputs=outputs)last_hidden_state = response.as_numpy("last_hidden_state")# 5. 客戶端后處理 (Mean Pooling)final_embedding = mean_pooling(last_hidden_state, encoded_input['attention_mask'])return final_embeddingasync def main():# 并發邏輯與Python后端客戶端相同tasks =async with aiohttpclient.InferenceServerClient(SERVER_URL) as client:for i in range(100):task_texts =tasks.append(send_request(client, task_texts))results = await asyncio.gather(*tasks)print(f"成功完成 {len(results)} 個并行任務。")print(f"第一個任務的嵌入向量形狀: {results.shape}")if __name__ == "__main__":asyncio.run(main())
5. ONNX后端性能優化策略總結
- 核心策略:增加實例數 (
instance_group
):與Python后端同理,這是利用多核CPU的關鍵。 - 模型優化:ONNX的優勢在于其生態系統。在部署前,您可以使用ONNX Runtime工具對模型進行圖優化和量化(Quantization)。將模型從FP32量化為INT8,可以在CPU上帶來數倍的性能提升,同時只有輕微的精度損失。
- 控制ONNX Runtime線程:雖然
instance_group
是主要的并行手段,您也可以在config.pbtxt
中微調每個ONNX實例的線程數,但這屬于更高級的優化,通常保持默認或設置為較小值即可。 - 將預處理/后處理移至客戶端:如示例所示,ONNX方案將分詞和池化操作放在客戶端。這降低了服務器的計算負載,但增加了客戶端的復雜性和依賴。
結論與對比
特性 | Python后端 | ONNX后端 |
---|---|---|
性能 | 較低 | 較高 (原生C++執行,無Python開銷) |
部署簡易度 | 非常簡單 (無需模型轉換) | 較復雜 (需要導出為ONNX) |
靈活性 | 極高 (可在model.py 中執行任意代碼) | 較低 (僅執行ONNX圖計算) |
客戶端 | 簡單 (只需發送文本) | 較復雜 (需要處理分詞和后處理) |
優化潛力 | 有限 (主要靠實例數) | 巨大 (圖優化、量化等) |
建議:
- 如果您的首要目標是快速原型開發和最大靈活性,請選擇Python后端。
- 如果您的目標是追求極致的生產性能和吞吐量,請投入時間選擇ONNX后端,并探索其量化等高級優化。
當然,這是一個非常實際且常見的場景。將包含自定義預處理邏輯的復雜流水線部署到Triton,正是其強大功能的體現。在這種情況下,Python后端和ONNX后端的組合使用策略會變得更加清晰。
下面,我將為您分別提供兩種方案的超詳細部署步驟,以滿足您“文件 -> 解析 -> 分塊 -> Embedding”的流水線需求,并重點關注在32核CPU服務器上的性能優化。
方案一:純Python后端實現完整流水線 (一體化方案)
這種方法最為直接,將您所有的自定義代碼(文件解析、分塊)和模型調用邏輯全部封裝在一個Triton Python后端模型中。
架構思路:客戶端發送原始文件字節流,Triton服務器上的一個Python模型完成所有工作,然后返回最終的嵌入向量。
1. 拉取Triton Docker鏡像
這一步保持不變,確保獲取包含Python后端的鏡像。
# 將<xx.yy>替換為最新或您需要的版本,例如 24.06
docker pull nvcr.io/nvidia/tritonserver:<xx.yy>-py3
2. 準備模型倉庫
您需要一個模型目錄,其中包含model.py
腳本、config.pbtxt
配置文件,以及模型運行所需的依賴。
-
創建目錄結構:
# 創建模型和版本目錄 mkdir -p model_repository/full_pipeline_py/1# 創建一個存放依賴的目錄 (可選但推薦) mkdir -p model_repository/full_pipeline_py/requirements
-
準備依賴:
由于Python后端默認環境中可能沒有sentence-transformers
或文件解析庫(如pypdf2
),您需要提供它們。最簡單的方式是創建一個requirements.txt
文件。# 保存為 model_repository/full_pipeline_py/requirements.txt sentence-transformers # 如果您需要解析PDF,可以添加 # pypdf2
Triton會在加載模型時自動使用pip安裝這些依賴。
-
創建
model.py
腳本 (核心):
這個腳本將實現您的完整流水線。# 保存為 model_repository/full_pipeline_py/1/model.py import json import numpy as np import torch from sentence_transformers import SentenceTransformer import triton_python_backend_utils as pb_utils import io # 示例:如果您需要解析PDF,可以導入 # from PyPDF2 import PdfReaderclass TritonPythonModel:def initialize(self, args):"""在模型加載時調用一次,用于加載模型和設置參數。"""# 關鍵性能優化:在多實例CPU部署中,限制每個實例的PyTorch線程數# 避免實例間線程競爭,讓Triton的進程級并行發揮最大作用。torch.set_num_threads(1)# 從模型目錄加載模型,強制使用CPU# 'args['model_repository']' 指向 /models/full_pipeline_py/self.model = SentenceTransformer(args['model_repository'], device='cpu')print('SentenceTransformer model loaded on CPU.')def _parse_and_chunk(self, file_bytes):"""私有輔助函數,用于實現文件解析和分塊邏輯。這是一個示例,您需要根據您的文件類型替換這里的邏輯。"""# --- 在這里實現您復雜的文件解析邏輯 ---# 示例1:假設輸入是簡單的txt文件try:text = file_bytes.decode('utf-8')except UnicodeDecodeError:text = "Error decoding file content."# 示例2:如果您處理PDF (需要安裝PyPDF2)# text = ""# with io.BytesIO(file_bytes) as f:# reader = PdfReader(f)# for page in reader.pages:# text += page.extract_text()# --- 在這里實現您的分塊邏輯 ---# 示例:按段落分塊chunks = [chunk for chunk in text.split('\n\n') if chunk.strip()]if not chunks:return [""] # 保證至少有一個空字符串塊,避免后續處理失敗return chunksdef execute(self, requests):"""處理每一批推理請求。"""responses =# Triton會將多個客戶端請求合并到'requests'列表中for request in requests:# 1. 從請求中獲取輸入張量 (原始文件字節)in_file_bytes_tensor = pb_utils.get_input_tensor_by_name(request, "RAW_FILE")# as_numpy()返回一個包含字節對象的NumPy數組,我們處理批次中的每個文件# 對于max_batch_size > 1,這里可能包含多個文件file_bytes_list = in_file_bytes_tensor.as_numpy()all_embeddings =for file_bytes in file_bytes_list:# 2. 對每個文件執行解析和分塊text_chunks = self._parse_and_chunk(file_bytes)# 3. 使用模型對所有塊進行推理# model.encode 本身支持批處理,效率很高chunk_embeddings = self.model.encode(text_chunks, convert_to_numpy=True)# 4. (可選) 聚合結果,例如,可以對所有塊的嵌入向量求平均final_embedding = np.mean(chunk_embeddings, axis=0)all_embeddings.append(final_embedding)# 5. 創建輸出張量# 將列表中的所有最終嵌入向量堆疊成一個批處理out_tensor = pb_utils.Tensor("FINAL_EMBEDDING", np.stack(all_embeddings).astype(np.float32))# 6. 創建并添加響應inference_response = pb_utils.InferenceResponse(output_tensors=[out_tensor])responses.append(inference_response)return responses
-
創建
config.pbtxt
配置文件:
此配置是性能優化的關鍵,我們將創建大量實例來利用32個CPU核心。# 保存為 model_repository/full_pipeline_py/config.pbtxt name: "full_pipeline_py" backend: "python" max_batch_size: 32 # 允許服務器同時處理多達32個文件請求input # 整個流水線的輸入是原始文件字節} ]output # 整個流水線的輸出是最終的聚合嵌入向量} ]# --- 性能優化配置 --- # 為32核CPU創建大量模型實例以實現最大并行度。 # 每個實例都是一個獨立的Python進程,可以并行處理請求。 instance_group# 動態批處理:對于文件處理依然有用。 # 它會將多個獨立的文件請求打包成一個批次,一次性傳遞給execute方法。 dynamic_batching {max_queue_delay_microseconds: 10000 # 10毫秒延遲換取更大批次preferred_batch_size: }
3. 啟動Triton服務器 (CPU模式)
docker run --rm -p 8000:8000 -p 8001:8001 -p 8002:8002 \
-v $(pwd)/model_repository:/models \
nvcr.io/nvidia/tritonserver:<xx.yy>-py3 \
tritonserver --model-repository=/models
4. 編寫并行客戶端
客戶端非常簡單,只需讀取文件并發送即可。為了壓測服務器,我們同樣使用asyncio
來模擬大量并發用戶。
# client_py_pipeline.py
import asyncio
import aiohttp
import timeSERVER_URL = "http://localhost:8000/v2/models/full_pipeline_py/infer"
FILE_PATH = "path/to/your/sample.txt" # 替換為您的示例文件路徑
CONCURRENT_REQUESTS = 100 # 模擬100個并發請求async def send_request(session, file_bytes):payload = {"inputs":,"datatype": "BYTES","data": [file_bytes.decode('latin-1')] # 使用aiohttp時需要這樣編碼}]}async with session.post(SERVER_URL, json=payload) as response:if response.status == 200:result = await response.json()return resultelse:print(f"Error: {response.status}")return Noneasync def main():with open(FILE_PATH, "rb") as f:file_bytes = f.read()async with aiohttp.ClientSession() as session:tasks =start_time = time.time()results = await asyncio.gather(*tasks)end_time = time.time()print(f"Sent {CONCURRENT_REQUESTS} concurrent requests in {end_time - start_time:.2f} seconds.")success_count = len([r for r in results if r])print(f"Received {success_count} successful responses.")if __name__ == "__main__":asyncio.run(main())
方案二:混合后端實現流水線 (性能優化方案)
這種方法更先進,也更復雜。它將流水線拆分為兩個部分,分別由最適合的后端處理:
- Python后端 (Orchestrator):負責處理文件IO、解析、分塊這些靈活的自定義邏輯。
- ONNX后端 (Accelerator):負責執行計算密集型的Embedding任務,性能遠超Python。
架構思路:客戶端發送文件 -> Python模型接收、解析、分塊 -> Python模型在服務器內部調用ONNX模型進行推理 -> Python模型聚合結果 -> 返回給客戶端。
1. 轉換模型為ONNX格式
這一步是前提。
pip install optimum[exporters]
optimum-cli export onnx --model BAAI/bge-base-en-v1.5 --task feature-extraction./embedding_onnx_model
2. 準備模型倉庫 (包含兩個模型)
-
創建目錄結構:
# 為ONNX模型創建目錄 mkdir -p model_repository/embedding_onnx/1 mv./embedding_onnx_model/model.onnx model_repository/embedding_onnx/1/# 為Python編排器模型創建目錄 mkdir -p model_repository/pipeline_orchestrator/1
-
配置
embedding_onnx
模型:
這個模型是內部服務,負責高性能計算。config.pbtxt
forembedding_onnx
:# 保存為 model_repository/embedding_onnx/config.pbtxt name: "embedding_onnx" backend: "onnxruntime" max_batch_size: 256 # 可以處理非常大的批次(所有文件的所有塊)input # 動態批處理, 動態序列長度},{name: "attention_mask"data_type: TYPE_INT64dims: [ -1, -1 ]} ]output} ]# --- 性能優化配置 --- # 同樣創建大量實例來利用CPU核心 instance_group
-
配置
pipeline_orchestrator
模型:
這個模型是流水線的入口,負責編排。-
準備依賴:
# 保存為 model_repository/pipeline_orchestrator/requirements.txt transformers # 只需要分詞器 # pypdf2 # 如果需要
-
model.py
forpipeline_orchestrator
(核心):# 保存為 model_repository/pipeline_orchestrator/1/model.py import json import numpy as np import triton_python_backend_utils as pb_utils from transformers import AutoTokenizerclass TritonPythonModel:def initialize(self, args):"""加載分詞器等。"""self.tokenizer = AutoTokenizer.from_pretrained("BAAI/bge-base-en-v1.5")print('Tokenizer loaded.')def _parse_and_chunk(self, file_bytes):# 這部分邏輯與方案一完全相同text = file_bytes.decode('utf-8')chunks = [chunk for chunk in text.split('\n\n') if chunk.strip()]return chunks if chunks else [""]def _mean_pooling(self, model_output, attention_mask):# ONNX模型輸出后處理token_embeddings = model_outputinput_mask_expanded = np.expand_dims(attention_mask, -1).repeat(token_embeddings.shape[-1], -1)sum_embeddings = np.sum(token_embeddings * input_mask_expanded, 1)sum_mask = np.clip(input_mask_expanded.sum(1), a_min=1e-9, a_max=None)return sum_embeddings / sum_maskasync def execute(self, requests):"""異步執行,可以并行處理對內部ONNX模型的調用。"""responses =# 異步處理所有請求for request in requests:# 1. 解析和分塊 (與方案一相同)in_file_bytes_tensor = pb_utils.get_input_tensor_by_name(request, "RAW_FILE")file_bytes_list = in_file_bytes_tensor.as_numpy()all_final_embeddings =for file_bytes in file_bytes_list:text_chunks = self._parse_and_chunk(file_bytes)# 2. 客戶端分詞encoded_input = self.tokenizer(text_chunks, padding=True, truncation=True, return_tensors='np')# 3. 構造對內部ONNX模型的推理請求infer_request = pb_utils.InferenceRequest(model_name='embedding_onnx',requested_output_names=['last_hidden_state'],inputs=),pb_utils.Tensor('attention_mask', encoded_input['attention_mask'])])# 4. 發送內部請求并等待響應 (異步執行)infer_response = await infer_request.async_exec()if infer_response.has_error():raise pb_utils.TritonModelException(infer_response.error().message())# 5. 從響應中提取結果并進行后處理last_hidden_state = pb_utils.get_output_tensor_by_name(infer_response, 'last_hidden_state').as_numpy()chunk_embeddings = self._mean_pooling(last_hidden_state, encoded_input['attention_mask'])# 6. 聚合結果final_embedding = np.mean(chunk_embeddings, axis=0)all_final_embeddings.append(final_embedding)# 7. 創建最終輸出out_tensor = pb_utils.Tensor("FINAL_EMBEDDING", np.stack(all_final_embeddings).astype(np.float32))inference_response = pb_utils.InferenceResponse(output_tensors=[out_tensor])responses.append(inference_response)return responses
-
config.pbtxt
forpipeline_orchestrator
:# 保存為 model_repository/pipeline_orchestrator/config.pbtxt name: "pipeline_orchestrator" backend: "python" max_batch_size: 32input} ]output} ] # 注意:這個編排器模型通常不需要自己的instance_group, # 因為它的主要瓶頸在于它調用的ONNX模型。 # 并行性由ONNX模型的多個實例來保證。
-
3. 啟動Triton服務器
命令完全相同,Triton會自動加載這兩個模型。
docker run --rm -p 8000:8000 -p 8001:8001 -p 8002:8002 \
-v $(pwd)/model_repository:/models \
nvcr.io/nvidia/tritonserver:<xx.yy>-py3 \
tritonserver --model-repository=/models
4. 編寫并行客戶端
好消息是,客戶端代碼與方案一完全相同! 所有的復雜性都被封裝在了服務器端。客戶端只需要調用pipeline_orchestrator
模型即可,它并不知道內部還有一個ONNX模型。
結論與最終建議
特性 | 方案一 (純Python) | 方案二 (混合后端) |
---|---|---|
性能 | 中等 | 高 |
部署復雜度 | 低 | 高 |
代碼維護 | 簡單 (所有邏輯在一個文件) | 復雜 (邏輯分散在兩個模型) |
靈活性 | 極高 | 極高 |
資源利用 | 好 | 最佳 (為不同任務使用最優后端) |
給您的建議:
-
從方案一開始:首先實現純Python后端的流水線。它更容易調試,能讓您快速驗證整個流程的正確性。對于中等負載,通過增加
instance_group
的count
,它的性能可能已經足夠滿足您的需求。 -
當性能成為瓶頸時,再轉向方案二:如果您的QPS(每秒查詢率)要求非常高,或者單個請求的延遲需要被極致壓縮,那么投入精力去實現混合后端方案是值得的。它將計算最密集的部分交給了最高效的ONNX后端,能最大化您32核CPU的吞吐能力。
方案二代表了Triton更高級的用法,是實現生產級高性能服務的理想架構。