tensorflow2.2的C++API调用跑模型

安装CUDA10.1和tensorflow2.2

CUDA10.1就不说了,主要是我们服务器本来就有-> 0.0
为什么是2.2呢,个人喜好。。

下载tensorflow源码

git clone https://github.com/tensorflow/tensorflow.git
cd tensorflow/
git checkout r2.2
./configure
bazel build --config=opt --config=cuda //tensorflow:libtensorflow_framework.so
bazel build --verbose-failures --noincompatible_do_not_split_linking_cmdline --config=opt --config=cuda //tensorflow:libtensorflow_cc.so //tensorflow/tools/pip_package:build_pip_package
编译差不多两句,具体可能出错,去百度吧。

最后主要编译出:

1、libtensorflow_cc.so
2、libtensorflow_framework.so

开始正文

我们先得到需要的模型参数:
1、.meta文件,是网络图
2、checkpoint文件,是训练时暂存的模型参数文件
或者:
.pb文件,是…(本文介绍上面那种)

获得方法:

一般网络是用python训练的
所以找到train.py里面的:
saver = tf.compat.v1.train.Saver(参数…)
这一句下面某句:
saver.save(sess, checkpoint_path, global_step=step, write_meta_graph=True)
就保存了图和参数文件

C++API读取tensorflow模型代码:

#include <tensorflow/cc/ops/io_ops.h>
#include <tensorflow/cc/ops/parsing_ops.h>
#include <tensorflow/cc/ops/array_ops.h>
#include <tensorflow/cc/ops/math_ops.h>
#include <tensorflow/cc/ops/data_flow_ops.h>

#include <yaml-cpp/yaml.h>
#include <tensorflow/core/public/session.h>
#include <tensorflow/core/protobuf/meta_graph.pb.h>
#include <tensorflow/core/platform/env.h>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <fstream>
#include <iostream>
#include <iomanip>

#include <vector>
using namespace std;
using namespace tensorflow;
using namespace tensorflow::ops;

