C/C++气象数据中心实战,手把手教你做工业级项目

赋料扬雄敌,诗看子建亲。这篇文章主要讲述C/C++气象数据中心实战,手把手教你做工业级项目相关的知识,希望能为你提供帮助。
??立即下载??

??立即下载??
近几年,c/c++已经成为助力程序猿走出内卷的最佳选择之一。c/c++优势就在于只要能写出简单的应用,就可秒杀90%的CRUD工程师。这次我们邀请有20多年c/c++开发经验的大牛,通过一个工业级的数据中心项目实打实的提升你的项目经验!成为真正的程序员,开僻你的职业蓝海!
1、配置C++版tensorflow使用时的第三方依赖
(1)protobuf下载及安装
Protobuf这玩意儿是重中之重,它的版本与tensorflow的版本密切相关,它的版本错了就无法work。


下载地址:https://github.com/google/protobuf/releases ,我下载的是3.5.0版本,如果你是下载新版的tensorflow,请确保protobuf版本也是最新的,安装步骤:
将下载的压缩包解压出来,获得一个protobuf-3.5.0的文件夹
    cd prtobuf-3.5.0
    ./configure
    sudo make -j8
    make check -j8
    sudo make install
    sudo ldconfig
    在protobuf-3.5.0文件中执行:
    ./configure --prefix=/home/xxx/Anaconda/protobuf-3.5.0
以上步骤可以完成Protubuf的源码的编译和安装
如果遇到什么问题,建议去看Protobuf的官方的编译安装指南:https://github.com/google/protobuf/blob/master/src/README.md
(2)Eigen下载与安装
Eigen是一个C++端的矩阵运算库,这个库只要下载压缩包,解压到某个自己知道的路径下即可
  先下载eigen的压缩包
  wget http://bitbucket.org/eigen/eigen/get/3.3.4.tar.bz2
  下载之后解压,重新命名为eigen3,放到某个路径下,安装就好
  mkdir build
  cd build
  cmake ..
  sudo make install
2、编译安装Tensorflow
(1)下载安装编译工具bazel
    先下载Bazel的安装包 https://github.com/bazelbuild/bazel/releases,我下载的是bazel-0.24.1-installer-linux-x86_64.sh
    然后执行安装 ./bazel-0.24.1-installer-linux-x86_64.sh --user
    安装完成后,需要添加环境变量:
    sudo gedit ~/.bashrc
    在文本最后添加语句: export PATH=/home/xxx/bin:$PATH
    source ~/.bashrc
    注意:bazel版本不能过高,否则会报错
(2)Tensorflow下载与编译
    # 先下载tensorflow源码 ,我下载的是tensorflow1.14
  git clone https://github.com/tensorflow/tensorflow.git
  # 进入tensorflow文件夹
  cd tensorflow
  # 执行configure
  ./configure
  这一步需要你指定python路径,需要有各种y/N的选择
  建议如下: python路径用anaconda的路径:/home/xxx/anaconda3/bin/python
  pyhon路径选择默认路径就可以了
  cuda要选择y,然后会自动搜索cudnn版本
  nccl选择默认的1.3,
  后面的不是选择N就是默认
      利用bazel进行编译
      bazel build --config=opt //tensorflow:libtensorflow_cc.so // 无显卡,cpu版本
  bazel build --config=opt --config=cuda //tensorflow:libtensorflow_cc.so // 有显卡


  ....漫长的等待编译,大约20分钟
  # 最后显示类似如下的信息,说明编译成功了:
  .... Target //tensorflow:libtensorflow_cc.so up-to-date:
  bazel-bin/tensorflow/libtensorflow_cc.so
  INFO: Elapsed time: 1192.883s, Critical Path: 174.02s
  INFO: 654 processes: 654 local.
  INFO: Build completed successfully, 656 total actions
    然后回到tensorflow目录下执行:
./tensorflow/contrib/makefile/download_dependencies.sh
#完成后会有一个downloads文件夹在makefile文件夹中


需要先安装相应依赖:
sudo apt-get install autoconf automake libtool
然后在tensorflow/contrib/makefile下执行
bash ./build_all_linux.sh文件,成功后会出现一个gen文件夹。
        编译完成后,整理库文件和头文件
  库文件:
  mkdir -p ../tf_test/lib
  cp bazel-bin/tensorflow/libtensorflow_cc.so ../tf_test/lib/
  cp bazel-bin/tensorflow/libtensorflow_framework.so ../tf_test/lib/   # 之前编译r0.12和r1.3版本的库,只需要
  libtensorflow_cc.so,1.4版本的似乎分成了两个so文件,即还需要libtensorflow_framework.so
  cp /tmp/proto/lib/libprotobuf.a ../tf_test/lib/
  头文件:
  mkdir -p ../tf_test/include/tensorflow
  cp -r bazel-genfiles/* ../tf_test/include/
  cp -r tensorflow/cc ../tf_test/include/tensorflow
  cp -r tensorflow/core ../tf_test/include/tensorflow
  cp -r third_party ../tf_test/include
  cp -r /tmp/proto/include/* ../tf_test/include
  cp -r /tmp/eigen/include/eigen3/* ../tf_test/include
  cp -r tensorflow/contrib/makefile/downloads/nsync/public ../tf_test/include/external/nsync/public


  不需要的.cc文件可以删掉:
  cd ../tf_test/
  find . -name "*.cc" -type f -delete
至此,TensorFlow编译工作已经全部结束,接下来就是如何使用TensorFlow的c++调用Python环境下训练的模型。


二、tensorflow的c++接口调用图像分类模型
通过上面的的过程,已经编译好了c++版本的TensorFlow,接下来,将利用TensorFlow的c++接口来调用训练好的图像分类模型。图像分类网络选用的是inception_v3,其pb模型可以直接从网上下载,地址为: https://pan.baidu.com/s/11aQR4u1FF7V95pfm9YlIMw,提取码:21uc


下面的c++代码是在eclipse中进行编写运行,在运行运行之前,需要将tensorflow、opencv等动态链接库(.so)包含进去。以下是main函数,亲测可用。


/*
* main.cpp
*
*   Created on: 2020年3月31日
*       Author: xxx
*/


