海思NNIE開發系列文章:
海思NNIE開發(一):海思Hi3559AV100/Hi3519AV100 NNIE深度學習模塊開發與調試記錄
海思NNIE開發(二):FasterRCNN在海思NNIE平臺上的執行流程(一)
海思NNIE開發(三):FasterRCNN在海思NNIE平臺上的執行流程(二)
海思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這個參數,它是一個結構體,如下:
typedef struct hiSAMPLE_SVP_NNIE_MODEL_S
{
SVP_NNIE_MODEL_S stModel;
SVP_MEM_INFO_S stModelBuf;//store Model file
}SAMPLE_SVP_NNIE_MODEL_S;
stModel存儲解析出來的模型網絡參數,我們來看SVP_NNIE_MODEL_S這個結構體:
/*NNIE model*/
typedef struct hiSVP_NNIE_MODEL_S
{
SVP_NNIE_RUN_MODE_E enRunMode;/*枚舉類型,網絡模型運行模式*/
HI_U32 u32TmpBufSize; /*輔助內存大小temp buffer size*/
HI_U32 u32NetSegNum;/*網絡模型中 NNIE 執行的網絡分段數,取值[1,8]*/
SVP_NNIE_SEG_S astSeg[SVP_NNIE_MAX_NET_SEG_NUM]/*網絡在 NNIE 引擎上執行的段信息*/;
SVP_NNIE_ROIPOOL_INFO_S astRoiInfo[SVP_NNIE_MAX_ROI_LAYER_NUM]; /*網絡模型中 RoiPooling 以及 PsRoiPooling 的信息數組ROIPooling info*/
SVP_MEM_INFO_S stBase/*網絡其他信息*/;
}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這個結構體:
/*Segment information*/
typedef struct hiSVP_NNIE_SEG_S
{
SVP_NNIE_NET_TYPE_E enNetType; /*網絡段的類型*/
HI_U16 u16SrcNum; /*網絡段的輸入節點數*/
HI_U16 u16DstNum;/*網絡段的輸出節點數*/
HI_U16 u16RoiPoolNum;/*絡段中包含的 RoiPooling 以及 PSRoiPooling layer 數*/
HI_U16 u16MaxStep;/*RNN/LSTM 網絡中序列的最大“幀數”*/
HI_U32 u32InstOffset;
HI_U32 u32InstLen;
SVP_NNIE_NODE_S astSrcNode[SVP_NNIE_MAX_INPUT_NUM]; /*網絡段的第 i 個輸入節點信息, SVP_NNIE_MAX_INPUT_NUM爲16*/
SVP_NNIE_NODE_S astDstNode[SVP_NNIE_MAX_OUTPUT_NUM];/*網絡段的第 i 個輸出節點信息, SVP_NNIE_MAX_OUTPUT_NUM爲16*/
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*/
}SVP_NNIE_SEG_S;
enNetType:這個參數枚舉類型,如下:
typedef enum hiSVP_NNIE_NET_TYPE_E
{
SVP_NNIE_NET_TYPE_CNN = 0x0, /* Non-ROI input cnn net,普通的CNN\DNN網絡類型 */
SVP_NNIE_NET_TYPE_ROI = 0x1, /* With ROI input cnn net,有RPN層輸出框信息的網絡類型*/
SVP_NNIE_NET_TYPE_RECURRENT = 0x2, /* RNN or LSTM net */
SVP_NNIE_NET_TYPE_BUTT
}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,如下:
/*Node information*/
typedef struct hiSVP_NNIE_NODE_S
{
SVP_BLOB_TYPE_E enType;/*節點的類型*/
union
{
struct
{
HI_U32 u32Width; /*節點內存形狀的寬*/
HI_U32 u32Height;/*節點內存形狀的高*/
HI_U32 u32Chn;/*節點內存形狀的通道數*/
}stWhc;
HI_U32 u32Dim;/*節點內存的向量維度*/
}unShape;
HI_U32 u32NodeId;/*節點在網絡中的 Id*/
HI_CHAR szName[SVP_NNIE_NODE_NAME_LEN];/*Report layer bottom name or data layer bottom name*/
}SVP_NNIE_NODE_S;
enType是枚舉類型,其類型SVP_BLOB_TYPE_E如下:
/*Blob type*/
typedef enum hiSVP_BLOB_TYPE_E
{
SVP_BLOB_TYPE_S32 = 0x0,/*Blob 數據元素爲 S32 類型*/
SVP_BLOB_TYPE_U8 = 0x1,/*Blob 數據元素爲 U8 類型*/
/*channel = 3*/
SVP_BLOB_TYPE_YVU420SP = 0x2,/*Blob 數據內存排布爲 YVU420SP*/
/*channel = 3*/
SVP_BLOB_TYPE_YVU422SP = 0x3,/*Blob 數據內存排布爲 YVU422SP*/
SVP_BLOB_TYPE_VEC_S32 = 0x4,/*Blob 中存儲向量,每個元素爲 S32 類型*/
SVP_BLOB_TYPE_SEQ_S32 = 0x5,/*Blob 中存儲序列,數據元素爲 S32 類型*/
SVP_BLOB_TYPE_BUTT
}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這一層,如下:
layer {
name: "rpn_cls_score"
type: "Convolution"
bottom: "rpn/output"
top: "rpn_cls_score_report"
convolution_param {
num_output: 18 # 2(bg/fg) * 9(anchors)
kernel_size: 1 pad: 0 stride: 1
weight_filler { type: "gaussian" std: 0.01 }
bias_filler { type: "constant" value: 0 }
}
}
這一層的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網絡