算能BM1684X部署手写数字识别模型

news2025/2/12 1:01:45

大致流程---------------------------------------------------------------

参考《sophon-sail_zh》

移植步骤------------------------------------------------------------------------

首先搭建好自己的网络模型,并导出为onnx格式--具体可以参照-->

GitHub - warren-wzw/MNIST-pytorch

  1. 将onnx模型使用tpu-mlir工具转化为bmodel格式--具体可以参照---> https://kdocs.cn/l/cdwzqT3Hbyje

拷贝至板端:scp test_output_fp* linaro@10.12.13.66:/data

远程连接另一台linux--->ssh -p 22 linaro@10.12.13.66

  1. 在板端搭建好sophon-sail环境----> https://kdocs.cn/l/ce7T9GNtS3D3

python版----------------------------------------------------------------------------------------

在板端新建一个MNIST文件夹,文件目录如下,其中datasets存放测试数据集train-images-idx3-ubyte,test_output_fp16_1b.bmodel以及test_output_fp32_1b.bmodel为onnx转化后的bmodel模型,test.py为测试代码。

  1. 主要的原理就是使用sophon提供的api加载能够适配于BM1684X的bmodel类型的模型,并使用他们的api进行模型的推理,官方sail的API可以参考-->

3. API 参考 — sophon-sail v23.03.01 文档

  1. 下面讲解一下测试代码
#import cv2
import numpy as np
import sophon.sail as sail
import time

num = -1 
inference_time =[0]
print("--0-5 1-0 2-4 3-1 4-9 5-2 6-1 7-3 8-1 9-4 for example:if num =9 the pic's num is 4")
 
engine = sail.Engine("./test_output_fp32_1b.bmodel",0,sail.IOMode.SYSIO) #load model-use FP32model on tpu-0 and use sys memery
#engine = sail.Engine("./test_output_fp16_1b.bmodel",0,sail.IOMode.SYSIO) #load model-use FP16 on tpu-0 and use sys memery

graph_name =engine.get_graph_names()[0]                      #get_graph_names-test_output
input_tensor_name = engine.get_input_names(graph_name)[0]    #get_input_names-input.1
output_tensor_name = engine.get_output_names(graph_name)[0]  #get_output_names-25_LogSoftmax

batchsize,channel,height,width = engine.get_input_shape(graph_name,input_tensor_name) #get batchsize-1,channel-1,input image's height-28 & width-28

#read image
with open("./datasets/train-images-idx3-ubyte","rb") as f:
    file = f.read()
for i in range(8000): 
    num =num +1  
    i = 16+784*num
    image1 = [int(str(item).encode('ascii'),16) for item in file[i:i+784]]

    #reshap input data
    input_data = np.array(image1,dtype=np.float32).reshape(1,1,28,28)  #reshape the image to 1 1 28 28
    input_data_final = {input_tensor_name:input_data}     #because the process's parmeter(input_data)  must be dictionary so use{}
    start_time = time.time()
    outputs = engine.process(graph_name,input_data_final) #model inference
    end_time = time.time()
    inference_time.append(end_time - start_time)  
 
    result = outputs[output_tensor_name]  #use output_tensor_name to get the tensor
    max_value=np.argmax(result)           #get the index of the best score
    print("----------------------------------the result is ",max_value,"the time is ",inference_time[num]*1000,"ms")

mean = (sum(inference_time) / len(inference_time))*1000
print("-----FP32--","loop ",num+1,"times","average time",mean,"ms")

  1. 测试结果

FP32

FP16

基本稳定在4%峰值可达8%

C++版本---------------------------------------------------------------------------------------------------------

首先安装好c++交叉编译环境

--> https://kdocs.cn/l/cbe77SdEwLKm

1:采用交叉编译的方式进行编译,新建文件夹MNIST

文件结构

CMakeFile.txt

main.cpp

#define USE_FFMPEG 1
#define USE_OPENCV 1
#define USE_BMCV 1
#include <stdio.h>
#include <sail/cvwrapper.h>
#include <iostream>
#include <string>
#include <numeric>
#include <sys/time.h>

#include "spdlog/spdlog.h"
#include "spdlog/fmt/fmt.h"
#include "engine.h"

using namespace std;
using namespace sail;
const std::string& bmodel_path_fp32="./test_output_fp32_1b.bmodel";
const std::string& bmodel_path_fp16="./test_output_fp16_1b.bmodel";
const int MODEL_IN_WIDTH = 28;
const int MODEL_IN_HEIGHT = 28;
const int MODEL_CHANNEL = 1;
const int loop_count = 1000;
int num = -1;

