最近因为项目需要,对intel openVINO的源码进行了解,以便为后面移植开发做准备。

OpenVINO的源码在opencv的github主页上可以找到,最新的opencv 4.1.2已经全新支持了OpenVINO,意味着一个新的平台即将展开,并且在嵌入式领域,边缘计算等场景,movidius大有赶超英伟达的趋势,因特尔在AI上的发力今后几年不可小看,很有可能在今后几年内占有一席之地。

废话不多说,OpenVINO的github源码地址为:https://github.com/opencv/dldt

由于openvino是18年刚刚出来,目前针对openvino源码分析还没有官方渠道,因特尔开发openvino工具包本意是将各种硬件平台进行封装操作,达到用户拿来就可以直接用,一般不需要注意里面细节,因为后面项目需要做移植,所以需要对openvino源码进行一定了解。

Class Core

core是interference Engine的管理核心,一般使用openvino之前都需要先创建一个core,负责其中的设备管理,网络下载等等初始化造成,是整个interference Engine的核心。

core类头文件位于\inference-engine\include\ie_core.hpp

cpp文件位于:inference-engine\src\inference_engine\ie_core.cpp

Core构造函数

core构造函数是整个openvino的程序的入口,主要功能是负责openvino中所支持的硬件设备类型注册(主要包括CPU,GPU, Modividus,VPU等),源码如下:

主要分三步:

  • 获取Impl类地址
  • 获取支持的plugins.xml配置文件
  • 根据plugins.xml配置文件获取支持的设备类型进行注册

获取Imple类地址

OpenVINO源码中大量使用了将具体实施的类和接口分类的模式,core类只是定义了一个接口类,类core类的具体实施的类是在Impl类中,首先保存其Imp类的地址到_impl变量中,方便以后调用。这样设计的好处就是能够将接口与实现分类,减少模块之间的耦合,Imple类的实现还是在inference-engine\src\inference_engine\ie_core.cpp文件中。

涉及到一个OpenVINO的编码规范,在类中的变量命名规则为在变量名前面要加"_",这一点和caffe变量命名规则不一样,请注意。

获取支持的plugins.xml配置文件

Core类的构造函数可以带一个xmlConfigFile配置文件参数,该配置文件就是openvino支持的设备类型配置xml文件,如果该参数没有配置(大部分情况下都是不配置的,使用默认配置),使用默认配置文件plugins.xml,该配置文件一般都是在安装的openvino的lib路径下,是和libinference_engine.so等lib放在同一个路径下面,如果不放在同一路径下面将会出错

下面是官方安装之后的plugins.xml文件配置,和安装时选择的支持设备类型有关:

<ie><plugins><plugin name="GNA" location="libGNAPlugin.so"></plugin><plugin name="HDDL" location="libHDDLPlugin.so"></plugin><plugin name="CPU" location="libMKLDNNPlugin.so"></plugin><plugin name="GPU" location="libclDNNPlugin.so"></plugin><plugin name="FPGA" location="libdliaPlugin.so"></plugin><plugin name="MYRIAD" location="libmyriadPlugin.so"></plugin></plugins>
</ie>

name为支持的设备类型名称,有GPU,CPU,MYRIAD等,location代表的时支持该设备所对应的lib,

各个设备所对应的lib可以查看《学习OpenVINO笔记之Inference Engine》

代码中是怎样找到这些路径的?接下来需要查看getIELibraryPath()函数实现

linux操作系统下 调用一个系统函数dladdr(), 用来获取动态库中getIELibraryPath函数的相关信息,其信息结构为Dl_info,其成员结构为:

struct {
const char *dli_fname;
void *dli_fbase;
const char *dli_sname;
void *dli_saddr;
size_t dli_size; /* ELF only */
int dli_bind; /* ELF only */
int dli_type;
};

其中dli_fname为该函数符号位于的lib名称(包含其路径信息),而 getIELibraryPath函数是位于libinference_engine.so中,获取的dli_fname为libinference_engine.so名称及路径,这样通过getPathName解析出路径名(libGNAPlugin.so这些lib都是以及plugins.xml等文件和libinference_engine.so放在一个路径),这样就可以获取到plugins.xml文件路径名,这是一个实现的小技巧

最后将获取到的路径名和plugins.xml拼接成配置文件名,进行下步处理。

根据plugins.xml配置文件获取支持的设备类型进行注册

接下来就是调用RegisterPlugins()函数读取xml中的信息,将其注册进去,

可以看到最后是调用的Imp类RegisterPluginsInRegistry接口

RegisterPluginsInRegistry

RegisterPluginsInRegistry接口代码分步骤来看:

OpenVINO解析xml文件使用的是开源第三方软件pugixml,调用load_file()加载并解析xml配置文件到xmlDoc,并检查其返回值res.status,是否成功,如果失败则直接扔出异常打断言。

