Hi3359AV100 NNIE開發(1)-RFCN(.wk)LoadModel函數參數解析

  之後隨筆將更多筆墨著重於NNIE開發系列,下文是關於Hi3359AV100 NNIE開發(1)-RFCN NNIE LoadModel函數與參數解析,通過對LoadModel函數的解析,能夠很好理解.wk文件的具體內容,為方便為對其他不同模型.wk載入時如何進行修改給出參照。

  在RFCN demo中把RFCN的.wk模型文件通過函數導出模型參數,具體如下所示:

1 static SAMPLE_SVP_NNIE_MODEL_S s_stRfcnModel = {0};
2 
3 HI_CHAR *pcModelName = "./data/nnie_model/detection/inst_rfcn_resnet50_cycle_352x288.wk";
4 
5 //函數輸入參數
6 SAMPLE_COMM_SVP_NNIE_LoadModel(pcModelName,&s_stRfcnModel);

  SAMPLE_COMM_SVP_NNIE_LoadModel函數定義原型如下:

1 SAMPLE_COMM_SVP_NNIE_LoadModel(
2         HI_CHAR * pszModelFile,
3          SAMPLE_SVP_NNIE_MODEL_S *pstNnieModel)

  LoadModel函數下SAMPLE_SVP_NNIE_MODEL_S參數定義:

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;

  給出SAMPLE_SVP_NNIE_MODEL_S結構體下SVP_NNIE_MODEL_S參數定義:

 1 /*NNIE model*/
 2 typedef struct hiSVP_NNIE_MODEL_S
 3 {
 4     SVP_NNIE_RUN_MODE_E     enRunMode;/*枚舉類型,網路模型運行模式*/
 5 
 6     HI_U32                  u32TmpBufSize; /*temp buffer size 輔助記憶體大小*/
 7     HI_U32                  u32NetSegNum; /*網路模型中 NNIE 執行的網路分段數,取值[1,8]*/
 8     SVP_NNIE_SEG_S          astSeg[SVP_NNIE_MAX_NET_SEG_NUM];/*網路在 NNIE 引擎上執行的段資訊*/
 9     SVP_NNIE_ROIPOOL_INFO_S astRoiInfo[SVP_NNIE_MAX_ROI_LAYER_NUM]; /*ROIPooling info*/
10 
11     SVP_MEM_INFO_S          stBase; /*網路其他資訊*/
12 }SVP_NNIE_MODEL_S;

  enRunModel:為枚舉類型,表示網路模型的運行模式,有SVP_NNIE_RUN_MODE_CHIP(只能在Chip上運行),以及SVP_NNIE_RUN_MODE_FUNC_SIM(只能用於PC端功能模擬)兩個枚舉值。可以通過列印可以看到RFCN網路模型的運行情況。

u32TempBufSize:為輔助記憶體大小。

u32NetSegNum:為網路模型中NNIE執行的網路分段數,取值為1~8。這裡的分段是指模型執行中可能會分成多段,一些段在NNIE上執行,一些段在CPU或DSP上執行,給出圖示之前,首先先給出SVP對擴展層的參考設計:

  當網路中存在 Non-support 層時,需要將網路進行切分,不支援的部分由用戶使用 CPU或者 DSP 等方式實現,統稱為非 NNIE 方式。由此整個網路會出現 NNIE->非 NNIE->NNIE… 的分段執行方式。以Faster RCNN為例,具體如下圖所示:

   u32NetSegNum就是指有多少段是在NNIE上執行的,如果一個網路模型全部都是在NNIE上執行,那麼這個u32NetSegNum就是1。由上圖可知FasterRCNN網路的NNIE執行分為兩段,即u32NetSegNum = 2。

  astSeg[SVP_NNIE_MAX_NET_SEG_NUM]:這個參數是一個結構體數組,SVP_NNIE_MAX_NET_SEG_NUM在hi_nnie.h中定義為8,這個數組表示每一段NNIE網路的各段的具體資訊,具體資訊有哪些,來看SVP_NNIE_MODEL_S結構體下SVP_NNIE_SEG_S這個結構體:

 1 /***************************************************************/
 2 /*Segment information*/
 3 typedef struct hiSVP_NNIE_SEG_S
 4 {
 5     SVP_NNIE_NET_TYPE_E enNetType;    /*網路段的類型*/
 6     HI_U16              u16SrcNum;         /*網路段的輸入節點數*/
 7     HI_U16              u16DstNum;         /*網路段的輸出節點數*/
 8     HI_U16              u16RoiPoolNum; /*網路段中包含的 RoiPooling 以及 PSRoiPooling layer 數*/
 9 
10     HI_U16              u16MaxStep;      /*RNN/LSTM 網路中序列的最大「幀數」*/
11 
12     HI_U32              u32InstOffset;
13     HI_U32              u32InstLen;
14 
15     SVP_NNIE_NODE_S     astSrcNode[SVP_NNIE_MAX_INPUT_NUM];/*網路段的第 i 個輸入節點資訊, SVP_NNIE_MAX_INPUT_NUM為16*/
16 
17     SVP_NNIE_NODE_S     astDstNode[SVP_NNIE_MAX_OUTPUT_NUM];/*網路段的第 i 個輸出節點資訊, SVP_NNIE_MAX_OUTPUT_NUM為16*/
18 
19     HI_U32              au32RoiIdx[SVP_NNIE_MAX_ROI_LAYER_NUM_OF_SEG]; /*Roipooling info index  網路段的第 i 個 RoiPooling 或者 PsRoiPooling 在SVP_NNIE_MODEL_S 中 SVP_NNIE_ROIPOOL_INFO_S 數組的下標,SVP_NNIE_MAX_ROI_LAYER_NUM_OF_SEG為2*/
20 }SVP_NNIE_SEG_S;

  SVP_NNIE_MODEL_S結構體SVP_NNIE_SEG_S結構體下enNetType參數為枚舉類型,具體如下所示:

