1. 程式人生 > >Hi3559AV100 NNIE開發(4)mobilefacenet.cfg引數配置挖坑解決與SVP_NNIE_Cnn實現分析

Hi3559AV100 NNIE開發(4)mobilefacenet.cfg引數配置挖坑解決與SVP_NNIE_Cnn實現分析

  前面隨筆給出了NNIE開發的基本知識,下面幾篇隨筆將著重於Mobilefacenet NNIE開發,實現mobilefacenet.wk的chip版本,並在Hi3559AV100上實現mobilefacenet網路功能,外接USB攝像頭通過MPP平臺輸出至VO HDMI顯示結果。下文是Hi3559AV100 NNIE開發(4)mobilefacenet.cfg引數配置挖坑解決與SVP_NNIE_Cnn實現分析,目前專案需要對mobilefacenet網路進行.wk的開發,下面給出在.wk生成過程中遇到的坑與解決方式,並給出SVP_NNIE_Cnn整體實現的各個step分析,為後面在板載上實現mobilefacenet網路打下基礎。

1、mobilefacenet.cfg引數配置挖坑解決

  CNN_convert_bin_and_print_featuremap.py和Get Caffe Output這裡的預處理方式都是先乘以【data_scale】,再減均值【mean_file】,而在量化生成 .mk 檔案時卻是先減均值再乘以scale的。

  給出預處理這一個環節對輸入資料data的處理方式:

1     data = inputs
2     if norm_type == '4' or norm_type == '5':
3        data = data * float(data_scale)

  data是uint8型別的array,是先乘以了【data_scale】的,也就是說和NNIE 生成wk中的操作順序是不一致的,對於mobilefacenet.cfg網路輸入資料預處理方法時,當norm_type = 5時,輸入資料減通道均值後再乘以 data_scale,如下所示:

 

   所在在實際操作中,需要對均值檔案進行處理,轉換方式如下:

 (data - 128.0) * 0.0078125 <==> data * 0.0078125 - 1

  因此這裡需要做的修改就是需要將【mean_file】pixel_mean_compare.txt修設定為1.0:

   最終生成mobilefacenet.wk,結果如下所示,具體的測試需要下一步進行。

 1 begin parameter compressing....
 2 
 3 end parameter compressing
 4 
 5 begin compress index generating....
 6 
 7 end compress index generating
 8 
 9 begin binary code generating....
10 
11 .........................................................................................................................
12 ....................................................................end binary code generating
13 
14 begin quant files writing....
15 
16 end quant files writing
17 
18 .
19 ===============D:\Hi3559_NNIE\3559\mobileface\mobileface.cfg Successfully!===============
20 
21 End [RuyiStudio Wk NNIE Mapper] [D:\Hi3559_NNIE\3559\mobileface\mobileface.cfg] mobileface

2、SVP_NNIE_Cnn實現分析

  下面給出SAMPLE_SVP_NNIE_Cnn函式的執行過程,主要分為下面八個步驟:

 1     HI_CHAR *pcSrcFile = "./data/nnie_image/y/0_28x28.y";
 2     HI_CHAR *pcModelName = "./data/nnie_model/classification/inst_mnist_cycle.wk";
 3 
 4 
 5     /*Set configuration parameter  */
 6     stNnieCfg.pszPic= pcSrcFile;
 7     stNnieCfg.u32MaxInputNum = u32PicNum; //max input image num in each batch
 8     stNnieCfg.u32MaxRoiNum = 0;
 9     stNnieCfg.aenNnieCoreId[0] = SVP_NNIE_ID_0;//set NNIE core
