深度学习模型部署指南-ONNX - TensorRT - Triton_第1页
深度学习模型部署指南-ONNX - TensorRT - Triton_第2页
深度学习模型部署指南-ONNX - TensorRT - Triton_第3页
深度学习模型部署指南-ONNX - TensorRT - Triton_第4页
深度学习模型部署指南-ONNX - TensorRT - Triton_第5页
已阅读5页,还剩59页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

深度学习模型部署指南

ONNX·TensorRT·Triton

从模型导出到高并发推理服务的全链路实战

10大章节·50+代码示例·30条优化技巧

模型部署实战系列

目录

第一章模型部署全景与核心挑战

第二章ONNX模型交换格式详解

第三章ONNXRuntime推理实战

第四章TensorRT加速原理与优化

第五章TensorRT引擎构建与部署

第六章TritonInferenceServer架构

第七章Triton模型仓库与配置实战

第八章性能对比、选型与混合部署

第九章生产环境监控、运维与安全

第十章常见问题排查与实战速查表

深度学习模型部署指南·ONNX/TensorRT/Triton

第一章模型部署全景与核心挑战

1.1为什么模型部署是独立课题

训练一个高精度的深度学习模型,与把它部署到生产环境并稳定服务,是两件完全不同的事情。训练阶段关注

的是模型精度、收敛速度、实验迭代效率;部署阶段关注的是推理延迟、吞吐量、资源占用、稳定性、可扩展性。

很多在实验室表现优异的模型,一旦上线就暴露出各种问题:延迟过高无法满足业务要求、显存占用超出硬件限

制、并发请求下性能急剧下降、不同硬件平台无法兼容。

模型部署的核心挑战可以归纳为五个方面。性能挑战:如何在有限的硬件资源下,把推理延迟降到最低、吞吐

量提到最高。兼容性挑战:训练框架(PyTorch、TensorFlow)与推理环境(服务器、边缘设备)的差异,需要中

间格式来桥接。工程挑战:如何管理多个模型版本、支持动态批处理、实现灰度发布、监控推理质量。成本挑战:

GPU资源昂贵,如何用更少的卡支撑更高的并发。可靠性挑战:服务必须7×24小时稳定运行,具备容错、降级、

熔断能力。

1.2部署技术栈全景

一个完整的深度学习部署技术栈通常包含四层。最上层是训练框架层(PyTorch、TensorFlow、JAX),负责模

型的定义和训练。第二层是模型交换格式层(ONNX),负责把不同框架训练的模型统一成标准格式。第三层是推

理引擎层(ONNXRuntime、TensorRT、OpenVINO),负责在特定硬件上高效执行模型。最下层是推理服务层

(Triton、TorchServe、TFServing),负责模型管理、请求调度、动态批处理、监控指标。

层次代表技术核心职责

训练框架PyTorch、TensorFlow、JAX模型定义、训练、导出

交换格式ONNX跨框架、跨平台的模型表示

推理引擎ONNXRuntime、TensorRT、OpenVINO图优化、算子融合、硬件加速

推理服务Triton、TorchServe、TFServing模型管理、批处理、服务化

1.3推理性能的关键指标

评估推理性能时,需要关注以下指标,它们共同决定了服务的用户体验和成本效率。

指标定义影响

延迟Latency单个请求从发出到返回的时间直接影响用户体验

吞吐量Throughput单位时间处理的请求数决定服务能力和成本

P50/P95/P99延迟延迟的分位数分布评估长尾延迟,P99影响体验

显存占用模型运行占用的GPU显存决定单卡能部署多少模型

GPU利用率GPU计算单元的繁忙程度反映资源利用效率

冷启动时间服务启动到可用的时间影响弹性扩缩容速度

1.4部署流程标准步骤

深度学习模型部署标准流程:

第1步:模型训练与验证

-在PyTorch/TensorFlow中完成训练

-验证模型精度达到上线标准

-固定模型结构和权重

第2步:模型导出

-导出为ONNX格式(通用)

-或直接导出为TensorRT引擎(NVIDIAGPU)

-验证导出前后输出一致性

