> 文档中心 > OpenHarmony AI 业务子系统

OpenHarmony AI 业务子系统


整体代码信息

  • Version : code-v3.1-Beta
目录名 描述
applications 应用程序样例,包括camera等
base 基础软件服务子系统集&硬件服务子系统集
build 组件化编译、构建和配置脚本
docs 说明文档
domains 增强软件服务子系统集
drivers 驱动子系统
foundation 系统基础能力子系统集
kernel 内核子系统
prebuilts 编译器及工具链子系统
test 测试子系统
third_party 开源第三方组件
utils 常用的工具集
vendor 厂商提供的软件
build.py 编译脚本文件

OpenHarmony AI 业务子系统

关于目前的状态

实际模型推理的逻辑,以及支持新的推理引擎

  • 例子中使用的模型: wk
    OpenHarmony AI 业务子系统

    • 如何将训练得到的模型,导出成该格式?–> 该格式是华为硬件平台对应的模型格式。将模型转为NNIE框架支持的wk模型——以tensorflow框架为例 - 知乎 (zhihu.com)
    • 每个算法sdk 封装成一个插件 plugin 的方式,实现i_plugin.h 的接口
      OpenHarmony AI 业务子系统
  • Plugin 需要实现的接口
class IPlugin {public:    virtual ~IPlugin() = default;    virtual const long long GetVersion() const = 0;    virtual const char *GetName() const = 0;    /**     * Get plugin inference mode.     *     * @return Inference mode, synchronous or asynchronous.     */    virtual const char *GetInferMode() const = 0;    /**     * Algorithmic inference interface for synchronous tasks.     *     * @param [in] request Request task which contains the specific information of the task.     * @param [out] response Results of encapsulated algorithmic inference.     * @return Returns 0 if the operation is successful, returns a non-zero value otherwise.     */    virtual int SyncProcess(IRequest *request, IResponse *&response) = 0;    /**     * Algorithmic inference interface for asynchronous tasks.     *     * @param [in] request Request task which contains the specific information of the task.     * @param [in] callback Callback which is used to return the result of asynchronous inference.     * @return Returns 0 if the operation is successful, returns a non-zero value otherwise.     */    virtual int AsyncProcess(IRequest *request, IPluginCallback *callback) = 0;    /**     * Initialize plugin.     *     * @param [in] transactionId Transaction ID.     * @param [in] inputInfo Data information needed to initialize plugin.     * @param [out] outputInfo The returned data information of initializing plugin.     * @return Returns 0 if the operation is successful, returns a non-zero value otherwise.     */    virtual int Prepare(long long transactionId, const DataInfo &inputInfo, DataInfo &outputInfo) = 0;    /**     * Unload model and plugin.     *     * @param [in] isFullUnload Whether to unload completely.     * @param [in] transactionId Transaction ID.     * @param [in] inputInfo Data information needed to unload model and plugin.     * @return Returns 0 if the operation is successful, returns a non-zero value otherwise.     */    virtual int Release(bool isFullUnload, long long transactionId, const DataInfo &inputInfo) = 0;    /**     * Set the configuration parameters of the plugin.     *     * @param [in] optionType The type of setting option.     * @param [in] inputInfo Configuration parameter needed to set up the plugin.     * @return Returns 0 if the operation is successful, returns a non-zero value otherwise.     */    virtual int SetOption(int optionType, const DataInfo &inputInfo) = 0;    /**     * Get the configuration parameters of plugin.     *     * @param [in] optionType The type of getting option.     * @param [in] inputInfo Parameter information for getting options.     * @param [out] outputInfo The configuration information of plugin.     * @return Returns 0 if the operation is successful, returns a non-zero value otherwise.     */    virtual int GetOption(int optionType, const DataInfo &inputInfo, DataInfo &outputInfo) = 0;};typedef IPlugin *(*IPLUGIN_INTERFACE)();} // namespace AI} // namespace OHOS#endif // I_PLUGIN_H
  • 关于支持新的推理引擎(无论是硬件厂商的还是第三方软件厂商),可通过继承EngineAdapter该类,实现对应的接口,可以参考华为提供的NNIE的方式
    • EngineAdapter
