瑞芯微Rockchip开发者社区
直播中

李平

7年用户 1193经验值
私信 关注
[问答]

如何将常用接口封装成类似于NCNN的接口调用形式?

如何将常用接口封装成类似于NCNN的接口调用形式?

回帖(1)

h1654155275.5684

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



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


[tr]错误码错误详情[/tr]
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
#include

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=%dn", 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=%dn", 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.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.index = i;
      ret = rknn_query(net->ctx, RKNN_QUERY_OUTPUT_ATTR, &(output_attr),
                       sizeof(rknn_tensor_attr));
      if (ret != RKNN_SUCC) {
          printf("rknn_query fail! ret=%dn", 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=%dn", ret);
      return -3;
  }
  ret = rknn_run(net->ctx, nullptr);
  if (ret < 0) {
      printf("rknn_run fail! ret=%dn", ret);
      return -4;
  }
  ret = rknn_outputs_get(net->ctx, io_num.n_output, outputs, NULL);
  if (ret < 0) {
      printf("rknn_outputs_get fail! ret=%dn", 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;
}
举报

更多回帖

发帖
×
20
完善资料,
赚取积分