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】

    推荐阅读