Tensorflow C++接口部署python深度学习训练模型

      tensorflow对python语言的支持非常好,大量的训练模型基本都是python端训练,但问题来了,生产上线的时候,用的最多的还是C/C++。目前关于C++部署的学习资料和介绍例子非常有限,很多资料都雷同相似,而且也未经过实际测试验证。针对其他不同的训练模型,难以适用,很可能到处碰到坑。 笔者就曾经碰过不少坑、浪费花了不少时间和精力。

      这次LINUX端Python训练Deeplab v3+网络、数据集为VOC2012、训练模型输出采用saveModelBuild方式保存为tensorflow的*.pb模式, VS2017 + opencv400 , tensorflow库为VS2017 CPP编译的1.8.0版本,具体代码如下:

/*****************************************************

tensorflow c++ 接口部署深度学习模型

Author:
    WSN@2019  
******************************************************/

#include "pch.h"
#include
#include"opencv2/opencv.hpp"

/* tensorflow 宏定义*/
//tensorflow/core/platform/windows/cpu_info.h
#define COMPILER_MSVC
#define NOMINMAX
#define PLATFORM_WINDOWS   

#include"tensorflow/core/public/session.h"
#include"tensorflow/core/platform/env.h"
#include"tensorflow/cc/saved_model/loader.h"
#include"google/protobuf/message.h"

using namespace tensorflow;
using namespace cv;
using namespace std;

tensorflow::Status loadGraph(std::string model_path, std::unique_ptr* sess)
{
    tensorflow::SessionOptions session_options;
    tensorflow::RunOptions run_options;
    tensorflow::SavedModelBundle bundle;
    tensorflow::Status status;
    constexpr char kSavedModelTagServe[] = "serve";   /* 模型tag名称 */
 
    status = LoadSavedModel(session_options, run_options, model_path, { kSavedModelTagServe }, &bundle);
    if (!status.ok()) 
    {
        std::cerr << "Error reading graph definition from " + model_path + ": " + status.ToString() << std::endl;
        return status;
    }

    *sess = std::move(bundle.session);

    return status;
}

