海思ive ann-mlp使用說明
版權宣告:本文為博主原創文章,歡迎轉載!轉載請寫明原文連結出處! https://blog.csdn.net/brightming/article/details/50895356
1 概述
海思對於深度學習,提供了多層感知器的人工神經網路預測支援。其操作比較簡單,載入由轉換工具轉換後的opencv訓練產生的模型檔案,組織測試資料,輸入模型進行預測。
操作的時候,重點要注意的是,海思對於接收到的輸入是按照s16q16的格式來解析的,所以,對於同樣一個數值,給opencv訓練,和給海思預測,就需要有不同的形式,以此,讓它們兩者從自己的角度來看,看到的是同一個數值。
2 基礎知識介紹
2.1 標準資料的記憶體表示
2.1.1 整數的表示
參考http://blog.163.com/yql_bl/blog/static/847851692008112013117685/
2.1.2 浮點數的表示
參考http://blog.163.com/yql_bl/blog/static/847851692008112013117685/
2.2 海思的資料型別
HI_UxQyFz\HI_SxQy:
U 後面的數字 x 表示是用 x bit 無符號資料表示整數部分;
S 後面的數字 x 表示用 x bit 有符號資料表示整數部分;
Q 後面的數字 y 表示用 y bit 資料表示小數部分;
F 後面的數字 z 表示用 z bit 來表示標誌位;
從左到右依次表示高 bit 位到低 bit 位。
如S16Q16表示,32bit的資料,左邊(高)16bit表示的是整數資料,右邊(低)16bit表示浮點資料。
那麼對於一個二進位制:0000000000000001 1010000000000000
就相當於是2^1+2^(-1)+2^(-3)=1.5625
2.2.1 標準資料與海思資料的轉換
同樣的記憶體內容,按照不同的格式去解析的話,會得到不同的值。
我們基於這樣的前提:標準格式表達的值,是真實的值。
將一個標準表示裡的值,按照海思的表達方式重新表達。或者將海思形式的值,轉換為標準的值。
3 操作過程說明
3.1 利用opencv訓練
這個就是正常的opencv的訓練方式。
3.2 模型轉換
海思提供了模型轉換工具,將opencv訓練產生的xml模型檔案轉換為二進位制的模型檔案,供海思載入。
3.3 模型載入
介面為:
HI_S32 HI_MPI_IVE_ANN_MLP_LoadModel(const HI_CHAR *pchFileName,
IVE_ANN_MLP_MODEL_S *pstAnnMlpModel)
【引數】
引數名稱
描述
輸入/輸出
pchFileName
模型檔案路徑及檔名。
不能為空。
輸入
pstAnnMlpModel
模型資料結構體指標。
不能為空。
輸出
3.4 初始化相關的記憶體
這裡的記憶體都涉及到了地址對齊的要求,需要使用HI_MPI_SYS_MmzAlloc介面進行記憶體分配。
3.4.1 輸入層的記憶體
輸入層的每一維都是一個SQ16.16的變數,32bit的長度。
輸入層所需要的記憶體空間=(輸入層的維數+1)*sizeof(SQ16.16)
地址對齊要求為16byte。
3.4.2 結果輸出層的記憶體
輸出層的每一維都是一個SQ16.16的變數,32bit的長度。
輸出層所需要的記憶體空間=(輸出層的維數)*sizeof(SQ16.16)
地址對齊要求為16byte。
3.4.3 儲存原始圖片的記憶體
原始圖片的資料讀取後儲存的記憶體。這個可以有,也可以沒有,看資料來源,以及怎麼處理資料來源,如模擬四象限分類的資料,完全可以手工模擬出來。
這個記憶體中儲存的是原始的資料,需要經過與opencv訓練時採取的一致的特徵提取方式提取(組織)特徵,然後將各特徵值,賦值給輸入層的記憶體。
對齊的要求,不少於16byte,高的取決於讀取的圖片的寬,計算出每一行的圖片實際要分配多少空間,具體為:
u16Stride=(width+(16-width%16)%16)。
具體分配的記憶體空間大小,首先按照每一行需要的空間的大小,然後根據圖片的型別來計算。如是8位單通道的,則可以直接計算:u16Stride* height;
如是420sp,則:u16Stride*height*3/2
如是422sp,則:u16Stride*height*2
如是16位但通道的,則:u16Stride*height*sizeof(HI_U16)
如是u8c3的,則:u16Stride*height*3
如是s32c1或u32c1的,則:u16Stride*height*sizeof(HI_U32)
如是s64c1或u64c1的,則:u16Stride*height*sizeof(HI_U64)
完全可以不需要這樣分配,可以根據opencv的介面來讀取圖片,進行特徵提取。關鍵還是在於把特徵傳給輸入層的記憶體。
3.5 建立查詢表
啟用函式的計算是指數型別的,計算較為耗時,建立了查詢表以後,可以查表得到結果,加快速度。
查詢表,其資料均為 S1Q15 型別數
據,最多 4096 個;鑑於當前 ANN 中支援的 Identify、Sigmoid、Gaussian 啟用函式為奇或偶函式,查詢表僅對輸入 ∈ u [0, pstActivFuncTab→s32TabInUpper]建表及查表;對 ANN 啟用函式建立查詢表時用於歸一化的 u8TabOutNorm 是表示移位的數目。
【定義】
typedef struct hiIVE_LOOK_UP_TABLE_S
{
IVE_MEM_INFO_S stTable;
HI_U16 u16ElemNum; /*LUT's elements number*/
HI_U8 u8TabInPreci;
HI_U8 u8TabOutNorm;
HI_S32 s32TabInLower; /*LUT's original input lower limit*/
HI_S32 s32TabInUpper; /*LUT's original input upper limit*/
}IVE_LOOK_UP_TABLE_S;
成員名稱
描述
stTable
查詢表建立後的資料記憶體塊資訊。
u32ElemNum
查詢表元素個數。
s32TabInLower
建立查詢表的數值範圍的下限。
s32TabInUpper
建立查詢表的數值範圍的上限。
u8TabInPreci
建立查詢表的精度,(s32TabInUpper - s32TabInLower)/(1<<u8TabInPreci)表示建立查詢表的間隔。
u8TabOutNorm
表示建立查詢表時為將原始資料歸一化進行移位的位數或者進行除法的除數
目前對於這個u8TabOutNorm還未弄清楚其使用機制。
示例程式碼為:
static HI_S32 SAMPLE_IVE_Ann_Mlp_CreateTable(IVE_LOOK_UP_TABLE_S* pstTable, HI_FLOAT fAlpha, HI_FLOAT fBeta)
{
HI_U32 i;
HI_S1Q15* ps1q15Tmp;
HI_FLOAT fExpIn;
HI_DOUBLE dExpOut;
//Check table size
if (pstTable->stTable.u32Size < pstTable->u16ElemNum * sizeof(HI_S1Q15))
{
SAMPLE_PRT("Invalid table size\n");
return HI_FAILURE;
}
ps1q15Tmp = (HI_S1Q15*)pstTable->stTable.pu8VirAddr;
for (i = 0; i < pstTable->u16ElemNum; i++)
{
fExpIn = (HI_FLOAT)i / (1 << pstTable->u8TabInPreci);
dExpOut = (2 / (1 + exp(-fAlpha * fExpIn)) - 1) * fBeta * (1 << 15) / (1 << pstTable->u8TabOutNorm);
ps1q15Tmp[i] = (HI_CLIP(SAMPLE_IVE_Round(dExpOut), (1 << 15) - 1, -(1 << 15)));
}
return HI_SUCCESS;
}
呼叫過程為:
pstAnnInfo->stTable.s32TabInLower = 0;
pstAnnInfo->stTable.s32TabInUpper = 1;//1;
pstAnnInfo->stTable.u8TabInPreci = 8;//12;
pstAnnInfo->stTable.u8TabOutNorm = 2;//2
pstAnnInfo->stTable.u16ElemNum=(pstAnnInfo->stTable.s32TabInUpper-pstAnnInfo->stTable.s32tabInLower)<<pstAnnInfo->stTable.u8TabInPreci;
u32Size = pstAnnInfo->stTable.u16ElemNum * sizeof(HI_U16);
s32Ret = SAMPLE_COMM_IVE_CreateMemInfo(&(pstAnnInfo->stTable.stTable), u32Size);
3.6 特徵提取與資料形式組織
特徵提取的方式根據識別的要求而自定義,如人臉識別的特徵提取與字元識別的特徵提取方式不同。
不管用什麼樣的方式進行特徵提取,都要保證:以相同的方式提取出來給opencv訓練,給海思預測。
一種字元識別的特徵提取方式描述如下:
測試(訓練)圖片是一張不是0就是255組成的黑白圖片,沒有其他灰度值。將這個圖片按照n*n(如4*4)的方式劃分,每個n*n的小圖片累加其灰度值,然後進行簡單的歸一化。這裡要注意了:因為海思看待輸入的方式是不同的,是以s16q16的方式來看待輸入的,所以,一個同樣的數值給opencv的時候,可以按照標準的方式給,但是給海思的時候,就必須要轉換成s16q16的表達方式了。(或者反過來也行,以s16q16的方式去解析當前的數值,給opencv,總之就是要讓兩者看到的數值是一樣的)。
如0.5,按照標準的float的表達的話,其二進位制方式為:
0 01111110 000000000000000000000000
具體float的表達方式參考相關資料。
但是要是以s16q16的表達方式來說,其二進位制,就是這樣的:
0000000000000000 1000000000000000
所以,在給海思的時候,給的是下面的這個二進位制值,這個二進位制值對應的int值就是32768,所以,給海思的時候,給的32768!
轉換某個數值為s16q16的方法,封裝了一個changeFloatToS16Q16函式來進行,具體在後面的“輔助工具與方法”中。
對於正數來說,其乘於65536得到的數值的二進位制表示,正好是該正數的s16q16的表達方式,所以可以看到海思預測時候的例子用的是直接乘於65536.
具體為:
static HI_VOID SAMPLE_IVE_Ann_Mlp_BinFeature_For_Predict(HI_U8* pu8GrayImg, HI_U16 u16Width, HI_U16 u16Height, HI_S16Q16* ps16q16BinFeature)
{
HI_U32 u32Step = 16;//4;
HI_U32 u16Sum = 0;
HI_U16 i, j;
HI_U16 m, n;
HI_U16 u16FeatureNum = 0;
printf("calculate BinFeature:\n");
for (i = 0; i < u16Height - u32Step + 1; i += u32Step)
{
for (j = 0; j < u16Width - u32Step + 1; j += u32Step)
{
u16Sum = 0;
for (m = i; m < i + u32Step; m++)
{
for (n = j; n < j + u32Step; n++)
{
u16Sum += pu8GrayImg[m * u16Width + n];
}
}
ps16q16BinFeature[u16FeatureNum++] = changeFloatToS16Q16(u16Sum*1.0/ (u32Step * u32Step * 255));
}
}
}
那對於訓練時,給opencv訓練的數值,就直接是:
ps16q16BinFeature[u16FeatureNum++] = u16Sum*1.0/ (u32Step * u32Step * 255);
3.7 執行預測
執行預測的介面為:
【語法】
HI_S32 HI_MPI_IVE_ANN_MLP_Predict(IVE_HANDLE *pIveHandle,
IVE_SRC_MEM_INFO_S *pstSrc, IVE_LOOK_UP_TABLE_S *pstActivFuncTab,
IVE_ANN_MLP_MODEL_S *pstAnnMlpModel, IVE_DST_MEM_INFO_S *pstDst, HI_BOOL
bInstant);
引數名稱
描述
輸入/輸出
pIveHandle
handle 指標。不能為空.
輸出
pstSrc
輸入樣本向量(特徵向量)指標。不能為空。
輸入
pstActivFuncTab
用於啟用函式計算的查詢表資訊指標。不能為空。
輸入
pstAnnMlpModel
模型資料結構體指標。不能為空。
輸入
pstDst
預測結果向量指標。不能為空。
輸出
bInstant
及時返回結果標誌。
輸入
引數名稱
支援型別
地址對齊
向量維數
pstSrc
一維 SQ16.16 向量,實際截斷到 SQ8.16 計算
16 byte
取值範圍:1~256;
實際值:pstAnnMlpModel→
au16LayerCount[0]
注意記憶體至少需要
sizeof(SQ16.16) *
( pstAnnMlpModel→
au16LayerCount[0] + 1)
pstDst
一維 SQ16.16 向量
16 byte
取值範圍:1~256;
實際值:pstAnnMlpModel→
au16LayerCount[pstAnnMlpMod
el→u8LayerNum -1]
以上的引數是:
分配好的輸入層空間,裡面有以s16q16表達的值;
查詢表的指標;
載入好的模型;
分配好的接收輸出預測值的空間;
至於控制代碼(handle)與標誌(bInstance)的解析為:
控制代碼(handle)
使用者在呼叫運算元建立任務時,系統會為每個任務分配一個 handle,用於標識不同的任務。
及時返回結果標誌 bInstant
使用者在建立某個任務後,希望及時得到該任務完成的資訊,則需要在建立該任務時,將 bInstant 設定為 HI_TRUE。否則,如果使用者不關心該任務是否完成,建議將 bInstant 設定為 HI_FALSE,這樣可以與後續任務組鏈執行,減少中斷次數,提升效能。
呼叫了該預測介面以後,根據返回的handle,需要進行query(需要迴圈),看任務的完成情況如何,進行相應的處理。如:
//建立任務
s32Ret = HI_MPI_IVE_ANN_MLP_Predict(&iveHandle,
&(pstAnnInfo->stSrc),
& (pstAnnInfo->stTable),
&(pstAnnInfo->stAnnModel),
&(pstAnnInfo->stDst),
bInstant);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("HI_MPI_IVE_ANN_MLP_Predict fail,Error(%#x)\n", s32Ret);
break;
}
//查詢任務情況
s32Ret = HI_MPI_IVE_Query(iveHandle, &bFinish, bBlock);
while (HI_ERR_IVE_QUERY_TIMEOUT == s32Ret)
{
usleep(100);
s32Ret = HI_MPI_IVE_Query(iveHandle, &bFinish, bBlock);
}
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("HI_MPI_IVE_Query fail,Error(%#x)\n", s32Ret);
break;
}
//準備輸出結果
u16LayerCount = pstAnnInfo->stAnnModel.au16LayerCount[pstAnnInfo->stAnnModel.u8LayerNum - 1];
for (k = 0; k < u16LayerCount; k++)
{
printf(" ps16q16Dst[%d]=%d,H16Q16=%f\n", k,ps16q16Dst[k],calculateS16Q16_c(ps16q16Dst[k]));
if (s16q16Response < ps16q16Dst[k])
{
s16q16Response = ps16q16Dst[k];
s32ResponseCls = k;
}
}
最後得到的s32ResponseCls 就是預測該測試樣本所屬的類別。
4 輔助工具與方法
4.1 模型檔案轉換工具
利用海思提供的ive_tool_xml2bin_ui.exe工具,在window下執行轉換。
4.2 資料表示方式轉換方法
4.2.1 獲得一個short的二進位制字串
//得到一個short的二進位制字串
//返回字串的長度
int decShortToBin(int dec,char *bstr){
int mod=0;
char tmpstr[64];
bzero(tmpstr,sizeof(tmpstr));
bzero(bstr,sizeof(bstr));
int i=0;
while(dec>0){
mod=dec%2;
dec/=2;
tmpstr[i]=mod+'0';
i++;
}
//cout<<"i="<<i<<endl;
while(i<sizeof(short)*8){
tmpstr[i++]='0';
}
//cout<<"tmpstr="<<tmpstr<<endl;
unsigned int len=strlen(tmpstr);
for(i=0;i<len;i++){
bstr[i]=tmpstr[len-i-1];
}
return (int)len;
}
4.2.2 獲得一個int資料的二進位制字串
int decIntToBin(int dec,char *bstr){
int mod=0;
char tmpstr[64];
bzero(tmpstr,sizeof(tmpstr));
bzero(bstr,sizeof(bstr));
int i=0;
while(dec>0){
mod=dec%2;
dec/=2;
tmpstr[i]=mod+'0';
i++;
}
//cout<<"i="<<i<<",sizeof(int)="<<sizeof(int)*8<<endl;
while(i<sizeof(int)*8){
tmpstr[i++]='0';
}
//cout<<"tmpstr="<<tmpstr<<endl;
unsigned int len=strlen(tmpstr);
for(i=0;i<len;i++){
bstr[i]=tmpstr[len-i-1];
}
return (int)len;
}
4.2.3 解析一個以s16q16格式表示的記憶體,其真正的值是多少
float calculateS16Q16_c(int value){
char bs[64];
decIntToBin(value,bs);
//cout<<"calculateS16Q16_c:value="<<value<<",binary="<<bs<<endl;
float fout=0;
//cout<<"calculateS16Q16_c----------begin"<<endl<<"fout=";
int i=16;
for(i=16;i<32;i++){//the higher 16bit standard for float value---------different from bitset
if(bs[i]=='1'){
fout+=pow(2,(i-16+1)*(-1));
//cout<<"+2^("<<(i-16+1)*(-1)<<")";
}
}
//cout<<"\ncalculateS16Q16_c result="<<fout<<endl;
for(i=0;i<16;i++){
if(bs[i]=='1'){
fout+=pow(2,(16-i-1));
}
}
return fout;
}
4.2.4 將一個float值,轉換為S16q16的值
將一個float值,表示為以s16q16表示的形式,返回的是s16q16的形式的記憶體,按照正常的理解所代表的值。
int changeFloatToS16Q16(float val){
int sign=1;
if(val<0){
sign=-1;
}
int intPart=0;
float floatPart=0;
intPart=(int)abs(val);
floatPart=(val>0?val:val*(-1))-intPart;
//for float part
bitset<16> fpbs;
float tmpFl=floatPart;
for(int i=15;i>=0;i--){
tmpFl=tmpFl*2;
if(tmpFl>=1){
fpbs[i]=1;
tmpFl-=1;
}else{
fpbs[i]=0;
}
}
int sPart=intPart*sign;
bitset<16> ipbs(sPart);
//out
//
// cout<<"float val="<<val<<",change to S16Q16,bitset(intPart)="<<ipbs<<",floatPart="<<fpbs<<endl;
bitset<32> resultBs;
int result=0;
for(int i=0;i<16;i++){//highest one is sign
resultBs[32-16+i]=ipbs[i];
}
for(int i=0;i<16;i++){
resultBs[i]=fpbs[i];
}
// cout<<"resultBs="<<resultBs<<endl;
result=resultBs.to_ulong();
return result;
}
5 完整示例
5.1 二維資料的訓練與預測
5.1.1 訓練二維資料
以y=kx直線進行劃分,在直線以下的為類別0,其他為類別1。
在訓練的時候,指定k,產生訓練資料,同時將一部分作為測試資料。
5.1.1.1 訓練入口
/**
* 以斜率=slope 來做分界,訓練一個mlp模型
*/
extern "C" void train_2_class_slope(float slope){//(int useExistModel,float from_x,float end_x,float from_y,float end_y,float x_step,float y_step){
CvANN_MLP annMlp;
int outputClassCnt=2;
bool loadModelFromFile=false;
Mat training_datas;
Mat trainClasses;
Mat oriTrainDatas;
generateFix2ClassSlopeTrainData(slope,training_datas,trainClasses);
training_datas.convertTo(training_datas,CV_32FC1);
trainClasses.convertTo(trainClasses,CV_32FC1);
cout<<"training_datas=\n"<<training_datas<<",oridata="<<oriTrainDatas<<endl;
cout<<"trainClasses=\n"<<trainClasses<<endl;
//建立mlp
Mat layers(1, 3, CV_32SC1);
layers.at<int>(0) = training_datas.row(0).cols;
cout<<"------------------------trainAnnModel.input sample cnt:"<<training_datas.rows<<",input layer features:"<<layers.at<int>(0,0)<<endl;
layers.at<int>(1)=3;
layers.at<int>(2) = outputClassCnt;//輸出
cout<<"outputClassCnt="<<outputClassCnt<<endl;
annMlp.create(layers, CvANN_MLP::SIGMOID_SYM, 0.6667f, 1.7159f);
//--------訓練mlp-----------//
// Set up BPNetwork‘s parameters
CvANN_MLP_TrainParams params;
params.train_method = CvANN_MLP_TrainParams::BACKPROP;
params.bp_dw_scale = 0.001;
params.bp_moment_scale = 0.0;
CvTermCriteria criteria;
criteria.max_iter = 300;
criteria.epsilon = 9.999999e-06;
criteria.type = CV_TERMCRIT_ITER | CV_TERMCRIT_EPS;
params.term_crit = criteria;
annMlp.train(training_datas, trainClasses, Mat(), Mat(), params);
cout<<"train finished"<<endl;
char _dstPath[256];
sprintf(_dstPath,"data/my/my_simple_2_class_20160307_slope_%.2f.xml",slope);
string dstPath(_dstPath);//="data/my/my_simple_2_class_20160307_slope_1.xml";
annMlp.save(dstPath.c_str());
cout<<"save model finished.model file="<<dstPath<<"\n";
//預測
Mat test_datas;
Mat testClasses;
int testCount=1;//每個象限的測試圖片數量
Mat oriTestData;
generate2ClassSlopeTestData(slope,test_datas,testClasses,oriTestData);//,from_x,end_x,from_y,end_y);
test_datas.convertTo(test_datas,CV_32FC1);
testClasses.convertTo(testClasses,CV_32FC1);
cout<<"test_datas=\n"<<test_datas<<",oridata="<<oriTestData<<endl;
// cout<<"testClasses=\n"<<testClasses<<endl;
int correctCount=0;
int errorCount=0;
cout<<"test_datas size="<<test_datas.rows<<endl;
int totalTestSize=test_datas.rows;
bool right=false;
// TestData_2Feature* cur=testDataHead;
int expected_idx=0;
for(int i=0;i<totalTestSize;i++){
Mat predict_result(1, outputClassCnt, CV_32FC1);
annMlp.predict(test_datas.row(i), predict_result);
Point maxLoc;
double maxVal;
minMaxLoc(predict_result, 0, &maxVal, 0, &maxLoc);
right=false;
if(test_datas.row(i).at<float>(0,0)*slope > test_datas.row(i).at<float>(0,1)){
expected_idx=0;
}else{
expected_idx=1;
}
if(expected_idx==maxLoc.x){
++correctCount;
right=true;
}else {
++errorCount;
}
cout<<"data:"<<test_datas.row(i)<<"("<<oriTestData.row(i)<<"),predict_result="<<predict_result<<",maxVal="<<maxVal<<",maxLoc.x="<<maxLoc.x<<",right?"<<right<<endl;
// cur=cur->next;
}
cout<<"total test data count="<<totalTestSize<<",correct count="<<correctCount<<",error count="<<errorCount<<",accurate="<<(correctCount)*1.0f/(totalTestSize)<<endl;
}
5.1.1.2 訓練與測試資料產生方法
/**
* y=x,劃分,
*/
void generateFix2ClassSlopeTrainData(float slope,Mat& mat,Mat& labels){
vector<float> dataVec;
vector<float> labVec;
float tmp1=0,tmp2=0;
printf("generateFix2ClassSlopeTrainData begin\n");
int multi=1;
float x_step=16;
float y_step=16;
int needTestSize=10;
int nowTestSize=0;
int loopcnt=0;
ostringstream os;
Int end_x=255;
Int end_y=255;
int getDataInterval=((end_x-0)/x_step * (end_y-0)/y_step)/needTestSize;
printf("getDataInterval=%d,totalTrainSize=%d\n",(deltaX/x_step * deltaY/y_step));
for(int x=0;x<end_x;x+=x_step){
for(int y=0;y<end_y;y+=x_step){
++loopcnt;
dataVec.clear();
multi*=-1;
tmp1=multi*(float)x;///255;
dataVec.push_back(tmp1);
tmp2=multi*(float)y;///255;
dataVec.push_back(tmp2);
// printf("tmp1=%f\n",tmp1);
// Mat tpmat=Mat(dataVec).reshape(1,1).clone();
mat.push_back(Mat(dataVec).reshape(1,1).clone());
labVec.clear();
if(tmp1*slope>tmp2){// x> 為類0
labVec.push_back(1.0f);
labVec.push_back(0.0f);
labels.push_back(Mat(labVec).reshape(1,1).clone());
if(loopcnt%getDataInterval==0){
os<<"0:";
}
}else{
labVec.push_back(0.0f);
labVec.push_back(1.0f);
labels.push_back(Mat(labVec).reshape(1,1).clone());
if(loopcnt%getDataInterval==0){
os<<"1:";
}
}
if(loopcnt%getDataInterval==0){
os<<x<<" "<<y<<endl;
}
}
}
//輸出一部分作為測試檔案
system("rm data/my/test2classdata_slope.list");
fstream ftxt;
string testfile="data/my/test2classdata_slope.list";
ftxt.open(testfile.c_str(), ios::out | ios::app);
if (ftxt.fail()) {
cout << "建立檔案:"<<testfile<<" 失敗!" <<endl;
getchar();
}
ftxt << os.str();
ftxt.close();
}
5.1.2 海思預測二維資料樣本的所屬類別
5.1.2.1 預測入口
/**
* 測a試?y=kx的?分?類え?情é況?
*/
HI_VOID SAMPLE_IVE_Ann_predict_2class_slope(float slope){
// HI_CHAR* pchBinFileName;
int height,width,image_type;
char pchBinFileName[256];
sprintf(pchBinFileName,"./data/my/my_simple_2_class_20160307_slope_%.2f.bin",slope);
// pchBinFileName = "./data/my/my_simple_2_class_20160307_slope_3.00.bin";
height=1;
width=2;
image_type=IVE_IMAGE_TYPE_S32C1;
HI_S32 s32Ret;
SAMPLE_IVE_ANN_INFO_S stAnnInfo;
printf("use model bin file:%s\n",pchBinFileName);
SAMPLE_COMM_IVE_CheckIveMpiInit();
s32Ret=SAMPLE_IVE_Ann_Mlp_2Class_Slope_Init(&stAnnInfo, pchBinFileName,image_type,height,width);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("SAMPLE_IVE_Ann_Mlp__2Class_Init fail\n");
goto ANN_FAIL;
}
// predict2ClassData(&stAnnInfo,slope);
predict2ClassSlopeData(&stAnnInfo,slope);
//uninit
SAMPLE_IVE_Ann_Mlp_Uninit(&stAnnInfo);
ANN_FAIL:
SAMPLE_COMM_IVE_IveMpiExit();
}
5.1.2.2 初始化
/******************************************************************************
* function : Ann mlp init
******************************************************************************/
static HI_S32 SAMPLE_IVE_Ann_Mlp_2Class_Slope_Init(SAMPLE_IVE_ANN_INFO_S* pstAnnInfo, HI_CHAR* pchBinFileName,int image_type,int height,int width )
{
SAMPLE_PRT("SAMPLE_IVE_Ann_Mlp_Init.....\n");
HI_S32 s32Ret = HI_SUCCESS;
HI_U32 u32Size;
memset(pstAnnInfo, 0, sizeof(SAMPLE_IVE_ANN_INFO_S));
/**
* 查é找ò表括?裡?的?數簓值μ範?圍§是?[0,1],?精?度è是?8位?,?即′1<<8=256,?
* 表括?示?要癮被?分?成é256段?。£
*
*
*/
pstAnnInfo->stTable.s32TabInLower = 0;
pstAnnInfo->stTable.s32TabInUpper = 1;//1;
pstAnnInfo->stTable.u8TabInPreci = 8;//12;
pstAnnInfo->stTable.u8TabOutNorm = 2;//2
pstAnnInfo->stTable.u16ElemNum = (pstAnnInfo->stTable.s32TabInUpper-pstAnnInfo->stTable.s32TabInLower) << pstAnnInfo->stTable.u8TabInPreci;
u32Size = pstAnnInfo->stTable.u16ElemNum * sizeof(HI_U16);
// SAMPLE_PRT("stTable.s32TabInLower=%d,s32TabInUpper=%d,u8TabInPreci=%d,u8TabOutNorm=%d,u16ElemNum=%d\n",pstAnnInfo->stTable.s32TabInLower,pstAnnInfo->stTable.s32TabInUpper,pstAnnInfo->stTable.u8TabInPreci,pstAnnInfo->stTable.u8TabOutNorm,pstAnnInfo->stTable.u16ElemNum);
s32Ret = SAMPLE_COMM_IVE_CreateMemInfo(&(pstAnnInfo->stTable.stTable), u32Size);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("SAMPLE_COMM_IVE_CreateMemInfo fail\n");
goto ANN_INIT_FAIL;
}
s32Ret = SAMPLE_IVE_Ann_Mlp_CreateTable(&(pstAnnInfo->stTable), 0.6667f, 1.7159f);
// s32Ret = SAMPLE_IVE_Ann_Mlp_CreateTable(&(pstAnnInfo->stTable), 1.0f, 1.0f);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("SAMPLE_IVE_Ann_Mlp_CreateTable fail\n");
goto ANN_INIT_FAIL;
}
SAMPLE_PRT("begin to load model:%s\n",pchBinFileName);
s32Ret = HI_MPI_IVE_ANN_MLP_LoadModel(pchBinFileName, &(pstAnnInfo->stAnnModel));
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("HI_MPI_IVE_ANN_MLP_LoadModel fail,Error(%#x)\n", s32Ret);
goto ANN_INIT_FAIL;
}
printf("finish load model:%s\n",pchBinFileName);
u32Size = pstAnnInfo->stAnnModel.au16LayerCount[0] * sizeof(HI_S16Q16);//輸?入?層?需è要癮的?空?間?大洙?小?:阰輸?入?層?的?元a素?個?數簓*每?個?元a素?的?大洙?小?
printf("allocate memory for input,size=%d\n",u32Size);
s32Ret = SAMPLE_COMM_IVE_CreateMemInfo(&(pstAnnInfo->stSrc), u32Size);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("SAMPLE_COMM_IVE_CreateMemInfo fail\n");
goto ANN_INIT_FAIL;
}
u32Size = pstAnnInfo->stAnnModel.au16LayerCount[pstAnnInfo->stAnnModel.u8LayerNum - 1] * sizeof(HI_S16Q16);//輸?出?類え?別纄信?息¢所ù需è空?間?的?大洙?小?:阰輸?出?層?類え?別纄數簓*每?個?類え?別纄數簓值μ的?佔?的?空?間?
// SAMPLE_PRT("annModel output class cnt=%d\n",pstAnnInfo->stAnnModel.au16LayerCount[pstAnnInfo->stAnnModel.u8LayerNum - 1]);
printf("allocate memory for output,size=%d\n",u32Size);
s32Ret = SAMPLE_COMM_IVE_CreateMemInfo(&(pstAnnInfo->stDst), u32Size);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("SAMPLE_COMM_IVE_CreateMemInfo fail\n");
goto ANN_INIT_FAIL;
}
ANN_INIT_FAIL:
// printf("s32Ret=%d,HI_SUCCESS=%d\n",s32Ret,HI_SUCCESS);
if (HI_SUCCESS != s32Ret)
{
SAMPLE_IVE_Ann_Mlp_Uninit(pstAnnInfo);
}
return s32Ret;
}
5.1.2.3 預測
/**
* 預¤測ay=kx的?分?類え?
*/
void predict2ClassSlopeData(SAMPLE_IVE_ANN_INFO_S* pstAnnInfo,float slope){
char* contFile="data/my/test2classdata_slope_eq_1.list";
printf("try to get file info:%s\n",contFile);
TestData_2Feature* head=get2FeatureData(contFile);
printf("after read file:%s,head=%p\n",contFile,head);
if(!head){
printf("fail to read contFile:%s\n",contFile);
return;
}
// printStringNode(head,"1");
// printStringNode(head,"2");
HI_S32 i, k;
HI_S32 s32Ret;
HI_S32 s32ResponseCls;
HI_U16 u16LayerCount;
HI_S16Q16* ps16q16Dst;
HI_S16Q16 s16q16Response;
HI_BOOL bInstant = HI_TRUE;
HI_BOOL bFinish;
HI_BOOL bBlock = HI_TRUE;
// HI_CHAR achFileName[IVE_FILE_NAME_LEN];
FILE* pFp = HI_NULL;
IVE_HANDLE iveHandle;
int xs[3]={-5,-4,3};
int ys[3]={99,-10,10};
srand(time(NULL));
int totalCount=0;
int correctCount=0;
TestData_2Feature* cur=head;
int cnt=0;
int expected_idx=0;
while(cur!=NULL){
// printf("flag=%d,filePath=%s,filenName=%s -->\n ",cur->flag,cur->fileFullPath,cur->fileName);
ps16q16Dst = (HI_S16Q16*)pstAnnInfo->stDst.pu8VirAddr;
s16q16Response = 0;
s32ResponseCls = -1;
HI_S16Q16* stSrc=(HI_S16Q16*)pstAnnInfo->stSrc.pu8VirAddr;
stSrc[0]=changeFloatToS16Q16(cur->x1);//轉換為以s16q16表示的資料
stSrc[1]=changeFloatToS16Q16(cur->x2);
s32Ret = HI_MPI_IVE_ANN_MLP_Predict(&iveHandle, &(pstAnnInfo->stSrc), \
& (pstAnnInfo->stTable), &(pstAnnInfo->stAnnModel), &(pstAnnInfo->stDst), bInstant);
if (s32Ret != HI_SUCCESS)
{
SAMPLE_PRT("HI_MPI_IVE_ANN_MLP_Predict fail,Error(%#x)\n", s32Ret);
break;
}
s32Ret = HI_MPI_IVE_Query(iveHandle, &bFinish, bBlock);
while (HI_ERR_IVE_QUERY_TIMEOUT == s32Ret)
{
usleep(100);
s32Ret = HI_MPI_IVE_Query(iveHandle, &bFinish, bBlock);
}
if (HI_SUCCESS != s32Ret)
{
SAMPLE_PRT("HI_MPI_IVE_Query fail,Error(%#x)\n", s32Ret);
break;
}
u16LayerCount = pstAnnInfo->stAnnModel.au16LayerCount[pstAnnInfo->stAnnModel.u8LayerNum - 1];
// SAMPLE_PRT("pstAnnInfo->CstAnnModel.u8LayerNum=%d,pstAnnInfo->stAnnModel.au16LayerCount[pstAnnInfo->stAnnModel.u8LayerNum - 1]=%d\n",pstAnnInfo->stAnnModel.u8LayerNum,pstAnnInfo->stAnnModel.au16LayerCount[pstAnnInfo->stAnnModel.u8LayerNum - 1]);
SAMPLE_PRT(" \n--predict2ClassSlopeData--Begin-- x1=%f(s16q16=%d),x2=%f(s16q16=%d)\n",cur->x1,changeFloatToS16Q16(cur->x1),cur->x2,changeFloatToS16Q16(cur->x2));
++totalCount;
for (k = 0; k < u16LayerCount; k++)
{
printf(" ps16q16Dst[%d]=%d,H16Q16=%f\n", k,ps16q16Dst[k],calculateS16Q16_c(ps16q16Dst[k]));
if (s16q16Response < ps16q16Dst[k])
{
s16q16Response = ps16q16Dst[k];
s32ResponseCls = k;
}
}
if(cur->x1*slope>cur->x2){
expected_idx=0;
}else{
expected_idx=1;
}
SAMPLE_PRT(" --predict2ClassSlopeData--End-- result:%s,flag:%d,class:%d ------\n\n",(expected_idx==s32ResponseCls?"right":"wrong"),expected_idx,s32ResponseCls);
cur=cur->next;
}
freeTestData_2FeatureNode(head);
}
附上斜率為的預測結果輸出:
[predict2ClassSlopeData]-830:
--predict2ClassSlopeData--Begin-- x1=0.220000(s16q16=14417),x2=0.100000(s16q16=6553)
ps16q16Dst[0]=46174,H16Q16=0.704559
ps16q16Dst[1]=20098,H16Q16=0.306671
[predict2ClassSlopeData]-847: --predict2ClassSlopeData--End-- result:right,flag:0,class:0 ------
[predict2ClassSlopeData]-830:
--predict2ClassSlopeData--Begin-- x1=-1.000000(s16q16=-65536),x2=-3.000000(s16q16=-196608)
ps16q16Dst[0]=48919,H16Q16=0.746445
ps16q16Dst[1]=15412,H16Q16=0.235168
[predict2ClassSlopeData]-847: --predict2ClassSlopeData--End-- result:right,flag:0,class:0 ------
[predict2ClassSlopeData]-830:
--predict2ClassSlopeData--Begin-- x1=1.000000(s16q16=65536),x2=0.200000(s16q16=13107)
ps16q16Dst[0]=48919,H16Q16=0.746445
ps16q16Dst[1]=15412,H16Q16=0.235168
[predict2ClassSlopeData]-847: --predict2ClassSlopeData--End-- result:right,flag:0,class:0 ------
[predict2ClassSlopeData]-830:
--predict2ClassSlopeData--Begin-- x1=0.200000(s16q16=13107),x2=0.700000(s16q16=45875)
ps16q16Dst[0]=16687,H16Q16=0.254623
ps16q16Dst[1]=51450,H16Q16=0.785065
[predict2ClassSlopeData]-847: --predict2ClassSlopeData--End-- result:right,flag:1,class:1 ------
[predict2ClassSlopeData]-830:
--predict2ClassSlopeData--Begin-- x1=0.400000(s16q16=26214),x2=0.900000(s16q16=58982)
ps16q16Dst[0]=16830,H16Q16=0.256805
ps16q16Dst[1]=51033,H16Q16=0.778702
[predict2ClassSlopeData]-847: --predict2ClassSlopeData--End-- result:right,flag:1,class:1 ------
[predict2ClassSlopeData]-830:
--predict2ClassSlopeData--Begin-- x1=0.690196(s16q16=45232),x2=0.062745(s16q16=4112)
ps16q16Dst[0]=48919,H16Q16=0.746445
ps16q16Dst[1]=15412,H16Q16=0.235168
[predict2ClassSlopeData]-847: --predict2ClassSlopeData--End-- result:right,flag:0,class:0 ------
[predict2ClassSlopeData]-830:
--predict2ClassSlopeData--Begin-- x1=224.000000(s16q16=14680064),x2=80.000000(s16q16=5242880)
ps16q16Dst[0]=17622,H16Q16=0.268890
ps16q16Dst[1]=45294,H16Q16=0.691132
[predict2ClassSlopeData]-847: --predict2ClassSlopeData--End-- result:wrong,flag:0,class:1 ------
[predict2ClassSlopeData]-830:
--predict2ClassSlopeData--Begin-- x1=-224.000000(s16q16=-14680064),x2=80.000000(s16q16=5242880)
ps16q16Dst[0]=17117,H16Q16=0.261185
ps16q16Dst[1]=51728,H16Q16=0.789307
[predict2ClassSlopeData]-847: --predict2ClassSlopeData--End-- result:right,flag:1,class:1 ------
---------------------
作者:brightming
來源:CSDN
原文:https://blog.csdn.net/brightming/article/details/50895356
版權宣告:本文為博主原創文章,轉載請附上博文連結!