嵌入式人工智能应用- EAIDK610-part three

@嵌入式人工智能应用- EAIDK610-part three
这里承接上文的讲的基础知识,这里继续介绍EAIDK-610的人工智能应用。

7 基于Tengine模型框架人工智能的部署

一般人工智能开发包含了六个步骤:

  1. 确定需求
  2. 准备数据
  3. 确定框架
  4. 训练模型
  5. 模型评估
  6. 模型部署。

本人作者在这里只谈第6部分,模型部署。 关于1~5部分的知识,读者可以自行搜索相关知识:譬如去tensorflow官网上面学习和进行模型训练。

端侧的人工智能应用开源框架有很多,本文这里用到开源框架是OPEN AI LAB公司的Tengine。Tengine 是OPEN AI LAB 为嵌入式设备开发的一个轻量级、高性能并且模块化的引擎。基于ARM平台高效的计算库实现,针对特定硬件平台的性能优化,吸取已有AI计算框架的优点,设计全新的计算图表示。

EAIDK-610系统已经继承tengine的库,所以在部署的时候十分方便。这里就两种常见的物体分类和人脸检测两种模型的操作步骤进行介绍,后续更新更多的模型应用方案。

Tengine的通用的基本操作流程如下:

  1. 初始化 Tengine - init_tengine
  2. 创建Tengine图- create_graph
  3. 获取输入节点 get_graph_input_tensor
  4. 申请内容空间 pre_graph
  5. 运行tengine run_graph
  6. 获取输出tensor get_graph_output_tensor
  7. 获取数据 get_tensor_buff
  8. 释放程序内容
    release_graph_tensor
    postrun_graph
    destroy_graph
    release_graph

所以对于利用Tengine开发,开发的流程是一样。只是导入模型不一样,后期对输出的数据处理不一样。其他基本开发流程是一样的。

7.1 Tengine部署

  • 7.1.1 src、main 和 object 三个文件中的makefile 添加pkg-config 查找tenginge的库,EAIDK-610已经默安装了库。
CXX=g++
CXXFLAGS= -I $(INC_PATH)
SRC=$(shell ls *.cpp)
OBJS=$(patsubst %.cpp,%.o,$(SRC))
LDDFLAGS= `pkg-config --libs fastcv` `pkg-config --libs tengine`
INCFLAGS= `pkg-config --cflags fastcv` `pkg-config --cflags tengine`
all: $(OBJS)	
%.o: %.cpp
	$(CXX)  $(CXXFLAGS) -c -o $(OBJ_PATH)/$@  $<  $(LDDFLAGS) $(INCFLAGS)
  • 7.1.2 识别的图片前期处理
    (1) 打开需要识别的图像
cv:: Mat img=cv::imread(image_file);
if(img.empty()==true)
{
    std::cout<<"input image isn't exit"<<std::endl;
    return 1;
}
else
{
    std::cout<<"input image is open"<<std::endl;
}

(2) 减少图像尺寸,譬如100100,300300都可以。

cv::Mat img_resize;
cv::resize(img,img_resize,cv::Size(img_w,img_h));  

(3)获取一张彩色图片的计算空间

float *input_data=(float *)malloc(img_w*img_h*3*sizeof(float));  

(4)对数据进行归一化处理

get_input_data(img_resize, input_data, img_h, img_w);   
  • 7.1.3 初始化tengine
init_tengine();
if(request_tengine_version("0.9")<0)
{
    std::cout<<"tengine version low"<<std::endl;
    return 1;
}
else
{
    std::cout<<"tengine initial succuss"<<std::endl;
}
  • 7.1.4 创建Tengine图
graph_t  graph=create_graph(nullptr,"caffe",proto_name.c_str(),mode_name.c_str()); 
if(graph==nullptr)
{
    std::cout<<"create graph failed"<<std::endl;
    std::cout<<"tengine error "<<get_tengine_errno()<<std::endl;
    return 1;
}
else
{
    std::cout<<"create graph success"<<std::endl;
}
  • 7.1.5 获取输入节点
tensor_t input_tensor= get_graph_input_tensor(graph,0,0);
int dims[]={1,3,img_w,img_h}; // 模型要求输入是4维数据,所以在原来图像增加一维
if(set_tensor_shape(input_tensor,dims,4)<0)  //设置输入的数据尺寸
{
        std::cout<<"tensor_shape fail"<<std::endl;
        return 1;
}
else
{
        std::cout<<"tensor shape success"<<std::endl;
}
  • 7.1.6 申请内容空间
prerun_graph(graph);
      if(set_tensor_buffer(input_tensor,input_data,3*img_h*img_w*sizeof(float))<0)
{
	std::cout<<"set tensor buff fail"<<std::endl;
	return 1;
}
else
{
	std::cout<<"set tensor buff success"<<std::endl;
}
  • 7.1.7 运行tengine
struct timeval t1,t2;
float avg_time=0;
gettimeofday(&t1,NULL);
for(int i=0;i<repeat_count;i++)
	run_graph(graph,1);    
gettimeofday(&t2,NULL);
float cmp_time=(float)(t2.tv_sec*1000000+t2.tv_usec - t1.tv_sec*1000000-t1.tv_usec) /1000;
// 计算平均值
avg_time= cmp_time/repeat_count;    std::cout<<"......................................................"<<std::endl;
std::cout<<"repeat time "<<repeat_count<<" average time is "<<avg_time<<std::endl; 
  • 7.1.8 获取输出tensor