int main()
{
    Mat img;
    Status status;

    std::cout << "Hello tensorflow!\n"; 
    
    /* 创建session和加载tensorflow模型 */
    SessionOptions options;
    std::unique_ptr session(NewSession(options));

    //NewSession(SessionOptions(), &session);
    loadGraph("D:/tensorflow/myModels/voc", &session);

    Mat segm;              /* 分割图 */
    int class_id = 21;     /* 支持21种物体识别分割 */
    std::vector colors;

    /* 构建颜色colors表 */
    if (colors.empty())
    {
        for (int label = 0; label < class_id; label++)
        {
            Vec3i color;
            int c;
            int j;
            color[0] = color[1] = color[2] = 0;
            c = label;
            j = 0;
            while (c)
            {
                color[0] |= ((c >> 0) & 1) << (7 - j);
                color[1] |= ((c >> 1) & 1) << (7 - j);
                color[2] |= ((c >> 2) & 1) << (7 - j);
                c >>= 3;
                j += 1;
            }
            colors.push_back(color);
        }
    }

    string  dir_path = "D:/deepLearning/dataset/voc2012/JPEGImages";  /* 测试图片路径 */
    vector file_list;            
    cv::glob(dir_path, file_list);        /* 从文件夹路径读取所有测试图片 */

    for (int ii = 0; ii < file_list.size(); ii++)
    {
        String pp = file_list[ii];

        Mat img = imread(pp, IMREAD_COLOR);
        Mat input;

        cout << "img:" << pp << endl;

        imshow("input", img);
        cvtColor(img, input, COLOR_BGR2RGB);

        input.convertTo(input, CV_32F);

        /* 从Opencv Mat格式构造tensorflow张量Tensor, N-H-W-C 格式, N = 1(batch size) 深度: C = 4 */
        float* pdata = (float*)input.data;
        Tensor input_tensor(DT_FLOAT, TensorShape({ 1, input.rows, input.cols, input.channels() }));
        auto input_tensor_mapped = input_tensor.tensor();    /* 4 位模型输出的维度 */

        /* 输入图象预处理 */
        //Mat mean_(input.rows, input.cols, CV_32FC3, Scalar(123.68, 116.78, 103.94));
        //Mat tmp;
        //input -= mean_;
        //input.convertTo(tmp, CV_8U);
        //Mat sample_normalized;
        //subtract(input, mean_, input);
        //imshow("input-pre", tmp);
        //waitKey();

        /* 拷贝数据到张量input */
        for (int i = 0; i < input.rows; i++)
        {
            float* source_row = pdata + (i * input.cols * input.channels());
            for (int j = 0; j < input.cols; j++)
            {
                float* vval = source_row + (j * input.channels());
                for (int c = 0; c < input.channels(); c++)
                {
                     float* source_value = vval + c;
                    input_tensor_mapped(0, i, j, c) = *source_value;
                }
            }
        }

        /* pb模型输入: "image_tensor" 根据模型中name定义字段,可以从signature_def中查看 */
        tensorflow::Tensor keep_prob(DT_FLOAT, TensorShape());
        std::vector> inputs = 
        {
            { "image_tensor", input_tensor },
        };

        std::vector outputs;

        /* pb模型输出时,"key:classes,name: ExpandDims:0","key: probabilities, name: softmax_tensor:0"
           即模型中定义的输出张量name字段 */
        status = session->Run(inputs, {"ExpandDims","softmax_tensor"}, {}, &outputs);
        if (!status.ok()) 
        {
            std::cerr << status.ToString() << endl;
            return -1;
        }

        /* 输出结果和可视化结果 */
        tensorflow::Tensor output  = std::move(outputs.at(0)); /* 类别calsses  */
        tensorflow::Tensor output2 = std::move(outputs.at(1)); /* 类别概率probabilities */
        auto out_shape = output2.shape();
        int ww, hh,depth,dims;

        //tfTensor2cvMat(output, cc_Out);

        ww = out_shape.dim_size(1);
        hh = out_shape.dim_size(2);
        depth = out_shape.dim_size(3);
        dims = out_shape.dims();

        //Mat cls_result = Mat::zeros(ww, hh, CV_8UC3);

        auto tensor_dat = output.tensor();
        int ch = output.dim_size(3);  /* depth */

        /* 分割结果着色 */
        segm.create(input.rows, input.cols, CV_32SC3);

        for (int row = 0; row < img.rows; row++)
        {    
            for (int col = 0; col < img.cols; col++)
            {
                int32  cls = tensor_dat(0, row, col, ch);
                int index = cls;

                if (cls < 21 && cls >= 1)
                    segm.at(row, col) = colors[cls];
                else
                    segm.at(row, col) = Vec3i(0,0,0);
            }
        }

        segm.convertTo(segm, CV_8U);       
        Mat tmp;
        addWeighted(img, 0.40, segm, 0.8, 0.0, tmp);   /* 混合原图 */


        imshow("segm", segm);
        imshow("mix", tmp);
    

        waitKey(20);
    }

    /* 关闭session */
    session->Close();


    return 1;
}


 

验证图片如下:

Tensorflow C++接口部署python深度学习训练模型_第1张图片

 

Tensorflow C++接口部署python深度学习训练模型_第2张图片

 

Tensorflow C++接口部署python深度学习训练模型_第3张图片

 

我已经将项目工程上传到了github,Models模型可以在我的github工程中,找到下载:

https://github.com/peterwkl2013/DeepVision

 

本文属于原创并经过测试,

 

如果觉得本文对您有了帮助,请给予的一点小鼓励

您的支持,是我继续前景的动力!!!谢谢~~

 

你可能感兴趣的:(Tensorflow C++接口部署python深度学习训练模型)