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 <fstream>
#include <utility>
#include <vector>
#include <iostream>

#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 <vector>

#define _SCL_SECURE_NO_WARNINGS

using 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<tensorflow::Session> session_;

		// anchors
		std::vector<std::vector<int>> masks_;
		std::vector<std::vector<int>> anchors_;



	protected:
		
		Status ReadLabelsFile(const string& file_name, std::vector<string>* 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<Tensor>* out_tensors);

		
		Status LoadGraph(const string& graph_file_name,
			std::unique_ptr<tensorflow::Session>* 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<std::vector<int>> anchors,
			const std::vector<std::vector<int>> 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<int> 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<string>* 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<tensorflow::RandomAccessFile> 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<string>()() = 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<Tensor>* 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<std::pair<string, tensorflow::Tensor>> 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<tensorflow::Session> 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<tensorflow::Session>* 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<float, 4>();
		
		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 = (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, 4>();
		float * source_data = (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<std::vector<int>> anchors,
		const std::vector<std::vector<int>> 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<float>(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<float>(0,i) = box_scores.row(i).at<float>(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<int> 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<Tensor> 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<cv::Mat> 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 <cstdlib>
#include <iostream>
#include <string>
//#include <boost/tuple/tuple.hpp>
//#include <boost/program_options.hpp>
#include<time.h>
#include<sstream>
#include <stdlib.h>
#include <sstream>
#include <fstream>
#include <unistd.h>
#include <dirent.h>
#include <utility>
#include <string>
#include <vector>
#include <tuple>
#include <algorithm>
#include <memory>

//this is opencv include files
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv/cxcore.h>


#define CROPPED

//this is eigen include files
#include <Eigen/Core>
#include <Eigen/Dense>

//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<string> &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<float>().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<float>(img.cols);
      float origin_img_height = static_cast<float>(img.rows);
      float width_scale = origin_img_width / static_cast<float>(input_width);
      float height_scale = origin_img_height / static_cast<float>(input_height);
      cv::resize(img,img1,cv::Size(416,416));
      if(img.empty())
      {
        cout<<"can't open the image!!!!!!!"<<endl;
        return -1;
      }
      Tensor resized_tensor(DT_FLOAT, TensorShape({1,input_height,input_width,3}));
  
      CVMat_to_Tensor(img1,&resized_tensor,input_height,input_width);
   
      vector<tensorflow::Tensor> 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<float, 3>();        
      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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章