5 算法程序解读
前面章节已经成功运行sample程序,迫不及待地想知道程序怎么写,好不好掌握。本文以手写体图片数字识别为例,介绍海思芯片上AI算法推理程序的框架、数据结构、API调用、运行流程等内容。
5.1 常用深度学习框架推理步骤
常用深度学习框架(caffe、TensorFlow等)的算法推理程序主要由三部分组成:预处理:准备推理输入数据,如图片颜色通道排列和分离,像素数据转换成浮点数,数据归一化处理等;
神经网络推理:对输入数据进行推理计算,并输出推理数据,在手写体识别例子中,输出的是预测为0~9这10个数字对应的概率值;
后处理:对推理输出的数据进行解析,得到最终推理结果,在手写体识别例子中,比较10个数字的概率值,最大概率对应的数字就是推理的结果。
对于异构计算平台,如GPU、TPU等,在预处理、后处理以及推理过程中部分网络层需要CPU参与计算的,就会涉及到异构计算单元之间的交互,如数据传输,过程同步等。这种交互由深度学习框架内部进行封装处理,开发者只要遵守框架的接口和过程等约定,就能成功进行推理计算。
5.2 海思芯片AI算法推理过程
5.2.1 初始化获取模型数据文件大小
在用户态申请MMZ内存作为模型数据缓存,大小为步骤1的模型文件大小
将模型数据文件读取(填充)到申请的MMZ内存空间中
从步骤3加载网络模型数据,并解析出网络模型
获取网络任务各段辅助内存大小,申请相应缓存空间(申请一块总的内存空间,再切分给任务缓存、输入数据缓存、输出数据缓存使用),设置各个缓存空间内存地址信息
申请网络推理结果后处理缓存空间,并设置参数
设置网络预测控制信息,参数数据来源于步骤4解析的网络模型参数数据
记录(设置)网络推理的辅助内存,即调用HI_MPI_SVP_NNIE_AddTskBuf接口
5.2.2 运行
预处理填充输入数
刷新缓存
推理执行网络推理
后处理刷新缓存
读取推理结果,并转换成用户需要的输出信息
5.2.3 销毁删除记录(设置)网络推理的辅助内存,即调用HI_MPI_SVP_NNIE_RemoveTskBuf接口
释放网络任务各段辅助内存
释放网络推理结果后处理缓存空间
卸载网络模型,并释放模型数据缓存
5.3 主要API说明
NNIE 模块提供了创建任务和查询任务的基本接口。 用户根据需求调用相应的算子接口创建任务,指定是否阻塞等待结果,即 bInstant 类型,并记录该任务返回的 handle 号。根据返回的 handle 号,指定阻塞方式,可以查询到该任务的完成状态。HI_MPI_SVP_NNIE_LoadModel:从用户事先加载到 buf 中的模型中解析出网络模型。
HI_MPI_SVP_NNIE_GetTskBufSize:获取给定网络任务各段辅助内存大小。
HI_MPI_SVP_NNIE_Forward:多节点输入输出的 CNN 类型网络预测。
HI_MPI_SVP_NNIE_ForwardWithBbox:多个节点 feature map 输入。
HI_MPI_SVP_NNIE_UnloadModel:卸载模型。
HI_MPI_SVP_NNIE_Query:查询任务是否完成。
HI_MPI_SVP_NNIE_AddTskBuf:记录 TskBuf 地址信息。
HI_MPI_SVP_NNIE_RemoveTskBuf:移除 TskBuf 地址信息。
5.4 参考程序解读
在海思SDK的package/mpp_smp_linux/sample/svp/nnie路径下可以找到参考程序代码。
很多人在阅读海思sample程序时,被各种结构体定义及关系给弄糊涂了。本来刚入门,面对海思官方文档标准API已经很陌生了,SAMPLE程序对API和结构体又进行了再次封装,且所有NNIE例子都写在同一个代码文件中(4000多行,一看就头大),增加读者阅读和理解代码的难度。
参考程序目录结构说明如下:
mpp_smp_linux
├── include SDK头文件
├── lib SDK动态库和静态库文件
└── sample
├── common sample公共程序和头文件
└── svp SVP模块参考程序
├── common SVP模块公共程序和头文件
└── nnie NNIE模块参考程序
├── sample_nnie_main.c NNIE参考程序main入口
├── sample_nnie_software 网络推理CPU执行部分,包括后处理
├── sample NNIE参考程序实现代码
└── data 测试数据目录
├── nnie_image 测试图片
└── nnie_model 测试模型
算法代码逻辑从main函数的case分支进入各个网络类型的处理函数,手写体识别对应SAMPLE_SVP_NNIE_Cnn函数,流程已在5.2小节中详细说明,这里讲解几个NNIE sample的公共数据结构。
模型管理结构:
typedef struct hiSAMPLE_SVP_NNIE_MODEL_S {
SVP_NNIE_MODEL_S stModel; // 解析后的模型结构,调用HI_MPI_SVP_NNIE_LoadModel解析的结果
SVP_MEM_INFO_S stModelBuf; // 模型文件的数据缓存,由用户填充
} SAMPLE_SVP_NNIE_MODEL_S;
引擎执行参数:
typedef struct hiSAMPLE_SVP_NNIE_PARAM_S {
// 模型结构参数
SVP_NNIE_MODEL_S* pstModel;
// 网络推理辅助内存tmpBuf大小,来源于pstModel的u32TmpBufSize字段
HI_U32 u32TmpBufSize;
// 网络任务各段辅助内存大小,由HI_MPI_SVP_NNIE_GetTskBufSize接口获取
HI_U32 au32TaskBufSize[SVP_NNIE_MAX_NET_SEG_NUM];
// 网络任务辅助内存起始信息
SVP_MEM_INFO_S stTaskBuf;
// 网络推理辅助内存tmpBuf起始信息
SVP_MEM_INFO_S stTmpBuf;
// store Lstm step info
SVP_MEM_INFO_S stStepBuf;
// 网络输入/输出的数据(blob)参数信息
SAMPLE_SVP_NNIE_SEG_DATA_S astSegData[SVP_NNIE_MAX_NET_SEG_NUM];
// CNN/DNN/RNN网络预测控制参数,参数数据来源于加载模型文件解析后的网络模型参数
SVP_NNIE_FORWARD_CTRL_S astForwardCtrl[SVP_NNIE_MAX_NET_SEG_NUM];
// 有 Bbox 输入的目标检测网络预测控制参数,参数数据来源于加载模型文件解析后的网络模型参数
SVP_NNIE_FORWARD_WITHBBOX_CTRL_S astForwardWithBboxCtrl[SVP_NNIE_MAX_NET_SEG_NUM];
} SAMPLE_SVP_NNIE_PARAM_S;
网络执行CPU部分(后处理)
typedef struct hiSAMPLE_SVP_NNIE_CNN_SOFTWARE_PARAM_S {
HI_U32 u32TopN; // 获取类别概率值最高的前N个
SVP_DST_BLOB_S stGetTopN; // 前N个类别输出的内存信息
SVP_MEM_INFO_S stAssistBuf; // 辅助内存信息
} SAMPLE_SVP_NNIE_CNN_SOFTWARE_PARAM_S;
5.5 注意事项硬件为了快速访问内存首地址或者跨行访问数据,在使用 DDR4 时,为提高访存效率,建议首地址使用 256 字节对齐,stride 使用 256 字节的奇数倍对齐。
典型的 RGB\HSV\LAB 图像 Planar 格式存储,NNIE 默认以 B\G\R、H\S\V、L\A\B 顺序按通道平面进行存储。
5.6 参考文献,
,