×

签到

分享到微信

打开微信,使用扫一扫进入页面后,点击右上角菜单,

点击“发送给朋友”或“分享到朋友圈”完成分享

【经验总结】cnrt之yolov3离线模型运行示例 wyy2021-01-25 15:57:02 回复 4 查看 思元270
【经验总结】cnrt之yolov3离线模型运行示例
分享到:

对yolov3离线模型运行仍然分为预处理、推理、后处理三个部分。由原模型生成的离线模型可以借助cnrt进行推理,从而脱离了深度学习框架。

首先是对cnrt的一些参数进行初始化,而这些参数从yolov3离线模型获得。部分代码如下:

//获取模型输入/输出的数据大小及节点个数
CNRT_CHECK(cnrtGetInputDataSize(&inputSizeS,&inputNum,function));
CNRT_CHECK(cnrtGetOutputDataSize(&outputSizeS,&outputNum,function));
    
//获取模型输入/输出的数据类型
CNRT_CHECK(cnrtGetInputDataType(&inputTypeS,&inputNum,function));
CNRT_CHECK(cnrtGetOutputDataType(&outputTypeS,&outputNum,function));

//分配 存放CPU端输入/输出地址的 指针数组
inputCpuPtrS = (void **)malloc(sizeof(void *) * inputNum);
outputCpuPtrS = (void **)malloc(sizeof(void *) * outputNum);
outputCpuNchwPtrS = (void **)malloc(sizeof(void *) * outputNum);

//分配 存放MLU端输入/输出地址的 指针数组
outputMluPtrS = (void **)malloc(sizeof(void *) * outputNum);
inputMluPtrS = (void **)malloc(sizeof(void *) * inputNum);
//为输入节点 分配CPU/MLU内存
    for (int i = 0; i < inputNum; i++)
    {   
        CNRT_CHECK(cnrtMalloc(&inputMluPtrS[i],inputSizeS[i])); //分配MLU上内存
        inputCpuPtrS[i] = (void *)malloc(inputSizeS[i]); //分配CPU上的内存
        
        //获取输入的维度信息 NHWC
        CNRT_CHECK(cnrtGetInputDataShape(&dimValues,&dimNum,i,function));                        
        printf("input shape:\n");
        for(int y=0;y<dimNum;y++)
        {
            printf("%d ",dimValues[y]);
        }
        printf("\n");

        input_width=dimValues[2];
        input_height=dimValues[1];
        batch_size=dimValues[0];
        free(dimValues);
    }
//为输出节点 分配CPU/MLU内存
for (int i = 0; i < outputNum; i++) {
   CNRT_CHECK(cnrtMalloc(&outputMluPtrS[i],outputSizeS[i])); //分配MLU上内存    
   outputCpuPtrS[i] = (void *)malloc(outputSizeS[i]); //分配CPU上的内存
        
   //获取输出的维度信息 NHWC
   CNRT_CHECK(cnrtGetOutputDataShape(&dimValues,&dimNum,i,function));      
   int count=1;
   printf("output shape:\n");
   for(int y=0;y<dimNum;y++)
   {
     printf("%d ",dimValues[y]);
     count=count*dimValues[y];
   }
   printf("\n");       
   outputCpuNchwPtrS[i] = (void *)malloc(count*sizeof(float)); //将输出转为float32类型,方便用户后处理
   output_count.push_back(count);
   free(dimValues);
}

//配置MLU输入/输出 地址的指针
param = (void **)malloc(sizeof(void *) * (inputNum + outputNum));
for (int i = 0; i < inputNum; i++) {
   param[i] = inputMluPtrS[i];
}
for (int i = 0; i < outputNum; i++) {
   param[i + inputNum] = outputMluPtrS[i];
}

对输入的数据做预处理,同在线推理数据预处理保持一致。同时需要注意可以从离线模型信息文件*.cambricon_twins中可以得到输入输出类型以及形状等信息,在做预处理时如果使用opencv接口时要使数据类型保持一致,比如此时我们用了CV_8UC4。部分代码如下:

          cv::Mat sample_temp;

          float img_w = input_image.cols;
          float img_h = input_image.rows;
          cv::Mat sample_temp_bgr(input_image.cols, input_image.rows, CV_8UC4);
          float img_scale = img_w < img_h ? (input_height / img_h) : (input_width / img_w);
          int new_w = std::floor(img_w * img_scale);
          int new_h = std::floor(img_h * img_scale);
          cv::cvtColor(input_image, sample_temp_bgr, CV_BGR2BGRA);
          cv::resize(sample_temp_bgr, sample_temp, cv::Size(new_w, new_h), CV_INTER_LINEAR);
          
          cv::Mat net_input_data_rgba(input_height,input_width,CV_8UC4,ptr);
          sample_temp.copyTo(net_input_data_rgba(
                                             cv::Range((static_cast(input_height) - new_h) / 2,
                                                       (static_cast(input_height) - new_h) / 2 + new_h),
                                             cv::Range((static_cast(input_width) - new_w) / 2,
                                                       (static_cast(input_width) - new_w) / 2 + new_w)));
          ptr+=(input_height*input_width*4);

调用离线模型进行推理,部分代码如下:

unsigned int      affinity=1<<dev_channel;    //设置通道亲和性,使用指定的MLU cluster做推理
cnrtInvokeParam_t   invokeParam;                //invoke参数
invokeParam.invoke_param_type=CNRT_INVOKE_PARAM_TYPE_0;
invokeParam.cluster_affinity.affinity=&affinity;
CNRT_CHECK(cnrtInvokeRuntimeContext_V2(ctx,nullptr,param,queue,&invokeParam));

对推理后数据做后处理,同在线推理数据后处理保持一致,部分代码如下:

vector<vector<vector>> getResults(float* outputData,
                                         int dimNumm,
                                         int *dimValues) {
  vector<vector<vector>> detections;

  // BangOp implementation
  float max_limit = 1;
  float min_limit = 0;
  int batchSize = dimValues[0];
  int count = dimValues[3];
  for (int i = 0; i < batchSize; i++) {
    int num_boxes = static_cast(outputData[i * count]);
    vector<vector> batch_box;
    for (int k = 0; k < num_boxes; k++) {
      int index = i * count + 64 + k * 7;
      vector single_box;
      float bl = std::max(
          min_limit, std::min(max_limit, outputData[index + 3]));  // x1
      float br = std::max(
          min_limit, std::min(max_limit, outputData[index + 5]));  // x2
      float bt = std::max(
          min_limit, std::min(max_limit, outputData[index + 4]));  // y1
      float bb = std::max(
          min_limit, std::min(max_limit, outputData[index + 6]));  // y2
      single_box.push_back(bl);
      single_box.push_back(bt);
      single_box.push_back(br);
      single_box.push_back(bb);
      single_box.push_back(outputData[index + 2]);
      single_box.push_back(outputData[index + 1]);
      if ((br - bl) > 0 && (bb - bt) > 0) {
        batch_box.push_back(single_box);
      }
    }
    detections.push_back(batch_box);
  }
  return detections;
}

更多cnrt离线模型示例可以参考:http://www.cambricon.com/docs/cnrt/user_guide_html/example/offline_mode.html

版权所有 © 2024 寒武纪 Cambricon.com 备案/许可证号:京ICP备17003415号-1
关闭