3. 使用OpenVINO加速边缘服务器上的推理
任务目标
在Intel NUC(或任意x86_64 Linux边缘服务器)上,使用OpenVINO Toolkit将PyTorch预训练的ResNet-50模型转换为OpenVINO中间表示(IR),并通过OpenVINO推理引擎完成图片分类推理,最终测量并对比CPU原生PyTorch推理与OpenVINO优化后的延迟和吞吐量。
环境与依赖
- 操作系统:Ubuntu 22.04 LTS(x86_64)
- 硬件:Intel NUC(第8代酷睿或更新,需支持AVX2指令集)
- Python:3.9~3.11
- 依赖安装:
pip install openvino-dev[onnx,tensorflow,pytorch]==2023.3.0
pip install torch torchvision onnx
实现步骤与代码
完整流程分为三步:模型导出为ONNX → 转换为OpenVINO IR格式 → 编写推理与性能测试脚本。以下代码将三步整合为一个可独立运行的Python脚本,在Intel NUC上直接执行即可完成全流程。
import time
import torch
import torchvision
import numpy as np
from pathlib import Path
from openvino.runtime import Core, PartialShape
# ========== 1. 导出ResNet-50为ONNX并转换为OpenVINO IR ==========
model = torchvision.models.resnet50(weights=torchvision.models.ResNet50_Weights.IMAGENET1K_V1)
model.eval()
onnx_path = "resnet50.onnx"
ir_path = Path("resnet50_ir")
# 固定输入尺寸为OpenVINO推理时的实际输入
dummy_input = torch.randn(1, 3, 224, 224)
torch.onnx.export(model, dummy_input, onnx_path,
input_names=["input"], output_names=["output"],
opset_version=13, dynamic_axes=None)
# 使用OpenVINO的模型转换API(无需单独调用mo命令行)
from openvino.tools.mo import convert_model
ov_model = convert_model(onnx_path, input_shape=[1, 3, 224, 224])
ov_model.reshape({0: PartialShape([1, 3, 224, 224])})
ov_model.save(ir_path)
print(f"IR模型已保存至: {ir_path}")
# ========== 2. 准备测试数据(随机噪声图,仅用于性能测量) ==========
# 注意:本案例聚焦性能测量,不涉及真实图片分类精度验证
input_tensor = torch.randn(1, 3, 224, 224)
input_numpy = input_tensor.numpy()
# ========== 3. PyTorch CPU推理性能基线 ==========
def benchmark_torch(model, input_tensor, num_iter=100):
# 预热10次
for _ in range(10):
with torch.no_grad():
model(input_tensor)
torch.cuda.synchronize() if torch.cuda.is_available() else None
latencies = []
start_total = time.perf_counter()
for _ in range(num_iter):
t0 = time.perf_counter()
with torch.no_grad():
model(input_tensor)
latencies.append((time.perf_counter() - t0) * 1000) # ms
total_time = time.perf_counter() - start_total
avg_latency = np.mean(latencies)
throughput = num_iter / total_time
return avg_latency, throughput
# ========== 4. OpenVINO推理性能测量 ==========
def benchmark_openvino(compiled_model, input_data, num_iter=100):
infer_request = compiled_model.create_infer_request()
# 预热
for _ in range(10):
infer_request.infer(input_data)
latencies = []
start_total = time.perf_counter()
for _ in range(num_iter):
t0 = time.perf_counter()
infer_request.infer(input_data)
latencies.append((time.perf_counter() - t0) * 1000)
total_time = time.perf_counter() - start_total
avg_latency = np.mean(latencies)
throughput = num_iter / total_time
return avg_latency, throughput
# ========== 5. 执行测量并输出结果 ==========
NUM_ITER = 200 # 测量迭代次数
print("--- PyTorch CPU 推理基线 ---")
torch.set_num_threads(8) # 与NUC物理核数对齐,可按实际调整
pt_latency, pt_throughput = benchmark_torch(model, input_tensor, NUM_ITER)
print(f"平均延迟: {pt_latency:.2f} ms | 吞吐量: {pt_throughput:.2f} FPS")
print("\n--- OpenVINO 推理 ---")
core = Core()
compiled_model = core.compile_model(str(ir_path / "resnet50.xml"), "CPU")
ov_latency, ov_throughput = benchmark_openvino(compiled_model, input_numpy, NUM_ITER)
print(f"平均延迟: {ov_latency:.2f} ms | 吞吐量: {ov_throughput:.2f} FPS")
print("\n--- 加速比 ---")
print(f"延迟加速比: {pt_latency / ov_latency:.2f}x")
print(f"吞吐量加速比: {ov_throughput / pt_throughput:.2f}x")
运行方式
# 在Intel NUC上执行(需已安装上述依赖)
python3 resnet50_openvino_benchmark.py
验证方法与判定标准
- 模型转换验证:脚本执行后,当前目录下应生成
resnet50_ir/文件夹,内含resnet50.xml和resnet50.bin两个文件,且无报错输出。 - 推理正确性验证:OpenVINO推理结果与PyTorch推理结果的argmax类别索引应一致(因输入为随机噪声,类别无实际意义,仅验证推理链路正确)。可在脚本末尾添加如下断言:
# 在脚本末尾追加(验证两种框架输出一致性)
with torch.no_grad():
pt_output = model(input_tensor).numpy()
ov_output = compiled_model([input_numpy])[0]
assert np.argmax(pt_output) == np.argmax(ov_output), "输出不一致,推理链路错误"
print("推理输出一致性验证通过")
- 性能判定标准:在Intel NUC(8代i5或更高)上,OpenVINO的延迟加速比通常应达到1.5x~3x,吞吐量提升2x~4x。若加速比低于1.2x,请检查:
① BIOS中是否开启Intel Turbo Boost;
②torch.set_num_threads()是否与NUC物理核心数匹配;
③ 是否使用了openvino-dev而非旧版openvino包。 - 结果判定:脚本输出的延迟和吞吐量为实际测量值,不同NUC配置结果会有差异。只要OpenVINO推理延迟低于PyTorch基线且输出一致性断言通过,即视为案例部署成功。
常见问题
- 模型转换报错:若
convert_model提示缺少依赖,执行pip install openvino-dev[onnx]补装ONNX前端。 - AVX2指令集不支持:OpenVINO 2023.3要求CPU支持AVX2。若NUC较旧(如6代以前),需改用OpenVINO 2022.3 LTS版本。
- 内存不足:ResNet-50推理约需500MB内存,若NUC内存小于4GB,建议将
NUM_ITER降至50。