转换模型
ncnn(https://github.com/Tencent/ncnn)编译好后,tools内有一个onnx2ncnn的工具,直接使用此工具即可将onnx模型转换为ncnn模型,命令如下:
cd /home/darrenzhang/ncnn/build/tools/onnx
./onnx2ncnn resnet18-v2-7.onnx resnet18.param resnet18.bin
生成resnet18的param文件和bin文件,其中,param文件保存了模型结构,bin文件保存了模型参数。
C++ 调用
测试ncnn模型的前向推理结果的正确性,导入ncnn的库和头文件后,调用代码如下:
CMakeLists.txt文件如下
cmake_minimum_required(VERSION 3.17)
project(ncnn_res_cls)
set( OpenCV_DIR /home/darrenzhang/opencv/usr/local/lib/cmake/opencv4)
find_package(OpenCV REQUIRED)
FIND_PACKAGE( OpenMP REQUIRED)
if(OPENMP_FOUND)
message("OPENMP FOUND")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()
set(CMAKE_CXX_STANDARD 11)
include_directories(/home/darrenzhang/ncnn/build/install/include/ncnn)
link_directories(/home/darrenzhang/ncnn/build/install/lib)
add_executable(ncnn_res_cls main.cpp)
target_link_libraries(ncnn_res_cls ${OpenCV_LIBS}
/home/darrenzhang/ncnn/build/install/lib/libncnn.a)
main.cpp代码如下
//
// Created by darrenzhang on 2021/3/3.
//
#include <opencv2/opencv.hpp>
#include <fstream>
#include "platform.h"
#include "net.h"
using namespace std;
using namespace cv;
vector<string> split(const string& str, const string& pattern) {
vector<string> ret;
if (pattern.empty()) return ret;
size_t start = 0, index = str.find_first_of(pattern, 0);
while (index != str.npos) {
if (start != index)
ret.push_back(str.substr(start, index - start));
start = index + 1;
index = str.find_first_of(pattern, start);
}
if (!str.substr(start).empty())
ret.push_back(str.substr(start));
return ret;
}
void get_label(vector<string> &labels, const char* file_path) {
FILE *fp = fopen(file_path, "r");
ifstream infile;
string temp;
const char*d = ":";
infile.open(file_path);
while(getline(infile, temp)) {
vector<string> line = split(temp, ":");
labels.push_back((line[1]));
}
}
static int print_topk(const std::vector<float>& cls_scores, int topk,vector<string> labels)
{
// partial sort topk with index
int size = cls_scores.size();
std::vector< std::pair<float, int> > vec;
vec.resize(size);
for (int i=0; i<size; i++)
{
vec[i] = std::make_pair(cls_scores[i], i);
}
std::partial_sort(vec.begin(), vec.begin() + topk, vec.end(),
std::greater< std::pair<float, int> >());
// print topk and score
for (int i=0; i<topk; i++)
{
float score = vec[i].first;
int index = vec[i].second;
string label = labels[index];
fprintf(stderr, "%d = %f %s \n", index, score ,label.c_str());
}
return 0;
}
int main() {
vector<string> labels;
get_label(labels, "/home/darrenzhang/CLionProjects/ncnn_res_cls/data/label.txt");
cv::Mat img = cv::imread("/home/darrenzhang/CLionProjects/ncnn_res_cls/data/test.jpg");
int img_w = img.cols;
int img_h = img.rows;
ncnn::Mat input_img = ncnn::Mat::from_pixels_resize(
img.data, ncnn::Mat::PIXEL_BGR, img.cols, img.rows, 224, 224
);
const float mean_vals[3] = {104.0f,117.0f,123.0f};
const float norm_vals[3] = {0.007843f, 0.007843f, 0.007843f};
input_img.substract_mean_normalize(mean_vals, norm_vals); // normalize for input img
ncnn::Net resnet18;
resnet18.load_param("/home/darrenzhang/CLionProjects/ncnn_res_cls/model/resnet.param");
resnet18.load_model("/home/darrenzhang/CLionProjects/ncnn_res_cls/model/resnet.bin");
ncnn::Extractor ex = resnet18.create_extractor(); // 定义解析器,解析特征平面
ex.set_num_threads(4);
ex.input("data", input_img);
ncnn::Mat out; // define the ncnn`s output
ex.extract("resnetv22_dense0_fwd", out); // extract the last layer`s output of the model
vector<float> output;
output.resize(out.w);
for (int i = 0; i < out.w; i ++)
output[i] = out[i];
print_topk(output, 2, labels);
}
报错如下:
locate libopencv_imgproc.so.4.1
进入到/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
在debug或者运行可执行文件的时候,可执行文件在cmake-build-debug文件夹中,所以模型路径和测试文件路径要根据可执行文件的路径来设置。