转换模型

ncnn(https://github.com/Tencent/ncnn)编译好后,tools内有一个onnx2ncnn的工具,直接使用此工具即可将onnx模型转换为ncnn模型,命令如下:

  1. cd /home/darrenzhang/ncnn/build/tools/onnx
  2. ./onnx2ncnn resnet18-v2-7.onnx resnet18.param resnet18.bin

sendpix1.jpg
生成resnet18的param文件和bin文件,其中,param文件保存了模型结构,bin文件保存了模型参数。

C++ 调用

测试ncnn模型的前向推理结果的正确性,导入ncnn的库和头文件后,调用代码如下:

CMakeLists.txt文件如下

  1. cmake_minimum_required(VERSION 3.17)
  2. project(ncnn_res_cls)
  3. set( OpenCV_DIR /home/darrenzhang/opencv/usr/local/lib/cmake/opencv4)
  4. find_package(OpenCV REQUIRED)
  5. FIND_PACKAGE( OpenMP REQUIRED)
  6. if(OPENMP_FOUND)
  7. message("OPENMP FOUND")
  8. set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
  9. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
  10. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
  11. endif()
  12. set(CMAKE_CXX_STANDARD 11)
  13. include_directories(/home/darrenzhang/ncnn/build/install/include/ncnn)
  14. link_directories(/home/darrenzhang/ncnn/build/install/lib)
  15. add_executable(ncnn_res_cls main.cpp)
  16. target_link_libraries(ncnn_res_cls ${OpenCV_LIBS}
  17. /home/darrenzhang/ncnn/build/install/lib/libncnn.a)

main.cpp代码如下

  1. //
  2. // Created by darrenzhang on 2021/3/3.
  3. //
  4. #include <opencv2/opencv.hpp>
  5. #include <fstream>
  6. #include "platform.h"
  7. #include "net.h"
  8. using namespace std;
  9. using namespace cv;
  10. vector<string> split(const string& str, const string& pattern) {
  11. vector<string> ret;
  12. if (pattern.empty()) return ret;
  13. size_t start = 0, index = str.find_first_of(pattern, 0);
  14. while (index != str.npos) {
  15. if (start != index)
  16. ret.push_back(str.substr(start, index - start));
  17. start = index + 1;
  18. index = str.find_first_of(pattern, start);
  19. }
  20. if (!str.substr(start).empty())
  21. ret.push_back(str.substr(start));
  22. return ret;
  23. }
  24. void get_label(vector<string> &labels, const char* file_path) {
  25. FILE *fp = fopen(file_path, "r");
  26. ifstream infile;
  27. string temp;
  28. const char*d = ":";
  29. infile.open(file_path);
  30. while(getline(infile, temp)) {
  31. vector<string> line = split(temp, ":");
  32. labels.push_back((line[1]));
  33. }
  34. }
  35. static int print_topk(const std::vector<float>& cls_scores, int topk,vector<string> labels)
  36. {
  37. // partial sort topk with index
  38. int size = cls_scores.size();
  39. std::vector< std::pair<float, int> > vec;
  40. vec.resize(size);
  41. for (int i=0; i<size; i++)
  42. {
  43. vec[i] = std::make_pair(cls_scores[i], i);
  44. }
  45. std::partial_sort(vec.begin(), vec.begin() + topk, vec.end(),
  46. std::greater< std::pair<float, int> >());
  47. // print topk and score
  48. for (int i=0; i<topk; i++)
  49. {
  50. float score = vec[i].first;
  51. int index = vec[i].second;
  52. string label = labels[index];
  53. fprintf(stderr, "%d = %f %s \n", index, score ,label.c_str());
  54. }
  55. return 0;
  56. }
  57. int main() {
  58. vector<string> labels;
  59. get_label(labels, "/home/darrenzhang/CLionProjects/ncnn_res_cls/data/label.txt");
  60. cv::Mat img = cv::imread("/home/darrenzhang/CLionProjects/ncnn_res_cls/data/test.jpg");
  61. int img_w = img.cols;
  62. int img_h = img.rows;
  63. ncnn::Mat input_img = ncnn::Mat::from_pixels_resize(
  64. img.data, ncnn::Mat::PIXEL_BGR, img.cols, img.rows, 224, 224
  65. );
  66. const float mean_vals[3] = {104.0f,117.0f,123.0f};
  67. const float norm_vals[3] = {0.007843f, 0.007843f, 0.007843f};
  68. input_img.substract_mean_normalize(mean_vals, norm_vals); // normalize for input img
  69. ncnn::Net resnet18;
  70. resnet18.load_param("/home/darrenzhang/CLionProjects/ncnn_res_cls/model/resnet.param");
  71. resnet18.load_model("/home/darrenzhang/CLionProjects/ncnn_res_cls/model/resnet.bin");
  72. ncnn::Extractor ex = resnet18.create_extractor(); // 定义解析器,解析特征平面
  73. ex.set_num_threads(4);
  74. ex.input("data", input_img);
  75. ncnn::Mat out; // define the ncnn`s output
  76. ex.extract("resnetv22_dense0_fwd", out); // extract the last layer`s output of the model
  77. vector<float> output;
  78. output.resize(out.w);
  79. for (int i = 0; i < out.w; i ++)
  80. output[i] = out[i];
  81. print_topk(output, 2, labels);
  82. }

报错如下:
sendpix2.jpg

locate  libopencv_imgproc.so.4.1

image.png
进入到/etc/ld.so.conf.d

cd etc/ld.so.conf.d
sudo vi OpenCV.conf
/home/darrenzhang/opencv/usr/local/lib/
sudo ldconfig -v

报错内容2:
内存溢出,使用断点调试发现如下错误,模型加载问题

fopen resnet.param failed
fopen resnet.bin failed
find_blob_index_by_name data failed
find_blob_index_by_name prob failed

image.png
在debug或者运行可执行文件的时候,可执行文件在cmake-build-debug文件夹中,所以模型路径和测试文件路径要根据可执行文件的路径来设置。