2. YOLOv8n模型TensorRT FP16转换
任务目标
将YOLOv8n的ONNX模型转换为TensorRT FP16推理引擎,并验证转换后引擎的推理速度与正确性。本案例聚焦于TensorRT引擎构建与基础性能测试,不涉及端到端目标检测后处理逻辑。
环境依赖
- TensorRT 8.6+(含
trtexec工具) - CUDA 11.8+、cuDNN 8.6+
- Python 3.8+,安装
pycuda、numpy、onnx - 已导出的YOLOv8n ONNX模型(输入尺寸1x3x640x640,动态或固定batch均可)
实现步骤
整个流程分为两步:先用trtexec命令行完成ONNX到FP16引擎的转换,再通过Python API加载引擎并测试推理延迟。转换命令如下:
trtexec --onnx=yolov8n.onnx \
--saveEngine=yolov8n_fp16.engine \
--fp16 \
--minShapes=images:1x3x640x640 \
--optShapes=images:1x3x640x640 \
--maxShapes=images:1x3x640x640
若ONNX模型已固定batch为1,可省略--minShapes/--optShapes/--maxShapes参数。转换成功后生成yolov8n_fp16.engine文件。
关键完整代码
以下Python代码加载生成的FP16引擎,对随机输入执行100次推理并统计平均延迟:
import numpy as np
import pycuda.driver as cuda
import pycuda.autoinit
import tensorrt as trt
import time
class TRTEngine:
def __init__(self, engine_path):
logger = trt.Logger(trt.Logger.WARNING)
with open(engine_path, 'rb') as f:
runtime = trt.Runtime(logger)
self.engine = runtime.deserialize_cuda_engine(f.read())
self.context = self.engine.create_execution_context()
self._allocate_buffers()
def _allocate_buffers(self):
self.inputs, self.outputs, self.bindings = [], [], []
for i in range(self.engine.num_bindings):
name = self.engine.get_binding_name(i)
shape = self.engine.get_binding_shape(i)
size = trt.volume(shape)
dtype = trt.nptype(self.engine.get_binding_dtype(i))
host_mem = cuda.pagelocked_empty(size, dtype)
device_mem = cuda.mem_alloc(host_mem.nbytes)
self.bindings.append(int(device_mem))
if self.engine.binding_is_input(name):
self.inputs.append({'name': name, 'host': host_mem, 'device': device_mem, 'shape': shape})
else:
self.outputs.append({'name': name, 'host': host_mem, 'device': device_mem, 'shape': shape})
def infer(self, input_data):
inp = self.inputs[0]
np.copyto(inp['host'], input_data.ravel())
cuda.memcpy_htod(inp['device'], inp['host'])
self.context.execute_v2(bindings=self.bindings)
for out in self.outputs:
cuda.memcpy_dtoh(out['host'], out['device'])
return [out['host'].reshape(out['shape']) for out in self.outputs]
def __del__(self):
for binding in self.inputs + self.outputs:
binding['device'].free()
engine = TRTEngine('yolov8n_fp16.engine')
input_data = np.random.randn(1, 3, 640, 640).astype(np.float32)
# 预热
for _ in range(10):
engine.infer(input_data)
# 计时测试
times = []
for _ in range(100):
start = time.perf_counter()
engine.infer(input_data)
times.append((time.perf_counter() - start) * 1000)
avg_ms = np.mean(times)
print(f"FP16平均推理延迟: {avg_ms:.2f} ms")
print(f"输出张量数量: {len(engine.outputs)}")
for i, out in enumerate(engine.outputs):
print(f"输出{i} shape: {out['shape']}")
运行与验证
- 确保
yolov8n_fp16.engine与Python脚本在同一目录。 - 执行脚本:
python test_trt.py - 通过条件:程序正常结束,输出平均延迟为有限正数(通常小于30ms),且输出张量shape与ONNX模型输出一致(YOLOv8n输出为1x84x8400)。
若需对比FP32性能,可用trtexec --onnx=yolov8n.onnx --saveEngine=yolov8n_fp32.engine生成FP32引擎,替换引擎路径后重新运行脚本,对比两者平均延迟即可验证FP16加速效果。