Toybrick

标题: [C++ API] 如何使用rknn_init初始化多个模型 [打印本页]

作者: nevin007    时间: 2019-3-5 15:34
标题: [C++ API] 如何使用rknn_init初始化多个模型
本帖最后由 nevin007 于 2019-3-7 17:39 编辑

rknn_init初始化模型时间长,当需要运行2个以上模型的时候,应该是将所有的模型统一做初始化。

但是我试着初始化两个rknn模型,使用C++API,定义两个context,运行时会报错:load model done.
rknn_init fail! ret=-6
即第一个模型可以初始化成功,第二个模型会初始化失败!
--------------------------------------------------------------------------------------------------------------

回复中有说使用Python_API可以同时初始化多个模型,我试了下确实可以,但是使用C++_API确实不行...
希望官方能确认下是使用的问题还是C++_API的问题,非常感谢!



作者: seedlin    时间: 2019-3-5 17:50
车牌识别的那个人写的就是2个模型同时运行的,你init必须是2个对象,你不会只创建一个rknn对象,然后init两次吧。
def load_model(modle_path):
        # Create RKNN object
        rknn = RKNN()

        print("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
        print('-->loading model')
        rknn.load_rknn(modle_path)
        print('loading model done')

        # init runtime environment
        print('--> Init runtime environment')
        ret = rknn.init_runtime()
        if ret != 0:
                print('Init runtime environment failed')
                exit(ret)
        print('done')
        print("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
        return rknn
作者: nevin007    时间: 2019-3-5 18:01
seedlin 发表于 2019-3-5 17:50
车牌识别的那个人写的就是2个模型同时运行的,你init必须是2个对象,你不会只创建一个rknn对象,然后init两 ...

我用的是c++的API,在init前好像只有加载rknn模型的操作
作者: elooon    时间: 2019-3-5 19:54
nevin007 发表于 2019-3-5 18:01
我用的是c++的API,在init前好像只有加载rknn模型的操作

你是只分配了一个rknn_context变量,然后对这个变量执行了两次init?
作者: nevin007    时间: 2019-3-6 09:57
elooon 发表于 2019-3-5 19:54
你是只分配了一个rknn_context变量,然后对这个变量执行了两次init?


int load_model(std::vector<const char *>& net,
                std::vector<rknn_context> &ctx)
{
    FILE *fp;
    int model_len=0;
    int ret = 0;
    rknn_context context=0;
    rknn_context context_2=0;

    // load rknn model1
    fp = fopen(net[0], "rb");
    if(fp == NULL) {
        printf("fopen %s fail!\n", net[0]);
        return -1;
    }
    fseek(fp, 0, SEEK_END);
    model_len = ftell(fp);               
    model_net_1 = malloc(model_len);         
    fseek(fp, 0, SEEK_SET);
    if(model_len != fread(model_net_1, 1, model_len, fp)) {
        printf("fread %s fail!\n", net[0]);
        free(model_net_1);
        return -1;
    }
    printf("model_len:%d\n",model_len);

    // rknn_init
    ret = rknn_init(&context, model_net_1, model_len, RKNN_FLAG_PRIOR_MEDIUM);                    
    if(ret < 0) {
        printf("rknn_init fail! ret=%d\n", ret);
        source_release(context, model_net_1);
        return -1;
    }
    ctx.push_back(context);
    printf("[debug] ctx[0]:%ld\n",context);
    fclose(fp);
    model_len = 0;


    // load rknn model2
    fp = fopen(net[1], "rb");
    if(fp == NULL) {
        printf("fopen %s fail!\n", net[1]);
        return -1;
    }
    fseek(fp, 0, SEEK_END);
    model_len = ftell(fp);               
    model_net_2 = malloc(model_len);         
    fseek(fp, 0, SEEK_SET);
    if(model_len != fread(model_net_2, 1, model_len, fp)) {
        printf("fread %s fail!\n", net[1]);
        free(model_net_2);
        return -1;
    }
    printf("model_len:%d\n",model_len);

    // rknn_init
    ret = rknn_init(&context_2, model_net_2, model_len, RKNN_FLAG_PRIOR_MEDIUM);                    
    if(ret < 0) {
        printf("rknn_init fail! ret=%d\n", ret);
        source_release(context_2, model_net_2);
        return -1;
    }
    ctx.push_back(context_2);
    printf("[debug] ctx[1]:%ld\n",context_2);
    fclose(fp);

    free(model_net_1);
    free(model_net_2);
    return 0;
}




我定义了2个context,运行后错误信息如下:
model_len:17347
[debug] ctx[0]:416131600
model_len:17350
rknn_init fail! ret=-6
ctx.size:1

只能注册一个模型...



作者: yhc    时间: 2019-3-6 10:25
请问单独初始化第二个模型可以吗
作者: nevin007    时间: 2019-3-6 10:30
yhc 发表于 2019-3-6 10:25
请问单独初始化第二个模型可以吗

可以的,单独运行上半部分或者下半部分都没有问题
作者: yhc    时间: 2019-3-6 10:51
-6是报RKNN_ERR_MODEL_INVALID,17350确定是第二个模型的大小是吗,有没有读错文件什么的呢
作者: nevin007    时间: 2019-3-6 11:39
本帖最后由 nevin007 于 2019-3-6 11:45 编辑
yhc 发表于 2019-3-6 10:51
-6是报RKNN_ERR_MODEL_INVALID,17350确定是第二个模型的大小是吗,有没有读错文件什么的呢 ...

是的,模型我都单独运行过,没有问题...不会是同时只能有一个ctx吧...
灰掉上半部分,初始化下半部分是正常的:
model_len:17350
[debug] ctx[1]:595593744
ctx.size:1

就是不能两个同时初始化...


作者: protossw512    时间: 2019-3-7 11:40
nevin007 发表于 2019-3-6 11:39
是的,模型我都单独运行过,没有问题...不会是同时只能有一个ctx吧...
灰掉上半部分,初始化下半部分是正 ...

你好,你在c++运行的时候有发现c++下面跑模型比python下面慢么?
作者: nevin007    时间: 2019-3-7 13:41
protossw512 发表于 2019-3-7 11:40
你好,你在c++运行的时候有发现c++下面跑模型比python下面慢么?

推理速度还好,主要是init时间太长了
作者: protossw512    时间: 2019-3-7 16:36
nevin007 发表于 2019-3-7 13:41
推理速度还好,主要是init时间太长了

我今天专门分别在两边测试了下,发现c++ inference的速度比Python慢差不多一倍。不知道是哪里的问题。。你的c++ api是0.9.3吗?
作者: nevin007    时间: 2019-3-7 16:48
protossw512 发表于 2019-3-7 16:36
我今天专门分别在两边测试了下,发现c++ inference的速度比Python慢差不多一倍。不知道是哪里的问题。。 ...

你好,我用的C++API版本是0.9.3,我测试过它自带的mobilenet-ssd,用SDK自带的测试函数:python约10ms,c++约12ms,你是怎么测试的?
作者: protossw512    时间: 2019-3-8 05:24
nevin007 发表于 2019-3-7 16:48
你好,我用的C++API版本是0.9.3,我测试过它自带的mobilenet-ssd,用SDK自带的测试函数:python约10ms,c ...

奇怪了,我这里直接跑那个rknn_ssd需要22ms。你是在pc上交叉编译好了然后再在3399pro上运行的吗?还是直接在3399pro上编译运行的?我是后者。
作者: protossw512    时间: 2019-3-8 07:09
protossw512 发表于 2019-3-8 05:24
奇怪了,我这里直接跑那个rknn_ssd需要22ms。你是在pc上交叉编译好了然后再在3399pro上运行的吗?还是直 ...

我终于找到原因了,因为我在init的时候加了RKNN_FLAG_COLLECT_PERF_MASK的flag,所以速度会变慢。。。然而不用加也能够测试速度。
作者: nevin007    时间: 2019-3-8 09:21
protossw512 发表于 2019-3-8 07:09
我终于找到原因了,因为我在init的时候加了RKNN_FLAG_COLLECT_PERF_MASK的flag,所以速度会变慢。。。然而 ...

那你能同时初始化多个模型再做推理么
作者: protossw512    时间: 2019-3-9 05:16
nevin007 发表于 2019-3-8 09:21
那你能同时初始化多个模型再做推理么

我还没试过,项目暂时还没用到多个模型。你是怎么实现的?是同样的rknn_context init多次么? 还是说不同的rknn_context?
作者: nevin007    时间: 2019-3-11 09:30
protossw512 发表于 2019-3-9 05:16
我还没试过,项目暂时还没用到多个模型。你是怎么实现的?是同样的rknn_context init多次么? 还是说不同 ...

不同的context,我试过python可以,c++不行...
作者: elooon    时间: 2019-3-11 16:25
nevin007 发表于 2019-3-11 09:30
不同的context,我试过python可以,c++不行...

I rewrite the official demo to init two models, it works.
just for test,ignore the dirty code.
code:

  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <stdlib.h>
  4. #include <fstream>
  5. #include <iostream>
  6. #include <algorithm>
  7. #include <queue>
  8. #include <sys/time.h>

  9. #include "rknn_api.h"
  10. #include "opencv2/core/core.hpp"
  11. #include "opencv2/imgproc/imgproc.hpp"
  12. #include "opencv2/highgui/highgui.hpp"

  13. using namespace std;

  14. template <class T>
  15. void get_top_n(T* prediction, int prediction_size, size_t num_results,
  16.                float threshold, std::vector<std::pair<float, int>>* top_results,
  17.                bool input_floating) {
  18.   // Will contain top N results in ascending order.
  19.   std::priority_queue<std::pair<float, int>, std::vector<std::pair<float, int>>,
  20.                       std::greater<std::pair<float, int>>>
  21.       top_result_pq;

  22.   const long count = prediction_size;  // NOLINT(runtime/int)
  23.   for (int i = 0; i < count; ++i) {
  24.     float value;
  25.     if (input_floating)
  26.       value = prediction[i];
  27.     else
  28.       value = prediction[i] / 255.0;
  29.     // Only add it if it beats the threshold and has a chance at being in
  30.     // the top N.
  31.     if (value < threshold) {
  32.       continue;
  33.     }

  34.     top_result_pq.push(std::pair<float, int>(value, i));

  35.     // If at capacity, kick the smallest value out.
  36.     if (top_result_pq.size() > num_results) {
  37.       top_result_pq.pop();
  38.     }
  39.   }

  40.   // Copy to output vector and reverse into descending order.
  41.   while (!top_result_pq.empty()) {
  42.     top_results->push_back(top_result_pq.top());
  43.     top_result_pq.pop();
  44.   }
  45.   std::reverse(top_results->begin(), top_results->end());
  46. }

  47. int ReadLabelsFile(const string& file_name,
  48.                             std::vector<string>* result,
  49.                             size_t* found_label_count) {
  50.   std::ifstream file(file_name);
  51.   if (!file) {
  52.     std::cerr << "Labels file " << file_name << " not found\n";
  53.     return -1;
  54.   }
  55.   result->clear();
  56.   string line;
  57.   while (std::getline(file, line)) {
  58.     result->push_back(line);
  59.   }
  60.   *found_label_count = result->size();
  61.   const int padding = 16;
  62.   while (result->size() % padding) {
  63.     result->emplace_back();
  64.   }
  65.   return 0;
  66. }

  67. int main(int argc, char** argv)
  68. {
  69.     const char *img_path = "/home/toybrick/work/test/tmp/dog.jpg";
  70.     const char *model_path = "/home/toybrick/work/test/tmp/mobilenet_v1-tf.rknn";
  71.     const char *model_path2 = "/home/toybrick/work/test/tmp/mobilenet_ssd.rknn";
  72.     const char *lable_path = "/home/toybrick/work/test/tmp/labels.txt";
  73.     const int output_elems = 1001;

  74.     const int img_width = 224;
  75.     const int img_height = 224;
  76.     const int img_channels = 3;

  77.     const int input_index = 0;      // node name "input"
  78.     const int output_index = 0;     // node name "MobilenetV1/Predictions/Reshape_1"

  79.     // Load image
  80.     cv::Mat img = cv::imread(img_path, 1);
  81.     if(!img.data) {
  82.         printf("cv::imread %s fail!\n", img_path);
  83.         return -1;
  84.     }
  85.     if(img.cols != img_width || img.rows != img_height)
  86.         cv::resize(img, img, cv::Size(img_width, img_height), (0, 0), (0, 0), cv::INTER_LINEAR);

  87.     //BGR->RGB
  88.     cv::cvtColor(img, img, cv::COLOR_BGR2RGB);

  89.     // Load model
  90.     FILE *fp = fopen(model_path, "rb");
  91.     if(fp == NULL) {
  92.         printf("fopen %s fail!\n", model_path);
  93.         return -1;
  94.     }
  95.     fseek(fp, 0, SEEK_END);
  96.     int model_len = ftell(fp);
  97.     void *model = malloc(model_len);
  98.     fseek(fp, 0, SEEK_SET);
  99.     if(model_len != fread(model, 1, model_len, fp)) {
  100.         printf("fread %s fail!\n", model_path);
  101.         free(model);
  102.         return -1;
  103.     }

  104.     // Start Inference
  105.     rknn_input inputs[1];
  106.     rknn_output outputs[1];
  107.     rknn_tensor_attr output0_attr;

  108.     int ret = 0;
  109.     void *model2;
  110.     rknn_context ctx1 = 0;
  111.     rknn_context ctx2 = 0;

  112.     ret = rknn_init(&ctx1, model, model_len, RKNN_FLAG_PRIOR_MEDIUM);
  113.     if(ret < 0) {
  114.         printf("rknn_init fail! ret=%d\n", ret);
  115.         goto Error;
  116.     }

  117.     printf("rknn_init 1 succeed! ret=%d\n", ret);

  118.     fclose(fp);
  119.     model_len = 0;

  120.     // Load model
  121.     fp = fopen(model_path2, "rb");
  122.     if(fp == NULL) {
  123.         printf("fopen %s fail!\n", model_path);
  124.         return -1;
  125.     }
  126.     fseek(fp, 0, SEEK_END);
  127.     model_len = ftell(fp);
  128.     model2 = malloc(model_len);
  129.     fseek(fp, 0, SEEK_SET);
  130.     if(model_len != fread(model2, 1, model_len, fp)) {
  131.         printf("fread %s fail!\n", model_path2);
  132.         free(model2);
  133.         return -1;
  134.     }

  135.     ret = rknn_init(&ctx2, model2, model_len, RKNN_FLAG_PRIOR_MEDIUM);
  136.     if(ret < 0) {
  137.         printf("rknn_init fail! ret=%d\n", ret);
  138.         goto Error;
  139.     }

  140.     printf("rknn_init 2 succeed! ret=%d\n", ret);

  141.     output0_attr.index = 0;
  142.     ret = rknn_query(ctx1, RKNN_QUERY_OUTPUT_ATTR, &output0_attr, sizeof(output0_attr));
  143.     if(ret < 0) {
  144.         printf("rknn_query fail! ret=%d\n", ret);
  145.         goto Error;
  146.     }

  147.     inputs[0].index = input_index;
  148.     inputs[0].buf = img.data;
  149.     inputs[0].size = img_width * img_height * img_channels;
  150.     inputs[0].pass_through = false;
  151.     inputs[0].type = RKNN_TENSOR_UINT8;
  152.     inputs[0].fmt = RKNN_TENSOR_NHWC;
  153.     ret = rknn_inputs_set(ctx1, 1, inputs);
  154.     if(ret < 0) {
  155.         printf("rknn_input_set fail! ret=%d\n", ret);
  156.         goto Error;
  157.     }

  158.     ret = rknn_run(ctx1, nullptr);
  159.     if(ret < 0) {
  160.         printf("rknn_run fail! ret=%d\n", ret);
  161.         goto Error;
  162.     }

  163.     outputs[0].want_float = true;
  164.     outputs[0].is_prealloc = false;
  165.     ret = rknn_outputs_get(ctx1, 1, outputs, nullptr);
  166.     if(ret < 0) {
  167.         printf("rknn_outputs_get fail! ret=%d\n", ret);
  168.         goto Error;
  169.     }

  170.     // Process output
  171.     if(outputs[0].size == output0_attr.n_elems * sizeof(float))
  172.     {
  173.         const size_t num_results = 5;
  174.         const float threshold = 0.001f;

  175.         std::vector<std::pair<float, int>> top_results;
  176.         get_top_n<float>((float*)outputs[0].buf, output_elems,
  177.                            num_results, threshold, &top_results, true);

  178.         std::vector<string> labels;
  179.         size_t label_count;
  180.         if (!ReadLabelsFile(lable_path, &labels, &label_count)) {
  181.             for (const auto& result : top_results) {
  182.                 const float confidence = result.first;
  183.                 const int index = result.second;
  184.                 std::cout << confidence << ": " << index << " " << labels[index] << "\n";
  185.             }
  186.         }
  187.     }
  188.     else
  189.     {
  190.         printf("rknn_outputs_get fail! get output_size = [%d], but expect %u!\n",
  191.             outputs[0].size, (uint32_t)(output0_attr.n_elems * sizeof(float)));
  192.     }

  193.     rknn_outputs_release(ctx1, 1, outputs);

  194. Error:
  195.     if(ctx1 > 0)        rknn_destroy(ctx1);
  196.     if(model)           free(model);
  197.     if(fp)              fclose(fp);
  198.     return 0;
  199. }
复制代码

作者: elooon    时间: 2019-3-11 16:29
outputs:

[toybrick@localhost build]$ ./rknn_mobilenet
rknn_init 1 succeed! ret=0
rknn_init 2 succeed! ret=0
0.842285: 156 Shih-Tzu
0.0474243: 155 Pekinese
0.0256042: 188 Yorkshire terrier
0.0138168: 205 Lhasa
0.00746155: 263 Brabancon griffon
作者: hjf515    时间: 2019-3-11 19:23
请问加载多个模型的问题有解决么?
我也需要加载多个模型,每次加载前都需要init,那就太慢了。
作者: nevin007    时间: 2019-3-12 10:22
elooon 发表于 2019-3-11 16:29
outputs:

[toybrick@localhost build]$ ./rknn_mobilenet

非常感谢!我测试了你的Demo,确实可以跑通。在此基础上,我进一步做了几个测试:
1、将model_path2(ctx2)替换成MTCNN中的RNet和ONet,结果也都可以同时初始化;
2、将model_path2(ctx2)替换成MTCNN中的PNet,运行时仍然会报错:
rknn_init 1 succeed! ret=0
rknn_init fail! ret=-6
3、在对PNet做模型转换时,设置do_quantization=False,即不做量化,替换第2步中的模型再次执行,结果可以正常初始化!
综上测试,可以看出,C++API支持初始化多个模型,但对于少数模型(如PNet这种全卷积网络)仅支持非量化的模型...
作者: nevin007    时间: 2019-3-12 10:23
hjf515 发表于 2019-3-11 19:23
请问加载多个模型的问题有解决么?
我也需要加载多个模型,每次加载前都需要init,那就太慢了。 ...

你好,可以参考22楼的测试结果
作者: elooon    时间: 2019-3-12 16:06
nevin007 发表于 2019-3-12 10:22
非常感谢!我测试了你的Demo,确实可以跑通。在此基础上,我进一步做了几个测试:
1、将model_path2(ctx2 ...

emmm....
Can PNet which is quantificated(do_quantization=True) be init succeed alone?
作者: nevin007    时间: 2019-3-12 17:01
elooon 发表于 2019-3-12 16:06
emmm....
Can PNet which is quantificated(do_quantization=True) be init succeed alone?

Multi-scale models, PNet1, PNet2 and so on, will be created when PNet is quantificated(do_quantization=True). As inference, PNet2 model which must be initialized after PNet1 has finished running. However, if do_quantization=False, they can be initialized simultaneously.




欢迎光临 Toybrick (https://t.rock-chips.com/) Powered by Discuz! X3.3