3. YOLOv8 OpenVINO 部署与 CPU 推理优化
任务目标
本案例将完成一个基于ONNX Runtime的GPU加速推理最小闭环:将YOLOv8n导出的ONNX模型分别绑定CPU和CUDA执行提供程序进行推理,统计并对比两者的端到端耗时。通过本案例,你将掌握ONNX Runtime GPU推理的环境配置方法、代码接入方式以及性能对比的验证路径。
环境与依赖
- 操作系统:Windows 10/11 或 Ubuntu 20.04+(本案例以Ubuntu命令为例)
- GPU:NVIDIA显卡,驱动版本 ≥ 525(CUDA 12.0兼容)
- Python 3.9+
- 依赖安装:
pip install onnxruntime-gpu opencv-python numpy
# 验证CUDA可用性
python -c "import onnxruntime as ort; print(ort.get_available_providers())"
# 预期输出中包含 'CUDAExecutionProvider'
关键完整代码
以下代码实现完整的CPU/GPU推理对比闭环。模型文件需提前导出(导出命令见代码后说明)。
import onnxruntime as ort
import numpy as np
import time
# ========== 配置 ==========
MODEL_PATH = "yolov8n.onnx"
INPUT_SIZE = 640
NUM_RUNS = 50 # 预热后正式测试次数
# ========== 准备输入数据 ==========
np.random.seed(0)
input_data = np.random.rand(1, 3, INPUT_SIZE, INPUT_SIZE).astype(np.float32)
# ========== 创建推理会话 ==========
# CPU会话
cpu_options = ort.SessionOptions()
cpu_options.intra_op_num_threads = 8
cpu_session = ort.InferenceSession(MODEL_PATH, sess_options=cpu_options, providers=['CPUExecutionProvider'])
# GPU会话(CUDA + TensorRT回退)
gpu_session = ort.InferenceSession(MODEL_PATH, providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
# 获取输入名称
input_name = cpu_session.get_inputs()[0].name
# ========== 预热 ==========
for _ in range(10):
cpu_session.run(None, {input_name: input_data})
gpu_session.run(None, {input_name: input_data})
# ========== 性能测试 ==========
def benchmark(session, runs=NUM_RUNS):
times = []
for _ in range(runs):
start = time.perf_counter()
session.run(None, {input_name: input_data})
times.append((time.perf_counter() - start) * 1000) # ms
return np.mean(times), np.std(times)
cpu_mean, cpu_std = benchmark(cpu_session)
gpu_mean, gpu_std = benchmark(gpu_session)
# ========== 输出结果 ==========
print(f"CPU 推理: {cpu_mean:.2f} ms ± {cpu_std:.2f} ms")
print(f"GPU 推理: {gpu_mean:.2f} ms ± {gpu_std:.2f} ms")
print(f"加速比: {cpu_mean / gpu_mean:.2f}x")
# ========== 正确性验证(输出形状一致性) ==========
cpu_out = cpu_session.run(None, {input_name: input_data})[0]
gpu_out = gpu_session.run(None, {input_name: input_data})[0]
print(f"输出形状一致: {cpu_out.shape == gpu_out.shape}")
print(f"最大数值差异: {np.abs(cpu_out - gpu_out).max():.6f}")
模型导出(若尚未准备)
若你还没有YOLOv8n的ONNX模型,使用以下命令从Ultralytics导出(需先安装ultralytics包):
pip install ultralytics
yolo export model=yolov8n.pt format=onnx opset=12 simplify=True
运行方式
python benchmark_onnx.py
验证方法与判定标准
- 环境验证:运行依赖安装后的验证命令,输出必须包含
CUDAExecutionProvider,否则说明CUDA/cuDNN配置不正确。 - 正确性验证:代码末尾会输出“输出形状一致”为
True,且“最大数值差异”小于1e-3(由于浮点运算顺序不同,CPU与GPU输出存在微小差异属正常)。 - 性能对比判定:GPU推理平均耗时显著低于CPU(通常加速比 > 2x 即为GPU生效)。若加速比接近1或小于1,请检查:
- 是否实际使用了GPU(通过
ort.get_available_providers()确认); - 输入尺寸是否过小(小尺寸下CPU可能反超);
- 是否已正确安装与CUDA版本匹配的cuDNN。
- 是否实际使用了GPU(通过
常见问题
- ImportError: DLL load failed:通常为CUDA/cuDNN版本不匹配。确认onnxruntime-gpu版本对应的CUDA版本:
pip show onnxruntime-gpu查看版本,然后安装匹配的CUDA和cuDNN。 - TensorRTExecutionProvider警告:不影响运行,可忽略或仅保留CUDAExecutionProvider。
- 显存不足:减小
NUM_RUNS或输入尺寸。
性能预期说明:本案例不预设具体加速比数值。实际加速效果取决于GPU型号、CPU性能、输入尺寸和模型复杂度。判定GPU生效的核心依据是:GPU推理耗时显著低于CPU,且输出与CPU一致。