rv1126部署模型模版(以手写数字识别模型为例)

本项目代码已开源,见文末

首先搭建好rknntoolkit以及rknpu环境

-->rknn_toolkit以及rknpu环境搭建-rv1126-优快云博客

MNIST->https://github.com/warren-wzw/MNIST-pytorch.git

大致流程

生成rknn文件

1:进入docker

docker run -t -i --privileged -v /dev/bus/usb:/de/bus/usb  \

-v /home/wzw/rk_npu_sdk/rknn-toolkit-master-v1.7.3:/rknn_toolkit rknn-toolkit:1.7.3 /bin/bash

2:进入/rknn_toolkit/examples/onnx,复制一个resnet50v2并命名为MNIST

3:准备以下文件

4:代码

import os
import urllib
import traceback
import time
import sys
import numpy as np
import cv2
from rknn.api import RKNN

ONNX_MODEL = 'model.onnx'
RKNN_MODEL = 'model.rknn'

if __name__ == '__main__':

    # Create RKNN object
    rknn = RKNN()

    # pre-process config
    print('--> Config model')
    rknn.config(target_platform=["rv1126"])
    print('done')

    # Load ONNX model
    print('--> Loading model')
    ret = rknn.load_onnx(model=ONNX_MODEL,
                         inputs=['input.1'],
                         input_size_list=[[1,28,28]],
                         outputs=['25'])
    if ret != 0:
        print('Load model failed!')
        exit(ret)
    print('done')

    # Build model
    print('--> Building model')
    ret = rknn.build(do_quantization=False)
    if ret != 0:
        print('Build model failed!')
        exit(ret)
    print('done')

    # Export RKNN model
    print('--> Export RKNN model')
    ret = rknn.export_rknn(RKNN_MODEL)
    if ret != 0:
        print('Export resnet50v2.rknn failed!')
        exit(ret)
    print('done')

    # Set inputs
    with open("./data/MNIST/raw/train-images-idx3-ubyte","rb") as f:
        file=f.read()
        num=100
        i = 16+784*num
        image1 = [int(str(item).encode('ascii'),16) for item in file[i:i+784]]
        input_data = np.array(image1,dtype=np.float32).reshape(1,1,28,28)
    #save the image
    image1_np = np.array(image1,dtype=np.uint8).reshape(28,28,1)
    file_name = "test.jpg"
    cv2.imwrite(file_name,image1_np)

    # init runtime environment
    print('--> Init runtime environment')
    ret = rknn.init_runtime()
    if ret != 0:
        print('Init runtime environment failed')
        exit(ret)
    print('done')

    # Inference
    print('--> Running model')
    outputs = rknn.inference(inputs=input_data)
    x = outputs[0]
    output = np.exp(x)/np.sum(np.exp(x))
    outputs = np.argmax([output])
    print("----------outputs----------",outputs)
    print('done')

    rknn.release()

5:python test.py

生成rknn文件

rknpu

复制一个mobilenet并命名为MNIST目录结构为:

将toolkit生成的rknn模型文件拷贝至model

build.sh

#!/bin/bash

set -e

# for rk1808 aarch64
# GCC_COMPILER=${RK1808_TOOL_CHAIN}/bin/aarch64-linux-gnu

# for rk1806 armhf
# GCC_COMPILER=~/opts/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf

# for rv1109/rv1126 armhf
GCC_COMPILER=/opt/atk-dlrv1126-toolchain/bin/arm-linux-gnueabihf

ROOT_PWD=$( cd "$( dirname $0 )" && cd -P "$( dirname "$SOURCE" )" && pwd )

# build rockx
BUILD_DIR=${ROOT_PWD}/build

if [[ ! -d "${BUILD_DIR}" ]]; then
  mkdir -p ${BUILD_DIR}
fi

cd ${BUILD_DIR}
cmake .. \
    -DCMAKE_C_COMPILER=${GCC_COMPILER}-gcc \
    -DCMAKE_CXX_COMPILER=${GCC_COMPILER}-g++
make -j4
make install

main.cc

