[RV1109/RV1126系列]-3.RV1109/1126 RKNN API接口的C++封装

请添加图片描述

  当我们转换并量化好模型后,在PC端简单验证后,一定想将自己的模型部署到板端运行测试,但瑞芯微官方给的纯C接口使用起来,感觉较为繁琐。抱着试一试的态度,本人尝试了将常用接口封装成类似于NCNN的接口调用形式,方便自己在工程部署上的应用,目前使用效果还凑合,特将其分享给大家,其中不足之处还望各位大佬指正。QAQ

1.RKNN API函数返回值错误码

错误码错误详情
RKNN_SUCC(0)执行成功
RKNN_ERR_FAIL(-1)执行出错
RKNN_ERR_TIMEOUT(-2)执行超时
RKNN_ERR_DEVICE_UNAVAILABLE(-3)NPU 设备不可用
RKNN_ERR_MALLOC_FAIL(-4)内存分配失败
RKNN_ERR_PARAM_INVALID(-5)传入参数错误
RKNN_ERR_MODEL_INVALID(-6)传入的 RKNN 模型无效
RKNN_ERR_CTX_INVALID(-7)传入的 rknn_context 无效
RKNN_ERR_INPUT_INVALID(-8)传入的 rknn_input 对象无效
RKNN_ERR_OUTPUT_INVALID(-9)传入的 rknn_output 对象无效
RKNN_ERR_DEVICE_UNMATCH(-10)版本不匹配
RKNN_ERR_INCOMPATILE_PRE_COMPILE_MODEL(-11)RKNN 模型使用 pre_compile 模式,但是和当前驱动不兼容
RKNN_ERR_INCOMPATILE_OPTIMIZATION_LEVEL_VERSION(-12)RKNN 模型设置了优化等级的选项,但是和当前驱动不兼容
RKNN_ERR_TARGET_PLATFORM_UNMATCH(-13)RKNN 模型和当前平台不兼容,一般是将 RK1808 的平台的 RKNN 模型放到了 RV1109/RV1126 上。
RKNN_ERR_NON_PRE_COMPILED_MODEL_ON_MINI_DRIVER(-14)RKNN 模型不是 pre_compile 模式,在 mini-driver 上无法执行

2.RKNN API函数介绍

  • rknn_init

    • 函数说明:初始化RKNN

    • 入参:

      1.rknn_context *context:rknn_context 指针。函数调用之后,context 将会被赋值。

      2.void *model:RKNN 模型的二进制数据。

      3.uint32_t size:模型大小。

      4.uint32_t flag:特定的初始化标志。

    • 返回值:int 错误码(见 1.RKNN API函数返回值错误码)。

  • rknn_destroy

    • 函数说明:销毁 rknn_context 对象及其相关资源。

    • 入参:rknn_context context:要销毁的 rknn_context 对象。

    • 返回值:int 错误码(见 1.RKNN API函数返回值错误码)。

  • rknn_query

    • 函数说明:查询模型与 SDK 的相关信息。
    • 入参:

      1.rknn_context context:rknn_context 对象。

      2.rknn_query_cmd cmd:查询命令。

      3.void* info:存放返回结果的结构体变量。

      4.uint32_t size:info 对应的结构体变量的大小。
    • 返回值:int 错误码(见 1.RKNN API函数返回值错误码)。
  • rknn_inputs_set

    • 函数说明:设置模型输入数据。

    • 入参:

      1.rknn_context context:rknn_contex 对象。

      2.uint32_t n_inputs:输入数据个数。

      3.rknn_input inputs[]:输入数据数组,数组每个元素是 rknn_input 结构体对象。

    • 返回值:int 错误码(见 1.RKNN API函数返回值错误码)。

  • rknn_run

    • 函数说明:执行一次模型推理。

    • 入参:

      1.rknn_context context:rknn_context 对象。

      2.rknn_run_extend* extend:保留扩展,当前没有使用,传入 NULL 即可。

    • 返回值:int 错误码(见 1.RKNN API函数返回值错误码)。

  • rknn_outputs_get

    • 函数说明:获取模型推理输出

    • 入参:

      1.rknn_context context:rknn_context 对象。

      2.uint32_t n_outputs:输出数据个数。

      3.rknn_output outputs[]:输出数据的数组,其中数组每个元素为 rknn_output 结构体对象,代表模型的一个输出。

      4.rknn_output_extend* extend:保留扩展,当前没有使用,传入 NULL 即可。

    • 返回值:int 错误码(见 1.RKNN API函数返回值错误码)。

  • rknn_outputs_release

    • 函数说明:释放 rknn_output 对象。

    • 入参:

      1.rknn_context context:rknn_context 对象。

      2.uint32_t n_outputs:输出数据个数。

      3.rknn_output outputs[]:要销毁的 rknn_output 数组。

    • 返回值:int 错误码(见 1.RKNN API函数返回值错误码)。