第3步:图优化

-常量折叠、算子融合

-死代码消除、布局优化

-精度校准(INT8量化)

第4步:推理引擎构建

-ONNXRuntime加载ONNX

-TensorRT构建优化引擎

-选择最优的精度模式(FP32/FP16/INT8)

第5步:服务化封装

-使用Triton/TorchServe部署

-配置动态批处理、并发模型

-暴露HTTP/gRPC接口

第6步:性能测试

-基准测试延迟和吞吐

-压力测试极限并发

-对比不同配置的性能

第7步:上线与监控

-灰度发布,逐步放量

-监控延迟、吞吐、错误率

-建立告警和自动扩缩容

部署不是一次性工作:模型部署是一个持续迭代的过程。上线后需要根据线上表现持续优化:模型可能因为

数据分布变化需要重新训练,性能可能因为流量增长需要重新调优,硬件可能因为成本考虑需要重新选型。建

立一套可持续的部署流水线,比单次成功的部署更有价值。

第二章ONNX模型交换格式详解

2.1ONNX的设计目标

ONNX(OpenNeuralNetworkExchange)是一个开放的模型表示标准,由Facebook和Microsoft于2017年联合

发起。它的核心目标是解决深度学习生态的碎片化问题:不同框架训练的模型无法互通,不同硬件平台的推理引擎

各不相同。ONNX通过定义一套与框架无关的计算图表示,让模型可以在框架之间自由迁移。

ONNX的核心价值在于三点。第一,框架无关:PyTorch、TensorFlow、PaddlePaddle等框架训练的模型都可以

导出为ONNX。第二,硬件无关:ONNX模型可以在CPU、GPU、NPU、FPGA等多种硬件上运行。第三,引擎无

关:ONNXRuntime、TensorRT、OpenVINO等多种推理引擎都支持加载ONNX模型。

2.2ONNX模型结构

ONNX模型本质上是一个计算图(ComputationalGraph),由节点(Node)、张量(Tensor)和属性

(Attribute)组成。每个节点代表一个算子(如Conv、Relu、MatMul),张量是节点之间传递的数据,属性是算子

的参数。

#ONNX模型的内部结构(概念示意)

Model

├──graph(计算图)

│├──node[](节点列表)

││├──node:Conv

│││├──input:["input","weight"]

│││├──output:["conv_out"]

│││└──attribute:{kernel_shape:[3,3],strides:[1,1]}

││├──node:Relu

│││├──input:["conv_out"]

│││└──output:["relu_out"]

││└──...

│├──initializer[](权重常量)

│├──input[](模型输入)

│└──output[](模型输出)

├──opset_import(算子集版本)

├──producer_name(导出工具)

└──metadata(元信息)

#查看ONNX模型结构的常用工具

importonnx

model=onnx.load("model.onnx")

print(onnx.helper.printable_graph(model.graph))

#检查模型合法性

onnx.checker.check_model(model)

#查看算子集版本

print(f"Opset:{model.opset_import[0].version}")

print(f"Producer:{ducer_name}")

2.3从PyTorch导出ONNX

#基础导出示例

importtorch

importtorch.nnasnn

classSimpleModel(nn.Module):

def__init__(self):

super().__init__()

self.conv1=nn.Conv2d(3,16,3,padding=1)

self.relu=nn.ReLU()

self.pool=nn.MaxPool2d(2)

self.fc=nn.Linear(16*16*16,10)

defforward(self,x):

x=self.conv1(x)

x=self.relu(x)

x=self.pool(x)

x=x.view(x.size(0),-1)

x=self.fc(x)

returnx

model=SimpleModel()

model.eval()

#构造示例输入(用于追踪计算图)

dummy_input=torch.randn(1,3,32,32)

#导出ONNX

torch.onnx.export(

model,

dummy_input,

"simple_model.onnx",

export_params=True,#导出权重

opset_version=17,#ONNX算子集版本

do_constant_folding=True,#常量折叠优化

input_names=["input"],#输入名

output_names=["output"],#输出名

dynamic_axes={#动态维度

"input":{0:"batch_size"},

"output":{0:"batch_size"}

}

)

