C++ 调用tensorflow

1.安装protobuf 3.6

# 安装依赖软件
sudo apt-get install autoconf automake libtool curl make g++ unzip
# 克隆版本为3.6.0的protobuf源码
git clone -b v3.6.0 https://github.com/protocolbuffers/protobuf.git
# 下载 protobuf 的子模块
cd protobuf
git submodule update --init --recursive


./autogen.sh
./configure
make
# make check 如果失败会导致使用某些功能时报错
make check
sudo make install
sudo ldconfig
# 输出protobuf版本信息则表示安装成功
protoc --version

2.安装eigen3

Tensorflow依赖Eigen矩阵运算库,在编译和使用视需要安装对应的版本.可以在 tensorflow/tensorflow/workspace.bzl 中找到对应版本的下载地址

  tf_http_archive(
      name = "eigen_archive",
      urls = [
          "https://mirror.bazel.build/bitbucket.org/eigen/eigen/get/2355b229ea4c.tar.gz",
           "https://bitbucket.org/eigen/eigen/get/2355b229ea4c.tar.gz",
       ],
# 解压下载的文件夹到 /usr/local/include
sudo tar -xzvf eigen-eigen-5a0156e40feb.tar.gz -C /usr/local/include
# 重命名为 eigen3
sudo mv /usr/local/include/eigen-eigen-5a0156e40feb /usr/local/include/eigen3

3.依赖C++库 Abseil 库

下载abseil-cpp,并放在子目录中

在cmake中添加 abseil-cpp

add_subdirectory(abseil-cpp)

target_link_libraries(xx ...  absl::base absl::synchronization absl::strings)

4.编译tensorflow

安装bazel

在tensorflow源码目录运行.configure

bazel build --config=opt --config=cuda //tensorflow/tools/pip_package:build_pip_package //tensorflow:libtensorflow_cc.so

编译python和c++库

生成python wheal文件

bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg

生成的c++ so包在 bazel-bin/tensorflow下面:libtensorflow_cc.so和libtensorflow_framework.so

4.1 编译其他依赖

  • 进入 tensorflow/contrib/makefile 目录下,运行 ./build_all_linux.sh ,成功后会出现一个gen文件夹

  • 若出现如下错误 /autogen.sh: 4: autoreconf: not found ,安装相应依赖即可 sudo apt-get install autoconf automake libtool

5.C++调用逻辑

tensorflow加载文件构建网络,所需加载的pb文件由checkpoints 和 pb 冻结生成.

创建头文件

#ifndef TENSORFLOW_C_RECOVER_TOOL_H
#define TENSORFLOW_C_RECOVER_TOOL_H

#include 

#include 
#include 
#include 
#include 
#include 

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

using namespace tensorflow;
using tensorflow::Tensor;
using tensorflow::Status;
using tensorflow::string;

using tensorflow::int32;
using namespace std;
using namespace cv;

class RecoverTool {

public:
    RecoverTool();

    int modelLoader(const string &model_path);

    string predict(cv::Mat &cvImg);

    void resize(Mat &inImg, Mat &outImg);

private:
    Session *session;

    string dict_vector = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-'_&.!?,\\\"";

    bool session_statu = false;

    void padding_img(Mat &src, Mat &out);

    string tensor_to_str(vector &outputs);
};


#endif //TENSORFLOW_C_RECOVER_TOOL_H

生成Session

RecoverTool::RecoverTool() {
    Status status = NewSession(SessionOptions(), &this->session);
    if (!status.ok()) {
        cout << "Session create failed.\n";
        cout << status.ToString() << "\n";
        this->session_statu = false;
    } else {
        this->session_statu = true;
        cout << "Session successfully created.\n";
    }
}

加载pb模型

int RecoverTool::modelLoader(const string &model_path) {
    tensorflow::GraphDef graphdef;
    Status status_load = ReadBinaryProto(Env::Default(), model_path, &graphdef);
    if (!status_load.ok()) {
        cout << "ERROR: Loading model failed..." << model_path << endl;
        cout << status_load.ToString() << "\n";
        return -1;
    }

    // Add the graph to the session
    Status status_create = this->session->Create(graphdef);
    if (!status_create.ok()) {
        cout << "ERROR: Creating graph in session failed..." << status_create.ToString() << endl;
        return -1;
    }
    return 0;
}

预测函数,需要先生成输入 tensor,tensor的维度( b,h,w,c)和 dtype 需要与模型一致.

string RecoverTool::predict(cv::Mat &cvImg) {
    std::vector outputs;

    int inputHeight = cvImg.size().height;
    int inputWidth = cvImg.size().width;

    // Run tensorflow
    cv::TickMeter tm;
    tm.start();

    // 生成输入 tensor
    tensorflow::Tensor imgTensorWithSharedData(
            tensorflow::DT_UINT8, {16, inputHeight, inputWidth, cvImg.channels()});

    // 将图片的数据加载到 tensor 中
    auto x_map = imgTensorWithSharedData.tensor();
    for (int b = 0; b < 16; b++) {
        for (int h = 0; h < inputHeight; h++) {
            const uchar *inData = cvImg.ptr(h);
            for (int w = 0; w < inputWidth; w++) {
                x_map(b, h, w, 0) = inData[w];
            }
        }
    }

    tensorflow::Status run_status = this->session->Run({{"input:0", imgTensorWithSharedData}},
                                                       {"crnn/dense_out:0"}, {}, &outputs);
    if (!run_status.ok()) {
        std::cerr << "TF_Session->Run Error: " << run_status << std::endl;
    }
    tm.stop();

    cout << "spent:" << tm.getTimeMilli() << endl;

    return tensor_to_str(outputs);
}

结果处理

string RecoverTool::tensor_to_str(vector &outputs) {

    Tensor t = outputs[0];                   // Fetch the first tensor
    int ndim = t.shape().dims();

    // Get the dimension of the tensor
    tensorflow::TTypes::Flat scores = outputs[0].flat(); // Tensor Shape: [batch_size, target_class_num]

    string result = "";
    for (int i = 0; i < scores.size(); i++) {
        int index = scores.data()[i];
        if (index != -1 && index < this->dict_vector.size()) {
            result += this->dict_vector.at(index);
        }
    }

    return result;
}

cmake 文件

cmake_minimum_required(VERSION 3.6)
project(tensorflow_c__)

set(CMAKE_CXX_STANDARD 14)

find_package(Threads REQUIRED)
find_package(OpenCV REQUIRED)

# protobuf
find_package(Protobuf REQUIRED)

include_directories(${Protobuf_INCLUDE_DIRS})

#opencv
include_directories(/usr/local/include)

#tensorflow
include_directories(~/tensorflow)
include_directories(/usr/local/include/eigen3)
include_directories(~/anaconda3/lib/python3.6/dist-packages/tensorflow/include)
include_directories(~/tensorflow/bazel-genfiles/)

#abseil-cpp
add_subdirectory(abseil-cpp)

add_executable(tensorflow_c__ main.cpp recover_tool.cpp recover_tool.h)

target_link_libraries(tensorflow_c__
        ~/tensorflow/bazel-bin/tensorflow/libtensorflow_cc.so
        ~/tensorflow/bazel-bin/tensorflow/libtensorflow_framework.so
        ${OpenCV_LIBS} ${Protobuf_LIBRARIES} absl::base absl::synchronization absl::strings)

cmake中include文件夹也可以直接指向 4.1 编译的文件夹

 

 

 

你可能感兴趣的:(深度学习,tensorflow)