/*-------------------------------------------
                Includes
-------------------------------------------*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <fstream>
#include <iostream>
#include <sys/time.h>

#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include <stb/stb_image_resize.h>

#include "rknn_api.h"

using namespace std;

const int MODEL_IN_WIDTH = 28;
const int MODEL_IN_HEIGHT = 28;
const int MODEL_CHANNEL = 1;
int ret =0;
int loop_count = 1000;

/*-------------------------------------------
                  Functions
-------------------------------------------*/
static inline int64_t getCurrentTimeUs()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000000 + tv.tv_usec;
}

static void printRKNNTensor(rknn_tensor_attr *attr)
{
    printf("index=%d name=%s n_dims=%d dims=[%d %d %d %d] n_elems=%d size=%d fmt=%d type=%d qnt_type=%d fl=%d zp=%d scale=%f\n",
           attr->index, attr->name, attr->n_dims, attr->dims[3], attr->dims[2], attr->dims[1], attr->dims[0],
           attr->n_elems, attr->size, 0, attr->type, attr->qnt_type, attr->fl, attr->zp, attr->scale);
}

static unsigned char *load_model(const char *filename, int *model_size)
{
    FILE *fp = fopen(filename, "rb");
    if (fp == nullptr)
    {
        printf("fopen %s fail!\n", filename);
        return NULL;
    }
    fseek(fp, 0, SEEK_END);
    int model_len = ftell(fp);
    unsigned char *model = (unsigned char *)malloc(model_len);
    fseek(fp, 0, SEEK_SET);
    if (model_len != fread(model, 1, model_len, fp))
    {
        printf("fread %s fail!\n", filename);
        free(model);
        return NULL;
    }
    *model_size = model_len;
    if (fp)
    {
        fclose(fp);
    }
    return model;
}

void Load_data(int num,unsigned char * input_image)
{
    int j=16+784*num;
    FILE *file = fopen("./model/data/MNIST/raw/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++];
                    //printf("%d ", input_aray[i][j][k][l]);
                    if(input_aray[i][j][k][l]==0){
                        //printf(" ");
                    }
                }
                //printf("\n");
            }
        }
         //printf("\n");
    } 
}

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

