MobileNet-SSD利用caffe-int8-convert-tools工具量化经验(二)
从NCNN框架的param和bin文件中提取权重参数
参考:ncnn:提取所有层特征值
在ncnn-master/src/net.cpp结尾添加函数:
int Extractor::extract_all_blobs()
{
for (int blob_index = 0; blob_index < (int)d->blob_mats.size(); blob_index++)
{
Mat outMat;
extract(blob_index, outMat);
// write to file
char path[256];
char id[8];
strcpy(path, "../../weights/");
sprintf(id, "%d", blob_index);
strcat(path, id);
strcat(path, ".txt");
FILE *fp = fopen(path, "w+");
if(!fp)
fprintf(stderr, "error open file\n");
// header
fprintf(fp, d->net->blobs()[blob_index].name.c_str());
fprintf(fp, "\n");
for (int idx = 0; idx < outMat.w * outMat.h * outMat.c; idx++)
fprintf(fp, "%f\n", outMat[idx]);
fclose(fp);
}
return 0;
}
将权重参数写到与ncnn-master同目录下的weights文件夹中。
另外写一个提取参数的测试cpp文件:
#include "../src/net.h"
#include "../src/net.cpp"
#include "../src/layer.h"
#include "../src/layer/convolution.h"
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#if defined(USE_NCNN_SIMPLEOCV)
#include "simpleocv.h"
#else
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#endif
#include <stdio.h>
#include <vector>
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s [imagepath]\n", argv[0]);
return -1;
}
const char* imagepath = argv[1];
//使用opencv以灰度图读取图片
cv::Mat m = cv::imread(imagepath, 1);
if (m.empty())
{
fprintf(stderr, "cv::imread %s failed\n", imagepath);
return -1;
}
//定义模型的网络
ncnn::Net mobilenet;
mobilenet.opt.use_vulkan_compute = true;
//加载模型
mobilenet.load_param("../../caffe-int8-convert-tools/test/bin_param/MobileNetSSD-int8.param");
mobilenet.load_model("../../caffe-int8-convert-tools/test/bin_param/MobileNetSSD-int8.bin");
/*ncnn::Convolution* conv1 = (ncnn::Convolution*)mobilenet.extract_layer(1);//(旧版本的函数)
ncnn::Mat conv1_weight;
conv1_weight = conv1->weight_data;
int i;
char path[256];
strcpy(path, "conv1.txt");
FILE *fp = fopen(path, "w+");
if(!fp)
fprintf(stderr, "error open file\n");
for(i=0;i<500;i++)
{
fprintf(fp, conv1_weight.data[i]);
}*/
//新版本函数(bug)
/*ncnn::Layer layers = mobilenet.layers;
const int layer_count = layers.size();
for (int i=0; i<layer_count; i++)
{
// find convoultion layer
if (layers[i]->type != "Convolution")
continue;
ncnn::Convolution* conv = (ncnn::Convolution*)layers[i];
ncnn::Mat conv_weight;
conv_weight = conv->weight_data;
// write to file
char path[256];
char name[16];
strcpy(path, "../../weights/");
sprintf(name, "%s", conv->name.c_str());
strcat(path, name);
strcat(path, ".txt");
FILE *fp = fopen(path, "w+");
if(!fp)
fprintf(stderr, "error open file\n");
for (int idx = 0; idx < 500; idx++)
fprintf(fp, "%f\n", conv_weight.data[idx]);
fclose(fp);
}*/
const int target_size = 300;
//获取图片的宽和高
int img_w = m.cols;
int img_h = m.rows;
//将opencv的图片转为ncnn格式的图片,并将图片缩放到300×300之间
ncnn::Mat in = ncnn::Mat::from_pixels_resize(m.data, ncnn::Mat::PIXEL_BGR, m.cols, m.rows, target_size, target_size);
//对图片进行归一化,将像素归一化到-1~1之间
const float mean_vals[3] = {127.5f, 127.5f, 127.5f};
const float norm_vals[3] = {1.0 / 127.5, 1.0 / 127.5, 1.0 / 127.5};
in.substract_mean_normalize(mean_vals, norm_vals);
ncnn::Extractor ex = mobilenet.create_extractor();
//将图片放入网络中,进行前向推理
ex.input("data", in);
ex.extract_all_blobs();
return 0;
}