foundation/ai/engine/services/common/platform/os_wrapper/engine_hal/interfaces/engine_adapter.h
class EngineAdapter {public:    virtual ~EngineAdapter() = default;    /* Initializes the algorithm and get the algorithm execution handle */    virtual int32_t Init(const char *modelPath, intptr_t &handle) = 0;    /* De-Initializes all the algorithms.  */    virtual int32_t Deinit() = 0;    /* Makes the model based on the given handle Inference once. */    virtual int32_t Invoke(intptr_t handle) = 0;    /* Gets the inputBuffer and inputSize after the handle related model is initialized. */    virtual int32_t GetInputAddr(intptr_t handle, uint16_t nodeId,     uintptr_t &inputBuffer, size_t &inputSize) = 0;    /* Gets the outputBuffer and outputSize after the handle related model is initialized. */    virtual int32_t GetOutputAddr(intptr_t handle, uint16_t nodeId,      uintptr_t &outputBuffer, size_t &outputSize) = 0;    /* Release the algorithm based on the given handle. */    virtual int32_t ReleaseHandle(intptr_t handle) = 0;};
  • NNIE实现的方式
device/hisilicon/hardware/ai/hal/hispark_taurus/include/nnie_adapter.h
- 存档的头文件,以及对应的静态库和动态库

OpenHarmony AI 业务子系统

  • 通过宏来选择不同的引擎
    OpenHarmony AI 业务子系统

现状

  • 基于目前的OpenHarmony 版本来看,虽然在子系统的配置文件中,存在定义,但是并没有定义相关的ohos.build文件。
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 关于使用./build.sh脚本编译时,编译rk3568没有涉及到这部分功能。

Exameple

将AI engine 注册成为一个server

  • 首先定义一个新的服务,并实现服务的生命周期函数
    OpenHarmony AI 业务子系统
    • 宏INHERIT_SERVICE 定义一些函数指针
      OpenHarmony AI 业务子系统
    • 宏INHERIT_IUNKNOWNENTRY类似一个模板,定义了一些变量,通过调用INHERIT_IUNKNOWNENTRY(AiInterface),在该结构体中定义一些一些属性。
      OpenHarmony AI 业务子系统
    • 查看AiInterface结构体,可以知道其中定义了如下函数指针,作为一些方法。
      OpenHarmony AI 业务子系统
    • 通过上面几部分,完成了一个struct 或 class的定义。
  • 其次,创建一个服务对象并同时定义默认功能,并向SAMGR注册服务即接口,定义服务的初始化入口。
    OpenHarmony AI 业务子系统
    • 在创建对象的时候,将struct中的函数指针完成赋值。注意其中的使用到的宏SERVER_IPROXY_IMPL_BEGIN和IPROXY_END 是为了对应之前使用到的INHERIT_IUNKNOWNENTRY(AiInterface),可以查看这两个宏的定义。
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
    • 在文件foundation/ai/engine/services/server/communication_adapter/source/sa_server.c中,定了变量g_aiEngine中赋值号右边的函数。此时完成最终的定义。
  • 在client端调用跨进程服务的对外接口,并调用IPC消息接口
    OpenHarmony AI 业务子系统
  • 在server查看Invoke函数的处理IPC消息
    OpenHarmony AI 业务子系统

More

该部分内容,更过可以查看foundation/distributedschedule/samgr_lite/README_zh.md文件,该部分是软总线部分的外部接口的介绍。

