引言
本文将从宏观上介绍华为MindSpore AI框架及其与NNRT(神经网络运行时)的协同工作方式。MindSpore作为AI推理框架,通过NNRT实现模型在NPU等硬件上的高效推理。
知识有限仅供参考
一、Mindspore Lite
MindSpore是华为自己开发的一套AI框架,与Onnx、Pytorch、TensorFlow功能类似,提供加载、推理、训练模型的功能,简单说就是通过MIndSpore 你可以像使用SDK API 一样简单使用模型。
1、模型加载
首先,需要将ms模型加载到Mindspore runtime中。这一步通常涉及到读取模型文件,并将其解析成内部数据结构。
2 、初始化
在模型加载完成后,需要进行一系列的初始化操作,包括内存分配、算子注册等。这些操作是为了确保模型推理能够顺利进行。
3、模型推理
在初始化完成后,就可以开始进行模型推理了。模型推理的核心是执行图中的各个算子(Operator),这些算子对应于深度学习模型中的各个层。Mindspore会根据模型的计算图,依次执行各个算子,完成模型的推理过程。
二、MindSpore+NNRT加载模型
MindSpore 默认是运行在CPU的,而有些模型运行在NPU、GPU等其他硬件上更高效,因此NNRT 应运而生,默认与MindSpore 强关联,经由NNRT 就可以实现相关加载、推理操作运行在NPU 或者其他绑定的硬件之上。
NNRT
Neural Network Runtime(NNRt, 神经网络运行时)是面向AI领域的跨芯片推理计算运行时,作为中间桥梁连通上层AI推理框架和底层加速芯片,实现AI模型的跨芯片推理计算。
从AI推理框架 把指定的模型传递到指定的硬件完成相关AI 运算。从某种程度上说NNRT 也是有自己的一套内部的模型图,AI推理框架可以调用NNRt的构图接口将推理框架的模型图转换为NNRt内部使用的模型图,然后调用NNRt的编译和执行接口在NNRt底层对接的AI加速硬件上进行模型推理。该方式可以实现无感知的跨AI硬件推理,但是首次加载模型速度较慢。AI推理框架和应用开发者也可以无需调用NNRt构图接口,直接使用某款具体硬件对应的离线模型在NNRt上执行模型推理。该方式仅能实现在特定AI硬件上执行推理,但是首次加载模型速度较快。更多详情参见OpenAtom OpenHarmony NNRT 。
NNRt目前支持常用算子56个,不过NNRt的算子并没有具体实现,仅作为内部模型图的元素对接底层AI硬件,具体算子实现其实是在AI硬件驱动中。
1、NNRT 架构
- 在线构图,AI推理框架需要调用NNRt的构图接口将推理框架的模型图转换为NNRt内部模型图。而系统内置的MindSpore Lite推理框架(具体可参考Mindspore Lite )通过MindIR模型图对接NNRt。由于MindIR模型图和NNRt内部模型图格式兼容,因此MindSpore Lite无需调用NNRt的构图接口即可对接NNRt。
- 模型编译:NNRt内部模型图或离线模型文件需要通过NNRt的编译接口在底层AI硬件驱动上编译为硬件相关的模型对象,后续就可以在该硬件上执行模型推理。
- 模型推理:基于已编译的模型对象创建执行器,设置推理的输入和输出张量,然后在AI硬件上执行模型推理。
- 内存管理:推理的输入和输出张量需要包含对应的数据内存,该模块负责在AI硬件驱动上申请共享内存并赋给张量,并在张量销毁时释放对应共享内存。通过AI硬件驱动上的共享内存可以实现输入和输出数据的“零拷贝”,提升推理性能。
- 设备管理:负责展示NNRt对接的AI硬件信息,并提供了选择AI硬件的功能。
- 模型缓存:已编译的模型对象写成模型缓存格式,保存在文件或一段内存中。在下一次编译模型时,可以直接从文件或内存形式的模型缓存中加载,大幅提升编译速度。
- 离线模型推理:除了支持通过构图接口构造模型图,NNRt也支持直接使用AI硬件相关的模型文件(简称为离线模型)进行推理。应用开发者使用AI硬件厂商提供的模型转换器将原始训练模型转换为AI硬件对应的离线模型文件,并将它部署在应用程序中,在应用运行期间通过NNRt的离线模型编译接口传入。离线模型仅能在对应AI硬件上编译和推理,无法支持跨AI硬件兼容。但由于离线模型和硬件直接相关,因此编译速度通常很快。
NNRT 工作前所有的设备都会被映射为其内部的HDI Device概念(又称为后端)并把其对应的句柄缓存起来, 当 NeuralNetworkRuntime 需要使用已注册的后端(比如在运行神经网络模型时选择合适的硬件加速器)时,它会查询内部注册表,找到已注册的后端实例,HDI Device 是通过宏展开与静态变量初始化机制自动完成注册工作的。换言之,就是把HDI服务的句柄保存到NNRT框架中的BackendManager单例中。在HDIDeviceV2_0Creator()方法中会调用V2_0::INnrtDevice::Get()方法获取V2_0::INnrtDevice实例,这个实例就是底层推理设备的抽象实例句柄,后续调用推理等流程都是通过该实例句柄调用的。
V2_0::INnrtDevice::Get()实现在//out/f8pro/gen/drivers/interface/nnrt/v2_0/innrt_device.h 编译时默认生成的HDI服务中的静态接口,目的是获取HDI服务的句柄。
最终我们是通过这个句柄调用到NnrtDeviceService里的API,进而调用到相关硬件的能力。
Device——>HDIDeviceV2_0——>INnrtDevice
PreparedModel——>HDIPreparedModelV2_0——>PreparedModelService
三、Mindspore 实现NNRT 接口
Mindspore 通过Delegate 机制来支持NNRT,它首先抽象了一个Kernel 基类对象,然后不同的设备对应的不同的子类,在进行AI运算时指定对应的子类。
1、模型加载流程(整体数据的流向)
2、推理流程
四、HDF
OpenHarmony 系统 HDF 驱动框架主要由驱动基础框架、驱动程序、驱动配置文件和驱动接口这四个部分组成。
HDF_INIT(g_sampleDriverEntry); 系统内核自动调用的一个宏,驱动入口对象注册到HDF框架,会调用HDF_INIT函数将驱动入口地址注册到HDF框架。
- HDF 驱动基础框架提供统一的硬件资源管理,驱动加载管理以及设备节点管理等功能。驱动框架采用的是主从模式设计,由Device Manager 和 Device Host 组成。Device Manager 提供了统一的驱动管理,Device Manager 启动时根据 Device Information 提供驱动设备信息加载相应的驱动Device Host,并控制 Host 完成驱动的加载。Device Host 提供驱动运行的环境,同时预置 Host Framework与 Device Manager 进行协同,完成驱动加载和调用。根据业务的需求Device Host 可以有多个实例。简而言之就是以统一的架构完成驱动和设备的匹配、加载工作。
Device Host ,不同的应用场景或者不同的设备类型的,比如说Input Host、Display Host、USB等等 - 驱动程序实现驱动具体的功能,每个驱动由一个或者多个驱动程序组成,每个驱动程序都对应着一个 Driver Entry驱动入口。Driver Entry 主要完成驱动的初始化和驱动接口绑定功能。图中蓝色部分就是Driver程序本身。
struct HdfDriverEntry g_nnrtdeviceDriverEntry = {
.moduleVersion = 1,
.moduleName = "nnrt",
.Bind = HdfNnrtDeviceDriverBind,
.Init = HdfNnrtDeviceDriverInit,
.Release = HdfNnrtDeviceDriverRelease,
};
-
驱动配置文件.hcs 主要由设备信息(Device Information)和设备资源(Device Resource)组成。Device Information 完成设备信息的配置。如配置接口发布策略,驱动加载的方式(动态加载或静态加载、优先级加载)等;Device Resource 完成设备资源的占有配置。如GPIO 管脚、寄存器等资源信息的配置。
-
驱动接口 HDI(Hardware Driver interface)提供标准化的接口定义和实现,驱动框架提供 IO Service 和 IO Dispatcher 机制,使得不同部署形态下驱动接口趋于形式致。简而言之就是给用户层提供的接口层。
五、uhdf和nnrt的通信
nnrt/Framework部位作为Client端角色——>通过IPC——>Proxy——>通过IPC——>Stup。
- Stup的载体是nnrt_device_service即Host 服务进程
- 驱动程序的载体是xxx_device_driver.cpp
- hdf_core 最终会被编译为一个可执行文件,会被多次调用用于加载so和拉起进程
- Host 进程(Host服务)是nnrt_device_service、Stup、nnrt_device_driver的
六、HDI和IDL
HDI 是一套与硬件设备通信的PC 框架,而IDL 就是HDI文件使用的语法格式,HDI 框架经过编译后就自动生成一套C/S 架构的IPC 通信模块,而NNRT 就是通过HDI 接口与硬件设备芯片IPC通信。
- HDI(Hardware Device Interface):OpenHarmony硬件设备接口,定义系统中跨进程通信的接口,实现服务间的跨进程通信。
- IDL(Interface Description Language):接口描述语言,是HDI接口的语言格式
HDI服务发布是基于用户态HDF驱动框架,所以需要实现一个驱动入口
七、NNRT HOST
NNRT HOST 本质上就一个HDI 服务为NNRT的接口的实现。该接口标准华为已经定义清楚,由IDL 文件描述。位于drivers/peripheral/nnrt/下是通过HDF 机制由系统启动时自动拉起的对应的进程名称为nnrt_host,作为一个部件依附于hdf子系统下的。