print("ONNX模型导出完成")

2.4导出复杂模型的注意事项

导出复杂模型时,常常遇到各种问题。以下是最常见的几类问题和解决方案。

问题原因解决方案

不支持某算子ONNX算子集未收录该算子升级opset_version;自定义算子;改写模型

动态控制流失败ONNX追踪模式不支持Python控制流使用torch.jit.script;改写为静态图

输出不一致追踪时未覆盖全部分支用多种输入追踪;检查模型中的if/for

精度下降某些算子的实现差异对比导出前后输出;使用容差较大的验证

大模型导出慢图规模大,优化耗时长关闭常量折叠;分阶段导出

Transformer导出失败自注意力的动态形状使用HuggingFace的optimum工具

#处理动态控制流的示例

importtorch

classDynamicModel(torch.nn.Module):

def__init__(self):

super().__init__()

self.fc=torch.nn.Linear(10,10)

defforward(self,x,use_branch:bool):

#使用torch.jit.script支持控制流

ifuse_branch:

returnself.fc(x)+1

else:

returnself.fc(x)-1

#方式一:使用torch.jit.script

scripted=torch.jit.script(DynamicModel())

#可以正常导出带控制流的模型

#方式二:改写为无控制流

classStaticModel(torch.nn.Module):

def__init__(self):

super().__init__()

self.fc=torch.nn.Linear(10,10)

defforward(self,x,offset):

#把分支逻辑改为参数

returnself.fc(x)+offset

#方式三:使用HuggingFaceOptimum(推荐用于Transformer)

fromoptimum.onnxruntimeimportORTModelForSequenceClassification

fromtransformersimportAutoTokenizer

model=ORTModelForSequenceClassification.from_pretrained(

"distilbert-base-uncased-finetuned-sst-2-english",

export=True

)

tokenizer=AutoTokenizer.from_pretrained(

"distilbert-base-uncased-finetuned-sst-2-english"

)

model.save_pretrained("./onnx_model")

2.5ONNX图优化

导出的ONNX模型通常包含大量冗余算子,可以通过图优化来精简。ONNX提供了多种优化级别。

#ONNX图优化示例

importonnx

fromonnxruntime.transformersimportoptimizer

#方式一:基础图优化

fromonnxruntime.transformers.optimizerimportoptimize_model

optimized=optimize_model(

"model.onnx",

model_type="bert",#模型类型,支持bert/gpt2/t5等

num_heads=12,#注意力头数

hidden_size=768,#隐藏层维度

opt_level=1,#优化级别0-3

use_gpu=True,

only_onnxruntime=False

)

optimized.save_model_to_file("model_optimized.onnx")

#方式二:使用onnx-simplifier

#pipinstallonnx-simplifier

importonnxsim

model=onnx.load("model.onnx")

simplified,check=onnxsim.simplify(

model,

input_shapes={"input":[1,3,224,224]},

dynamic_input_shape=False

)

onnx.save(simplified,"model_simplified.onnx")

#方式三:使用onnxruntime的图形优化

importonnxruntimeasort

sess_options=ort.SessionOptions()

sess_options.graph_optimization_level=ort.GraphOptimizationLevel.ORT_ENABLE_ALL

sess_options.optimized_model_filepath="model_optimized_ort.onnx"

session=ort.InferenceSession("model.onnx",sess_options)

#优化级别说明:

#ORT_DISABLE_ALL:禁用所有优化

#ORT_ENABLE_BASIC:基础优化(常量折叠、死代码消除)

#ORT_ENABLE_EXTENDED:扩展优化(算子融合、布局优化)

#ORT_ENABLE_ALL:全部优化(推荐)

2.6ONNX模型验证

#验证ONNX模型正确性

importonnx

importonnxruntimeasort

importnumpyasnp

importtorch

defvalidate_onnx(onnx_path,torch_model,dummy_input):

"""验证导出前后输出一致性"""

#1.检查ONNX模型合法性

model=onnx.load(onnx_path)

onnx.checker.check_model(model)

print("ONNX模型格式检查通过")

