前言

通过python训练的tensorflow h5模型进行预测的时候,效率不够。本人测试,在i5 16线程的电脑上,运行久后,单次预测的时候会达到500ms以上,很影响效率。这时候,就需要转成c++进行预测了。c++ opencv的dnn模型,正好可以进行预测,效率可以提升至少一倍。很适合在工业场景下使用。

opencv环境搭建

可以参考 https://blog.csdn.net/FFZZHH/article/details/156658651?spm=1001.2014.3001.5501

模型转换

opencv dnn模型,是不能直接加载h5模型的,需要将h5模型转成pb模型,代码如下:

import tensorflow as tf
from tensorflow.python.framework.convert_to_constants import convert_variables_to_constants_v2
 def h5ToPb(h5_file_path, pb_model_path,pb_model_name):
        """
        冻结模型,可以将训练好的.h5模型文件转成.pb文件
        :param h5_file_path: h5模型文件路径
        :param pb_model_path: pb模型文件保存路径
        :param pb_model_name: pb模型文件名称
        :return:
        """
        model = tf.keras.models.load_model(h5_file_path, compile=False)
        model.summary()

        full_model = tf.function(lambda input_1: model(input_1))
        full_model = full_model.get_concrete_function(tf.TensorSpec(model.inputs[0].shape, model.inputs[0].dtype))

        # Get frozen ConcreteFunction
        frozen_func = convert_variables_to_constants_v2(full_model)
        frozen_func.graph.as_graph_def()

        layers = [op.name for op in frozen_func.graph.get_operations()]
    
        tf.io.write_graph(graph_or_graph_def=frozen_func.graph,
                      logdir=pb_model_path,
                      name=pb_model_name,
                      as_text=False)

调用代码:

 modelPath="D:\\python\\pbmodel"
 h5Path = "D:\\python\\h5model/model.h5"
 h5ToPb(h5Path,modelPath,"model.bp")

c++ opencv加载pb模型

#include "opencv2/opencv.hpp"
using namespace cv;
using namespace cv::dnn;
using namespace std;
Net  net;
bool setCheckMat(cv::Mat & checkMat){
    float f, f2;//预测结果为两个标签, 各自概率
    f = checkMat.at<float>(0,0);
    f2 = checkMat.at<float>(0,1);
    //如果有n个标签,可以这样 checkMat.at<float>(0,2);checkMat.at<float>(0,3);....checkMat.at<float>(0,n-1);
    if(f > f2){//标签1的概率大于标签2
        return true;
    }else{
        return false;
    }
}

cv::Mat checkPic(const cv::Mat & checkMat,cv::dnn::Net * net){
    double d = 1.0/255;//归一化,我用的pb模型有进行归一化,所以这里的数据也要归一化
    cv::Scalar mean{0,0,0};
    bool swapRB = false;
    cv::Mat blob = blobFromImage(checkMat,d,cv::Size(checkWidth,checkHeight),mean,swapRB,false);
    net->setInput(blob);
    Mat out = net->forward();
    blob.release();

    return out;
}

bool checkImage(const std::string & path ){
    Mat image = cv::imread(path);
    Mat outMat = checkPic(image,&net);
    image.release();
    bool is = setCheckMat(outMat);
    outMat.release();
    return is;
}


int main(){
     string path = "D:\\python\\pbmodel\\model.pb"
     net = cv::dnn::readNetFromTensorflow(path);
         //设置计算后台
     net.setPreferableBackend(DNN_BACKEND_OPENCV);//使用opencv dnn作为后台计算
     string imagePath = "D:\\a.png"//可以替换成你们的图片
     bool is = checkImage(imagePath);
     return 0;
}

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