赋料扬雄敌,诗看子建亲。这篇文章主要讲述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
推荐阅读
- 操作系统学习
- #yyds干货盘点#k8s中的核心组件
- 什么是数据包嗅探(如何理解?)
- 什么是加密货币(如何通俗理解加密货币?)
- Python使用Selenium的SMS Bomber
- 如何理解C中的静态函数(如何使用?)
- Python函数名称中允许使用哪些字符()
- 用作数据结构的C编程概念是什么()
- HTTP、FTP和SMTP有什么区别()