static inline int64_t getCurrentTimeUs()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000000 + tv.tv_usec;
}
void Load_data(int num,unsigned char * input_image)
{
    int j=16+784*num;
    FILE *file = fopen("./datasets/train-images-idx3-ubyte", "rb");
    if (file == NULL) {
        printf("can't open the file!\n");
    }
    fseek(file,j,SEEK_SET);
    fread(input_image,sizeof(char),784,file);
/*     for(int i=0;i<MODEL_IN_WIDTH;i++){
        for(int j=0;j<MODEL_IN_WIDTH;j++){
            printf("%4d",input_image[i*28+j]);
        }
        printf("\n");
    } */ 
    fclose(file);
}

void Array_change(float input_aray[][MODEL_CHANNEL][MODEL_IN_WIDTH][MODEL_IN_HEIGHT],unsigned char *input_image)
{
   int index=0;
    for (int i = 0; i < 1; i++) {
        for (int j = 0; j < MODEL_CHANNEL; j++) {
            for (int k = 0; k < MODEL_IN_HEIGHT; k++) {
                for (int l = 0; l < MODEL_IN_WIDTH; l++) {
                    input_aray[i][j][k][l] = (float)input_image[index++];
                    //cout<<input_aray[i][j][k][l]<<" ";
                }
                //cout<<endl;
            }
        }
        //cout<<endl;
    } 
}

void Bubble_sort(float *buffer,int num)
{
    float temp;
    for(int i=0; i<num;i++){
        for(int j=0; j<num-i-1;j++){
            if(buffer[j]>buffer[j+1]){
                temp = buffer[j];
                buffer[j]=buffer[j+1];
                buffer[j+1]=temp;
            }
        }
    }
}

void dump_shape(std::vector<int> shape)
{
    cout<<"[  ";
    for (const int& value : shape) {
        std::cout << value << " ";
    }
     cout<<"]"<<endl;
}
bool inference(int device_id)
{
    int64_t time[loop_count] = {};
    unsigned char input_image[784]={};
    float input_aray[1][MODEL_CHANNEL][MODEL_IN_HEIGHT][MODEL_IN_WIDTH]={};
    int64_t sum=0;
    float buffer_copy[]={};
    // init Engine
    sail::Engine engine(device_id);    
    // load bmodel without builtin input and output tensors
    engine.load(bmodel_path_fp32);
    // get model info
    auto graph_name = engine.get_graph_names().front();
    auto input_name = engine.get_input_names(graph_name).front();
    auto output_name = engine.get_output_names(graph_name).front();
    std::vector<int> input_shape = {1, 1, 28, 28};
    std::map<std::string, std::vector<int>> input_shapes;
    input_shapes[input_name] = input_shape;
    auto output_shape = engine.get_output_shape(graph_name, output_name);
    auto input_dtype = engine.get_input_dtype (graph_name, input_name);
    auto output_dtype = engine.get_output_dtype(graph_name, output_name);
    cout<<"----------------graph_name is "<<graph_name<<endl;
    cout<<"----------------input_name is "<<input_name<<endl;
    cout<<"----------------output_name is "<<output_name<<endl;
    cout<<"----------------input_dtype is "<<input_dtype<<endl;
    cout<<"----------------output_dtype is "<<output_dtype<<endl;
    cout<<"output shape is ";
    dump_shape(output_shape);
    cout<<"input shape is ";
    dump_shape(input_shape);
    // get handle to create input and output tensors
    sail::Handle handle = engine.get_handle();

    // allocate input and output tensors with both system and device memory
    sail::Tensor in(handle, input_shape, input_dtype, true, true);
    sail::Tensor out(handle, output_shape, output_dtype, true, true);
    std::map<std::string, sail::Tensor*> input_tensors = {{input_name, &in}};
    std::map<std::string, sail::Tensor*> output_tensors = {{output_name, &out}};
    // prepare input and output data in system memory with data type of float32
    float* input = nullptr;
    float* output = nullptr;
    int in_size = std::accumulate(input_shape.begin(), input_shape.end(),
                                    1, std::multiplies<int>());
    int out_size = std::accumulate(output_shape.begin(), output_shape.end(),
                                    1, std::multiplies<int>());
    if (input_dtype == BM_FLOAT32) {
        input = reinterpret_cast<float*>(in.sys_data());
    } 
    else {
        input = new float[in_size];
    }
    if (output_dtype == BM_FLOAT32) {
        output = reinterpret_cast<float*>(out.sys_data());
    } 
    else {
        output = new float[out_size];
    }
    //loop 
    for(int times=0;times<loop_count;times++) {
        num++;
        Load_data(num,input_image);
        Array_change(input_aray,input_image);
        bool status=in.own_dev_data();
        cout<<"own_dev_data "<<status<<endl;
        status=in.own_sys_data();
        cout<<"own_sys_data "<<status<<endl;
        in.reset_sys_data(input_aray,input_shape);
         
        // set io_mode SYSO:Both input and output tensors are in system memory.
        engine.set_io_mode(graph_name, sail::  SYSIO);

        bm_data_type_t ret =in.dtype();
        printf("in.dtype is %d\n", ret);

        //inference
        int64_t start_time = getCurrentTimeUs();
        engine.process(graph_name, input_tensors, input_shapes, output_tensors);
        int64_t end_time = getCurrentTimeUs();
        time[times]=end_time-start_time;
        sum = sum+time[times];
        //post process
        auto real_output_shape = engine.get_output_shape(graph_name, output_name);
        float* output_data = reinterpret_cast<float*>(out.sys_data());
        for(int i = 0; i < 10;i++){
            buffer_copy[i]=output_data[i];
            //printf("output_data is %f \n",output_data[i]);
        }
        Bubble_sort(output_data,10);
        for(int i =0;i<10;i++){
            if(buffer_copy[i]==output_data[9]){
                printf("------------------------------------------the pic value is %d \n",i);
            }
        }

        /* cout<<"real_output_shape is "<<"[  ";
        dump_shape(real_output_shape);*/
        printf(": Elapse Time = %.3f ms \n", time[times] / 1000.f);
    }
    printf("--------loop %d times sum is %.4f ms average time is %.3f ms\n", loop_count,sum / 1000.f,(sum / 1000.f)/loop_count);
    return true;
}
int main()
{
    int device_id = 0;
    int tpu_num=get_available_tpu_num();
    printf("the tpu number is %d\n", tpu_num);
    
    bool status = inference(device_id);
    return 0;    
}

