CUDA10.1就不说了,主要是我们服务器本来就有-> 0.0
为什么是2.2呢,个人喜好。。
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、…自己发觉吧