(71条消息) 海思NNIE开发(二):FasterRCNN在海思NNIE平台上的执行流程(一)

海思NNIE开发系列文章:

海思NNIE开发(一):海思Hi3559AV100/Hi3519AV100 NNIE深度学习模块开发与调试记录

海思NNIE开发(二):FasterRCNN在海思NNIE平台上的执行流程(一)

海思NNIE开发(三):FasterRCNN在海思NNIE平台上的执行流程(二)

海思NNIE开发(四):NNIE模块读入JPEG图片或视频

海思NNIE开发(五):基于Hi3559AV100的FasterRCNN、RFCN、SSD、Yolov2、Yolov3性能综合测评

-----------------------------------------------------------------------------------------------------------------------------------

前文:

本博客将以系列文章讲解FasterRCNN等深度学习网络模型在海思NNIE平台上的执行原理。本篇将讲解NNIE平台上几个存储模型网络参数的几个结构体,以及NNIE分段执行的概念。

正文:

以SAMPLE_SVP_NNIE_FasterRcnn这个sample为例解析海思NNIE模型网络参数。

首先来看以下函数:

s32Ret = SAMPLE_COMM_SVP_NNIE_LoadModel(pcModelName,&s_stFasterRcnnModel);

该函数用于从wk文件中解析出模型的网络参数。我们来看s_stFasterRcnnModel这个参数,它是一个结构体,如下:

  1. typedef struct hiSAMPLE_SVP_NNIE_MODEL_S
  2. {
  3. SVP_NNIE_MODEL_S stModel;
  4. SVP_MEM_INFO_S stModelBuf;//store Model file
  5. }SAMPLE_SVP_NNIE_MODEL_S;

stModel存储解析出来的模型网络参数,我们来看SVP_NNIE_MODEL_S这个结构体:

  1. /*NNIE model*/
  2. typedef struct hiSVP_NNIE_MODEL_S
  3. {
  4. SVP_NNIE_RUN_MODE_E enRunMode;/*枚举类型,网络模型运行模式*/
  5. HI_U32 u32TmpBufSize; /*辅助内存大小temp buffer size*/
  6. HI_U32 u32NetSegNum;/*网络模型中 NNIE 执行的网络分段数,取值[1,8]*/
  7. SVP_NNIE_SEG_S astSeg[SVP_NNIE_MAX_NET_SEG_NUM]/*网络在 NNIE 引擎上执行的段信息*/;
  8. SVP_NNIE_ROIPOOL_INFO_S astRoiInfo[SVP_NNIE_MAX_ROI_LAYER_NUM]; /*网络模型中 RoiPooling 以及 PsRoiPooling 的信息数组ROIPooling info*/
  9. SVP_MEM_INFO_S stBase/*网络其他信息*/;
  10. }SVP_NNIE_MODEL_S;

在Sample_nnie_main这个sample中加入打印语句,输出如下:

enRunModel:为枚举类型,表示网络模型的运行模式,有SVP_NNIE_RUN_MODE_CHIP(只能在Chip上运行),以及SVP_NNIE_RUN_MODE_FUNC_SIM(只能用于PC端功能仿真)两个枚举值。通过以上打印可以看到FasterRCNN网络模型只能在Chip上运行。

u32TempBufSize:为辅助内存大小,以上打印为21094400.

u32NetSegNum:为网络模型中NNIE执行的网络分段数,取值为1~8。这里的分段是指模型执行中可能会分成多段,一些段在NNIE上执行,一些段在CPU或DSP上执行。如下图所示:

这个u32NetSegNum就是指有多少段是在NNIE上执行的,如果一个网络模型全部都是在NNIE上执行,那么这个u32NetSegNum就是1。通过以上打印可知FasterRCNN网络的NNIE执行分为两段。