#2.在ONNXRuntime中运行

ort_session=ort.InferenceSession(onnx_path)

ort_inputs={

ort_session.get_inputs()[0].name:dummy_input.numpy()

}

ort_output=ort_session.run(None,ort_inputs)[0]

#3.在PyTorch中运行

torch_model.eval()

withtorch.no_grad():

torch_output=torch_model(dummy_input).numpy()

#4.对比输出

diff=np.abs(ort_output-torch_output)

max_diff=diff.max()

mean_diff=diff.mean()

print(f"最大差异:{max_diff:.6e}")

print(f"平均差异:{mean_diff:.6e}")

#5.判断一致性

ifmax_diff<1e-4:

print("输出一致性验证通过")

returnTrue

else:

print("警告:输出差异较大,需要检查")

returnFalse

#使用

model=SimpleModel()

model.eval()

dummy_input=torch.randn(1,3,32,32)

validate_onnx("simple_model.onnx",model,dummy_input)

ONNX导出的常见陷阱:第一,导出时必须调用model.eval(),否则Dropout和BatchNorm行为不一致。

第二,动态维度必须通过dynamic_axes显式声明,否则batch维度会被固定。第三,导出后必须验证输出一

致性,不能假定导出无误差。第四,不同opset_version支持的算子不同,要根据推理引擎的能力选择。第

五,导出大模型时注意内存占用,可能需要分批导出。

第三章ONNXRuntime推理实战

3.1ONNXRuntime的定位

ONNXRuntime(ORT)是Microsoft开源的跨平台推理引擎,专为ONNX模型设计。它支持CPU、GPU

(CUDA/TensorRT)、NPU等多种硬件后端,在云端和边缘设备上都有广泛应用。ONNXRuntime的核心优势在

于:跨平台支持广泛、图优化能力强、与ONNX格式深度集成、部署简单。

3.2安装与基础推理

#安装

#CPU版本

pipinstallonnxruntime

#GPU版本(CUDA)

pipinstallonnxruntime-gpu

#查看支持的执行提供器

importonnxruntimeasort

print(ort.get_available_providers())

#输出示例:['TensorrtExecutionProvider','CUDAExecutionProvider','CPUExecutionProvider']

#基础推理示例

importonnxruntimeasort

importnumpyasnp

#创建推理会话

session=ort.InferenceSession(

"simple_model.onnx",

providers=[

("CUDAExecutionProvider",{

"device_id":0,

"arena_extend_strategy":"kNextPowerOfTwo",

"gpu_mem_limit":2*1024*1024*1024,#2GB

}),

"CPUExecutionProvider"

]

)

#查看模型输入输出

forinpinsession.get_inputs():

print(f"输入:{},形状:{inp.shape},类型:{inp.type}")

foroutinsession.get_outputs():

print(f"输出:{},形状:{out.shape},类型:{out.type}")

#执行推理

input_data=np.random.randn(1,3,32,32).astype(np.float32)

outputs=session.run(

None,#输出名,None表示全部输出

{"input":input_data}#输入字典

)

print(f"输出形状:{outputs[0].shape}")

3.3会话配置优化

#优化ONNXRuntime会话配置

importonnxruntimeasort

#创建会话选项

sess_options=ort.SessionOptions()

#图优化级别

sess_options.graph_optimization_level=\

ort.GraphOptimizationLevel.ORT_ENABLE_ALL

#线程配置

sess_ra_op_num_threads=4#算子内并行线程数

sess_er_op_num_threads=2#算子间并行线程数

sess_options.execution_mode=ort.ExecutionMode.ORT_SEQUENTIAL

#ORT_SEQUENTIAL:顺序执行

#ORT_PARALLEL:并行执行

#内存优化

sess_options.enable_cpu_mem_arena=True

sess_options.enable_mem_pattern=True

sess_options.enable_mem_reuse=True

#日志配置

sess_options.log_severity_level=3#0=Verbose,1=Info,2=Warning,3=Error

sess_options.log_verbosity_level=1

#优化后的模型保存

sess_options.optimized_model_filepath="optimized_model.onnx"