打印结果

fp32

fp16

int8

bm-smi

基本稳定在2%,峰值为4

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/864359.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

aspose 使用ftl模板生成word和pdf

1 先找到word模板&#xff0c;用${}&#xff0c;替换变量&#xff0c;保存&#xff0c;然后另存为xml,最后把xml后缀改成ftl。 如下图&#xff1a; word 模板文件 ftl模板文件如下: 2 代码生成 下面函数将ftl填充数据&#xff0c;并生成word和pdf /*** * param dataMap 模板…

c++继承总结

一 继承的由来 我使用类也有一段时间了&#xff0c;慢慢觉得我们做一件事时&#xff0c;就是要先描述&#xff0c;例如写一个管理系统登记学校成员的信息&#xff0c;我们就要先对在学校内的老师和学生做描述&#xff0c;学生要有年龄&#xff0c;班级&#xff0c;姓名&#xf…

postman接口测试中文汉化教程

想必同学们对于接口测试工具postman的使用并不陌生&#xff0c;以及最近大为流行的国产工具apifox。对于使用过的同学来说&#xff0c;两者区别以及优缺点很容易别展示出来&#xff0c;postman相比apifox来说更加轻量&#xff0c;但是apifox更加符合国人的使用习惯....中国人给…

谷歌云 | BigQuery 现在支持用于查询开放表格式的清单文件

Cloud Ace 是谷歌云全球战略合作伙伴&#xff0c;拥有 300 多名工程师&#xff0c;也是谷歌最高级别合作伙伴&#xff0c;多次获得 Google Cloud 合作伙伴奖。作为谷歌托管服务商&#xff0c;我们提供谷歌云、谷歌地图、谷歌办公套件、谷歌云认证培训服务。 开放表格式依赖嵌…

C++:string类模拟实现

C&#xff1a;string类模拟实现 成员变量构造和析构容量相关1.获取容器大小(_size)和容量(_capacity)2.扩容(reserve)3.更改容器大小 修改相关1.尾插2.指定位置插入3.指定位置删除4.清空5.交换两个对象 比较相关访问相关迭代器相关查找相关其它成员函数1.截取子串2.取得C格式字…

交融动画学习

学习抖音&#xff1a; 渡一前端教科频道 利用 filter 的属性实现交融效果 变成 让后利用这个效果实现一个功能 实现代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><style>* {margin: 0;…

c# .net mvc的IHttpHandler奇妙之旅--图片文件请求安全过滤,图片防盗链

在阅读该文章前,请先阅读该文章 c# .net mvc的IHttpHandler奇妙之旅。.net的生命周期和管道你听说过吗?你可以利用他处理业务如:跳转业务页面,文件请求的安全过滤,等等,还有许多神秘业务等着你去发现_橙-极纪元的博客-CSDN博客 该篇文章延续上面文章的第二小节《二、文件…

StarRocks企业级数据库

第1章 StarRocks简介 1.1 StarRocks介绍 StarRocks是新一代极速全场景MPP数据库 StraRocks充分吸收关系型OLAP数据库和分布式存储系统在大数据时代的优秀研究成果&#xff0c;在业界实践的基础上&#xff0c;进一步改进优化、升级架构&#xff0c;并增添了众多全新功能&…

