一个简单的NCNN模型测试代码

NCNN模型测试

将Caffe、Pytorch等训练的模型转成NCNN模型(*.param和*.bin)之后就可以读取图像并执行推理任务了。

一、定义一个网络对象并加载模型参数

加载模型参数的方法有三种:

1. 直接加载转好的*.param和*.bin文件

ncnn::Net net;
net.load_param("./mymodel.param");
net.load_model("./mymodel.bin");

2. 加载二进制文件1

由于*.param文件中定义的网络结构且是直接可见的,因此不适合直接发布。NCNN提供了ncnn2mem工具可以将*.param和*.bin转成二进制数组的形式:
ncnn2mem mymodel.param mymodel.bin mymodel_idx.h mymodel_param.h
运行后会生成三个文件:mymodel.param.bin、mymodel_idx.h和mymodel_param.h

mymodel.param.bin便是mymodel.param文件的二进制形式,此时可以直接加载二进制param和bin:

ncnn::Net net;
net.load_param("./mymodel.param.bin");
net.load_model("./mymodel.bin");

3、加载二进制文件2

2中生成的文件中还有两个头文件mymodel_idx.h和mymodel_param.h,mymodel_idx.h中记录了网络各层blob的id,方便确定输入和输出层:

#ifndef NCNN_INCLUDE_GUARD_mymodel_idx_h
#define NCNN_INCLUDE_GUARD_mymodel_idx_h
namespace mymodel_param_id {
const int LAYER_data = 0;
const int BLOB_data = 0;
const int LAYER_conv1 = 1;
const int BLOB_conv1 = 1;
const int LAYER_relu1 = 2;
const int BLOB_conv1_relu1 = 2;
const int LAYER_pool1 = 3;
const int BLOB_pool1 = 3;
//......

mymodel_param.h头文件中则以二进制数组的形式记录了*.param和*.bin:

static const unsigned char mymodel_param_bin[] = {
0xdd,0x85,0x76,0x00,0x13,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x03,0x00,0x00,0x00,0x17,0xff,0xff,0xff,0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x06,0x00,0x00,0x00,
0x60,0x09,0x00,0x00,0x17,0xff,0xff,0xff,0x1a,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x17,0xff,0xff,0xff,
//......
static const unsigned char mymodel_bin[] = {
0x00,0x00,0x00,0x00,0xf9,0x60,0x83,0xbe,0xba,0x43,0x8b,0xbd,0xba,0x65,0x63,0xbd,
0x08,0x6e,0xa8,0x3d,0x8a,0xf1,0x83,0xbc,0x61,0xc6,0x11,0xbe,0x6f,0xcf,0x37,0x3c,
0x4d,0x6a,0x4b,0x3d,0x76,0x72,0x54,0x3c,0x20,0x05,0x7e,0xbc,0xc5,0x85,0x87,0xbe,
0x50,0x04,0x24,0xbe,0xef,0x34,0x5a,0x3d,0xa2,0xe5,0x99,0x3c,0x57,0x12,0xa7,0xbd,
0xd6,0xc4,0x4b,0xbe,0xbe,0x37,0x6c,0xbe,0x5a,0x8d,0xfc,0x3d,0xf3,0xb0,0x3b,0xbb,
0x72,0x3d,0x6d,0xbd,0x8c,0x9a,0x2e,0xbe,0x5e,0x54,0xde,0x3d,0xa0,0x25,0xf4,0xbc,
0xa0,0xcd,0x03,0x3e,0x03,0x96,0x58,0x3e,0x5c,0x0c,0x2d,0x3d,0x47,0x7b,0xdd,0xbd,
0x78,0x05,0xd5,0xbd,0x8a,0x83,0x22,0xbc,0xa1,0x05,0x2f,0x3d,0xf3,0xb9,0x11,0xbe,
0x7b,0xdf,0x00,0xbe,0x54,0x04,0x82,0xbd,0x0e,0xcf,0xb8,0xbd,0x96,0xbf,0x56,0xbd,
0x3c,0x44,0x0c,0x3c,0xd9,0xa9,0x83,0x3c,0xb2,0xdb,0xfd,0xbc,0x6f,0x74,0x9f,0x3b,
//......

所以也可以这样加载模型:

ncnn::Net net;
net.load_param(mymodel_param_bin);
net.load_model(mymodel_bin);

二、读取图像并进行预处理

//调用opencv读取一幅图像
cv::Mat img_bgr = cv::imread("1.jpg");

//对图像进行缩放和格式转换
ncnn::Mat in = ncnn::Mat::from_pixels_resize(img_bgr.data, ncnn::Mat::PIXEL_BGR, img_bgr.cols, img_bgr.rows, 64, 64);

//减均值除方差
const float mean_vals[3] = {87.0f, 87.0f, 91.0f};
const float norm_vals[3] = {0.007843f, 0.007843f, 0.007843f};
in.substract_mean_normalize(mean_vals, norm_vals);

三、提取特征

提取特征并分析特征

//创建特征提取器
ncnn::Extractor ex = net.create_extractor();

//输入数据
ex.input("data", in);//如果是第二或第三中参数加载方式则是:ex.input(idx_input, in);

//提取特征
ncnn::Mat out;
ex.extract("softmax", out);//如果是第二或第三中参数加载方式则是:ex.input(idx_output, out);

//分析特征(这里是2分类)
float *out_data = (float*)out.data;
if(out_data[0] > out_data[1])
{
    ;
}
else
{
    ;
}

四、测试代码编译

这里在Linux下用cmake编译,CMakeList.txt如下:

cmake_minimum_required(VERSION 3.5)
find_package(OpenCV REQUIRED core highgui imgproc imgcodecs)

include_directories(/home/NCNN/ncnn/build/install/include/ncnn)
link_directories(/home/NCNN/ncnn/build/install/lib)

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()  

add_executable(demo test.cpp)

target_link_libraries(demo ncnn ${OpenCV_LIBS})

五、其它

可以通过get_cpu_count()来获取CPU核数,并通过get_freq_khz()来获取每个核的主频,根据主频大小选择绑定的核:set_cpu_thread_affinity()。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值