3.封装代码

net.h

#ifndef _RKNN_NET_H
#define _RKNN_NET_H

#include "opencv2/opencv.hpp"
#include "rknn_api.h"

typedef struct {
  int w;
  int h;
  int c;
  float* data;
} Tensor;

class Extractor;
class Net {
public:
  rknn_context ctx;
  Net() = default;
  ~Net();
  Net(const Net& rhs) = delete;
  Net& operator=(const Net& rhs) = delete;
  void clear();
  int loadModel(const char* filename);
  Extractor createExtractor() const;
};

class Extractor {
private:
  const Net* net;
  rknn_input_output_num io_num;
  rknn_output* outputs;
  rknn_tensor_attr* output_attr;

public:
  ~Extractor();
  int input(const cv::Mat& in);
  int extract(int blob_index, Tensor& feat);

protected:
  friend Extractor Net::createExtractor() const;
  Extractor(const Net* net);
};

#endif

net.cpp

#include "rknn_net.h"

#include <stdio.h>
#include <stdlib.h>

Net::~Net() { clear(); }

int Net::loadModel(const char *filename) {
  FILE *fp = fopen(filename, "rb");
  if (fp == nullptr) {
      printf("fopen %s fail!\n", filename);
      return -1;
  }
  fseek(fp, 0, SEEK_END);
  size_t 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);
      model = nullptr;
      return -2;
  }
  if (fp) {
      fclose(fp);
  }
  int ret = rknn_init(&ctx, model, model_len, 0);
  if (ret < 0) {
      free(model);
      model = nullptr;
      printf("rknn_init fail! ret=%d\n", ret);
      return -3;
  }
  free(model);
  model = nullptr;
  return 0;
}

Extractor Net::createExtractor() const { return Extractor(this); }

void Net::clear() {
  if (ctx >= 0) {
      rknn_destroy(ctx);
  }
}

Extractor::Extractor(const Net *_net) : net(_net) {
  int ret =
      rknn_query(net->ctx, RKNN_QUERY_IN_OUT_NUM, &io_num, sizeof(io_num));
  if (ret != RKNN_SUCC) {
      printf("rknn_query fail! ret=%d\n", ret);
      return;
  }

  outputs = (rknn_output *)malloc(sizeof(rknn_output) * io_num.n_output);
  memset(outputs, 0, sizeof(rknn_output) * io_num.n_output);
  for (size_t i = 0; i < io_num.n_output; i++) {
      outputs[i].want_float = 1;
  }

  output_attr =
      (rknn_tensor_attr *)malloc(sizeof(rknn_tensor_attr) * io_num.n_output);
  memset(output_attr, 0, sizeof(rknn_tensor_attr) * io_num.n_output);

  for (size_t i = 0; i < io_num.n_output; i++) {
      output_attr[i].index = i;
      ret = rknn_query(net->ctx, RKNN_QUERY_OUTPUT_ATTR, &(output_attr[i]),
                       sizeof(rknn_tensor_attr));
      if (ret != RKNN_SUCC) {
          printf("rknn_query fail! ret=%d\n", ret);
      }
  }
}

Extractor::~Extractor() {
  rknn_outputs_release(net->ctx, io_num.n_output, outputs);
  if (outputs) {
      free(outputs);
      outputs = nullptr;
  }
  if (output_attr) {
      free(output_attr);
      output_attr = nullptr;
  }
}

int Extractor::input(const cv::Mat &in) {
  if (in.empty()) {
      return -1;
  }
  rknn_input inputs[io_num.n_input];
  memset(inputs, 0, sizeof(inputs));
  inputs[0].index = 0;
  inputs[0].type = RKNN_TENSOR_UINT8;
  inputs[0].size = in.cols * in.rows * in.channels();
  inputs[0].fmt = RKNN_TENSOR_NHWC;
  inputs[0].buf = in.data;

  int ret = rknn_inputs_set(net->ctx, io_num.n_input, inputs);
  if (ret < 0) {
      printf("rknn_input_set fail! ret=%d\n", ret);
      return -3;
  }
  ret = rknn_run(net->ctx, nullptr);
  if (ret < 0) {
      printf("rknn_run fail! ret=%d\n", ret);
      return -4;
  }
  ret = rknn_outputs_get(net->ctx, io_num.n_output, outputs, NULL);
  if (ret < 0) {
      printf("rknn_outputs_get fail! ret=%d\n", ret);
      return -5;
  }
  return 0;
}

int Extractor::extract(int blob_index, Tensor &feat) {
  feat.c = output_attr[blob_index].dims[2];
  feat.h = output_attr[blob_index].dims[1];
  feat.w = output_attr[blob_index].dims[0];
  feat.data = (float *)outputs[blob_index].buf;
  return 0;
}


源码文件点我下载

  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Ant5985

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

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

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

打赏作者

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

抵扣说明:

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

余额充值