#创建会话

session=ort.InferenceSession(

"model.onnx",

sess_options=sess_options,

providers=["CUDAExecutionProvider","CPUExecutionProvider"]

)

#性能分析

sess_options.enable_profiling=True

sess_file_file_prefix="ort_profile"

#运行后生成profile文件

#session.end_profiling()可以结束并保存

3.4动态批处理与多流执行

#动态批处理:自动处理不同batchsize的输入

importonnxruntimeasort

importnumpyasnp

session=ort.InferenceSession(

"dynamic_model.onnx",

providers=["CUDAExecutionProvider"]

)

#不同batchsize的输入

forbatch_sizein[1,4,8,16,32]:

input_data=np.random.randn(batch_size,3,224,224).astype(np.float32)

output=session.run(None,{"input":input_data})

print(f"Batch{batch_size}:输出形状{output[0].shape}")

#多流执行:并行处理多个请求

importconcurrent.futures

definference(session,data):

returnsession.run(None,{"input":data})

#使用线程池并发推理

withconcurrent.futures.ThreadPoolExecutor(max_workers=4)asexecutor:

futures=[

executor.submit(inference,session,np.random.randn(1,3,224,

224).astype(np.float32))

for_inrange(8)

]

results=[f.result()forfinfutures]

print(f"完成{len(results)}个推理请求")

3.5ONNXRuntime的CUDA优化

#CUDA执行提供器的详细配置

importonnxruntimeasort

cuda_provider_options={

"device_id":0,

"arena_extend_strategy":"kNextPowerOfTwo",#或kSameAsRequested

"gpu_mem_limit":4*1024*1024*1024,#4GB

"cudnn_conv_algo_search":"EXHAUSTIVE",#或HEURISTIC,DEFAULT

"do_copy_in_default_stream":True,

"cudnn_conv_use_max_workspace":"1",

"enable_cuda_graph":"1",#启用CUDAGraph

"use_tf32":"1",#启用TF32(Ampere+)

}

session=ort.InferenceSession(

"model.onnx",

providers=[("CUDAExecutionProvider",cuda_provider_options)]

)

#TensorRT执行提供器(在NVIDIAGPU上性能最优)

trt_provider_options={

"device_id":0,

"trt_max_workspace_size":4*1024*1024*1024,

"trt_fp16_enable":True,

"trt_int8_enable":False,

"trt_engine_cache_enable":True,

"trt_engine_cache_path":"./trt_cache",

"trt_timing_cache_enable":True,

}

session=ort.InferenceSession(

"model.onnx",

providers=[("TensorrtExecutionProvider",trt_provider_options),

("CUDAExecutionProvider",cuda_provider_options)]

)

3.6性能测试

#ONNXRuntime性能测试脚本

importonnxruntimeasort

importnumpyasnp

importtime

defbenchmark(session,input_shape,num_runs=100,warmup=10):

"""基准测试"""

input_data=np.random.randn(*input_shape).astype(np.float32)

input_name=session.get_inputs()[0].name

#预热

for_inrange(warmup):

session.run(None,{input_name:input_data})

#计时

latencies=[]

for_inrange(num_runs):

start=time.perf_counter()

session.run(None,{input_name:input_data})

end=time.perf_counter()

latencies.append((end-start)*1000)#毫秒

latencies=np.array(latencies)

return{

"mean_ms":latencies.mean(),

"p50_ms":np.percentile(latencies,50),

"p95_ms":np.percentile(latencies,95),

"p99_ms":np.percentile(latencies,99),

"throughput_qps":1000/latencies.mean(),

}

#测试不同batchsize

session=ort.InferenceSession("model.onnx")

forbsin[1,4,8,16,32]:

stats=benchmark(session,(bs,3,224,224))

print(f"Batch{bs}:")

print(f"平均延迟:{stats['mean_ms']:.2f}ms")

print(f"P99延迟:{stats['p99_ms']:.2f}ms")

print(f"吞吐量:{stats['throughput_qps']:.1f}QPS")

ONNXRuntime的适用场景:ONNXRuntime最适合需要跨平台、跨硬件部署的场景。它可以在Windows、