1 /*Network  type 例子見後面表格 */
2 typedef enum hiSVP_NNIE_NET_TYPE_E
3 {
4     SVP_NNIE_NET_TYPE_CNN  = 0x0, /* Non-ROI input cnn net,普通的CNN\DNN網路類型 */
5     SVP_NNIE_NET_TYPE_ROI  = 0x1, /* With ROI input cnn net,有RPN層輸出框資訊的網路類型*/
6     SVP_NNIE_NET_TYPE_RECURRENT = 0x2, /* RNN or LSTM net */
7  
8     SVP_NNIE_NET_TYPE_BUTT
9 }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長短期記憶網路。
  SVP_NNIE_MODEL_S結構體SVP_NNIE_SEG_S結構體下u16SrcNum:表示這個段的輸入節點數,即這個段網路有多少個輸入,也是後面的astSrcNode數組的元素的有效個數。

  SVP_NNIE_MODEL_S結構體SVP_NNIE_SEG_S結構體下u16DstNum:表示這個段的輸出節點數,即這個段網路有多少個輸出,也是後面的astDstNode數組的元素的有效個數。

  SVP_NNIE_MODEL_S結構體SVP_NNIE_SEG_S結構體下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 
14         HI_U32 u32Dim; /*節點記憶體的向量維度*/
15     }unShape;
16 
17     HI_U32 u32NodeId; /*節點在網路中的 Id*/
18     HI_CHAR szName[SVP_NNIE_NODE_NAME_LEN];/*Report layer bottom name or data layer bottom name*/
19 }SVP_NNIE_NODE_S;

  SVP_NNIE_MODEL_S結構體SVP_NNIE_SEG_S結構體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 
 6     SVP_BLOB_TYPE_U8        =  0x1, /*Blob 數據元素為 U8 類型*/
 7 
 8     /*channel = 3*/
 9     SVP_BLOB_TYPE_YVU420SP  =  0x2, /*Blob 數據記憶體排布為 YVU420SP*/
10 
11     /*channel = 3*/
12     SVP_BLOB_TYPE_YVU422SP  =  0x3,/*Blob 數據記憶體排布為 YVU422SP*/
13 
14     SVP_BLOB_TYPE_VEC_S32   =  0x4, /*Blob 中存儲向量,每個元素為 S32 類型*/
15 
16     SVP_BLOB_TYPE_SEQ_S32   =  0x5,/*Blob 中存儲序列,數據元素為 S32 類型*/
17 
18     SVP_BLOB_TYPE_BUTT
19 }SVP_BLOB_TYPE_E;

  (以Fast RCNN為例)通過列印輸出SVP_NNIE_MODEL_S結構體中的astSeg,即列印兩段NNIE網路資訊的輸入輸出節點資訊,具體如下:

   從列印的資訊,我們首先看段與節點的類型,這個對於以後的分析有用,因為後面的一些初始化操作會根據不同的類型有不同的操作,如下表:

  將以上列印與下面網路圖結合,這裡的節點名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作為輸出。

  通過點擊Ruyistudio 軟體中Mark 按鈕進入工具自動標記後的 Prototxt 的網路拓撲圖:(以Fast RCNN為例)