astSeg[SVP_NNIE_MAX_NET_SEG_NUM]:这个参数是一个结构体数组,SVP_NNIE_MAX_NET_SEG_NUM在hi_nnie.h中定义为8,这个数组表示每一段NNIE网络的各段的具体信息,具体信息有哪些,我们来看SVP_NNIE_SEG_S这个结构体:

  1. /*Segment information*/
  2. typedef struct hiSVP_NNIE_SEG_S
  3. {
  4. SVP_NNIE_NET_TYPE_E enNetType; /*网络段的类型*/
  5. HI_U16 u16SrcNum; /*网络段的输入节点数*/
  6. HI_U16 u16DstNum;/*网络段的输出节点数*/
  7. HI_U16 u16RoiPoolNum;/*络段中包含的 RoiPooling 以及 PSRoiPooling layer 数*/
  8. HI_U16 u16MaxStep;/*RNN/LSTM 网络中序列的最大“帧数”*/
  9. HI_U32 u32InstOffset;
  10. HI_U32 u32InstLen;
  11. SVP_NNIE_NODE_S astSrcNode[SVP_NNIE_MAX_INPUT_NUM]; /*网络段的第 i 个输入节点信息, SVP_NNIE_MAX_INPUT_NUM为16*/
  12. SVP_NNIE_NODE_S astDstNode[SVP_NNIE_MAX_OUTPUT_NUM];/*网络段的第 i 个输出节点信息, SVP_NNIE_MAX_OUTPUT_NUM为16*/
  13. HI_U32 au32RoiIdx[SVP_NNIE_MAX_ROI_LAYER_NUM_OF_SEG]; /*网络段的第 i 个 RoiPooling 或者 PsRoiPooling 在SVP_NNIE_MODEL_S 中 SVP_NNIE_ROIPOOL_INFO_S 数组的下标,SVP_NNIE_MAX_ROI_LAYER_NUM_OF_SEG为2*/
  14. }SVP_NNIE_SEG_S;

enNetType:这个参数枚举类型,如下:

  1. typedef enum hiSVP_NNIE_NET_TYPE_E
  2. {
  3. SVP_NNIE_NET_TYPE_CNN = 0x0, /* Non-ROI input cnn net,普通的CNN\DNN网络类型 */
  4. SVP_NNIE_NET_TYPE_ROI = 0x1, /* With ROI input cnn net,有RPN层输出框信息的网络类型*/
  5. SVP_NNIE_NET_TYPE_RECURRENT = 0x2, /* RNN or LSTM net */
  6. SVP_NNIE_NET_TYPE_BUTT
  7. }SVP_NNIE_NET_TYPE_E;

包含4种类型:SVP_NNIE_NET_TYPE_CNN表示普通的的CNN网络, SVP_NNIE_NET_TYPE_ROI有RPN层输出框信息的网络类型,这里其实就是指Faster RCNN的NNIE模型中的Proposal层,这个层包含RPN输出框信息,且由CPU来执行。SVP_NNIE_NET_TYPE_RECURRENT则表示RNN循环神经网络或者LSTM长短期记忆网络。

u16SrcNum:表示这个段的输入节点数,即这个段网络有多少个输入,也是后面的astSrcNode数组的元素的有效个数

u16DstNum:表示这个段的输出节点数,即这个段网络有多少个输出,也是后面的astDstNode数组的元素的有效个数

astSrcNode与astDstNode:表示这个段的输入和输出节点的具体信息,其类型为SVP_NNIE_NODE_S,如下:

  1. /*Node information*/
  2. typedef struct hiSVP_NNIE_NODE_S
  3. {
  4. SVP_BLOB_TYPE_E enType;/*节点的类型*/
  5. union
  6. {
  7. struct
  8. {
  9. HI_U32 u32Width; /*节点内存形状的宽*/
  10. HI_U32 u32Height;/*节点内存形状的高*/
  11. HI_U32 u32Chn;/*节点内存形状的通道数*/
  12. }stWhc;
  13. HI_U32 u32Dim;/*节点内存的向量维度*/
  14. }unShape;
  15. HI_U32 u32NodeId;/*节点在网络中的 Id*/
  16. HI_CHAR szName[SVP_NNIE_NODE_NAME_LEN];/*Report layer bottom name or data layer bottom name*/
  17. }SVP_NNIE_NODE_S;