Cadence OrCAD Capture CIS批量替换GND符号的方法

🏡《总目录》   🏡《宝典目录》 目录 1,概述2,方法3,总结1,概述 如下图所示,有时由于绘图是从多个地方复制粘贴而来,一个图纸中会存在多种GND符号。此时比较容易引起GND网络名不同意的问题,为了避免该问题可对其批量替换。 2,方法 第1步:选择需要替换的GND符号…

【Nginx】Nginx的优化和防盗链

nginx版本迭代比较快 *工作中&#xff0c;在发版期&#xff0c;通常先备份文件并备注时间&#xff0c;方便后期故障后回档 例&#xff1a; cp nginx.conf nginx.conf.bak.2023.0805 隐藏版本号的两种方法*** 1.修改配置文件 vim /usr/local/nginx/conf/nginx.conf 在http模…

分享花店行业小程序平台搭建教程

随着移动互联网的快速发展&#xff0c;花店也开始意识到拥有一个专属的小程序能够提升用户体验、增加销售额。那么&#xff0c;如何快速搭建一个漂亮、实用的花店小程序呢&#xff1f;下面就为大家介绍一下具体的步骤。 第一步&#xff0c;使用第三方制作平台。如乔拓云网是一个…

Linux下C语言调用libcurl库获取天气预报信息

一、概述 当前文章介绍如何在Linux&#xff08;Ubuntu&#xff09;下使用C语言调用libcurl库获取天气预报的方法。通过HTTP GET请求访问百度天气API&#xff0c;并解析返回的JSON数据&#xff0c;可以获取指定城市未来7天的天气预报信息。 二、设计思路 【1】使用libcurl库进…

24届近5年南京大学自动化考研院校分析

今天给大家带来的是南京大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、南京大学 学校简介 南京大学是一所历史悠久、声誉卓著的高等学府。其前身是创建于1902年的三江师范学堂&#xff0c;此后历经两江师范学堂、南京高等师范学校、国立东南大学、国立第四中…

数字孪生和元宇宙之间的差别与联系是什么?

元宇宙和数字孪生是两个引人瞩目的概念&#xff0c;它们在虚拟与现实世界的交汇点上呈现出独特的视角和应用。虽然二者都涉及数字化和模拟技术&#xff0c;但在其差异与联系上&#xff0c;我们可以发现深刻的内涵和潜力。 首先&#xff0c;元宇宙是一个更为宽泛的概念&#xf…

嵌入式是大坑吗?

嵌入式不是坑&#xff0c;但里面遍地是坑。一不小心&#xff0c;你就会掉进去。 嵌入式覆盖的范围太广&#xff0c;低端的产品太多。 单片机叫嵌入式&#xff0c;开发板叫嵌入式&#xff0c;摄像头叫嵌入式&#xff0c;手机、平板电脑、通讯基站、无人机、机器人、自动驾驶汽…

C++之红黑树剖析

博主&#xff1a;拖拉机厂第一代码手 gitee:拖拉机厂第一代码手 已收录到专栏C&#xff0c;点击访问 目录 &#x1f4b4;红黑树简介&#x1f4b5;红黑树的插入操作&#x1f4b6;红黑树的删除操作&#x1f4b7;红黑树的实现&#x1f4b8;红黑树节点的定义&#x1f4b8;红黑树结构…

autoware 之 op_behavior_selector行为选择器状态机代码分析

autoware 1 op_behavior_selector行为选择器状态机代码分析 /这里是整个状态机运行时的结构&#xff1a;/ //停止状态:[#停止状态]//任务完成状态:[#任务完成状态]//转向状态:[*前进状态,#转向状态]//停止信号停止状态:[*停止信号等待状态,#停止信号停止状态]//前进状态 :[*目…

C语言学习系列-->看淡指针(1)

文章目录 一、概述二、指针变量和地址2.1 取地址操作符2.2 指针变量和解引用操作符2.2.1 指针变量2.2.2 拆解指针类型2.2.4 解引用操作符 2.3 指针变量的大小 三、指针变量的意义3.1 指针的解引用指针-整数 四、 const修饰指针五、指针运算5.1 指针- 整数5.2 指针-指针5.3 指针…

OpenText 企业安全 调查 产品简介

关于OpenText OpenText是一家信息软件公司&#xff0c;使企业能够通过市场领先的信息管理解决方案&#xff08;内部或云中&#xff09;获得洞察力。 全球面临的数字风险 市场合力驱动的信息管理 处于风暴中心的信息 →安全漏洞和数据保护 • 防止威胁并将破坏影响降至最低 …