void get_tensor_message(rknn_context ctx,rknn_tensor_attr *attrs,uint32_t num,int io)
{
    for (int i = 0; i < num; i++) {
        attrs[i].index = i;
        if(io==1){
        ret = rknn_query(ctx, RKNN_QUERY_INPUT_ATTR, &(attrs[i]), sizeof(rknn_tensor_attr));
        }
        else{
            ret = rknn_query(ctx, RKNN_QUERY_OUTPUT_ATTR, &(attrs[i]), sizeof(rknn_tensor_attr));
        }
        if (ret != RKNN_SUCC) {
            printf("rknn_query fail! ret=%d\n", ret);
        }
        printRKNNTensor(&(attrs[i]));
    }
}
void print_Array(int num,float *buffer)
{
    for(int i =0;i<num;i++){
        printf("%f\n",buffer[i]);
    }
}
/*-------------------------------------------
                  Main Function
-------------------------------------------*/
int main(int argc, char **argv)
{
    rknn_context ctx;
    int model_len = 0;
    unsigned char *model;
    int num=-1;
    int64_t time[1000]={};
    int64_t sum=0;

    const char *model_path = "./model/model.rknn";

    // Load RKNN Model
    model = load_model(model_path, &model_len);

    ret = rknn_init(&ctx, model, model_len, 0);
    if (ret < 0)
    {
        printf("rknn_init fail! ret=%d\n", ret);
        return -1;
    }

    // Get Model Input Output Info
    rknn_input_output_num io_num;
    ret = rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, &io_num, sizeof(io_num));
    if (ret != RKNN_SUCC)
    {
        printf("rknn_query fail! ret=%d\n", ret);
        return -1;
    }
    printf("model input num: %d, output num: %d\n", io_num.n_input, io_num.n_output);

    printf("input tensors:\n");
    rknn_tensor_attr input_attrs[io_num.n_input];
    memset(input_attrs, 0, sizeof(input_attrs));
    get_tensor_message(ctx,input_attrs,io_num.n_input,1);

    printf("output tensors:\n");
    rknn_tensor_attr output_attrs[io_num.n_output];
    memset(output_attrs, 0, sizeof(output_attrs));
    get_tensor_message(ctx,output_attrs,io_num.n_output,0);

    for(int i=0;i<loop_count;i++){
        printf("------------------------loop %d\n",i);
        // Load image
        unsigned char input_image[784]={};
        float input_aray[1][MODEL_CHANNEL][MODEL_IN_HEIGHT][MODEL_IN_WIDTH]={};
        num++;
        Load_data(num,input_image);
        Array_change(input_aray,input_image);
        // Set Input Data
        rknn_input inputs[1];
        memset(inputs, 0, sizeof(inputs));
        inputs[0].index = 0;
        inputs[0].type = RKNN_TENSOR_FLOAT32;
        inputs[0].size = input_attrs[0].size;
        inputs[0].fmt = RKNN_TENSOR_NCHW;
        inputs[0].buf = input_aray;

        ret = rknn_inputs_set(ctx, io_num.n_input, inputs);
        if (ret < 0)
        {
            printf("rknn_input_set fail! ret=%d\n", ret);
            return -1;
        }

        // Run
        printf("rknn_run\n");
        int64_t start_us = getCurrentTimeUs();
        ret = rknn_run(ctx, nullptr);
        if (ret < 0){
            printf("rknn_run fail! ret=%d\n", ret);
            return -1;
        }
        time[i] = getCurrentTimeUs() - start_us;
        sum=sum+time[i];
        printf(": Elapse Time = %.2fms sum %.2f", time[i] / 1000.f,sum / 1000.f);

        // Get Output
        rknn_output outputs[1];
        memset(outputs, 0, sizeof(outputs));
        outputs[0].want_float = 1;
        ret = rknn_outputs_get(ctx, 1, outputs, NULL);
        if (ret < 0)
        {
            printf("rknn_outputs_get fail! ret=%d\n", ret);
            return -1;
        }
        //postprocess
        float *buffer = (float *)outputs[0].buf;
        float buffer_copy[]={};
        for(int i=0;i<10;i++){
            buffer_copy[i]=buffer[i];      
        }
        Bubble_sort(buffer);
       /*  printf("buffer is \n");
        print_Array(10,buffer);
        printf("\nbuffer_copy is \n");
        print_Array(10,buffer_copy); */
        for(int i =0;i<10;i++){
            if(buffer_copy[i]==buffer[9]){
                printf("----------the pic value is %d \n",i);
            }
        }
        // Release rknn_outputs
        rknn_outputs_release(ctx, 1, outputs);
    }
    
    
    printf("--------- loop time : %d average time is %.2f ms\n",loop_count,(sum / 1000.f)/loop_count);

    // Release
    if (ctx >= 0)
    {
        rknn_destroy(ctx);
    }
    if (model)
    {
        free(model);
    }
    return 0;
}

打印结果

fp16

uint8

 个人开源项目---各平台算法部署模版

