OnnxRuntime 性能调优

OnnxRuntime 性能调优

文档的一些笔记:

性能调优小工具 ONNX GO Live Tool

这玩意儿有俩docker容器来实现支持,一个优化容器和一起模型转换容器。暂时具体不清楚原理,还没来得及看,后面试试。

什么执行单元(Execution Provider, EP)能够提供最好的性能表现

CPU版本的ONNX Runtime提供了完整的算子支持,因此只要编译过的模型基本都能成功运行。一个要注意的点是为了减少编译的二进制包能够足够小,算子只支持常见的数据类型,如果是一些非常见数据类型,请去提交PR。

CUDA版本的算子并不能完全支持,如果模型中有一部分不支持的算子,将会切换到CPU上去计算,这部分的数据切换是有比较大的性能影响。当然也可以contribute或者提交issue。

对于TRT和CUDA的区别,在同设备上TRT会比CUDA有着更好的性能表现,但是这个状况也局限于特定的模型以及算子是被TRT支持。

性能调优的一些建议
  • Shared arena based allocator

    通过配置多个session中共享内存区域配置,可以减少内存消耗

  • 线程调控

    • 如果编译支持OpenMP,那么使用OpenMP的环境变量来控制预测线程数量。
    • 如果没有OpenMP支持,使用合适的ORT API来进行操控。
    • 当使用并行实行的时候inter op线程并不会受到OpenMP设置的影响,且总是应该使用ORT APIs来进行设置。
  • 默认CPU执行单元的相关设置(MLAS)

    默认EP使用了很多旋钮来控制线程数量。举个例子:

    import onnxruntime as rt
    
    sess_options = rt.SessionOptions()
    
    sess_options.intra_op_num_threads = 2
    sess_options.execution_mode = rt.ExecutionMode.ORT_SEQUENTIAL
    sess_options.graph_optimization_level = rt.GraphOptimizationLevel.ORT_ENABLE_ALL
    
    • Thread Count

      • sess_options.intra_op_num_threads = 2 控制了运行模型时的线程数量。
    • Sequential vs Parallel Execution

      • sess_options.execution_mode = rt.ExecutionMode.ORT_SEQUENTIAL 控制了计算图内部的算子是顺序计算还是并行计算,当一个模型含有多个分支的时候,设置为False会有比较大的性能提升。
      • sess_options.execution_mode = rt.ExecutionMode.ORT_PARALLEL时(即模型内计算图中的并行), 你可以设置 sess_options.inter_op_num_threads 来对并行计算的线程数量进行控制。这里注意是inter不是intra,和Thread Count里面的那个不一样
    • sess_options.graph_optimization_level = rt.GraphOptimizationLevel.ORT_ENABLE_ALL

      图结构优化设置,分为三个level,BasicExtendLayout Optimizations。默认所有的优化都是ENABLE。

  • MKL_DNN / nGraph执行单元

    这俩玩意儿依赖openmp支持来实现并行化,对于这俩需要使用openmp的环境变量来进行性能调整。

    • OMP_NUM_THREADS=n
      • 控制线程池大小
    • OMP_WAIT_POLICY=PASSIVE / ACTIVE
      • 线程是否是thread spinning模式(线程调度的一种方式)。
      • PASSIVE 吞吐量模式,CPU只有在完成当前任务后被释放。当CPU使用率已经很高了,用这个模式。
      • ACTIVE 永远不会释放CPU,会以一个死循环的方式来检查下一个任务是否已经准备好。当你要低时延,用这个模式。
  • IO绑定

    在使用非CPU执行单元时,在执行计算图(调用Run)之前,在目标设备上安排输入和输出的数据内存空间是最有效的。很长一串的内容不去讲,讲一句话话,用过PyTorch么,其实就是在你进行net.forward(data)的时候,先用data.to(torch.device(‘xxx’))把数据拿到目标运算设备上。

    • C++

      Ort::Env env;
      Ort::Session session(env, model_path, session_options);
      Ort::IoBinding io_binding{session};
      auto input_tensor = Ort::Value::CreateTensor<float>(memory_info, input_tensor_values.data(), input_tensor_size, input_node_dims.data(), 4);
      io_binding.BindInput("input1", input_tensor);
      Ort::MemoryInfo output_mem_info{"Cuda", OrtDeviceAllocator, 0,
                                      OrtMemTypeDefault};
      
      // Use this to bind output to a device when the shape is not known in advance. If the shape is known you can use the other overload of this function that takes an Ort::Value as input (IoBinding::BindOutput(const char* name, const Value& value)).
      // This internally calls the BindOutputToDevice C API.
      
      io_binding.BindOutput("output1", output_mem_info);
      session.Run(run_options, io_binding);
      
    • Python

      https://github.com/microsoft/onnxruntime/blob/master/docs/python/inference/api_summary.rst#iobinding

    • C#

      https://github.com/microsoft/onnxruntime/blob/master/csharp/test/Microsoft.ML.OnnxRuntime.Tests/OrtIoBindingAllocationTest.cs

一些Trouble shooting

详见Link

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值