在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配置文件(用于定义模型行为和优化)。

  1. 创建目录结构

    mkdir -p model_repository/embedding_py/1
    
  2. 创建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.')
    
  3. 创建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个实例,客户端必须能够并行地发送请求。使用asyncioaiohttp是实现高并发客户端的有效方式。

# 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. 准备模型仓库
  1. 创建目录结构并移动模型

    mkdir -p model_repository/embedding_onnx/1
    mv./embedding_onnx_model/model.onnx model_repository/embedding_onnx/1/
    
  2. 创建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配置文件,以及模型运行所需的依赖。

  1. 创建目录结构

    # 创建模型和版本目录
    mkdir -p model_repository/full_pipeline_py/1# 创建一个存放依赖的目录 (可选但推荐)
    mkdir -p model_repository/full_pipeline_py/requirements
    
  2. 准备依赖
    由于Python后端默认环境中可能没有sentence-transformers或文件解析库(如pypdf2),您需要提供它们。最简单的方式是创建一个requirements.txt文件。

    # 保存为 model_repository/full_pipeline_py/requirements.txt
    sentence-transformers
    # 如果您需要解析PDF,可以添加
    # pypdf2
    

    Triton会在加载模型时自动使用pip安装这些依赖。

  3. 创建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
    
  4. 创建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())

方案二:混合后端实现流水线 (性能优化方案)

这种方法更先进,也更复杂。它将流水线拆分为两个部分,分别由最适合的后端处理:

  1. Python后端 (Orchestrator):负责处理文件IO、解析、分块这些灵活的自定义逻辑。
  2. 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. 准备模型仓库 (包含两个模型)
  1. 创建目录结构

    # 为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
    
  2. 配置embedding_onnx模型
    这个模型是内部服务,负责高性能计算。

    • config.pbtxt for embedding_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
      
  3. 配置pipeline_orchestrator模型
    这个模型是流水线的入口,负责编排。

    • 准备依赖

      # 保存为 model_repository/pipeline_orchestrator/requirements.txt
      transformers # 只需要分词器
      # pypdf2 # 如果需要
      
    • model.py for pipeline_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 for pipeline_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)方案二 (混合后端)
性能中等
部署复杂度
代码维护简单 (所有逻辑在一个文件)复杂 (逻辑分散在两个模型)
灵活性极高极高
资源利用最佳 (为不同任务使用最优后端)

给您的建议:

  1. 从方案一开始:首先实现纯Python后端的流水线。它更容易调试,能让您快速验证整个流程的正确性。对于中等负载,通过增加instance_groupcount,它的性能可能已经足够满足您的需求。

  2. 当性能成为瓶颈时,再转向方案二:如果您的QPS(每秒查询率)要求非常高,或者单个请求的延迟需要被极致压缩,那么投入精力去实现混合后端方案是值得的。它将计算最密集的部分交给了最高效的ONNX后端,能最大化您32核CPU的吞吐能力。

方案二代表了Triton更高级的用法,是实现生产级高性能服务的理想架构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/92937.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/92937.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/92937.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java动态调试技术原理

本文转载自 美团技术团队胡健的Java 动态调试技术原理及实践, 通过学习java agent方式进行动态调试了解目前很多大厂开源的一些基于此的调试工具。 简介 断点调试是我们最常使用的调试手段&#xff0c;它可以获取到方法执行过程中的变量信息&#xff0c;并可以观察到方法的执…

人工智能-python-OpenCV 图像基础认知与运用

文章目录OpenCV 图像基础认知与运用1. OpenCV 简介与安装OpenCV 的优势安装 OpenCV2. 图像的基本概念2.1. 图像的存储格式2.2. 图像的表示3. 图像的基本操作3.1. 创建图像窗口3.2. 读取与显示图像3.3. 保存图像3.4. 图像切片与区域提取3.5. 图像大小调整4. 图像绘制与注释4.1. …

Windows电脑添加、修改打印机的IP地址端口的方法

本文介绍在Windows电脑中&#xff0c;为打印机添加、修改IP地址&#xff0c;从而解决电脑能找到打印机、但是无法打印问题的方法。最近&#xff0c;办公室的打印机出现问题——虽然在电脑的打印机列表能找到这个打印机&#xff0c;但是选择打印时&#xff0c;就会显示文档被挂起…

告别复杂配置!Spring Boot优雅集成百度OCR的终极方案

1. 准备工作 1.1 注册百度AI开放平台 访问百度AI开放平台 注册账号并登录 进入控制台 → 文字识别 → 创建应用 记录下API Key和Secret Key 2. 项目配置 2.1 添加依赖 (pom.xml) <dependencies><!-- Spring Boot Web --><dependency><groupId>o…

「iOS」——内存五大分区

UI学习iOS-底层原理 24&#xff1a;内存五大区总览一、栈区&#xff08;Stack&#xff09;1.1 核心特性1.2 优缺点1.3函数栈与栈帧1.3 堆栈溢出风险二、堆区&#xff08;Heap&#xff09;;2.1 核心特性2.2 与栈区对比三、全局 / 静态区&#xff08;Global/Static&#xff09;3.…

每日一题【删除有序数组中的重复项 II】