### 部署深度强化学习模型RV1126平台 #### RV1126硬件特性概述 RV1126是一款专为低功耗、高性能计算设计的嵌入式处理器,适用于边缘计算场景下的多种人工智能应用。该芯片集成了神经网络处理单元(NPU),能够高效支持卷积神经网络(CNN)和其他类型的机器学习模型推理。 #### 准备工作环境 为了顺利部署深度强化学习模型RV1126设备,在开发主机上需安装必要的软件包和配置相应的编译工具链。具体操作如下: - 安装交叉编译器GCC ARM Embedded Toolchain用于构建适合ARM架构的目标文件; - 下载并设置好RV1126 SDK,其中包含了针对特定硬件优化过的库函数以及示程序; - 使用Python虚拟环境隔离项目依赖项,并通过pip命令安装额外所需的第三方模块如TensorFlow Lite等轻量化框架[^1]; ```bash # 创建并激活新的Python虚拟环境 python3 -m venv env_rv1126 source env_rv1126/bin/activate # 更新pip版本 pip install --upgrade pip setuptools wheel # 安装tensorflow-lite解释器以及其他辅助工具 pip install tflite-runtime numpy opencv-python matplotlib scikit-image ``` #### 转换训练好的模型 由于原始训练得到的是基于GPU服务器上的全精度浮点数表示形式(.h5,.pb),而RV1126内部NPU仅能识别整型或混合精度格式(TFLITE,ONNX).因此需要借助官方提供的转换脚本将源模型转化为适配目标平台的数据结构. 对于已经完成离线训练过程获得的最佳参数组合checkpoint file (.pth/.pt): ```python import torch from torchvision import models model = models.resnet18(pretrained=False) model.load_state_dict(torch.load('best_model.pth')) dummy_input = torch.randn(1, 3, 224, 224) torch.onnx.export(model,dummy_input,"resnet18.onnx",opset_version=11, do_constant_folding=True,input_names=['input'],output_names=['output']) ``` 接着利用`onnx-simplifier`, `tvm.relay.frontend.from_onnx()` 或者其他开源项目进一步简化Onnx graph定义,最终导出成TFlite FlatBuffer二进制流供后续加载解析: ```shell !pip install onnxsim==0.3.9 !python -m onnxsim resnet18.onnx simplified_resnet18.onnx ``` 最后一步则是调用`tflite_convert`接口实现从Simplified Onnx Model向Target Format TFlite File转变: ```shell tflite_convert \ --saved_model_dir=simplified_resnet18.onnx \ --output_file=resnet18.tflite \ --input_shapes=1,3,224,224 \ --inference_type=FLOAT \ --input_arrays=input \ --output_arrays=output ``` #### 编写C++代码集成TFLite Interpreter API 当准备好经过量化的Lite版Model之后就可以着手编写实际运行于裸机端的应用逻辑了。这里给出一段简单的模板作为参考说明如何初始化解释器实、分配张量内存空间并将输入数据填充进去等待预测结果返回。 ```cpp #include <iostream> #include "tensorflow/lite/interpreter.h" #include "tensorflow/lite/kernels/register.h" #include "tensorflow/lite/model.h" int main() { // 加载已保存下来的Flatbuffer Buffer对象 std::unique_ptr<tflite::FlatBufferModel> model = tflite::FlatBufferModel::BuildFromFile("resnet18.tflite"); if (!model){ fprintf(stderr,"Failed to mmap model\n"); return EXIT_FAILURE; } // 构建默认Op Resolver来注册内置算子集合 tflite::ops::builtin::BuiltinOpResolver resolver; // 新建Interpreter Builder负责组装整个Graph拓扑关系图谱 std::unique_ptr<tflite::Interpreter> interpreter; auto builder_status=model->NewInterpreter(&resolver,&interpreter); if(!builder_status.ok()){ printf("Failed to construct interpreter:%s\n", builder_status.message().c_str()); return EXIT_FAILURE; } // 设置Input Tensor Shape Info & Allocate Memory Space Automatically TfLiteStatus allocate_tensors_status=interpreter->AllocateTensors(); if (allocate_tensors_status != kTfLiteOk){ printf("Failed to allocate tensors.\n"); return EXIT_FAILURE; } float* input_tensor_data= interpreter->typed_input_tensor<float>(0); /* 填充具体的像素值 */ for(int i=0;i<224 * 224 * 3;++i){ input_tensor_data[i]=/* ... */; } // 执行前馈传播运算获取Output Feature Maps interpreter->Invoke(); const float* output_tensor_data= interpreter->typed_output_tensor<float>(0); /* 处理输出层产生的分类得分 */ } ``` #### 测试验证效果 上传上述工程产物至板级资源管理器后执行编译链接流程生成可执行映像文件`.elf`。连接串口调试助手监视日志打印情况确认无误后再断开电源重启进入正式测试环节观察实时性能指标变化趋势是否满足预期要求。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

warren@伟~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值