#include < fstream>
#include < utility>
#include < iostream>
#include < vector>
#include < opencv2/opencv.hpp>
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/graph/default_device.h"
#include "tensorflow/cc/client/client_session.h"


// 定义一个函数将Opencv的Mat数据转化为tensorflow的tensor,在python里面只要对cv2.imread()读进来的矩阵进行np.reshape之后,数据类型就成了一个tensor,即tensor与矩阵一样,然后就连可以输入到网络的入口了
// 而C++版本,网络的输入也需要是tensor数据类型,因此需要将输入图片转换成一个tensor,若使用Opencv读取图片,格式是一个Mat,需要考虑怎样将一个Mat转换为tensor
void CVMat_to_Tensor(cv::Mat img,tensorflow::Tensor * output_tensor,int input_rows, int input_cols)

imshow("input image",img);
// 对输入图像进行resize处理
resize(img,img,cv::Size(input_cols,input_rows));
imshow("resizes image",img);


// 归一化
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);


cv::waitKey(1000);
cv::destroyAllWindows();



int main(int argc, char ** argv)

/* --------------------配置关键信息------------------------------------*/
std::string model_path = "./model/inception_v3_2016_08_28_frozen.pb"; // pb模型地址
std::string image_path = "./model/cat.jpg"; // 测试图片
int input_height = 299; // 输入网络的图片高度
int input_width = 299; // 输入网络的图片宽度
std::string input_tensor_name = "input"; // 网络的输入节点的名称
std::string output_tensor_name = "InceptionV3/Predictions/Reshape_1"; // 网络的输出节点的名称


/* --------------------创建session------------------------------------*/
tensorflow::Session * session;
tensorflow::Status status = tensorflow::NewSession(tensorflow::SessionOptions(), & session); // 创建新会话Session


/* --------------------从pb文件中读取模型------------------------------------*/
tensorflow::GraphDef graphdef; //为当前的模型定义一张图
tensorflow::Status status_load = tensorflow::ReadBinaryProto(tensorflow::Env::Default(),model_path,& graphdef); // 从pb文件中读取图模型
if (!status_load.ok()) // 判断读取模型是否正确,错误的话则打印出错误的信息

  std::cout < < "ERROR: Loading model failed..." < < model_path < < std::endl;
  std::cout < < status_load.ToString() < < "\\n";
  return -1;

tensorflow::Status status_create = session-> Create(graphdef); // 将模型导入会话Session中
if (!status_create.ok()) // 判断将模型导入会话中是否成功,错误的话打印出错误信息

  std::cout < < "ERROR: Creating graph in session failed..." < < status_create.ToString() < < std::endl;
  return -1;

std::cout < < "< ------Sucessfully created session and load graph------> " < < std::endl;


/* --------------------载入测试图片------------------------------------*/
cv::Mat img = cv::imread(image_path,0); // 读取图片,读取灰度图
if (img.empty())

  std::cout < < "cant open the image!!!!!" < < std::endl;
  return -1;

// 创建一个tensor作为输入网络的接口
tensorflow::Tensor resized_tensor(tensorflow::DT_FLOAT,tensorflow::TensorShape(1,input_height,input_width,3));
// 将opencv读取的Mat格式的图片存入tensor
CVMat_to_Tensor(img,& resized_tensor,input_height,input_width);
std::cout < < resized_tensor.DebugString() < < std::endl;


/* --------------------用网络进行测试------------------------------------*/
std::cout < < std::endl < < "< ------------------Runing the model with test_image-------------------> " < < std::endl;
// 前向运行,输出结果一定是一个tensor的vector
std::vector< tensorflow::Tensor> outputs;
std::string output_node = output_tensor_name; // 输出节点名
tensorflow::Status status_run = session-> Run(input_tensor_name,resized_tensor,output_node,,& outputs);
if (!status_run.ok())

  std::cout < < "ERROR: Run failed..." < < std::endl;
  std::cout < < status_run.ToString() < < std::endl;
  return -1;



// 把输出值提取出来
std::cout < < "Output tensor size: " < < outputs.size() < < std::endl;
for (std::size_t i = 0; i < outputs.size(); i++)

  std::cout < < outputs[i].DebugString() < < std::endl;

tensorflow::Tensor t = outputs[0];
auto tmap = t.tensor< float,2> ();
int output_dim = t.shape().dim_size(1);


int output_class_id = -1;
double output_prob = 0.0;
for (int j = 0; j < output_dim; j++)

  std::cout < < "Class " < < j < < " prob: " < < tmap(0,j) < < "," < < std::endl;
  if (tmap(0,j) > = output_prob)
 
  output_class_id = j;
  output_prob = tmap(0,j);
 

// 输出结果
std::cout < < "Final class id : " < < output_class_id < < std::endl;
std::cout < < "Final class prob : " < < output_prob < < std::endl;







————————————————
版权声明:本文为CSDN博主「AI小白一枚」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
【C/C++气象数据中心实战,手把手教你做工业级项目】原文链接:https://blog.csdn.net/qq_40716944/article/details/105255438

    推荐阅读