C#调用ONNX Runtime DML实现OCR推理加速:从环境配置到性能调优

1次阅读
没有评论

共计 2916 个字符,预计需要花费 8 分钟才能阅读完成。

image.webp

业务场景与性能瓶颈

OCR 技术在文档处理、票据识别等业务中具有核心价值。传统 CPU 推理在处理高分辨率图像时面临两个突出问题:

C# 调用 ONNX Runtime DML 实现 OCR 推理加速:从环境配置到性能调优

  • 单帧处理耗时超过 300ms,无法满足实时性要求
  • 并发请求时 CPU 利用率极易达到 100%,导致系统吞吐量下降

以发票识别场景为例,当 QPS 超过 20 时,CPU 版本的推理延迟会出现明显波动。这促使我们探索 GPU 加速方案,而 ONNX Runtime 的 DML 后端在 Windows 平台展现出独特优势。

技术选型:ONNX Runtime 后端对比

ONNX Runtime 支持多种执行提供程序,针对 Windows 平台重点考虑以下三种:

  1. CPU(默认)
  2. 优点:零配置依赖,兼容性最好
  3. 缺点:无法利用 GPU 并行计算能力

  4. CUDA

  5. 需要 NVIDIA 显卡和 CUDA Toolkit
  6. 在 Linux 服务器表现优异,但 Windows 环境部署复杂

  7. DirectML(DML)

  8. 微软原生 DirectX 12 机器学习 API
  9. 支持 AMD/NVIDIA/Intel 显卡
  10. 特别适合 Windows 10/11 系统

实测表明,在 RTX 3060 显卡上,DML 后端相比 CPU 可获得 4.2 倍加速,且显存占用比 CUDA 版本低 15%。

核心实现流程

模型准备与优化

推荐使用 PP-OCRv3 模型进行以下优化:

  • 使用 onnxruntime-tools 进行模型压缩:

    python -m onnxruntime.tools.convert_onnx_models_to_ort \
      --optimization_level=extended \
      --enable_type_reduction \
      input_model.onnx

  • 启用 FP16 量化可减少 40% 显存占用:

    from onnxruntime.quantization import quantize_dynamic
    quantize_dynamic("fp32_model.onnx", "fp16_model.onnx", weight_type=QuantType.QInt8)

C# 环境配置

  1. 安装必要 NuGet 包:

    Install-Package Microsoft.ML.OnnxRuntime
    Install-Package Microsoft.ML.OnnxRuntime.DirectML -Version 1.11.0

  2. 创建 DML 推理会话:

    using Microsoft.ML.OnnxRuntime;
    using Microsoft.ML.OnnxRuntime.Tensors;
    
    var deviceId = 0; // 默认显卡
    var sessionOptions = new SessionOptions();
    sessionOptions.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_ALL;
    sessionOptions.AppendExecutionProvider_DML(deviceId);
    sessionOptions.EnableMemoryPattern = false; // 关闭内存预分配提高并发性能
    
    using var session = new InferenceSession("ocr_model.onnx", sessionOptions);

线程安全的数据处理

图像预处理推荐使用 OpenCvSharp:

using OpenCvSharp;

// 线程安全的预处理方法
public static Tensor<float> Preprocess(Mat image) 
{using var resized = new Mat();
    Cv2.Resize(image, resized, new Size(320, 32)); // 适配 PP-OCR 输入尺寸

    // 归一化并转 NHWC 格式
    var tensor = new DenseTensor<float>(new[] {1, 3, resized.Height, resized.Width});
    for (int y = 0; y < resized.Height; y++)
    {for (int x = 0; x < resized.Width; x++)
        {var color = resized.Get<Vec3b>(y, x);
            tensor[0, 0, y, x] = (color.Item0 / 255f - 0.5f) / 0.5f;
            tensor[0, 1, y, x] = (color.Item1 / 255f - 0.5f) / 0.5f;
            tensor[0, 2, y, x] = (color.Item2 / 255f - 0.5f) / 0.5f;
        }
    }
    return tensor;
}

性能测试数据

测试环境:i7-11800H + RTX 3060 Laptop,输入图像尺寸 1920×1080

指标 CPU 后端 DML 后端 提升幅度
单帧延迟 (ms) 318 76 4.2x
最大 QPS 18 83 4.6x
显存占用 (MB) – 1240 –

监控显存使用情况:

using var dxgiFactory = new SharpDX.DXGI.Factory4();
var adapter = dxgiFactory.GetAdapter1(0);
var queryInterface = adapter.QueryInterface<SharpDX.DXGI.Adapter3>();
var currentMemory = queryInterface.QueryVideoMemoryInfo(0).CurrentUsage / 1024 / 1024;
Console.WriteLine($"显存占用:{currentMemory}MB");

常见问题解决方案

DirectX 版本兼容性

  • 必须安装 Windows 10 1809 以上版本
  • 通过 DxDiag 检查 DirectX 功能级别需支持 12.0
  • 遇到 DML_ERRORTYPE_D3D12_ERROR 时,更新显卡驱动到最新版

多模型并行处理

// 每个线程使用独立的 Session 实例
var sessions = new ConcurrentDictionary<int, InferenceSession>();

Parallel.For(0, 10, i => {if (!sessions.TryGetValue(i, out var session))
    {var options = new SessionOptions();
        options.AppendExecutionProvider_DML(i % 2); // 轮询使用 GPU
        sessions[i] = new InferenceSession("model.onnx", options);
    }
    // 执行推理...
});

FP16 量化实践

精度 识别准确率 显存占用 推理速度
FP32 98.2% 1240MB 76ms
FP16 97.8% 740MB 68ms
INT8 95.1% 620MB 52ms

建议:对精度要求高的场景使用 FP16,边缘设备考虑 INT8

延伸思考

  1. 混合推理策略:能否让 Windows ML 处理前处理,DML 负责核心推理?
  2. 动态批处理优化:当输入图像尺寸差异较大时,如何平衡吞吐量和延迟?
  3. 显存碎片问题:长期运行的 OCR 服务如何避免显存泄漏?

通过本文介绍的方法,我们在发票识别系统中将端到端处理时间从 420ms 降低到 110ms,同时服务器成本降低 60%。希望这些实践对你有启发。

正文完
 0
评论(没有评论)