Hi3559AV100 NNIE開發(4)mobilefacenet.cfg參數配置挖坑解決與SVP_NNIE_Cnn實現分析
- 2021 年 3 月 11 日
- 筆記
- hi3559, Hi35xx項目開發, mobilefacenet.cfg, NNIE_SVP_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(pcModelName,&s_stCnnModel)從用戶事先加載到 buf 中的模型中解析出網絡模型,其函數實現較為複雜,具體的函數參數解析和函數運行過程已經在前面隨筆給出了,需要的話,可以參考隨筆:
Hi3559AV100 NNIE開發(1)-RFCN(.wk)LoadModel函數參數解析 (//www.cnblogs.com/iFrank/p/14500648.html)
Hi3559AV100 NNIE開發(2)-RFCN(.wk)LoadModel及NNIE Init函數運行過程分析 (//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函數運行過程分析 (//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實現。