tensor_t  output_tensor=get_graph_output_tensor(graph,0,0);
int out_dims[4];
get_tensor_shape(output_tensor,out_dims,4); 
  • 7.1.9 获取数据
float *output_data=(float *)(get_tensor_buffer(output_tensor));
int num=out_dims[1];
  • 7.1.10 对输出处理,不同的模型,就是处理这块有点差别`
// 对获取的图像进行标注
post_process_ssd(img,0.5,output_data,num,save_file.c_str());  
  • 7.1.11 释放内存
release_graph_tensor(output_tensor);
release_graph_tensor(input_tensor);
postrun_graph(graph);
destroy_graph(graph);    
free(input_data);
release_tengine();

7.2 物体检测模型载入

  • 7.2.1 模型介绍

本次使用的模型是 MobileNet-SSD,SSD算是一种one-stage的目标检测框架或者算法。而MobileNet是这种算法所使用的具体的网络结构,用来提取特征。

  • 7.2.2 模型载入

物体检测的算法可以识别21种物体种类。把识别出来的物体用不同框标注出来,同时标注出来识别的种类和概率。然后把识别结果存在一个jpg的图片。

void post_process_ssd(const char* image_file, float threshold, const float* outdata, int num)
{
    const char* class_names[] = {"background", "aeroplane", "bicycle", "bird", "boat", "bottle",
                                 "bus", "car", "cat", "chair", "cow", "diningtable",
                                 "dog", "horse", "motorbike", "person", "pottedplant", "sheep",
                                 "sofa", "train", "tvmonitor"};

    image im = imread(image_file);

    int raw_h = im.h;
    int raw_w = im.w;

    Box_t* boxes = malloc(sizeof(Box_t) * DEFAULT_MAX_BOX_COUNT);
    int box_count = 0;

    fprintf(stderr, "detect result num: %d \n", num);
    for (int i = 0; i < num; i++)
    {
        if (outdata[1] >= threshold)
        {
            Box_t box;

            box.class_idx = outdata[0];
            box.score = outdata[1];
            box.x0 = outdata[2] * raw_w;
            box.y0 = outdata[3] * raw_h;
            box.x1 = outdata[4] * raw_w;
            box.y1 = outdata[5] * raw_h;

            boxes = realloc(boxes, sizeof(Box_t) * (box_count + 1));
            boxes[box_count] = box;
            box_count++;

            fprintf(stderr, "%s\t:%.1f%%\n", class_names[box.class_idx], box.score * 100);
            fprintf(stderr, "BOX:( %d , %d ),( %d , %d )\n", box.x0, box.y0, box.x1, box.y1);
        }
        outdata += 6;
    }
    for (int i = 0; i < box_count; i++)
    {
        Box_t box = boxes[i];
        draw_box(im, box.x0, box.y0, box.x1, box.y1, 2, 125, 0, 125);
    }

    free(boxes);

    save_image(im, "mobilenet_ssd_out");
    free_image(im);
    fprintf(stderr, "======================================\n");
    fprintf(stderr, "[DETECTED IMAGE SAVED]:\n");
    fprintf(stderr, "======================================\n");
}

7.3 人脸识别模型载入

人脸识别处理结果,用框标注出来。标注识别的概率。然后把识别结果存在一个jpg的图片。

void Post_Process_ssd(cv::Mat& img, float threshold, float* outdata, int num, const std::string& save_name)
{
    std::vector<Box> boxes;
    int line_width=img.cols*0.005;
    std::cout<<"****************************************"<<std::endl;
    int detect_face_num=0;
    for(int i=0;i<num;i++)
    {
        if(outdata[1] >= threshold)
        {
            detect_face_num++;
            Box box;
            box.class_idx=outdata[0];
            box.score=outdata[1];
            box.x0 = outdata[2] * img.cols;
            box.y0 = outdata[3] * img.rows;
            box.x1 = outdata[4] * img.cols;
            box.y1 = outdata[5] * img.rows;
            boxes.push_back(box);
            std::cout<<"face num is "<<detect_face_num<<"score is "<< box.score*100<<std::endl;
        }
        outdata++;
    }
    std::cout<<" whole face number is "<<detect_face_num<<std::endl;

    for(int  i=0;i<boxes.size();i++)
    {
        Box box=boxes[i];
        cv::rectangle(img,cv::Rect(box.x0,box.y0,(box.x1-box.x0),(box.y1-box.y0)),cv::Scalar(255,255,0),cv::LINE_8);
        std::ostringstream score_str;
        score_str.precision(3);
        score_str<<box.score;
        std::string label=score_str.str();
        int baseline=0;
        cv::Size label_size=cv::getTextSize(label,cv::FONT_HERSHEY_SIMPLEX,0.3,1,&baseline);
        cv::rectangle(img,
        cv::Rect(cv::Point(box.x0, box.y0 - label_size.height),cv::Size(label_size.width, label_size.height + baseline)),
        cv::Scalar(255, 255, 0), CV_FILLED);
        cv::putText(img, label, cv::Point(box.x0, box.y0), cv::FONT_HERSHEY_SIMPLEX, 0.3, cv::Scalar(0, 0, 0));

    }
    cv::imwrite(save_name, img);
    std::cout << "======================================\n";
    std::cout << "[DETECTED IMAGE SAVED]:\t" << save_name << "\n";
    std::cout << "======================================\n";
}
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HHONGQI123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值