海思ive ann-mlp使用说明

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 ------

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: 西安海思机试题是针对Java编程语言的一道考试题目。海思机试题通常要求考生能够熟练掌握Java语言的基本语法和常用类库,并能够运用这些知识解决简单的编程问题。 在机试题中,通常会涉及到一些基本的编程概念,如变量、循环、条件判断、函数等。考生需要使用Java语言来实现特定的功能或逻辑,并输出正确的结果。 对于西安海思机试题,可能会包含以下一些例子: 1. 写一个程序,输出从1到100的所有偶数。 解题思路:使用循环从1到100遍历,判断每个数字是否为偶数,如果是则输出。 2. 写一个程序,求一个数组中的最大值和最小值。 解题思路:使用循环遍历数组中的每个元素,通过比较更新最大值和最小值。 3. 写一个程序,判断一个字符串是否是回文字符串。 解题思路:使用循环将字符串反转,并与原字符串进行比较,如果相同则是回文字符串。 对于这些机试题,考生应该具备良好的编程思维和逻辑分析能力,善于利用Java语言特性和类库来解决问题。此外,高效的编码能力和代码风格的优化也是考生需要具备的能力。 要准备西安海思机试题,考生可以通过复习Java基本语法、数据类型、循环、条件判断和函数等知识,并通过编写代码实践来提升自己的编程技巧。还可以参考一些教材、教程或者在线编程平台上的题库进行练习和加深理解。 最后,机试题不仅仅是一次考试,更重要的是通过实践来提升自己的编程能力和解决问题的能力。希望以上回答对你有所帮助。 ### 回答2: 西安海思机试题是一道关于Java的题目。Java是一种常见的高级编程语言,具有跨平台的特性,可以用于开发各种类型的软件应用程序。机试题通常用来测试考生在编程领域的技能和知识。 对于这样的机试题,可能会包括一系列的编程题目,考察考生的语法知识、算法和逻辑思维能力等方面。在解答机试题时,需要考生清晰理解题目的要求,并用合适的Java代码进行解答。 解答机试题的关键在于理解题目要求,并用合适的算法和Java编程语言来实现解决方案。在解答过程中,还需要注意代码的规范性、可读性和效率。 对于想要参加西安海思机试的考生,建议他们提前准备,复习并熟悉Java编程语言的基础知识和常见的算法。此外,也可以通过练习机试题,提高自己的解决问题和编程能力。 总之,西安海思机试题-java是一种考察考生Java编程能力和知识技能的方式。参加机试需要考生具备扎实的编程基础和算法思维,同时也需要平时勤加练习和积累,提高自己在编程领域的能力。 ### 回答3: 西安海思机试题是一个关于Java编程的考试题目。在这个机试题中,考生需要完成一些与Java语言相关的编程任务,以展示自己的编程能力。根据题目的要求,考生可能需要使用Java编程语言来实现一些功能,如算法设计、数据结构操作等。 在西安海思机试题中,考生需要具备扎实的Java编程基础以及良好的逻辑思维能力。他们需要理解题目要求,分析问题,并设计出合适的解决方案。在编程过程中,考生需要熟练运用Java的各种语法、类库和工具,以便高效地完成任务。此外,考生还需要注意代码的可读性和可维护性,以便其他程序员理解并维护他们的代码。 西安海思机试题涉及的内容可能包括但不限于以下几个方面: 1. Java基础知识:如基本语法、面向对象编程概念、异常处理、输入输出等。 2. 数据结构与算法:如链表、栈、队列、排序算法等。 3. 多线程编程:如线程创建与启动、同步与互斥、线程池等。 4. 网络编程:如TCP/IP通信、Socket编程等。 5. 数据库操作:如JDBC编程、SQL语句执行等。 在准备西安海思机试题时,考生可以通过以下途径提升自己的编程能力: 1. 学习和掌握Java编程语言的基础知识,包括语法、集合框架、IO操作等。 2. 多进行编程练习,不断提高自己的编码能力。 3. 阅读与Java相关的书籍、文章以及开源项目,学习他人的经验和优秀的编码风格。 4. 加入编程社区或者论坛,与其他程序员交流经验。 5. 参加在线教育平台或培训机构的Java课程,接受系统的培训。 总之,参加西安海思机试题是提升自己Java编程能力的一个很好的机会。通过扎实的基础知识和充分的准备,考生可以在这个机试中展现出自己的编程实力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值