# 安装依赖软件
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
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
下载abseil-cpp,并放在子目录中
在cmake中添加 abseil-cpp
add_subdirectory(abseil-cpp)
target_link_libraries(xx ... absl::base absl::synchronization absl::strings)
安装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
进入 tensorflow/contrib/makefile 目录下,运行 ./build_all_linux.sh
,成功后会出现一个gen文件夹
若出现如下错误 /autogen.sh: 4: autoreconf: not found ,安装相应依赖即可 sudo apt-get install autoconf automake libtool
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 编译的文件夹