读取成功之后,就要获取xml配置文件:

解析xml里面的节点,上述代码不在一一解释,每个设备类型挂载一个<plugin >解析,获取到每个plugin节点下的name以及location,还有extension等信息,将其注册到pluginRegistry中,以供后面查看使用。

上述xml文件格式,官方有明确解释:https://docs.openvinotoolkit.org/latest/classInferenceEngine_1_1Core.html

name为所支持的设备类型,location为所对应的设备类型的lib. Properties为所对应的该设备类型的一些属性,Externsion为该设备类型的外挂第三方的一些库。

总结

Core的构造函数比较简单,本质上就是将plugin.xml文件的所支持的设备给注册上去,但是真是的环境中是否有这个设备目前并没有涉及到。

SetConfig()

SetConfig()函数为设置设备的某些属性值,该API第一个参数为设置的属性及值,其类型为一个map, std::map<std::string, std::string>, 第一个为属性名称,第二个为属性值。

首先解析其入参deviceName_,是否带有device id,如有带id其格式为:

<devicename><.><deviceid>

接下来调用Impl类的SetConfigForPlugins()函数

SetConfigForPlugins

将设置的属性保存到所对应的pluginRegistry和plugins中,其中pluginRegistry为所支持的所有设备类型,而plugins是真正运行所创建的plugins。

支持config配置项可以从ie_plugin_config.h头文件可以看到,官方链接:https://docs.openvinotoolkit.org/latest/ie__plugin__config_8hpp.html

LoadNetwork

loadNetwork是整个OpenVINO的实施的关键,负责将IR下载到movidius中,整个loadNetwork的流程调用比较复杂,里面涉及了很多C++中的编程技巧。首先来看下入口源码:

入口函数比较简单,就是先对特殊的设备类型进行检查,如何deviceName是“HETERO:"则将冒号去掉,解析出deviceName中的device name和dedevice id,再次看到OpenVINO的另外一个编程规范,局部变量后面要加上"_".

最后会调用Imple类的GetCPPPluginByName,获取到相应的设备类型创建的Plugin,最后调用LoadNetwork下载网络,再次看到比较重要的一个概念Plugin,OpenVINO为每个设备类型创建相对应的Plugin,将设备抽象为具体的Plugin进行处理,这是OpenVINO的一个管理核心

下一步比较关键是LoadNetwork中实施比较关键的一步,调用过程比较繁琐:

将上述过程安装六个步骤分析

第一步

再次看到了plugins这个东东,主要是记录以及创建的plugin.如果已经创建则不再创建。

第二步

加载相对应的设备类型的动态lib,并获取lib中的CreatePluginEngine函数接口地址,这么复杂的操作,被完全藏在了SOPointer的构造函数中,InferenceEnginePluginPtr定义如下:

最后是调用SOPointer的构造函数:

该函数仅有短短几句话,但是包含的信息比较多。

首先调用创建一个Loader类:

Loader类在此主要指的是SharedObjectLoader类,该类主要是加载一个共享库

猜的没错,调用dlopen加载打开一个共享库,并返回其句柄指针。

将共享库的句柄指针保存在_so_loader中。

