Triton Inference Server是一個適用于深度學習與機器學習模型的推理服務引擎,支持將TensorRT、TensorFlow、PyTorch或ONNX等多種AI框架的模型部署為在線推理服務,并支持多模型管理、自定義backend等功能。本文為您介紹如何通過鏡像部署的方式部署Triton Inference Server模型服務。
部署服務:單模型
在OSS存儲空間中創建模型存儲目錄,并根據模型存儲目錄格式要求配置模型文件與配置文件。具體操作請參見管理目錄。
每個模型目錄下都至少包含一個模型版本目錄和一個模型配置文件:
模型版本目錄:包含模型文件,且必須以數字命名,作為模型版本號,數字越大版本越新。
模型配置文件:用于提供模型的基礎信息,通常命名為
config.pbtxt
。
假設模型存儲目錄在
oss://examplebucket/models/triton/
路徑下,模型存儲目錄的格式如下:triton └──resnet50_pt ├── 1 │ └── model.pt ├── 2 │ └── model.pt ├── 3 │ └── model.pt └── config.pbtxt
其中:config.pbtxt 為配置文件,文件內容示例如下:
name: "resnet50_pt" platform: "pytorch_libtorch" max_batch_size: 128 input [ { name: "INPUT__0" data_type: TYPE_FP32 dims: [ 3, -1, -1 ] } ] output [ { name: "OUTPUT__0" data_type: TYPE_FP32 dims: [ 1000 ] } ] # 使用GPU推理 # instance_group [ # { # kind: KIND_GPU # } # ] # 模型版本配置 # version_policy: { all { }} # version_policy: { latest: { num_versions: 2}} # version_policy: { specific: { versions: [1,3]}}
config.pbtxt文件中關鍵配置說明如下:
參數
是否必選
描述
name
否
默認為模型存儲目錄名。如果指定了名稱,也必須與模型存儲目錄名稱保持一致。
platform/backend
是
platform與backend至少配置一項:
platform:用于指定模型框架。常用的模型框架包含:tensorrt_plan、onnxruntime_onnx、pytorch_libtorch、tensorflow_savedmodel、tensorflow_graphdef等。
backend:用于指定模型框架或使用Python代碼自定義推理邏輯。
可指定的模型框架與platform完全一樣,只是設置的名稱不同,框架包含:tensorrt、onnxruntime、pytorch、tensorflow等。
使用Python代碼自定義推理邏輯,具體操作,請參見部署服務:使用backend。
max_batch_size
是
用于指定模型請求批處理的最大數量,若不開啟批處理功能,則將該項設置為0。
input
是
用于指定以下屬性:
name:輸入數據的名稱。
data_type:數據類型。
dims:維度。
output
是
用于指定以下屬性:
name:輸入數據的名稱。
data_type:數據類型。
dims:維度。
instance_group
否
當資源配置中有GPU資源時,默認使用GPU進行模型推理,否則默認使用CPU。您也可以通過配置instance_group參數,來顯式指定模型推理使用的資源,配置格式如下:
instance_group [ { kind: KIND_GPU } ]
其中kind可配置為KIND_GPU或KIND_CPU。
version_policy
否
用于指定模型版本,配置示例如下:
version_policy: { all { }} version_policy: { latest: { num_versions: 2}} version_policy: { specific: { versions: [1,3]}}
不配置該參數:默認加載版本號最大的模型版本。示例中resnet50_pt模型會加載模型版本3。
all{}:表示加載該模型所有版本。示例中resnet50_pt會加載模型版本1、2和3。
latest{num_versions:}:例如配置為
num_versions: 2
,示例中resnet50_pt會加載最新的2個模型版本,即版本2和3。specific{versions:[]}:表示加載指定版本。示例中resnet50_pt會加載模型版本1和3。
部署Triton Inference Server服務。
Triton Inference Server支持配置以下兩種端口,在場景化模型部署中,系統默認使用8000端口,若您需要使用8001端口,則需要執行步驟e,否則忽略步驟e即可。
8000(端口):支持HTTP請求,在8000端口啟動HTTP服務。
8001:支持gRPC請求,在8001端口啟動gRPC服務。
具體操作步驟如下:
登錄PAI控制臺,在頁面上方選擇目標地域,并在右側選擇目標工作空間,然后單擊進入EAS。
在模型在線服務(EAS)頁面,單擊部署服務,然后在場景化模型部署區域,單擊Triton部署。
在Triton部署頁面,配置以下關鍵參數,其他參數配置說明,請參見服務部署:控制臺。
參數
描述
服務名稱
自定義配置服務名稱。
模型配置
在本方案中,配置類型選擇對象存儲(OSS),將OSS配置為步驟1中已準備的模型所在的OSS存儲路徑,例如
oss://example/models/triton/
。(可選)單擊頁面右側的切換為自定義部署,修改環境信息區域的端口號為8001,同時您需要在服務配置中添加以下配置。
說明服務默認在8000端口啟動HTTP服務,支持HTTP請求。若您需要該服務支持gRPC請求,您需要將端口號修改為8001,系統會在8001端口啟動gRPC服務。
"metadata": { "enable_http2": true }, "networking": { "path": "/" }
參數配置完成后,單擊部署。
部署服務:多模型
EAS部署多模型服務的方式與部署單模型服務相同,您只需創建如下所示的多個模型存儲目錄即可,服務會加載所有的模型,并部署在同一個服務中。具體部署方式請參見部署服務:單模型。
triton
├── resnet50_pt
| ├── 1
| │ └── model.pt
| └── config.pbtxt
├── densenet_onnx
| ├── 1
| │ └── model.onnx
| └── config.pbtxt
└── mnist_savedmodel
├── 1
│ └── model.savedmodel
│ ├── saved_model.pb
| └── variables
| ├── variables.data-00000-of-00001
| └── variables.index
└── config.pbtxt
部署服務:使用backend
backend是模型推理計算的具體實現部分,它既可以調用現有的模型框架(如TensorRT、ONNX Runtime、PyTorch、TensorFlow等),也可以自定義模型推理邏輯(如模型預處理、后處理)。
backend支持 C++、Python兩種語言,與C++相比, Python使用起來更加靈活方便,因此以下內容主要介紹Python backend的使用方式。
更新模型目錄結構
以PyTorch為例,使用Python backend自定義模型的計算邏輯,模型目錄結構示例如下:
resnet50_pt ├── 1 │ ├── model.pt │ └── model.py └── config.pbtxt
與常規的模型目錄結構相比,backend需要在模型版本目錄下新增一個model.py文件,用于自定義模型的推理邏輯,并且配置文件config.pbtxt內容也需要做相應修改。
自定義推理邏輯
model.py文件需要定義名為TritonPythonModel的類,并實現initialize、execute、finalize三個關鍵的接口函數。該文件內容示例如下:
import json import os import torch from torch.utils.dlpack import from_dlpack, to_dlpack import triton_python_backend_utils as pb_utils class TritonPythonModel: """必須以 "TritonPythonModel" 為類名""" def initialize(self, args): """ 初始化函數,可選實現,在加載模型時被調用一次,可用于初始化與模型屬性、模型配置相關的信息。 Parameters ---------- args : 字典類型,其中keys和values都為string 類型,具體包括: * model_config:JSON格式模型配置信息。 * model_instance_kind:設備型號。 * model_instance_device_id:設備ID。 * model_repository:模型倉庫路徑。 * model_version:模型版本。 * model_name:模型名。 """ # 將JSON字符串類型的模型配置內容轉為Python的字典類型。 self.model_config = model_config = json.loads(args["model_config"]) # 獲取模型配置文件中的屬性。 output_config = pb_utils.get_output_config_by_name(model_config, "OUTPUT__0") # 將Triton types轉為numpy types。 self.output_dtype = pb_utils.triton_string_to_numpy(output_config["data_type"]) # 獲取模型倉庫的路徑。 self.model_directory = os.path.dirname(os.path.realpath(__file__)) # 獲取模型推理使用的設備,本例中使用GPU。 self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print("device: ", self.device) model_path = os.path.join(self.model_directory, "model.pt") if not os.path.exists(model_path): raise pb_utils.TritonModelException("Cannot find the pytorch model") # 通過.to(self.device)將pytorch模型加載到GPU上。 self.model = torch.jit.load(model_path).to(self.device) print("Initialized...") def execute(self, requests): """ 模型執行函數,必須實現;每次請求推理都會調用該函數,若設置了 batch 參數,還需由用戶自行實現批處理功能 Parameters ---------- requests : pb_utils.InferenceRequest類型的請求列表。 Returns ------- pb_utils.InferenceResponse 類型的返回列表。列表長度必須與請求列表一致。 """ output_dtype = self.output_dtype responses = [] # 遍歷request列表,并為每個請求都創建對應的response。 for request in requests: # 獲取輸入tensor。 input_tensor = pb_utils.get_input_tensor_by_name(request, "INPUT__0") # 將Triton tensor轉換為Torch tensor。 pytorch_tensor = from_dlpack(input_tensor.to_dlpack()) if pytorch_tensor.shape[2] > 1000 or pytorch_tensor.shape[3] > 1000: responses.append( pb_utils.InferenceResponse( output_tensors=[], error=pb_utils.TritonError( "Image shape should not be larger than 1000" ), ) ) continue # 在GPU上進行推理計算。 prediction = self.model(pytorch_tensor.to(self.device)) # 將Torch output tensor轉換為Triton tensor。 out_tensor = pb_utils.Tensor.from_dlpack("OUTPUT__0", to_dlpack(prediction)) inference_response = pb_utils.InferenceResponse(output_tensors=[out_tensor]) responses.append(inference_response) return responses def finalize(self): """ 模型卸載時調用,可選實現,可用于模型清理工作。 """ print("Cleaning up...")
重要如果使用GPU進行推理計算,此時在模型配置文件config.pbtxt中指定
instance_group.kind
為GPU的方式無效,需要通過model.to(torch.device("cuda"))
將模型加載到GPU,并在請求計算時調用pytorch_tensor.to(torch.device("cuda"))
將模型輸入Tensor分配到GPU。您只需要在部署服務時配置GPU資源,即可使用GPU進行推理計算。如果使用批處理功能,此時在模型配置文件config.pbtxt中設置max_batch_size參數的方式無效,您需要自行在execute函數中實現請求批處理的邏輯。
request與response必須一一對應,每一個request都要返回一個對應的response。
更新配置文件
配置文件config.pbtxt內容示例如下:
name: "resnet50_pt" backend: "python" max_batch_size: 128 input [ { name: "INPUT__0" data_type: TYPE_FP32 dims: [ 3, -1, -1 ] } ] output [ { name: "OUTPUT__0" data_type: TYPE_FP32 dims: [ 1000 ] } ] parameters: { key: "FORCE_CPU_ONLY_INPUT_TENSORS" value: {string_value: "no"} }
其中關鍵參數說明如下,其余配置與之前保持一致即可。
backend:需指定為python。
parameters:可選配置,當模型推理使用GPU時,可將FORCE_CPU_ONLY_INPUT_TENSORS參數設置為no,來避免推理計算時輸入Tensor在CPU與GPU之間來回拷貝產生不必要的開銷。
部署服務。
使用Python backend必須設置共享內存,最后通過如下配置創建模型服務,即可實現自定義模型推理邏輯。關于如何使用客戶端創建模型服務,請參見服務部署:EASCMD或DSW。
{ "metadata": { "name": "triton_server_test", "instance": 1, }, "cloud": { "computing": { "instance_type": "ml.gu7i.c8m30.1-gu30", "instances": null } }, "containers": [ { "command": "tritonserver --model-repository=/models", "image": "eas-registry-vpc.<region>.cr.aliyuncs.com/pai-eas/tritonserver:23.02-py3", "port": 8000, "prepare": { "pythonRequirements": [ "torch==2.0.1" ] } } ], "storage": [ { "mount_path": "/models", "oss": { "path": "oss://oss-test/models/triton_backend/" } }, { "empty_dir": { "medium": "memory", // 配置共享內存為1 GB。 "size_limit": 1 }, "mount_path": "/dev/shm" } ] }
其中:
name:需要自定義模型服務名稱。
storage.oss.path:更新為您的模型存儲目錄所在的OSS Bucket路徑。
containers.image:將<region>替換為當前地域,例如:華東2(上海)為cn-shanghai。
調用服務:發送服務請求
您可以通過客戶端發送請求來使用模型服務,Python代碼示例如下:
發送HTTP請求
端口號配置為8000時,服務支持發送HTTP請求。
import numpy as np import tritonclient.http as httpclient # url為EAS服務部署后生成的訪問地址。 url = '1859257******.cn-hangzhou.pai-eas.aliyuncs.com/api/predict/triton_server_test' triton_client = httpclient.InferenceServerClient(url=url) image = np.ones((1,3,224,224)) image = image.astype(np.float32) inputs = [] inputs.append(httpclient.InferInput('INPUT__0', image.shape, "FP32")) inputs[0].set_data_from_numpy(image, binary_data=False) outputs = [] outputs.append(httpclient.InferRequestedOutput('OUTPUT__0', binary_data=False)) # 獲取 1000 維的向量 # 指定模型名稱、請求Token、輸入輸出。 results = triton_client.infer( model_name="<model_name>", model_version="<version_num>", inputs=inputs, outputs=outputs, headers={"Authorization": "<test-token>"}, ) output_data0 = results.as_numpy('OUTPUT__0') print(output_data0.shape) print(output_data0)
其中關鍵參數配置說明如下:
參數
描述
url
配置服務訪問地址,服務訪問地址需要省略
http://
。您可以在模型在線服務(EAS)頁面,單擊服務名稱,然后在服務詳情頁簽中單擊查看調用信息,查看公網調用地址。model_name
配置模型目錄名稱,例如resnet50_pt。
model_version
配置實際的模型版本號,每次只能對一個模型版本發送請求。
headers
將<test-token>替換為服務Token,您可以在公網地址調用頁簽查看Token。
發送gRPC請求
端口號配置為8001,并添加gRPC相關配置后,服務支持發送gRPC請求。
#!/usr/bin/env python import grpc from tritonclient.grpc import service_pb2, service_pb2_grpc import numpy as np if __name__ == "__main__": # 定義服務的訪問地址。 host = ( "service_name.115770327099****.cn-beijing.pai-eas.aliyuncs.com:80" ) # 服務Token,實際應用中應使用真實的Token。 token = "test-token" # 模型名稱和版本。 model_name = "resnet50_pt" model_version = "1" # 創建gRPC元數據,用于Token驗證。 metadata = (("authorization", token),) # 創建gRPC通道和存根,用于與服務器通信。 channel = grpc.insecure_channel(host) grpc_stub = service_pb2_grpc.GRPCInferenceServiceStub(channel) # 構建推理請求。 request = service_pb2.ModelInferRequest() request.model_name = model_name request.model_version = model_version # 構造輸入張量,對應模型配置文件中定義的輸入參數。 input = service_pb2.ModelInferRequest().InferInputTensor() input.name = "INPUT__0" input.datatype = "FP32" input.shape.extend([1, 3, 224, 224]) # 構造輸出張量,對應模型配置文件中定義的輸出參數。 output = service_pb2.ModelInferRequest().InferRequestedOutputTensor() output.name = "OUTPUT__0" # 創建輸入請求。 request.inputs.extend([input]) request.outputs.extend([output]) # 構造隨機數組并序列化為字節序列,作為輸入數據。 request.raw_input_contents.append(np.random.rand(1, 3, 224, 224).astype(np.float32).tobytes()) #數值類型 # 發起推理請求,并接收響應。 response, _ = grpc_stub.ModelInfer.with_call(request, metadata=metadata) # 提取響應中的輸出張量。 output_contents = response.raw_output_contents[0] # 假設只有一個輸出張量。 output_shape = [1, 1000] # 假設輸出張量的形狀是[1, 1000]。 # 將輸出字節轉換為numpy數組。 output_array = np.frombuffer(output_contents, dtype=np.float32) output_array = output_array.reshape(output_shape) # 打印模型的輸出結果。 print("Model output:\n", output_array)
其中關鍵參數配置說明如下:
參數
描述
host
需要配置為服務訪問地址,服務訪問地址需要省略
http://
并在末尾添加:80
。您可以在模型在線服務(EAS)頁面,單擊服務名稱,然后在服務詳情頁簽中單擊查看調用信息,查看公網調用地址。token
將<test-token>替換為服務Token,您可以在公網地址調用頁簽查看Token。
model_name
配置模型目錄名稱,例如resnet50_pt。
model_version
配置實際的模型版本號,每次只能對一個模型版本發送請求。
相關文檔
如何基于TensorFlow Serving推理服務引擎部署EAS服務,請參見TensorFlow Serving鏡像部署。
如何使用Modelscope、Huggingface鏡像將相應的開源模型部署為EAS服務,請參見Modelscope模型部署和HuggingFace鏡像部署。
您也可以開發自定義鏡像,使用自定義鏡像部署EAS服務。具體操作,請參見服務部署:自定義鏡像。
服務部署完成后,您可以通過自動壓測工具,對部署的服務進行壓測,從而了解EAS服務的使用性能。詳情請參見服務自動壓測。
場景化模型部署成功后,您可以調用該服務來驗證模型效果,詳情請參見EAS使用案例匯總。