10     s_stCnnSoftwareParam.u32TopN = 5;
11 
12 
13 
14     /*Sys init ---step1*/
15     SAMPLE_COMM_SVP_CheckSysInit();
16 
17     /*CNN Load model  ------step2*/
18     s32Ret = SAMPLE_COMM_SVP_NNIE_LoadModel(pcModelName,&s_stCnnModel);
19 
20 
21     /*CNN parameter initialization   -------step3*/
22     /*Cnn software parameters are set in SAMPLE_SVP_NNIE_Cnn_SoftwareParaInit,
23      if user has changed net struct, please make sure the parameter settings in
24      SAMPLE_SVP_NNIE_Cnn_SoftwareParaInit function are correct*/
25     s_stCnnNnieParam.pstModel = &s_stCnnModel.stModel;
26     s32Ret = SAMPLE_SVP_NNIE_Cnn_ParamInit(&stNnieCfg,&s_stCnnNnieParam,&s_stCnnSoftwareParam);
27 
28 
29     /*record tskBuf  -------step4*/
30     s32Ret = HI_MPI_SVP_NNIE_AddTskBuf(&(s_stCnnNnieParam.astForwardCtrl[0].stTskBuf));
31 
32 
33     /*Fill src data -------step5*/
34     SAMPLE_SVP_TRACE_INFO("Cnn start!\n");
35     stInputDataIdx.u32SegIdx = 0;
36     stInputDataIdx.u32NodeIdx = 0;
37     s32Ret = SAMPLE_SVP_NNIE_FillSrcData(&stNnieCfg,&s_stCnnNnieParam,&stInputDataIdx);
38 
39 
40     /*NNIE process(process the 0-th segment)   -------step6*/
41     stProcSegIdx.u32SegIdx = 0;
42     s32Ret = SAMPLE_SVP_NNIE_Forward(&s_stCnnNnieParam,&stInputDataIdx,&stProcSegIdx,HI_TRUE);
43 
44 
45 
46     /*Software process     --------step7*/
47     /*if user has changed net struct, please make sure SAMPLE_SVP_NNIE_Cnn_GetTopN
48      function's input datas are correct*/
49     s32Ret = SAMPLE_SVP_NNIE_Cnn_GetTopN(&s_stCnnNnieParam,&s_stCnnSoftwareParam);
50 
51 
52 
53     /*Print result      --------step8*/
54     SAMPLE_SVP_TRACE_INFO("Cnn result:\n");
55     s32Ret = SAMPLE_SVP_NNIE_Cnn_PrintResult(&(s_stCnnSoftwareParam.stGetTopN),
56              s_stCnnSoftwareParam.u32TopN);

  (1)step1為SAMPLE_COMM_SVP_CheckSysInit()

  完成的是MPP系統的初始化,主要實現的是Sys_Init和VB_Init,實現MPP記憶體池的配置,具體實現如下:

 1 HI_VOID SAMPLE_COMM_SVP_CheckSysInit(HI_VOID)
 2 {
 3     ..............
 4     SAMPLE_COMM_SVP_SysInit()
 5     {
 6         //省略了部分過程,列出實現關鍵函式
 7         HI_MPI_SYS_Exit();
 8         HI_MPI_VB_Exit();
 9 
10         memset(&struVbConf,0,sizeof(VB_CONFIG_S));
11 
12         struVbConf.u32MaxPoolCnt             = 2;
13         struVbConf.astCommPool[1].u64BlkSize = 768*576*2;
14         struVbConf.astCommPool[1].u32BlkCnt  = 1;
15 
16         s32Ret = HI_MPI_VB_SetConfig((const VB_CONFIG_S *)&struVbConf);  //設定MPP視訊快取池屬性
17 
18 
19         s32Ret = HI_MPI_VB_Init();  //初始化MPP快取池
20 
21 
22         s32Ret = HI_MPI_SYS_Init(); //初始化MPP系統
23 
24     }
25 
26     .............  
27 }

  (2)step2為SAMPLE_COMM_SVP_NNIE_LoadModel

  函式從使用者事先載入到 buf 中的模型中解析出網路模型,其函式實現較為複雜,具體的函式引數解析和函式執行過程已經在前面隨筆給出了,需要的話,可以參考隨筆:

  Hi3559AV100 NNIE開發(1)-RFCN(.wk)LoadModel函式引數解析 (https://www.cnblogs.com/iFrank/p/14500648.html)

  Hi3559AV100 NNIE開發(2)-RFCN(.wk)LoadModel及NNIE Init函式執行過程分析   (https://www.cnblogs.com/iFrank/p/14503482.html)

  (3)step3為SAMPLE_SVP_NNIE_Cnn_ParamInit

  首先給出呼叫與定義,便於分析:

 1 /*Set configuration parameter*/
 2 stNnieCfg.pszPic= pcSrcFile;
 3 stNnieCfg.u32MaxInputNum = u32PicNum; //max input image num in each batch
 4 stNnieCfg.u32MaxRoiNum = 0;
 5 stNnieCfg.aenNnieCoreId[0] = SVP_NNIE_ID_0;//set NNIE core
 6 
 7 s_stCnnSoftwareParam.u32TopN = 5;
 8 
 9 s_stCnnNnieParam.pstModel = &s_stCnnModel.stModel;
10 s32Ret = SAMPLE_SVP_NNIE_Cnn_ParamInit(&stNnieCfg,
11                                        &s_stCnnNnieParam,
12                                        &s_stCnnSoftwareParam);
13                                        
14                                        
15                                        
16 static HI_S32 SAMPLE_SVP_NNIE_Cnn_ParamInit(SAMPLE_SVP_NNIE_CFG_S* pstNnieCfg,
17                                             SAMPLE_SVP_NNIE_PARAM_S *pstCnnPara, 
18                                 SAMPLE_SVP_NNIE_CNN_SOFTWARE_PARAM_S* pstCnnSoftWarePara)
19 {
20     ........
21     
22     /*init hardware para*/
23     s32Ret = SAMPLE_COMM_SVP_NNIE_ParamInit(pstNnieCfg,
24                                             pstCnnPara);
25 
26 
27     /*init software para*/
28     if(pstCnnSoftWarePara!=NULL)
29     {
30         s32Ret = SAMPLE_SVP_NNIE_Cnn_SoftwareParaInit(pstNnieCfg,
31                                                       pstCnnPara,
32                                                       pstCnnSoftWarePara);
33                                "Error(%#x),SAMPLE_SVP_NNIE_Cnn_SoftwareParaInit failed!\n",s32Ret);
34     }
35     
36     ........
37 }

  其中SAMPLE_COMM_SVP_NNIE_ParamInit函式及引數分析可見之前隨筆:

   Hi3559AV100 NNIE開發(2)-RFCN(.wk)LoadModel及NNIE Init函式執行過程分析   (https://www.cnblogs.com/iFrank/p/14503482.html),之前的隨筆介紹的很詳細,這裡就不在贅述了。

  對SAMPLE_SVP_NNIE_Cnn_SoftwareParaInit函式,首先給出定義:

 1 static HI_S32 SAMPLE_SVP_NNIE_Cnn_SoftwareParaInit(
 2     SAMPLE_SVP_NNIE_CFG_S* pstNnieCfg,
 3     SAMPLE_SVP_NNIE_PARAM_S *pstCnnPara, 
SAMPLE_SVP_NNIE_CNN_SOFTWARE_PARAM_S* pstCnnSoftWarePara) 4 { 5 HI_U32 u32GetTopNMemSize = 0; 6 HI_U32 u32GetTopNAssistBufSize = 0; 7 HI_U32 u32GetTopNPerFrameSize = 0; 8 HI_U32 u32TotalSize = 0; 9 HI_U32 u32ClassNum = pstCnnPara->pstModel->astSeg[0].astDstNode[0].unShape.stWhc.u32Width; 10 HI_U64 u64PhyAddr = 0; 11 HI_U8* pu8VirAddr = NULL; 12 HI_S32 s32Ret = HI_SUCCESS; 13 14 /*get mem size*/ 15 u32GetTopNPerFrameSize = pstCnnSoftWarePara->u32TopN*sizeof(SAMPLE_SVP_NNIE_CNN_GETTOPN_UNIT_S); 16 u32GetTopNMemSize = SAMPLE_SVP_NNIE_ALIGN16(u32GetTopNPerFrameSize)*pstNnieCfg->u32MaxInputNum; 17 u32GetTopNAssistBufSize = u32ClassNum*sizeof(SAMPLE_SVP_NNIE_CNN_GETTOPN_UNIT_S); 18 u32TotalSize = u32GetTopNMemSize+u32GetTopNAssistBufSize; 19 20 /*malloc mem*/ 21 s32Ret = SAMPLE_COMM_SVP_MallocMem("SAMPLE_CNN_INIT",NULL,(HI_U64*)&u64PhyAddr, 22 (void**)&pu8VirAddr,u32TotalSize); 23 SAMPLE_SVP_CHECK_EXPR_RET(HI_SUCCESS != s32Ret,s32Ret,SAMPLE_SVP_ERR_LEVEL_ERROR, 24 "Error,Malloc memory failed!\n"); 25 memset(pu8VirAddr, 0, u32TotalSize); 26 27 /*init GetTopn */ 28 pstCnnSoftWarePara->stGetTopN.u32Num= pstNnieCfg->u32MaxInputNum; 29 pstCnnSoftWarePara->stGetTopN.unShape.stWhc.u32Chn = 1; 30 pstCnnSoftWarePara->stGetTopN.unShape.stWhc.u32Height = 1; 31 pstCnnSoftWarePara->stGetTopN.unShape.stWhc.u32Width = u32GetTopNPerFrameSize/sizeof(HI_U32); 32 pstCnnSoftWarePara->stGetTopN.u32Stride = SAMPLE_SVP_NNIE_ALIGN16(u32GetTopNPerFrameSize); 33 pstCnnSoftWarePara->stGetTopN.u64PhyAddr = u64PhyAddr; 34 pstCnnSoftWarePara->stGetTopN.u64VirAddr = (HI_U64)pu8VirAddr; 35 36 /*init AssistBuf */ 37 pstCnnSoftWarePara->stAssistBuf.u32Size = u32GetTopNAssistBufSize; 38 pstCnnSoftWarePara->stAssistBuf.u64PhyAddr = u64PhyAddr+u32GetTopNMemSize; 39 pstCnnSoftWarePara->stAssistBuf.u64VirAddr = (HI_U64)pu8VirAddr+u32GetTopNMemSize; 40 41 return s32Ret; 42 }

  函式體內最主要功能是實現s_stCnnSoftwareParam引數的賦值,包含大量賦值語句,其中s_stCnnSoftwareParam結構體各個元素賦值的意義等需要的時候再進行研討,此外函式還實現在使用者態分配 MMZ 記憶體。通過對兩個函式的分析,step3 SAMPLE_SVP_NNIE_Cnn_ParamInit()完成。

  (4)step4為HI_MPI_SVP_NNIE_AddTskBuf

  為了記錄 TskBuf 地址資訊,其作用和注意事項:

  ①記錄 TskBuf 地址資訊,用於減少核心態記憶體對映次數,提升效率;

  ②TskBuf 地址資訊的記錄是通過連結串列進行管理,連結串列長度預設值為 32,連結串列長度可通過模組引數 nnie_max_tskbuf_num 進行配;

  ③若沒呼叫 HI_MPI_SVP_NNIE_AddTskBuf 預先把 TskBuf 地址資訊記錄到系統,那麼之後呼叫 Forward/ForwardWithBbox 每次都會 Map/Unmap 操作 TskBuf 核心態虛擬地址,效率會比較低。  

  給出函式呼叫和定義:

1 /*SAMPLE_COMM_SVP_NNIE_LoadModel(pcModelName,&s_stCnnModel);*/     
2 s_stCnnNnieParam.pstModel = &s_stCnnModel.stModel;
3     
4 s32Ret = HI_MPI_SVP_NNIE_AddTskBuf(&(s_stCnnNnieParam.astForwardCtrl[0].stTskBuf));
5 
6 
7 //定義
8 HI_S32 HI_MPI_SVP_NNIE_AddTskBuf(const SVP_MEM_INFO_S* pstTskBuf);

  (5)step5為SAMPLE_SVP_NNIE_FillSrcData

  實現src資料的填充,此函式十分關鍵,對所給影象資料:./data/nnie_image/y/0_28x28.y進行處理,為了更好的分析資料處理函式,首先給出函式呼叫資訊:

 1     stNnieCfg.pszPic= pcSrcFile;
 2     stNnieCfg.u32MaxInputNum = u32PicNum; //max input image num in each batch
 3     stNnieCfg.u32MaxRoiNum = 0;
 4     stNnieCfg.aenNnieCoreId[0] = SVP_NNIE_ID_0;//set NNIE core
 5 
 6 /*SAMPLE_COMM_SVP_NNIE_LoadModel(pcModelName,&s_stCnnModel);*/
 7 s_stCnnNnieParam.pstModel = &s_stCnnModel.stModel;
 8 
 9     stInputDataIdx.u32SegIdx = 0;
10     stInputDataIdx.u32NodeIdx = 0;
11     s32Ret = SAMPLE_SVP_NNIE_FillSrcData(&stNnieCfg,
                          &s_stCnnNnieParam,
                          &stInputDataIdx);

  為了更加清楚函式功能,先給出函式定義,方便後面分析(忽略一些次要資訊):

  1 static HI_S32 SAMPLE_SVP_NNIE_FillSrcData(SAMPLE_SVP_NNIE_CFG_S* pstNnieCfg,
  2                                         SAMPLE_SVP_NNIE_PARAM_S *pstNnieParam, 
  3                                         SAMPLE_SVP_NNIE_INPUT_DATA_INDEX_S* pstInputDataIdx)

  總的來說,函式實現以下功能:

  ①open file fopen(pstNnieCfg->pszPic,"rb");  

 1 //定義檔名
 2 HI_CHAR *pcSrcFile = "./data/nnie_image/y/0_28x28.y";
 3 
 4 stNnieCfg.pszPic= pcSrcFile;
 5 
 6 //函式定義
 7 HI_S32 SAMPLE_SVP_NNIE_FillSrcData(SAMPLE_SVP_NNIE_CFG_S* pstNnieCfg,
 8                                    SAMPLE_SVP_NNIE_PARAM_S *pstNnieParam, 
 9                                    SAMPLE_SVP_NNIE_INPUT_DATA_INDEX_S* pstInputDataIdx)
10 //函式呼叫
11 SAMPLE_SVP_NNIE_FillSrcData(&stNnieCfg,
12                             &s_stCnnNnieParam,
13                             &stInputDataIdx);
14 
15 fp = fopen(pstNnieCfg->pszPic,"rb");

  ②為後面fread讀取資料量確定u32VarSize大小:

 1     /*get data size   s32Ret = fread(pu8PicAddr,u32Dim*u32VarSize,1,fp);*/
 2     if(SVP_BLOB_TYPE_U8 <= pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].enType &&
 3         SVP_BLOB_TYPE_YVU422SP >= pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].enType)
 4     {
 5         u32VarSize = sizeof(HI_U8);
 6     }
 7     else
 8     {
 9         u32VarSize = sizeof(HI_U32);
10     }

  ③隨即通過pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].enType引數(引數找定義,應該是與輸入模型.wk的模型引數有關,後面可以直接通過printf進行列印輸出,看結果是啥)進行if-lese分支選擇,之後通過fread對fp檔案指標讀取資料,確定資料記憶體地址,並重新整理 cache 裡的內容到記憶體並且使 cache 裡的內容無效,最後fclose(fp)。

  先給出enType引數型別:

   程式碼實現:

 1     /*fill src data*/
 2     if(SVP_BLOB_TYPE_SEQ_S32 == pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].enType)
 3     {
 4         u32Dim = pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stSeq.u32Dim;
 5         u32Stride = pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Stride;
 6         pu32StepAddr = (HI_U32*)(pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stSeq.u64VirAddrStep);
 7         pu8PicAddr = (HI_U8*)(pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u64VirAddr);
 8         for(n = 0; n < pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num; n++)
 9         {
10             for(i = 0;i < *(pu32StepAddr+n); i++)
11             {
12                 s32Ret = fread(pu8PicAddr,u32Dim*u32VarSize,1,fp);
13                 SAMPLE_SVP_CHECK_EXPR_GOTO(1 != s32Ret,FAIL,SAMPLE_SVP_ERR_LEVEL_ERROR,"Error,Read image file failed!\n");
14                 pu8PicAddr += u32Stride;
15             }
16             u32TotalStepNum += *(pu32StepAddr+n);
17         }
18         SAMPLE_COMM_SVP_FlushCache(pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u64PhyAddr,
19             (HI_VOID *) pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u64VirAddr,
20             u32TotalStepNum*u32Stride);
21     }
22     else
23     {
24         u32Height = pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stWhc.u32Height;
25         u32Width = pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stWhc.u32Width;
26         u32Chn = pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stWhc.u32Chn;
27         u32Stride = pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Stride;
28         pu8PicAddr = (HI_U8*)(pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u64VirAddr);
29         if(SVP_BLOB_TYPE_YVU420SP== pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].enType)
30         {
31             for(n = 0; n < pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num; n++)
32             {
33                 for(i = 0; i < u32Chn*u32Height/2; i++)
34                 {
35                     s32Ret = fread(pu8PicAddr,u32Width*u32VarSize,1,fp);
36                     SAMPLE_SVP_CHECK_EXPR_GOTO(1 != s32Ret,FAIL,SAMPLE_SVP_ERR_LEVEL_ERROR,"Error,Read image file failed!\n");
37                     pu8PicAddr += u32Stride;
38                 }
39             }
40         }
41         else if(SVP_BLOB_TYPE_YVU422SP== pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].enType)
42         {
43             for(n = 0; n < pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num; n++)
44             {
45                 for(i = 0; i < u32Height*2; i++)
46                 {
47                     s32Ret = fread(pu8PicAddr,u32Width*u32VarSize,1,fp);
48                     SAMPLE_SVP_CHECK_EXPR_GOTO(1 != s32Ret,FAIL,SAMPLE_SVP_ERR_LEVEL_ERROR,"Error,Read image file failed!\n");
49                     pu8PicAddr += u32Stride;
50                 }
51             }
52         }
53         else
54         {
55             for(n = 0; n < pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num; n++)
56             {
57                 for(i = 0;i < u32Chn; i++)
58                 {
59                     for(j = 0; j < u32Height; j++)
60                     {
61                         s32Ret = fread(pu8PicAddr,u32Width*u32VarSize,1,fp);
62                         SAMPLE_SVP_CHECK_EXPR_GOTO(1 != s32Ret,FAIL,SAMPLE_SVP_ERR_LEVEL_ERROR,"Error,Read image file failed!\n");
63                         pu8PicAddr += u32Stride;
64                     }
65                 }
66             }
67         }
68         SAMPLE_COMM_SVP_FlushCache(pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u64PhyAddr,
69             (HI_VOID *) pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u64VirAddr,
70             pstNnieParam->astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num*u32Chn*u32Height*u32Stride);
71     }
72 
73     fclose(fp);

  (6)step6為SAMPLE_SVP_NNIE_Forward實現NNIE process

  便於分析先給出函式的呼叫及引數的定義:

 1     s_stCnnNnieParam.pstModel = &s_stCnnModel.stModel;
 2     /* SAMPLE_COMM_SVP_NNIE_LoadModel(pcModelName,&s_stCnnModel); */
 3     
 4     stInputDataIdx.u32SegIdx = 0;
 5     stInputDataIdx.u32NodeIdx = 0;
 6     
 7     stProcSegIdx.u32SegIdx = 0;
 8     
 9     s32Ret = SAMPLE_SVP_NNIE_Forward(&s_stCnnNnieParam,
10                                      &stInputDataIdx,
11                                      &stProcSegIdx,
12                                      HI_TRUE);
13     
14     static HI_S32 SAMPLE_SVP_NNIE_Forward(
15                         SAMPLE_SVP_NNIE_PARAM_S *pstNnieParam,
16                         SAMPLE_SVP_NNIE_INPUT_DATA_INDEX_S* pstInputDataIdx,
17                         SAMPLE_SVP_NNIE_PROCESS_SEG_INDEX_S* pstProcSegIdx,
18                         HI_BOOL bInstant)

  SAMPLE_SVP_NNIE_Forward中①SAMPLE_COMM_SVP_FlushCache函式主要實現將記憶體資料重新整理到記憶體中;②HI_MPI_SVP_NNIE_Forward函式同時對輸入樣本(s)進行CNN預測,對對應樣本(s)進行輸出響應;③HI_MPI_SVP_NNIE_Query函式用於查詢nnie上執行函式的狀態,在阻塞模式下,系統等待,直到被查詢的函式被呼叫;在非阻塞模式下,查詢當前狀態,不做任何操作。

   (7)step7為SAMPLE_SVP_NNIE_Cnn_GetTopN實現軟體過程

  給出函式呼叫與引數細節:

 1     s_stCnnNnieParam.pstModel = &s_stCnnModel.stModel;
 2     /* SAMPLE_COMM_SVP_NNIE_LoadModel(pcModelName,&s_stCnnModel); */
 3                         
 4     s_stCnnSoftwareParam.u32TopN = 5;
 5     SAMPLE_SVP_NNIE_Cnn_ParamInit(&stNnieCfg, //通過此函式對s_stCnnSoftwareParam進行了賦值操作
 6                                   &s_stCnnNnieParam,
 7                                   &s_stCnnSoftwareParam); 
 8     
 9     s32Ret = SAMPLE_SVP_NNIE_Cnn_GetTopN(&s_stCnnNnieParam,
10                                          &s_stCnnSoftwareParam);            
11 
12     HI_S32   SAMPLE_SVP_NNIE_Cnn_GetTopN(SAMPLE_SVP_NNIE_PARAM_S*pstNnieParam,
13                                         SAMPLE_SVP_NNIE_CNN_SOFTWARE_PARAM_S* pstSoftwareParam)    

  此函式目前基本不修改,函式內部具體實現目前暫不說明,只需注意一點如果改變了網路結構,請確保SAMPLE_SVP_NNIE_Cnn_GetTopN

函式的輸入資料正確。

   (8)step8為SAMPLE_SVP_NNIE_Cnn_PrintResult列印blob引數值

  給出函式呼叫與引數細節:

 1     s_stCnnNnieParam.pstModel = &s_stCnnModel.stModel;
 2     /* SAMPLE_COMM_SVP_NNIE_LoadModel(pcModelName,&s_stCnnModel); */
 3                         
 4     s_stCnnSoftwareParam.u32TopN = 5;
 5     SAMPLE_SVP_NNIE_Cnn_ParamInit(&stNnieCfg, //通過此函式對s_stCnnSoftwareParam進行了賦值操作
 6                                   &s_stCnnNnieParam,
 7                                   &s_stCnnSoftwareParam); 
 8     
 9     s32Ret = SAMPLE_SVP_NNIE_Cnn_PrintResult(&(s_stCnnSoftwareParam.stGetTopN),
10                                              s_stCnnSoftwareParam.u32TopN);
11                                              
12       HI_S32 SAMPLE_SVP_NNIE_Cnn_PrintResult(SVP_BLOB_S *pstGetTopN,
13                                              HI_U32 u32TopN)    

   有什麼問題,大家可以提出來,一起討論,後面將給出mobilefacenet的NNIE實