Tensorflow|Tensorflow c++的Inference
关于Tensorflow c++做Inference的文章基本说是少,介绍也不太系统,在这里结合yolov3具体讲下怎么做。首先是tensorflow的源码编译,这是第一关,网上也有相关教程,在这里就不赘述了。其次无论我们是训练任何模型,我们都保存有训练的ckpt,和生成的pb文件,这个pb文件里面保存了图和权重,也可以通过读取图用tensorboard可视化,这个pb文件就是做Iference的主要用的文件,无论我们是怎么一个过程,我们的最终目的就是通过这个pb文件,输入一个图像,得到最后结果。下面直接上代码,yolov3的下载地址为https://download.csdn.net/download/weixin_41015185/10883593,如有问题请联系作者。事先说明,这是一个测试文件,并没有训练好,只是让大家有个思路,不过也许会有效果。
大家可以摘取代码自由发挥,主要是要把里面的内容搞懂。
头文件
#ifndef DEEPLEARNING_H
#define DEEPLEARNING_H#define COMPILER_MSVC#include
#include
#include
#include #include "opencv2/opencv.hpp"#include "tensorflow/cc/ops/const_op.h"
#include "tensorflow/cc/ops/image_ops.h"
#include "tensorflow/cc/ops/array_ops.h"
#include "tensorflow/cc/ops/standard_ops.h"
#include "tensorflow/core/framework/graph.pb.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/graph/default_device.h"
#include "tensorflow/core/graph/graph_def_builder.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/lib/core/threadpool.h"
#include "tensorflow/core/lib/io/path.h"
#include "tensorflow/core/lib/strings/stringprintf.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/util/command_line_flags.h"#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/platform/default/logging.h"
#include "tensorflow/core/framework/shape_inference.h"
#include #define _SCL_SECURE_NO_WARNINGSusing tensorflow::Flag;
using tensorflow::Tensor;
using tensorflow::Status;
using tensorflow::string;
using tensorflow::int32;
namespace Apollo
{ class DeepLearning
{
private:std::string name_{ "DeepLearning" };
string graph_;
string labels_;
int32 input_width_;
int32 input_height_;
float input_mean_;
float input_std_;
string input_layer_;
string learning_phase_;
string output_layer_1_;
string output_layer_2_;
string output_layer_3_;
bool self_test_;
string root_dir_{ "" };
std::unique_ptr session_;
// anchors
std::vector> masks_;
std::vector> anchors_;
protected:Status ReadLabelsFile(const string& file_name, std::vector* result,
size_t* found_label_count);
Status ReadEntireFile(tensorflow::Env* env, const string& filename,
Tensor* output);
Status ReadTensorFromImageFile(const string& file_name, const int input_height,
const int input_width, const float input_mean,
const float input_std,
std::vector* out_tensors);
Status LoadGraph(const string& graph_file_name,
std::unique_ptr* session);
int cvtMat2Tensor(cv::Mat input, tensorflow::Tensor& input_tensor);
cv::Mat cvtTensor2Mat(const tensorflow::Tensor& input_tensor);
int setParams();
int _process_feats(
const cv::Mat out,
const std::vector> anchors,
const std::vector> mask,
cv::Mat *boxes,
cv::Mat *box_confidences,
cv::Mat *box_class_probs);
int _filter_boxes(
const cv::Mat& boxes,
const cv::Mat& box_confidences,
const cv::Mat& box_class_probs,
cv::Mat *new_boxes,
cv::Mat *classes,
cv::Mat *scores);
int _nms_boxes(cv::Mat *boxes, cv::Mat* scores);
int _yolo_out(const cv::Mat outs, std::vector shape);
public:
DeepLearning() {}
~DeepLearning() {}int initialize();
int run(cv::Mat InputImg);
};
}#endif
cpp文件
#include "DeepLearning.h"
using namespace cv;
namespace Apollo
{
Status DeepLearning::ReadLabelsFile(const string& file_name, std::vector* result,
size_t* found_label_count) {
std::ifstream file(file_name);
if (!file) {
return tensorflow::errors::NotFound("Labels file ", file_name,
" not found.");
}
result->clear();
string line;
while (std::getline(file, line)) {
result->push_back(line);
}
*found_label_count = result->size();
const int padding = 16;
while (result->size() % padding) {
result->emplace_back();
}
return Status::OK();
}
Status DeepLearning::ReadEntireFile(tensorflow::Env* env, const string& filename,
Tensor* output) {
tensorflow::uint64 file_size = 0;
TF_RETURN_IF_ERROR(env->GetFileSize(filename, &file_size));
string contents;
contents.resize(file_size);
std::unique_ptr file;
TF_RETURN_IF_ERROR(env->NewRandomAccessFile(filename, &file));
tensorflow::StringPiece data;
TF_RETURN_IF_ERROR(file->Read(0, file_size, &data, &(contents)[0]));
if (data.size() != file_size) {
return tensorflow::errors::DataLoss("Truncated read of '", filename,
"' expected ", file_size, " got ",
data.size());
}
output->scalar()() = data.ToString();
return Status::OK();
}
Status DeepLearning::ReadTensorFromImageFile(const string& file_name, const int input_height,
const int input_width, const float input_mean,
const float input_std,
std::vector* out_tensors) {
auto root = tensorflow::Scope::NewRootScope();
using namespace ::tensorflow::ops;
string input_name = "file_reader";
string output_name = "normalized";
Tensor input(tensorflow::DT_STRING, tensorflow::TensorShape());
TF_RETURN_IF_ERROR(
ReadEntireFile(tensorflow::Env::Default(), file_name, &input));
auto file_reader =
Placeholder(root.WithOpName("input"), tensorflow::DataType::DT_STRING);
std::vector> inputs = {
{ "input", input },
};
const int wanted_channels = 3;
tensorflow::Output image_reader;
if (tensorflow::StringPiece(file_name).ends_with(".png")) {
image_reader = DecodePng(root.WithOpName("png_reader"), file_reader,
DecodePng::Channels(wanted_channels));
}
else if (tensorflow::StringPiece(file_name).ends_with(".gif")) {image_reader =
Squeeze(root.WithOpName("squeeze_first_dim"),
DecodeGif(root.WithOpName("gif_reader"), file_reader));
}
else if (tensorflow::StringPiece(file_name).ends_with(".bmp")) {
image_reader = DecodeBmp(root.WithOpName("bmp_reader"), file_reader);
}
else {image_reader = DecodeJpeg(root.WithOpName("jpeg_reader"), file_reader,
DecodeJpeg::Channels(wanted_channels));
}auto float_caster =
Cast(root.WithOpName("float_caster"), image_reader, tensorflow::DT_FLOAT);
auto dims_expander = ExpandDims(root, float_caster, 0);
auto resized = ResizeBilinear(
root, dims_expander,
Const(root.WithOpName("size"), { input_height, input_width }));
Div(root.WithOpName(output_name), Sub(root, resized, { input_mean }),
{ input_std });
tensorflow::GraphDef graph;
TF_RETURN_IF_ERROR(root.ToGraphDef(&graph));
std::unique_ptr session(
tensorflow::NewSession(tensorflow::SessionOptions()));
TF_RETURN_IF_ERROR(session->Create(graph));
TF_RETURN_IF_ERROR(session->Run({ inputs }, { output_name }, {}, out_tensors));
return Status::OK();
}
Status DeepLearning::LoadGraph(const string& graph_file_name,
std::unique_ptr* session) {
tensorflow::GraphDef graph_def;
Status load_graph_status =
ReadBinaryProto(tensorflow::Env::Default(), graph_file_name, &graph_def);
if (!load_graph_status.ok()) {
return tensorflow::errors::NotFound("Failed to load compute graph at '",
graph_file_name, "'");
}auto options = tensorflow::SessionOptions();
options.config.set_allow_soft_placement(true);
std::cout << "Allow soft placement:" << options.config.allow_soft_placement() << std::endl;
session->reset(tensorflow::NewSession(options));
Status session_create_status = (*session)->Create(graph_def);
if (!session_create_status.ok()) {
return session_create_status;
}
return Status::OK();
} int DeepLearning::cvtMat2Tensor(Mat Image, tensorflow::Tensor& input_tensor)
{
auto input_tensor_mapped = input_tensor.tensor();
Image.convertTo(Image, CV_32FC3);
cv::resize(Image, Image, cv::Size(input_width_, input_height_));
Image = Image - input_mean_;
Image = Image / input_std_;
int height = Image.size().height;
int width = Image.size().width;
int depth = Image.channels();
std::cout << "The image type is" << Image.type() << std::endl;
std::cout << height << width << depth << std::endl;
const float * source_data = https://www.it610.com/article/(float*)Image.data;
for (int y = 0;
y < height;
++y) {
const float* source_row = source_data + (y * width * depth);
for (int x = 0;
x < width;
++x) {
const float* source_pixel = source_row + (x * depth);
for (int c = 0;
c < depth;
++c) {
const float* source_value = source_pixel + c;
input_tensor_mapped(0, y, x, c) = *source_value;
}
}
}return 1;
} cv::Mat DeepLearning::cvtTensor2Mat(const tensorflow::Tensor& input_tensor)
{
tensorflow::TensorShape input_tensor_shape = input_tensor.shape();
if (input_tensor_shape.dims() != 4)
{
std::cout <<"The input tensor shape is not 4 dimension!" << std::endl;
exit(0);
}int height = input_tensor_shape.dim_size(1);
int width = input_tensor_shape.dim_size(2);
int depth = input_tensor_shape.dim_size(3);
cv::Mat ReturnMat(height, width, CV_32FC(depth));
auto input_tensor_mapped = input_tensor.tensor();
float * source_data = https://www.it610.com/article/(float*)ReturnMat.data;
for (int y = 0;
y < height;
++y) {
float* source_row = source_data + (y * width * depth);
for (int x = 0;
x < width;
++x) {
float* source_pixel = source_row + (x * depth);
for (int c = 0;
c < depth;
++c) {
float* source_value = source_pixel + c;
*source_value = input_tensor_mapped(0, y, x, c);
}
}
}return ReturnMat;
} int DeepLearning::setParams()
{
graph_ ="../../YOLOv3-master/model_files/yolo_coco.pb";
labels_ = "../../YOLOv3-master/data/coco_classes.txt";
input_width_ = 416;
input_height_ = 416;
input_mean_ = 0;
input_std_ = 255;
input_layer_ = "input_1";
output_layer_1_ = "conv2d_59/BiasAdd";
output_layer_2_ = "conv2d_67/BiasAdd";
output_layer_3_ = "conv2d_75/BiasAdd";
self_test_ = 0;
masks_.push_back({ 6,7,8 });
masks_.push_back({ 3,4,5 });
masks_.push_back({ 0,1,2 });
anchors_.push_back({10, 13});
anchors_.push_back({16, 30});
anchors_.push_back({33, 23});
anchors_.push_back({30, 61});
anchors_.push_back({62, 45});
anchors_.push_back({59, 119});
anchors_.push_back({116, 90});
anchors_.push_back({156,198});
anchors_.push_back({373,326});
return 1;
}
int DeepLearning::_process_feats(
const cv::Mat out,
const std::vector> anchors,
const std::vector> mask,
cv::Mat *boxes,
cv::Mat *box_confidences,
cv::Mat *box_class_probs)
{ } int DeepLearning::_filter_boxes(
const cv::Mat& boxes,
const cv::Mat& box_confidences,
const cv::Mat& box_class_probs,
cv::Mat *new_boxes,
cv::Mat *classes,
cv::Mat *scores)
{cv::Mat box_scores(cv::Size(box_class_probs.rows, box_class_probs.cols), CV_32FC1);
for(int i = 0;
i < box_class_probs.rows;
i++ )
{
box_scores.row(i) = box_confidences.at(0, i) * box_class_probs.row(i);
}cv::Mat box_classes(cv::Size(box_scores.rows, box_scores.cols), CV_32FC1);
for (int i = 0;
i < box_scores.rows;
i++)
{
double minVal;
double maxVal;
cv::Point minLoc;
cv::Point maxLoc;
minMaxLoc(box_scores.row(i), &minVal, &maxVal, &minLoc, &maxLoc);
box_scores.at(0,i) = box_scores.row(i).at(maxLoc.x, maxLoc.y);
}box_classes = } int DeepLearning::_nms_boxes(cv::Mat *boxes, cv::Mat* scores)
{ } int DeepLearning::_yolo_out(const cv::Mat outs, std::vector shape)
{ } int DeepLearning::initialize()
{
setParams();
string graph_path;
graph_path = tensorflow::io::JoinPath(root_dir_, graph_);
Status load_graph_status = LoadGraph(graph_path, &session_);
if (!load_graph_status.ok()) {
LOG(ERROR) << load_graph_status;
return -1;
}
return 1;
} int DeepLearning::run(Mat InputImg)
{
tensorflow::Tensor resized_tensor(tensorflow::DT_FLOAT, tensorflow::TensorShape({ 1,input_height_, input_width_, 3}));
cvtMat2Tensor(InputImg, resized_tensor);
std::vector outputs;
std::cout << "input layer:" << input_layer_ << std::endl;
Status run_status = session_->Run({ { input_layer_, resized_tensor } },
{ output_layer_1_,output_layer_2_, output_layer_3_ }, {}, &outputs);
if (!run_status.ok()) {
LOG(ERROR) << "Running model failed: " << run_status;
return -1;
}std::vector OutputMat(3);
for (int i = 0;
i < 3;
i++)
{
OutputMat[i] = cvtTensor2Mat(outputs[i]);
}std::cout << "Output Mat1(from tensor1) size:"
<< OutputMat[0].rows << ", "
<< OutputMat[0].cols << ", "
<< OutputMat[0].channels() << std::endl;
std::cout << "Output Mat2(from tensor2) size:"
<< OutputMat[1].rows << ", "
<< OutputMat[1].cols << ", "
<< OutputMat[1].channels() << std::endl;
std::cout << "Output Mat3(from tensor3) size:"
<< OutputMat[2].rows << ", "
<< OutputMat[2].cols << ", "
<< OutputMat[2].channels() << std::endl;
return 1;
}}
至于cmakelist文件很简单,添加相关库就行
~/projects/nihao/lib/libtensorflow_cc.so
~/projects/nihao/lib/libtensorflow_framework.so
include_directories(
#tensorflow
~/tensorflow
~/tensorflow/bazel-genfiles
~/tensorflow/bazel-bin/tensorflow
~/tensorflow/tensorflow/contrib/makefile/downloads/nsync/public
~/tensorflow/tensorflow/contrib/makefile/gen/include
)
在给大家举一个小例子
//this is system include files
#include
#include
#include
//#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include //this is opencv include files
#include
#include
#include
#include #define CROPPED//this is eigen include files
#include
#include //this is apollo camera tracker include files
#include "modules/perception/obstacle/camera/tracker/cascaded_camera_tracker.h"
#include "modules/perception/obstacle/camera/common/visual_object.h"
#include "modules/perception/obstacle/camera/filter/object_camera_filter.h"
#include "modules/perception/obstacle/camera/filter/object_camera_extended_kalman_filter.h"
#include "modules/perception/obstacle/camera/filter/object_camera_extended_kalman_filter.h"
//this is apollo lidar tracker include files
#include "modules/perception/obstacle/camera/converter/geometry_camera_converter.h"
#include "modules/perception/obstacle/base/types.h"
//this is tensorflow include files
#include "tensorflow/cc/ops/const_op.h"
#include "tensorflow/cc/ops/image_ops.h"
#include "tensorflow/cc/ops/standard_ops.h"#include "tensorflow/core/framework/graph.pb.h"
#include "tensorflow/core/framework/tensor.h"#include "tensorflow/core/graph/default_device.h"
#include "tensorflow/core/graph/graph_def_builder.h"#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/lib/core/threadpool.h"
#include "tensorflow/core/lib/io/path.h"
#include "tensorflow/core/lib/strings/stringprintf.h"#include "tensorflow/core/public/session.h"
#include "tensorflow/core/util/command_line_flags.h"#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/types.h"using namespace tensorflow::ops;
using namespace tensorflow;
using namespace std;
using namespace cv;
using tensorflow::Flag;
using tensorflow::Tensor;
using tensorflow::Status;
using tensorflow::string;
using tensorflow::int32 ;
using namespace std;
void FindFiles(string root ,vector &files)
{
DIR *dir;
struct dirent *ent;
if ((dir = opendir (root.c_str())) != NULL)
{
while ((ent = readdir (dir)) != NULL)
{
if(!strcmp(ent->d_name,".")||!strcmp(ent->d_name,".."))
continue;
files.push_back(ent->d_name);
}
closedir (dir);
}
}
void CVMat_to_Tensor(Mat img,Tensor* output_tensor,int input_rows,int input_cols)
{
resize(img,img,cv::Size(input_cols,input_rows),0,0,1);
img.convertTo(img,CV_32FC3);
img=img/255;
float *p = output_tensor->flat().data();
cv::Mat tempMat(input_rows, input_cols, CV_32FC3, p);
img.convertTo(tempMat,CV_32FC3);
}int main(int argc,char ** argv)
{string model_path="/home/dingjiangang/projects/nihao/model/yolo.pb";
int input_height =416;
int input_width=416;
string input_tensor_name="input_1";
string output_tensor_name="decode/FinalOutput/ExpandDims";
Session* session;
Status status = NewSession(SessionOptions(), &session);
GraphDef graphdef;
Status status_load = ReadBinaryProto(Env::Default(), model_path, &graphdef);
if (!status_load.ok()) {
cout << "ERROR: Loading model failed..." << model_path << std::endl;
cout << status_load.ToString() << "\n";
return -1;
}
Status status_create = session->Create(graphdef);
if (!status_create.ok()) {
cout << "ERROR: Creating graph in session failed..." << status_create.ToString() << std::endl;
return -1;
}
cout << "<----Successfully created session and load graph.------->"<< endl;
cv::Mat img;
cv::Mat img1;
VideoCapture Capture;
Capture.open("/home/dingjiangang/projects/nihao/test/3.mp4");
int frame = 0;
while(1)
{
clock_t start=clock();
double timestamp=(double)(start)/CLOCKS_PER_SEC;
Capture >> img;
float origin_img_width = static_cast(img.cols);
float origin_img_height = static_cast(img.rows);
float width_scale = origin_img_width / static_cast(input_width);
float height_scale = origin_img_height / static_cast(input_height);
cv::resize(img,img1,cv::Size(416,416));
if(img.empty())
{
cout<<"can't open the image!!!!!!!"< outputs;
string output_node = output_tensor_name;
Status status_run = session->Run({{input_tensor_name, resized_tensor}}, {output_node}, {}, &outputs);
if (!status_run.ok())
{
cout << "ERROR: RUN failed..."<< std::endl;
cout << status_run.ToString() << "\n";
return -1;
}
Tensor t = outputs[0];
auto tmap = t.tensor();
int output_box_num = t.shape().dim_size(1);
clock_t end=clock();
double timestamp1=(double)(end)/CLOCKS_PER_SEC;
cout << tiemstamp1 - timestamp << endl;
++frame;
}
Capture.release();
session->Close();
return EXIT_SUCCESS;
}
【Tensorflow|Tensorflow c++的Inference】
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量