删除有序数组中的重复项 II思路class Solution { public:int removeDuplicates(vector<int>& nums) {if(nums.size()<2){return nums.size();}int index 2;for (int i 2; i < nums.size();i ) {if(nums[i] ! nums[index-2]) {nums[index]nums[i];}}return ind…

兼容性问题记录

1、dialog设置高度MATCH_PARENT全屏后&#xff0c;三星机型和好像是一加&#xff0c;会带出顶部状态栏&#xff0c;设置隐藏状态栏属性无效。解决方法&#xff1a;高度不设置为MATCH_PARENT&#xff0c;通过windowmanager.getdefaultdisplay来获取并设置高度&#xff0c;再设置…

6.数组和字符串

在C语言中&#xff0c;数组和字符串是基础且重要的概念。它们用于存储和操作一系列相同类型的元素或字符序列。数组1. 数组定义与初始化数组是一系列相同类型的数据项的集合&#xff0c;这些数据项可以通过一个共同的名字来引用。数组中的每个元素都有一个索引&#xff08;也称…

odoo代码分析(一)

Odoo 是一套基于网络的开放式源代码商业应用套件,既可以作为独立应用运行,也可以作为集成的全功能 ERP 系统使用。Odoo 平台采用模块化架构,允许组织根据自身需求起步,并在需求增长时扩展功能。 什么是 Odoo? Odoo 提供了一个完整的商业应用生态系统,包括: 客户关系管…

从“人工眼”到‘智能眼’:EZ-Vision视觉系统如何重构生产线视觉检测精度?

制造业是我国实体经济的基础&#xff0c;是国内经济增长的重要引擎。制造业智能化建设是当下的必然趋势&#xff0c;然而目前依旧有很多中小型企业因为成本原因&#xff0c;无法加快智能化制造的步伐。在智能检测领域更是如此&#xff0c;很多企业依旧在采用人工检测&#xff0…

Etcd原理基础学习

etcd 是一个开源的分布式键值存储系统&#xff0c;专注于提供高可用性、强一致性的数据存储与访问&#xff0c;广泛应用于分布式系统的服务发现、配置管理和协调任务。以下是其核心特性和应用场景的详细介绍。接下来就看看Etcd如何实现服务注册&#xff0c;以及如何通过Raft算法…

【硬件-笔试面试题】硬件/电子工程师,笔试面试题-32,(知识点:模数转换器,信噪比,计算公式,)

目录 1、题目 2、解答 步骤一&#xff1a;明确理想 ADC 的信噪比公式 步骤二&#xff1a;推导公式的来源 步骤三&#xff1a;得出答案 3、相关知识点 一、信噪比&#xff08;SNR&#xff09;的定义 二、理想 ADC 的量化噪声 三、满量程正弦波信号的功率 四、信噪比公…

Redis过期数据的删除策略是什么?有哪些?

定时删除&#xff1a;- 每个设置了TTL的key中都会创建一个计时器&#xff0c;等到过期时间就会立即删除- 对内存友好&#xff0c;但是会占用大量的CPU资源去处理过期数据&#xff0c;从而影响缓存的吞吐量和响应时间惰性删除&#xff1a;- 设置了key的过期后&#xff0c;不会立…

linux dd命令详解

dd 是一个功能强大的 Unix/Linux 命令行工具&#xff0c;用于低级别的字节流操作&#xff0c;常用于创建、复制、转换和处理文件或设备数据。它在 macOS 和 Linux 系统上都可用&#xff0c;但在 macOS 上有一些细微差异。本文将详细讲解 dd 命令的用法&#xff0c;包括参数、常…

多线程同步技术是用于协调多个线程访问共享资源或执行顺序的机制,以避免数据竞争、死锁、线程不安全等问题

多线程同步技术是用于协调多个线程访问共享资源或执行顺序的机制,以避免数据竞争、死锁、线程不安全等问题。 在提供的代码中,存在多线程操作加热板的场景,涉及锁竞争和硬件资源访问,优化多线程同步可以显著提升程序性能和稳定性。 以下是多线程同步技术的详细解释、常见…

CRMEB标准版,从创建数据表到实现最基础增删改查的实现过程

很多使用了CRMEB单商户系统的童鞋在进行二开的时候&#xff0c;都会遇到新建了数据表之后不知道对数据表怎么进行操作。那么&#xff0c;这篇文章将带你完整的实现一遍&#xff0c;以后就不会怕啦。一、创建数据表就以最简单的为例&#xff0c;创建一个学生的信息表编号姓名性别…

J2EE模式---数据访问对象模式

数据访问对象模式基础概念数据访问对象模式&#xff08;Data Access Object Pattern&#xff0c;简称 DAO 模式&#xff09;是一种结构型设计模式&#xff0c;其核心思想是将数据访问逻辑与业务逻辑分离&#xff0c;通过一个抽象层&#xff08;DAO&#xff09;来处理数据的持久…

【OpenCV篇】OpenCV——02day.图像预处理(1)

目录 前言 一、图像色彩空间转换 1 RGB颜色空间 2 颜色加法 3 颜色加权加法 4 HSV颜色空间 5 RGB转Gray(灰度) 二、灰度实验 1 灰度图 2 最大值法 3 平均值法 4 加权均值法 5 两个极端的灰度值 三、图像二值化处理 二值图像 1 阈值法(THRESH_BINARY) 2 反阈值…

经典IDE之Turbo C

写的程序不多&#xff0c;换过的 IDE 不少&#xff0c;本文将列举曾经用过的不同 C 语言相关的 IDE 环境&#xff0c;既是纪念&#xff0c;也是回忆。值得注意的是 IDE 的出现是为了提高开发效率&#xff0c;有一个相对成熟的编译环境和程序。从编程的角度来看&#xff0c;过分…

Go 多模块仓库标签管理教程

为了方便自己开发&#xff0c;自己写了个小工具&#xff1a;DzhGO 代码生成工具 功能特点标题 初始化项目基础结构生成插件模块代码生成模型和实体代码生成服务接口和实现代码支持 admin 和 app 两种模块类型生成项目基础目录 具体介绍看仓库&#xff1a; https://github.co…