通过ID_LOAD_ALGORITHM来看这个调用栈

  • 从一个app端开始,
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 最后,APP端调用的接口,开始到AI Engine中的cline
    • 通过不同的FUNID来调用对应的响应函数,以ID_LOAD_ALGORITHM为例来看。大概是三部分,一部分在client端,一部分在通信部分,最后一部分在server端。
      • client
        OpenHarmony AI 业务子系统
        OpenHarmony AI 业务子系统
        OpenHarmony AI 业务子系统
        OpenHarmony AI 业务子系统
        OpenHarmony AI 业务子系统
      • 中间
        OpenHarmony AI 业务子系统
        OpenHarmony AI 业务子系统
        OpenHarmony AI 业务子系统
        • 关于跨client 和server必然存在一个双方共同使用部分,现在使用IPC传递一个IpcIo 一个双向链表, client和server双方对同一个IpcIo进行读写。
          • 首先可以查看IpcIo的定义, 可以通过查看IpcIoInit函数对于其中的各个内容起到的作用有更深刻的理解
            OpenHarmony AI 业务子系统
            OpenHarmony AI 业务子系统
          • 以LoadAlgorithmProxy为例,关于其中的ParcelClientInfo, ParcelAlgorithmInfo 和 ParcelDataInfo 最终操作的均是将数据push到IpcIo中。
            OpenHarmony AI 业务子系统
          • 对比看server端,
            OpenHarmony AI 业务子系统
          • 跳入UnParcelInfo函数,可以发现是对于client中ParcelClientInfo, ParcelAlgorithmInfo 和 ParcelDataInfo 的逆过程,读出client中写入的数据
            OpenHarmony AI 业务子系统
          • 关于在server端结果写入到另外一个IpcIo 对象 reply, 关于该对象的初始化,应该是samgr_lite组件来完成(推理),关于client如何获取这些server写入的数据,查看关于IClientProxy接口的定义,可以发现,最后的参数CallbackBuff是一个用来处理响应数据的回调函数。
            OpenHarmony AI 业务子系统
        • 查看回调函数CallbackBuff定义,可以发现从另外一个IpcIo对象中读取server吸入的数据。这样子,基于已有的samgr_lite接口,完成了clinet和server端数据的通信。
          OpenHarmony AI 业务子系统
      • server端
        OpenHarmony AI 业务子系统
        OpenHarmony AI 业务子系统
        OpenHarmony AI 业务子系统
        • 在engine->GetPlugin()调用中获取一个std::shared_ptr, 查看关于class Plugin的定义,可以发现其中包含IPlugin *pluginAlgorithm_, 通过该指针,调用IPlugin相关的方法, 自定义的算法插件,继承IPlugin并完成对应的接口定义。
          OpenHarmony AI 业务子系统
          OpenHarmony AI 业务子系统
          OpenHarmony AI 业务子系统

同步执行 Sync

  • 我们还是从client 端来看整个调用栈,目的理解对于整个然间作拓展的缘由,进而学习整个软件设计,像整个软件开发生态链,向上挺进。
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 其实到现在的话,与之前设置算法ID其实并没有太多的区别。
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 查看其中的msgHandler_,类型IHandler, 关于同步运行类型SyncMsgHandler也继承自该类型,同样异步运行类型也继承自该类型AsyncMsgHandler
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 查看模板类SimpleEventNotifier, 存在一个关于ISemaphore的智能指针producer_, 并相关的方法AddToBack, 将数据保存到属性T *value_, 并让信号量自增,GetFromFront, 等待一段时间,查看信号量是否成功自减,如果成功,将对应的数据返回。
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 关于ISemaphore信号量的定义,可以具体查看下面的内容,若了解,可以直接跳过。 其中关于宏定义的使用还是挺有意思的。
    OpenHarmony AI 业务子系统
  • 接着SyncMsgHandler继续往下走,查看SendRequest方法具体做什么,将request和notifier封装成一个Task,压入queue_,查看Task的定义,发现也没做什么,只是封装下数据,然后关于quque_ 其实是从engine中直接传递下去的。
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    • 关于查看queue_ 数据传递。
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
  • 关于目前为止,只是发现将request及相关的数据压入了queue_,并且在IHandler 与Engine层面使用的是同一分queue_, 那么这个数据到底是怎么处理的?
    • 这个需要回到,算法加载,创建Engine部分,并开始初始化该Engine,在调用Engine的构造函数中,将queue 引用同时传递给EngineWorker,实例化对象, EngineWorker继承于IWorker。
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
    • 查看Engine::Initialize(), 可以发现SyncMsgHandler(*queue_, plugin_->GetPluginAlgorithm()),并在线程中,开始执行thread_->StartThread(&worker_), 之后调用EngineWorker::OneAction() , 先取出一个任务queue_.PopFront(task);,然后处理任务task.handler->Process(task); 实际调用SyncMsgHandler::Process(const Task &task), 开始调用pluginAlgorithm_->SyncProcess(request, response);完成实际处理,(task.notifier)->AddToBack(response); 通知信号量,自增。 最终,完成SyncMsgHandler::ReceiveResponse(int timeOut, SimpleEventNotifier &notifier, IResponse *&response)
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统

