pytorch resnet18转换为ncnn


模型简化:

python3 -m onnxsim input_onnx_model output_onnx_model

转换完成后,需要注意:
1.图像归一化方式:
如果训练过程中,图像归一化为:

preprocess_transform = transforms.Compose([
        transforms.ToPILImage(),
        transforms.Resize((224, 224)),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225])
        ])

那么,ncnn测试时,同样需要讲图像归一化:

ncnn::Mat in = ncnn::Mat::from_pixels_resize(image.data, ncnn::Mat::PIXEL_BGR2RGB, w, h, 224, 224);
const float mean_vals[3] = {0.485f*255.f, 0.456f*255.f, 0.406f*255.f};
const float norm_vals[3] = {1/0.229f/255.f, 1/0.224f/255.f, 1/0.225f/255.f};
in.substract_mean_normalize(mean_vals, norm_vals);

其中ncnn::Mat::PIXEL_BGR2RGB,根据训练的格式变动。

完整代码如下

#include "net.h"
#include 
#include 
#include 

void resnet_init(ncnn::Net* net, const char* paramfile, const char* binfile)
{
	if(net == NULL) net = new ncnn::Net;
	net->load_param(paramfile);
	net->load_model(binfile);
}

void resnet_release(ncnn::Net* net)
{
	if(net == NULL) return;
	net->clear();
	delete net;
}

static int print_topk(const std::vector& cls_scores, int topk)
{
    // partial sort topk with index
    int size = cls_scores.size();
    std::vector > 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 >());

    // print topk and score
    for (int i = 0; i < topk; i++)
    {
        float score = vec[i].first;
        int index = vec[i].second;
        fprintf(stderr, "%d = %f\n", index, score);
    }

    return 0;
}

void softmax(std::vector& scores)
{
	float sum = 0.0f;
	for(int i = 0; i < scores.size(); i++)
	{
		float s = scores[i];
		scores[i] = std::exp(s);
		//scores[i] = std::exp(scores[i]);
		sum += scores[i];
	}
	printf("sum = %.3f\n", sum);
	for(int i = 0; i < scores.size(); i++)
	{
		scores[i] /= sum;
	}
}

void findmax(std::vector scores)
{
	float max = -1;
	int index = -1;
	for(int i = 0; i < scores.size(); i++)
	{
		if(scores[i] > max){
			max = scores[i];
			index = i;
		}
	}
	printf("max: %.3f, id = %d\n", max, index);
}

void forward(ncnn::Net* net, const cv::Mat& image)
{
	int w = image.cols;
	int h = image.rows;
	ncnn::Mat in = ncnn::Mat::from_pixels_resize(image.data, ncnn::Mat::PIXEL_BGR2RGB, w, h, 224, 224);

    const float mean_vals[3] = {0.485f*255.f, 0.456f*255.f, 0.406f*255.f};
	const float norm_vals[3] = {1/0.229f/255.f, 1/0.224f/255.f, 1/0.225f/255.f};
	in.substract_mean_normalize(mean_vals, norm_vals);

	
	ncnn::Mat out;
	ncnn::Extractor ex = net->create_extractor();
	ex.set_light_mode(true);
	ex.set_num_threads(4);
	ex.input("label", in);
	ex.extract("result", out);


    ncnn::Layer* softmax = ncnn::create_layer("Softmax");

    ncnn::ParamDict pd;
    softmax->load_param(pd);

    softmax->forward_inplace(out, net->opt);

    delete softmax;

    out = out.reshape(out.w * out.h * out.c);
    std::vector cls_scores;
    cls_scores.resize(out.w);
    for (int j = 0; j < out.w; j++)
    {
        cls_scores[j] = out[j];
    }
    print_topk(cls_scores, 2);

}

int main(int argc, char** argv)
{
	ncnn::Net* net = new ncnn::Net;

	resnet_init(net, "models/resnet18_cat_dog.param", "models/resnet18_cat_dog.bin");
	cv::Mat src = cv::imread("cat_dog_test/dog/33.jpg");
	forward(net, src);
	delete net;
	return 0;
}