接着查找该共享库的CreatePluginEngine函数地址:

 _pointedObj(details::shared_from_irelease(SymbolLoader<Loader>(_so_loader).template instantiateSymbol<T>(SOCreatorTrait<T>::name)

SOCreatorTrait<T>::name的定义如下:

为 CreatePluginEngine函数名, instantiateSymbol()函数定义如下:

最后调用bind_function()函数:

获取到CreatePluginEngine在动态库的地址。

第二步骤的主要作用就是从对应的设备so中找到CreatePluginEngine()函数地址,由此可以看到每个设备对应的so都有一个CreatePluginEngine函数,该函数是其对应的主要入口,具体每个设备对应的相应的处理函数后面再详细描述。

第三步

根据获取到的CreatePluginEngine()函数地址,运行该函数生成一个相对应InferencePlugin, Plugin是整个OpenVINO的管理核心。

第四步

获取到相对应InferencePlugin中的主要API, IInferencePluginAPI该API是一个通用的API,是实际设备具体的执行

IInferencePluginAPI类接口

API名称 作用
virtual void SetName(const std::string & pluginName)  设置Plugin name
virtual std::string GetName() 获取Plugin name
virtual void SetCore(ICore *core) 设置Plugin中的Core
virtual const ICore& GetCore()  获取Plugin中的Core
virtual Parameter GetConfig(const std::string& name, const std::map<std::string, Parameter> & options) 获取Plugin中的配置
virtual Parameter GetMetric(const std::string& name, const std::map<std::string, Parameter> & options)  获取Plugin中的Metric

该类中的函数都是纯虚函数,具体的实现都是在各自的so中实现。

第五步

根据获取到的API,设置相对应的配置,如Core、Extension之类的,并生成一个新的InferencePlugin类

第六步

将该plugin对应的InferencePlugin类保存在plugins中。

最后将获取到InferencePlugin中调用LoadNetwork加载网络。

遗留两个问题需要待下一步进行剥洋葱

1:Myriad的CreatePluginEngine()实现

2:LoadNetwork()具体实现

OpenVINO InferenceEngine之Core类相关推荐

  1. OpenVINO InferenceEngine之读取IR

    目录 CNNNetReader API列表 CNNNetReader构造函数 CNNNetReaderImpl构造函数 xml网络拓扑文件结构 CNNNetReader::ReadNetwork CN ...

  2. Android 系统内的守护进程 - core类中的服务 (5) : logd

    声明 工作需要,分析logd 其实很好奇Android系统中的一些关键守护进程服务的作用: 本文使用的代码是LineageOS的cm-14.1,对应Android 7.1.2,可以参考我的另一篇博客: ...

  3. OpenVINO InferenceEngine之FormatParser

    目录 FormatParser::Parse 创建CNNetwork类 获取所有Layer节点 解析每层layer数据 获取到Layer id 获取到layer type 获取layer name 获 ...

  4. OpenVINO InferenceEngine之CNNNet、CNNLayer、Blob介绍

    OpenVINO IE模块对整个网络拓扑结构的管理主要是通过Net 和Layer,Data(Blob)进行管理的,看起来和caffe中的Net,Layer,Blob是一样的层次结构,是不是有点惊奇,技 ...

  5. OpenVINO InferenceEngine 之Grap file

    OpenVINO 在推理中将网络拓扑结构,最终转换成Grap,以grap file形式发送到movidius中 Grap file 文件格式为:ElfN_Ehdr + mv_blob_header + ...

  6. OpenVINO InferenceEngine framework

    最近研究OpenVINO中的推理代码,大概总结以下框架,只是自己的理解

  7. OpenVINO Inference Engine之LoadNetwork

    在<OpenVINO InferenceEngine之Core类>之中只是简单了介绍了一下loadNetwork的整个流程,还没有涉及到真正的加载动作.如上文中所示,在加载网络之前需要首先 ...

  8. 学习OpenVINO笔记之Inference Engine Device Query API

    Device Query API是OpenVINO在R2版本时整合引入新的API,主要可以用来查询不同设备属性和配置参数,可以让开发者更加了解设备配置,使用起来更加方便.R2 API与 R1版本相比较 ...

  9. 英特尔® Distribution of OpenVINO™ toolkit 2021 版的发布说明

    注意 2020 版的发布说明,请参阅英特尔® Distribution of OpenVINO™ toolkit 2020 版的发布说明. 简介 英特尔® Distribution of OpenVI ...

最新文章

  1. 错误602,未能在sysindexes中找到数据库 的解决办法
  2. Python字符串截取值
  3. 牛客练习赛38 E 出题人的数组 2018ccpc桂林A题 贪心
  4. 【Python学习】 简单语法与常见错误(持续更新)
  5. eclipse常用设置及调试快捷键
  6. javq接口_java 接口详解
  7. 蓝桥杯 ALGO-78 算法训练 确定元音字母位置
  8. oracle 触发器代码,Oracle触发器实例代码
  9. 《测绘管理与法律法规》——测绘质量管理体系
  10. Windows Mac 光盘刻录软件
  11. 一封没有读出来的感谢信,勾勒出蔡文胜30年创业史!
  12. 商城购物系统设计与实现(Java毕业设计-SSM项目)
  13. python中的eval函数的使用详解
  14. 一名自由程序员:我所整理和收集的前端面试题(五)
  15. 以Mesos和Docker为核心的云操作系统
  16. go 字符转ASCII 字符转成数字
  17. 物联网工程毕业设计选题推荐
  18. 今日multi_turtlebot3尝试
  19. DNS域名解析服务详解
  20. 计算机启动后桌面图标都没有了,我的电脑开机后桌面上的图标都没了怎么办?...

热门文章

  1. Maven 手动安装Jar包的例子
  2. SpringBoot2 整合JTA组件,多数据源事务管理
  3. 架构组件:基于shard-jdbc中间件,实现数据分库分表
  4. 数据结构拾遗(3) --红黑树的设计与实现(下)
  5. 小程序成长之路(四)-- 深入腾讯云(环境搭建)
  6. Swift应用案例 2.闭包入门到精通
  7. Centos eclipse打开文件自动退出
  8. linux下忘记mysql root密码解决办法
  9. location的hash部分和使用window.onhashchange实现ajax请求内容时使用浏览器后退和前进功能...
  10. Base64编码解码与实现