// 定义一个函数讲OpenCV的Mat数据转化为tensor,python里面只要对cv2.read读进来的矩阵进行np.reshape之后,
// 数据类型就成了一个tensor,即tensor与矩阵一样,然后就可以输入到网络的入口了,但是C++版本,网络开放的入口
// 也需要将输入图片转化成一个tensor,所以如果用OpenCV读取图片的话,就是一个Mat,然后就要考虑怎么将Mat转化为Tensor了
void CVMat_to_Tensor(cv::Mat img, Tensor *output_tensor, int input_rows, int input_cols)
{
    //图像进行resize处理
    resize(img, img, cv::Size(input_cols, input_rows));
    //归一化
    //img.convertTo(img, CV_32FC1);
    //img = 1 - img / 255;
    //创建一个指向tensor的内容的指针
    float *p = output_tensor->flat<float>().data();
    //创建一个Mat,与tensor的指针绑定,改变这个Mat的值,就相当于改变tensor的值
    cv::Mat tempMat(input_rows, input_cols, CV_32FC1, p);
    img.convertTo(tempMat, CV_32FC1);
}
void tensor2Mat(Tensor &t, cv::Mat &image, int H, int W)
{
    float *p = t.flat_inner_dims<float>().data();
    // float *p = t.flat<float>().data();
    image = cv::Mat(H, W, CV_32F, p);
    image.convertTo(image, CV_32F);
}
void writeMatToFile(cv::Mat &m, string filename)
{
    std::ofstream fout(filename);
    if (!fout)
    {
        std::cout << "File Not Opened" << std::endl;
        return;
    }
    for (int i = 0; i < m.rows; i++)
    {
        for (int j = 0; j < m.cols; j++)
        {
            fout << setprecision(4) << m.at<float>(i, j) << " ";
        }
        fout << std::endl;
    }
    fout.close();
}
int main()
{
    YAML::Node doc;
    const string default_setting_path_ = "xx.yaml";
    // load yaml
    doc = YAML::LoadFile(default_setting_path_.c_str());
    YAML::Node net = doc["net"];
    YAML::Node match = doc["match"];
    YAML::Node config = net["config"];
    // parse
    const string path = doc["model_path"].as<std::string>();
    
    // set up your input paths
    const string pathToGraph = path + ".meta";
    const string checkpointPath = path;

    auto session = NewSession(SessionOptions());
    if (session == nullptr)
    {
        throw runtime_error("Could not create Tensorflow session.");
    }
    Status status;
    // Read in the protobuf graph we exported
    MetaGraphDef graph_def;
    status = ReadBinaryProto(Env::Default(), pathToGraph, &graph_def);
    if (!status.ok())
    {
        throw runtime_error("Error reading graph definition from " + pathToGraph + ": " + status.ToString());
    }
    // Add the graph to the session
    status = session->Create(graph_def.graph_def());
    if (!status.ok())
    {
        throw runtime_error("Error creating graph: " + status.ToString());
    }
    //输出每一层的名字,这里以后需要用到,方便定义输入输出
    for (int i = 0; i < graph_def.graph_def().node_size(); i++)
    {
        std::string name = graph_def.graph_def().node(i).name();
        std::cout << name << std::endl;
    }
    //接下来两句,根据模型的层输入和层输出写,比如输入只有一个tensor,名字是"input:0"
    //输出有三个tensor,名字分别是:1、A;2、B;3、C;
    std::string input_tensor_name = std::string("input:0");
    std::vector<std::string> output_tensor_name = {std::string("A"), std::string("B"), std::string("C")};

    // Read weights from the saved checkpoint
    Tensor checkpointPathTensor(DT_STRING, TensorShape());
    checkpointPathTensor.scalar<tensorflow::tstring>()() = checkpointPath;
    status = session->Run({
                              {graph_def.saver_def().filename_tensor_name(), checkpointPathTensor},
                          },
                          {}, {graph_def.saver_def().restore_op_name()}, nullptr);
    if (!status.ok())
    {
        throw runtime_error("Error loading checkpoint from " + checkpointPath + ": " + status.ToString());
    }
    cout << 1 << endl;
    //到这里模型参数读取完成,下面开始读取模型的输入,例子是一张图片
    const string image_path = "test_img.jpg";
    cv::Mat image = cv::imread(image_path);
    cv::Mat out_image_;
    cv::cvtColor(image, out_image_, cv::COLOR_BGR2GRAY);
    int max_dim = max(image.cols, image.rows);
    // std::cout << out_image_.rows << " " << out_image_.cols << " " << out_image_.channels() << std::endl;
    //如果图片分辨率太高,进行下采样
    if (max_dim > net["max_dim"].as<int>())
    {
        double downsample_ratio = (net["max_dim"].as<int>()) * 1.0 / (max_dim);
        cv::resize(out_image_, out_image_, cv::Size(0, 0), downsample_ratio, downsample_ratio);
    }
	//如果采用多尺度,设置多尺度参数。
    double scale_f = 0;
    double min_scale = 0;
    double n_scale = 0;
    double sigma = 0;
    if (config["multi_scale"].as<int>())
    {
        scale_f = 1 / pow(2, 0.50);
        min_scale = max(0.3, 128.0 / max(image.rows, image.cols));
        n_scale = floor(max(log(min_scale) / log(scale_f), 1.0));
        sigma = 0.8;
    }
    else
        n_scale = 1;
        
	//多尺度运行模型
    for (int i = 0; i < n_scale; i++)
    {
        if (i > 0)
        {
            cv::GaussianBlur(out_image_, out_image_, cv::Size(0, 0), sigma / scale_f);
            std::cout << out_image_.rows << " " << out_image_.cols << " " << out_image_.channels() << std::endl;
            cv::resize(out_image_, out_image_, cv::Size(0, 0), scale_f, scale_f);
        }
        //创建一个tensor作为输入网络的接口
        Tensor resized_tensor(DT_FLOAT, TensorShape({1, out_image_.rows, out_image_.cols, 1}));
        //将Opencv的Mat格式的图片存入tensor
        CVMat_to_Tensor(out_image_, &resized_tensor, out_image_.rows, out_image_.cols);
        cout << resized_tensor.DebugString() << endl;
        cout << endl
             << "<-------------Running the model with test_image--------------->" << endl;
        //定义输入tensor,由tensor名字+变量组成
        std::vector<std::pair<string, Tensor>> input_tensor = {{input_tensor_name, resized_tensor}};
        //定义输出tensor,输出结果一定是一个tensor的vector
        vector<tensorflow::Tensor> outputs;
        //前向运行,该处由输入tensor,输出tensor名+输出tensor
        Status status_run = session->Run(input_tensor, output_tensor_name, {}, &outputs);
        if (!status_run.ok())
        {
            cout << "ERROR: RUN failed..." << std::endl;
            cout << status_run.ToString() << "\n";
            return -1;
        }
        //把输出值给提取出来
        cout << "Output tensor size:" << outputs.size() << std::endl;
        for (std::size_t j = 0; j < outputs.size(); j++)
        {
            cout << outputs[j].DebugString() << endl;
        }
        cv::Mat des;
        tensor2Mat(outputs[0], des, outputs[0].shape().dim_size(1), outputs[0].shape().dim_size(2));
        cout << des.size() << std::endl;
    }
    imshow("KeyPoints Image", des);
    cv::waitKey(0);
    return 0;
}