enType是枚举类型,其类型SVP_BLOB_TYPE_E如下:

  1. /*Blob type*/
  2. typedef enum hiSVP_BLOB_TYPE_E
  3. {
  4. SVP_BLOB_TYPE_S32 = 0x0,/*Blob 数据元素为 S32 类型*/
  5. SVP_BLOB_TYPE_U8 = 0x1,/*Blob 数据元素为 U8 类型*/
  6. /*channel = 3*/
  7. SVP_BLOB_TYPE_YVU420SP = 0x2,/*Blob 数据内存排布为 YVU420SP*/
  8. /*channel = 3*/
  9. SVP_BLOB_TYPE_YVU422SP = 0x3,/*Blob 数据内存排布为 YVU422SP*/
  10. SVP_BLOB_TYPE_VEC_S32 = 0x4,/*Blob 中存储向量,每个元素为 S32 类型*/
  11. SVP_BLOB_TYPE_SEQ_S32 = 0x5,/*Blob 中存储序列,数据元素为 S32 类型*/
  12. SVP_BLOB_TYPE_BUTT
  13. }SVP_BLOB_TYPE_E;

通过打印输出SVP_NNIE_MODEL_S结构体中的astSeg,即打印两段NNIE网络信息的输入输出节点信息,如下:

从打印的 信息,我们首先看段与节点的类型,这个对于以后的分析有用,因为后面的一些初始化操作会根据不同的类型有不同的操作,如下表:

段类型/段类型值 输入/输出 节点名 节点类型/节点类型值

第1段

SVP_NNIE_NET_TYPE_CNN/0 输入 data SVP_BLOB_TYPE_S32/0
输出 conv5 SVP_BLOB_TYPE_S32/0
rpn_cls_score SVP_BLOB_TYPE_S32/0
rpn_bbox_pred SVP_BLOB_TYPE_S32/0
rpn_cls_prob_reshape SVP_BLOB_TYPE_S32/0

第2段

SVP_NNIE_NET_TYPE_ROI/1 输入 conv5 SVP_BLOB_TYPE_S32/0
输出 bbox_pred SVP_BLOB_TYPE_VEC_S32/4
cls_prob SVP_BLOB_TYPE_VEC_S32/4

将以上打印与下面网络图结合,这里的节点名szName,个人的理解是,如果作为输入节点,则显示的是该层的bottom的名字,如果作为输出节点,则显示top的名字。第1段有1个输入节点,即data层的输入。输出节点的数量打印显示是4个输出,而下面的网络图中只有3个输出,即conv5, rpn_bbox_pred, rpn_cls_prob_reshape,打印显示多了一个rpn_cls_score。在RuyiStudio的网络图里rpn_cls_score是在第一段的中间,并非作为输出,为什么会把它当输出呢?玄机就在网络描述文件.prototxt里面,我们来看rpn_cls_score这一层,如下:

  1. layer {
  2. name: "rpn_cls_score"
  3. type: "Convolution"
  4. bottom: "rpn/output"
  5. top: "rpn_cls_score_report"
  6. convolution_param {
  7. num_output: 18 # 2(bg/fg) * 9(anchors)
  8. kernel_size: 1 pad: 0 stride: 1
  9. weight_filler { type: "gaussian" std: 0.01 }
  10. bias_filler { type: "constant" value: 0 }
  11. }
  12. }

这一层的top输出是rpn_cls_score_report,即rpn_cls_score加了后缀_report。我们打开《HiSVP开发指南》的3.2.7章节,如下:

可以看到,中间层的top加上_report后当作该段的一个输出,因此从打印那里可以看到这一段有rpn_cls_score作为输出。

 

第2段有1个输入节点,conv5,这里显示的u32NodeId为0,那么这个u32NodeId应该是指该节点在该段中的序号。这个段的输出节点bbox_pred, cls_prob,显示序号为7和9。

这里还有个疑问,不知道这个u32NodeId序号是怎么排的,例如第1段的输出节点conv5,序号为8,但从下图来看,应该是7(relu层应该跟conv5同一个序号)。但是rpn_cls_prob_reshape的序号怎么是19,rpn_bbox_pred的序号为13也对不上。

 

注:以上网络使用的是以下FasterRCNN网络

(0)

相关推荐