异步执行 Async

  • 关于异步执行主要有两部分,即注册回调函数,以及完成执行。

注册回调函数

  • 目前提供的两个demo ,图片分类以及语音识别,均使用的是同步执行,在文件foundation/ai/engine/services/client/client_executor/include/i_aie_client.inl 没有发现 直接的接口,往下一层foundation/ai/engine/services/client/communication_adapter/source/sa_client_proxy.cpp中,可以发现存在预留的接口RegisterCallbackProxy
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 先查看注册saAsyncHandler->RegisterAsyncHandler(clientInfo->clientId);中做的工作
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 接着查看启动中做的工作saAsyncHandler->StartAsyncProcess(clientInfo->clientId, adapter);
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 接着查看下classAsyncProcessWorker 构造函数所作工作。初始化属性工作
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 关于线程的启动,跳过,直接查看OneAction工作,关于线程具体如何工作,可以查看前面的同步执行,过程是一样。
    OpenHarmony AI 业务子系统
  • 先跳过如果获取response,查看IpcIoResponse 工作。
    OpenHarmony AI 业务子系统
  • 关于SvcIdentity *svcIdentity = adapter_->GetEngineListener(); 就是将之前保存好的SvcIdentity 取出来。
  • 关于Transact(nullptr, *svcIdentity, ON_ASYNC_PROCESS_CODE, &io, &reply, LITEIPC_FLAG_ONEWAY, nullptr); 工作内容,
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 我们接着查看下 如果获取 response IResponse *response = handler_->FetchCallbackRecord(); 首先,前面实例化了一个ClientListenerHandler 对象。查看下构造函数。实例化了一个对象Event。
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 那么,接着IResponse *response = handler_->FetchCallbackRecord(); 从类ClientListenerHandler 中属性responses_ 取出 响应, 该属性十一两个list 专门保存 响应, 那么可以知道,异步执行时,必然是将属性保存到responses_, 通过上面的Event 来控制这个写入,读出。
    OpenHarmony AI 业务子系统

异步执行

  • 通过上面注册回调函数过程,响应必然会保存到ClientListenerHandler 的responses_ 中。
  • 首先,与同步执行相似,先初始化Engine。
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 查看下Handler 具体定义
    OpenHarmony AI 业务子系统
  • bool isStarted = thread_->StartThread(&worker_); 开始执行任务队列,现在任务队列还是为空。 等待
  • 直接从foundation/ai/engine/services/client/communication_adapter/source/sa_client_adapter.cpp 开始这个过程,前面的部分,与之前相似。
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 查看实例化future 工作内容。并且在Future 中, 包含请求和响应。
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 随着Task 压入队列, 那么开始执行工作,也就是开始执行请求。 之前的队列是复制到EngineWorker 中,
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
    OpenHarmony AI 业务子系统
  • 到现在为止,reques 终于执行了
  • 关键是,response 如何返回呢? ? ?
    • 其实是因为算法SDK 中的异步执行没有实现导致,没有联通。
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
    • 在异步执行完之后,调用int OnEvent(PluginEvent event, IResponse *response) override;
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
      OpenHarmony AI 业务子系统
  • 到此,就可以获取到响应了。
  • zh-cn/readme/AI业务子系统.md · OpenHarmony/docs - 码云 - 开源中国 (gitee.com)
  • (18条消息) 跨平台:GN实践详解(ninja, 编译, windows/mac/android实战)_TechGhost的博客-CSDN博客_gn编译