接下来写CMakeLists.txt

cmake_minimum_required(VERSION 3.8)
project(Tensorflow_test)

add_definitions(-std=c++11)

find_package(OpenCV 3.0 QUIET)

## Resolve system dependency on yaml-cpp, which apparently does not
## provide a CMake find_package() module.
## Insert your header file compatible specified path like '#include <yaml-cpp/yaml.h>'
find_package(PkgConfig REQUIRED)
pkg_check_modules(YAML_CPP REQUIRED yaml-cpp)
find_path(YAML_CPP_INCLUDE_DIR
  NAMES yaml_cpp.h
  PATHS ${YAML_CPP_INCLUDE_DIRS}
)
find_library(YAML_CPP_LIBRARY
  NAMES YAML_CPP
  PATHS ${YAML_CPP_LIBRARY_DIRS}
)
find_package(Eigen3 3.1.0 REQUIRED)
link_directories(${YAML_CPP_LIBRARY_DIRS})
if(NOT ${YAML_CPP_VERSION} VERSION_LESS "0.5")
add_definitions(-DHAVE_NEW_YAMLCPP)
endif(NOT ${YAML_CPP_VERSION} VERSION_LESS "0.5")
#这里是tensorflow的源码路径,根据下面库文件目录设置TENSORFLOW_DIR
set(TENSORFLOW_ROOT_DIR TENSORFLOW_DIR)
include_directories(
        include
        ${TENSORFLOW_ROOT_DIR}/bazel-bin/tensorflow/include
        ${TENSORFLOW_ROOT_DIR}/bazel-bin/tensorflow/include/src
        ${OpenCV_INCLUDE_DIRS}
        ${YAML_CPP_INCLUDE_DIRS}
)
add_executable(Tensorflow_test src/ASLextractor.cpp)

target_link_libraries(Tensorflow_test
        ${TENSORFLOW_ROOT_DIR}/bazel-bin/tensorflow/libtensorflow_cc.so
        ${TENSORFLOW_ROOT_DIR}/bazel-bin/tensorflow/libtensorflow_framework.so
        ${OpenCV_LIBS}
        ${YAML_CPP_LIBRARIES}
        )

ok,结束,简单的一个使用C++运行tensorflow的代码。

实际应用需要修改的一些地方:

1、网络输入tensor名字
2、网络输出tensor名字
3、CMakeList.txt的路径
4、…自己发觉吧

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值