这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 企业专区 » OpenVINO生态社区 » OpenVINO推理性能优化

共2条 1/1 1 跳转至

OpenVINO推理性能优化

工程师
2020-07-28 14:25:30     打赏

OpenVINO最新版本是2020.4版本,自从2020.1版本以后,增加支持了C的API,这里还是以常用的C++的API来说明如何调优和加速。

这里简单以视觉模型来说明推理过程,和调优方法:

假设你已经完成模型转换,即将开源框架(如TF, Caffe)训练出来的模型转为IR格式。整个推理流程可以用下图来描述,下面根据这个流程来描述可以调优的方法和经验。

图1 推理流程

1. 装载插件库

InferenceEngine::Core core; // 管理处理器和扩展插件

2. 读取模型结构

auto network = core.ReadNetwork("model.xml");

3. 配置输入和输出

OpenVINO默认的通道顺序是BGR,在输入的时候,如果拿到的数据不是BGR格式,需要预处理通道顺序,这里通过setColorFormat接口进行调整。预处理不仅可以调整通道,还可以Resize算法类型,设置平均图(逐像素平均或逐通道平均)。

图2 图像通道类型

注意:如果是NV12或I420格式,不支持批量推理。

// 输入InferenceEngine::InputsDataMap input_info(network.getInputsInfo());/** Iterate over all input info**/for (auto &item : input_info) {
    auto input_data = item.second;
    input_data->setPrecision(Precision::U8);
    input_data->setLayout(Layout::NCHW);
    input_data->getPreProcess().setResizeAlgorithm(RESIZE_BILINEAR);
    input_data->getPreProcess().setColorFormat(ColorFormat::RGB);}// 输出InferenceEngine::OutputsDataMap output_info(network.getOutputsInfo());for (auto &item : output_info) {
    auto output_data = item.second;
    output_data->setPrecision(Precision::FP32);  // 设置输出精度    output_data->setLayout(Layout::NC);}

4. 装载模型

装载模型有两种方式,一种是默认配置,只需指定设备型号,如CPU,另外一种方式,可以通过第3个参数增加优化配置选项,其中,config的配置以<key, value>形式给出。

auto executable_network = core.LoadNetwork(network, "CPU");// 或者std::map<std::string, std::string> config = {{ PluginConfigParams::KEY_PERF_COUNT, PluginConfigParams::YES }};auto executable_network = core.LoadNetwork(network, "CPU", config);

画重点:优化选项都有哪些?如何配置这些选项?

[公式]

上面的优化选项中,KEY_CPU_THROUGHPUT_STREAMS和KEY_CPU_THREADS_NUM比较常用,其他的选项根据需要进行配置。

假如你有一台CLX6240服务器,36核,KEY_CPU_THROUGHPUT_STREAMS的数目是推理流总数,网络较小就多开点推理流,大网络就烧开点,KEY_CPU_THREADS_NUM是绑定线程数,即每个推理流都会同时多线程并发计算,用多少核,就配置多少线程并发。

5. 创建推理请求

auto infer_request = executable_network.CreateInferRequest();

6. 准备输入

这里根据部署模型的情况情况来说明输入的数据准备

  • 单一网络

这里输入图像或数据必须和Blob的大小对准(手动Resize),以及具有正确的色彩格式。

/** Iterate over all input blobs **/for (auto & item : inputInfo) {
    auto input_name = item->first;
    /** Get input blob **/
    auto input = infer_request.GetBlob(input_name);
    /** Fill input tensor with planes. First b channel, then g and r channels **/
    ...}
  • 级联网络

从一个网络的输出获得Blob,输入下一个网络的输入Blob。

auto output = infer_request1->GetBlob(output_name);infer_request2->SetBlob(input_name, output);
  • 级联网络中处理ROI

当第一个网络的输出ROI是第二个网络的输入,无需重新为ROI结果分配内存,例如,当第一个网络检测视频帧上的对象时(存储为输入Blob),第二个网络接收检测到的边界框(帧内的ROI)作为输入。在这种情况下,允许第二个网络重用预先分配的输入blob(由第一个网络使用),并且只裁剪ROI,而不分配新的内存通过InferenceEngine::make_shared_blob()接口(参数为InferenceEngine::Blob::Ptr和InferenceEngine::ROI)。

/** inputBlob points to input of a previous network and    cropROI contains coordinates of output bounding box **/InferenceEngine::Blob::Ptr inputBlob;InferenceEngine::ROI cropRoi;.../** roiBlob uses shared memory of inputBlob and describes cropROI    according to its coordinates **/auto roiBlob = InferenceEngine::make_shared_blob(inputBlob, cropRoi);infer_request2->SetBlob(input_name, roiBlob);

分配适当类型和大小的Blob,然后将图像和数据输入到Blob中,通过InferenceEngine::InferRequest::SetBlob()接口设置到请求里。

/** Iterate over all input blobs **/for (auto & item : inputInfo) {
    auto input_data = item->second;
    /** Create input blob **/
    InferenceEngine::TBlob<unsigned char>::Ptr input;
    // assuming input precision was asked to be U8 in prev step    input = InferenceEngine::make_shared_blob<unsigned char, InferenceEngine::SizeVector>(InferenceEngine::Precision:U8, input_data->getDims());
    input->allocate();
    infer_request->SetBlob(item.first, input);
    /** Fill input tensor with planes. First b channel, then g and r channels **/
    ...}

7. 推理

  • 异步模式

异步模式会立即返回结果,不会阻塞主线程,使用wait()等待推理结果。

infer_request->StartAsync();infer_request.Wait(IInferRequest::WaitMode::RESULT_READY);

Wait()有三种模式可用:

1) 指定阻塞最大时间,该方法会被阻塞,直到指定的超时过期或结果可用(以先出现的时间为准)。

2)InferenceEngine::IInferRequest::WaitMode::RESULT_READY, 一直等待,直到有推理结果出来。

3) InferenceEngine::IInferRequest::WaitMode::STATUS_ONLY, 立即返回请求状态,它不会阻塞或中断当前线程。

  • 同步模式

infer_request->Infer();


8. 检查输出并处理结果

不推荐通过std::dynamic_pointer_cast将Blob到TBlob转换,最好通过buffer()和as()来做。

for (auto &item : output_info) {
    auto output_name = item.first;
    auto output = infer_request.GetBlob(output_name);
    {
        auto const memLocker = output->cbuffer(); // use const memory locker        // output_buffer is valid as long as the lifetime of memLocker        const float *output_buffer = memLocker.as<const float *>();
        /** output_buffer[] - accessing output blob data **/

到此为止,就完成了整个推理的API调用和相关配置。也期待你能以正确的姿势来使用OpenVINO,性能得到一定得提升。


点击下载OpenVINO工具包

对计算机视觉感兴趣?这个社区推荐给你~

>>点击了解OpenVINO生态开发社区




关键词: OpenVINO     性能     优化    

工程师
2020-08-02 23:08:31     打赏
2楼

优化效果还是不错的


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]