Linux、macOS、Android、iOS上运行,支持CPU、CUDA、TensorRT、DirectML、OpenVINO等多种后端。如

果目标平台是NVIDIAGPU且追求极致性能,TensorRT是更好的选择;如果需要跨多种硬件,ONNXRuntime

的通用性更有优势。

第四章TensorRT加速原理与优化

4.1TensorRT的定位

TensorRT是NVIDIA推出的高性能深度学习推理SDK,专为NVIDIAGPU优化。它通过图优化、算子融合、精

度校准、内核自动调优等技术,把模型在NVIDIAGPU上的推理性能提升数倍。TensorRT在自动驾驶、视频分析、

推荐系统、大语言模型推理等场景中广泛应用。

TensorRT的性能优势主要来自四个方面。算子融合:把Conv+BN+ReLU融合为一个算子,减少内存访问和内

核启动开销。精度校准:用FP16或INT8替代FP32,在精度损失可控的前提下大幅提升吞吐量。内核自动调优:

为每个算子选择最适合当前GPU架构的实现。动态形状优化:为不同的输入形状预编译最优的内核。

4.2TensorRT优化技术详解

优化技术原理加速效果

层融合LayerFusion把多个连续算子合并为一个减少30%-50%延迟

精度校准PrecisionCalibrationFP32→FP16/INT8FP16约2倍,INT8约4倍

内核自动调优KernelAuto-Tuning为每个算子选择最优实现10%-30%提升

动态张量内存DynamicTensorMemory复用内存,减少分配开销减少显存占用20%-40%

多流执行Multi-StreamExecution并行处理多个请求提升吞吐量

CUDAGraph把整个推理流程录制为图减少内核启动开销

4.3精度模式选择

TensorRT支持FP32、FP16、INT8三种精度模式。精度越低,速度越快,但精度损失也越大。选择合适的精度

模式是部署中的关键决策。

精度速度精度损失适用场景

FP32基准无对精度要求极高的场景

FP16约2倍极小(<0.1%)大多数场景的推荐选择

INT8约4倍较小(0.5%-2%)对速度要求高、能接受精度损失

INT4约8倍较大大语言模型量化

4.4使用trtexec构建引擎

#trtexec是TensorRT自带的命令行工具,用于构建和测试引擎

#基础用法:从ONNX构建FP32引擎

trtexec--onnx=model.onnx\

--saveEngine=model_fp32.engine\

--workspace=4096

#构建FP16引擎

trtexec--onnx=model.onnx\

--saveEngine=model_fp16.engine\

--fp16\

--workspace=4096

#构建INT8引擎(需要校准数据)

trtexec--onnx=model.onnx\

--saveEngine=model_int8.engine\

--int8\

--calib=calibration.cache\

--workspace=4096

#指定输入形状(动态形状)

trtexec--onnx=model.onnx\

--saveEngine=model_dynamic.engine\

--minShapes=input:1x3x224x224\

--optShapes=input:8x3x224x224\

--maxShapes=input:32x3x224x224\

--fp16

#基准测试

trtexec--loadEngine=model_fp16.engine\

--batch=8\

--iterations=100\

--warmUp=10\

--duration=10

#查看引擎信息

trtexec--loadEngine=model_fp16.engine--dumpProfile

4.5PythonAPI构建引擎

#使用PythonAPI构建TensorRT引擎

importtensorrtastrt

importnumpyasnp

#创建Logger和Builder

logger=trt.Logger(trt.Logger.WARNING)

builder=trt.Builder(logger)

#创建Network(显式批处理模式)

network=builder.create_network(

1<<int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)

)

#创建Parser并加载ONNX

parser=trt.OnnxParser(network,logger)

withopen("model.onnx","rb")asf:

ifnotparser.parse(f.read()):

foriinrange(parser.num_errors):

print(parser.get_error(i))

raiseRuntimeError("ONNX解析失败")

#配置Builder

config=builder.create_builder_config()

config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE,4<<30)#4GB

#启用FP16

ifbuilder.platform_has_fast_fp16:

config.set_flag(trt.BuilderFlag.FP16)

#启用INT8(需要校准器)

#config.set_flag(trt.BuilderFlag.INT8)

#8_calibrator=MyCalibrator(...)

#设置动态形状

profile=builder.create_optimization_profile()

profile.set_shape(

"input",

min=(1,3,224,224),

opt=(8,3,224,224),

max=(32,3,224,224)

)

config.add_optimization_profile(profile)

#构建引擎

engine=builder.build_serialized_network(network,config)

ifengineisNone:

raiseRuntimeError("引擎构建失败")

#保存引擎

withopen("model_fp16.engine","wb")asf:

f.write(engine)

print("引擎构建完成")

4.6INT8量化与校准

#INT8校准器实现

importtensorrtastrt

importnumpyasnp

importpycuda.driverascuda

importpycuda.autoinit

classEntropyCalibrator(trt.IInt8EntropyCalibrator2):

def__init__(self,calibration_data,cache_file="calibration.cache"):

super().__init__()

self.cache_file=cache_file

self.data=calibration_data

self.batch_size=1

self.current_index=0

#分配GPU内存

self.device_input=cuda.mem_alloc(

self.data[0].nbytes*self.batch_size

)

defget_batch_size(self):

returnself.batch_size

defget_batch(self,names):

ifself.current_index+self.batch_size>len(self.data):

returnNone

batch=self.data[self.current_index:self.current_index+self.batch_size]

batch=np.ascontiguousarray(batch)

cuda.memcpy_htod(self.device_input,batch)

self.current_index+=self.batch_size

return[int(self.device_input)]

defread_calibration_cache(self):

try:

withopen(self.cache_file,"rb")asf:

returnf.read()

exceptFileNotFoundError:

returnNone

defwrite_calibration_cache(self,cache):

withopen(self.cache_file,"wb")asf:

f.write(cache)

#准备校准数据(代表性样本,通常100-500张)

calibration_data=np.random.randn(500,3,224,224).astype(np.float32)

#构建INT8引擎

config.set_flag(trt.BuilderFlag.INT8)

8_calibrator=EntropyCalibrator(calibration_data)

engine=builder.build_serialized_network(network,config)

#保存

withopen("model_int8.engine","wb")asf:

f.write(engine)

4.7引擎推理

#TensorRT引擎推理示例

importtensorrtastrt

importpycuda.driverascuda

importpycuda.autoinit

importnumpyasnp

classTRTInference:

def__init__(self,engine_path):

logger=trt.Logger(trt.Logger.WARNING)

withopen(engine_path,"rb")asf:

runtime=trt.Runtime(logger)

self.engine=runtime.deserialize_cuda_engine(f.read())

self.context=self.engine.create_execution_context()

#分配内存

self.inputs=[]

self.outputs=[]

self.bindings=[]

self.stream=cuda.Stream()

foriinrange(self.engine.num_bindings):

name=self.engine.get_binding_name(i)

shape=self.engine.get_binding_shape(i)

dtype=trt.nptype(self.engine.get_binding_dtype(i))

ifself.engine.binding_is_input(i):

size=int(d(shape))

host_mem=cuda.pagelocked_empty(size,dtype)

device_mem=cuda.mem_alloc(host_mem.nbytes)

self.inputs.append({

"name":name,"host":host_mem,

"device":device_mem,"shape":shape

})

else:

size=int(d(shape))

host_mem=cuda.pagelocked_empty(size,dtype)

device_mem=cuda.mem_alloc(host_mem.nbytes)

self.outputs.append({

"name":name,"host":host_mem,

"device":device_mem,"shape":shape

})

self.bindings.append(int(device_mem))

definfer(self,input_data):

#拷贝输入到GPU

np.copyto(self.inputs[0]["host"],input_data.ravel())

cuda.memcpy_htod_async(

self.inputs[0]["device"],

self.inputs[0]["host"],

self.stream

)

#执行推理

self.context.execute_async_v2(

bindings=self.bindings,

stream_handle=self.stream.handle

)

#拷贝输出回CPU

foroutinself.outputs:

cuda.memcpy_dtoh_async(out["host"],out["device"],self.stream)

self.stream.synchronize()

return[

out["host"].reshape(out["shape"])

foroutinself.outputs

]

#使用

trt_model=TRTInference("model_fp16.engine")

input_data=np.random.randn(1,3,224,224).astype(np.float32)

outputs=trt_model.infer(input_data)

print(f"输出形状:{outputs[0].shape}")

TensorRT部署的注意事项:第一,TensorRT引擎与GPU架构绑定,A100上构建的引擎不能在V100上运

行,需要在目标硬件上构建。第二,TensorRT版本与CUDA、cuDNN版本强绑定,升级时需要重新构建引

擎。第三,INT8量化的精度损失需要仔细评估,建议先用FP16,精度不达标时再考虑INT8。第四,动态形状

会增加显存占用和构建时间,只在实际需要时使用。第五,TensorRT不支持所有ONNX算子,遇到不支持时

需要自定义插件。

第五章TensorRT引擎构建与部署

5.1引擎构建的最佳实践

TensorRT引擎构建是一个耗时的过程(几分钟到几十分钟),需要仔细规划。以下是最佳实践。

实践一:在目标硬件上构建。TensorRT引擎针对具体的GPU架构优化,不同架构的引擎不通用。如果部署

环境有多种GPU,需要为每种架构分别构建。

实践二:固定TensorRT版本。TensorRT引擎与版本强绑定,升级TensorRT需要重新构建所有引擎。建议在

项目中锁定版本,通过容器镜像保证环境一致。

实践三:合理设置workspace。workspace是构建引擎时可用的显存,越大则优化空间越大。建议设置为GPU

显存的50%-80%,但不要设置过大导致OOM。

实践四:使用时序缓存。TensorRT的timingcache可以复用上一次构建时的调优结果,大幅缩短构建时间。

#使用时序缓存加速引擎构建

importtensorrtastrt

logger=trt.Logger(trt.Logger.WARNING)

builder=trt.Builder(logger)

config=builder.create_builder_config()

#加载已有的timingcache

timing_cache=None

cache_path="timing.cache"

try:

withopen(cache_path,"rb")asf:

timing_cache=config.create_timing_cache(f.read())

exceptFileNotFoundError:

timing_cache=config.create_timing_cache(b"")

config.set_timing_cache(timing_cache,ignore_mismatch=True)

#...构建引擎...

#保存timingcache供下次使用

withopen(cache_path,"wb")asf:

f.write(config.get_timing_cache().serialize())

5.2引擎序列化与反序列化

#引擎的保存与加载

importtensorrtastrt

#保存引擎

defsave_engine(engine,path):

withopen(path,"wb")asf:

f.write(engine)

print(f"引擎已保存:{path}")

#加载引擎

defload_engine(path):

logger=trt.Logger(trt.Logger.WARNING)

withopen(path,"rb")asf:

runtime=trt.Runtime(logger)

engine=runtime.deserialize_cuda_engine(f.read())

returnengine

#引擎信息查看

defprint_engine_info(engine):

print(f"输入/输出绑定数:{engine.num_bindings}")

foriinrange(engine.num_bindings):

name=engine.get_binding_name(i)

shape=engine.get_binding_shape(i)

dtype=engine.get_binding_dtype(i)

is_input=engine.binding_is_input(i)

print(f"[{i}]{name}:shape={shape},dtype={dtype},input={is_input}")

#查看优化后的层信息

inspector=engine.create_engine_inspector()

print(inspector.get_engine_information(

trt.LayerInformationFormat.JSON

))

5.3动态形状与优化配置文件

#动态形状配置详解

importtensorrtastrt

builder=trt.Builder(logger)

network=builder.create_network(

1<<int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)

)

parser=trt.OnnxParser(network,logger)

withopen("dynamic_model.onnx","rb")asf:

parser.parse(f.read())

config=builder.create_builder_config()

config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE,4<<30)

#为每个输入创建优化配置文件

profile=builder.create_optimization_profile()

#方式一:单个输入

profile.set_shape(

"input",

min

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论