centos下編譯tensorflow c++ API坑比較多,最近有幸都踩了一遍
tensorflow版本和bazel版本protobuf版本都必須對應的上,比如
- tf1.14對應:bazel-0.24.1-installer-linux-x86_64.sh protobuf-all-3.7.0.zip(3.7.1據說也可以)
- tf1.13對應:bazel-0.19.2 protobuf-3.6.1.2
其中tf1.13的編譯參考 1、https://blog.csdn.net/pursuit_zhangyu/article/details/104473245 這里的步驟是可以的用,tf1.13編譯失敗過好多次最后還是成功了,主要是從外網下載坑多。
主要講一下tensorflow1.14編譯和無網下的編譯姿勢。
參考:1、https://blog.csdn.net/sinat_37532065/article/details/83211988
一、下載資源
bazel-0.24.1-installer-linux-x86_64.sh protobuf-all-3.7.0.zip jdk-8u261-linux-x64.tar.gz cmake-3.10.2.tar.gz Anaconda3-5.2.0-Linux-x86_64.sh
其中,bazel和protobuf的版本比較固定。java、cmake、python3.6或3.7環境有就可以,版本根據需要來。
二、安裝依賴
yum install gcc g++ gcc-c++ libstdc++-devel gcc-6 g++-6 yum install zip unzip yum install make yum install git yum install future yum install zlib1g-dev zlib zlib-devel.x86_64 yum install autoconf automake libtool curl patch pip install distributed future
三、源碼安裝cmake
tar -zxvf cmake-3.6.2.tar.gz cd cmake-3.6.2 ./bootstrap make & make install cmake --version
四、安裝java
參考:https://www.cnblogs.com/stulzq/p/9286878.html
注:適用於只寫入臨時變量,關閉終端即失效的場景。 長久生效的配置見鏈接 https://www.cnblogs.com/stulzq/p/9286878.html tar -zxvf jdk-8u261-linux-x64.tar.gz export JAVA_HOME=**************/jdk1.8.0_261 export JRE_HOME=${JAVA_HOME}/jre export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib export PATH=${JAVA_HOME}/bin:$PATH
五、安裝bazel
chmod +x bazel-0.24.1-installer-linux-x86_64.sh ./bazel-0.24.1-installer-linux-x86_64.sh bazel安裝后卸載:刪除~/bin文件夾,刪除~/.bazel(/root/.cache/bazel)文件夾,修改設置的環境變量 注:bazel: /usr/local/bin/bazel /usr/local/lib/bazel export PATH="$PATH:$HOME/bin" 注:只寫入臨時變量的方法,關閉終端即失效的場景。
長久生效配置見鏈接 https://www.cnblogs.com/stulzq/p/9286878.html
六、安裝protobuf
tar zxvf protobuf-all-3.7.0.zip unzip protobuf-all-3.7.0.zip mkdir protobuf_bin ./autogen.sh ./configure --prefix=************************/protobuf_bin make -j4 make install export PATH=$PATH:*********************/protobuf_bin/bin export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:************/protobuf_bin/lib export CPLUS_INCLUDE_PATH=*************/protobuf_bin/include
長久生效配置見鏈接 https://www.cnblogs.com/stulzq/p/9286878.html
七、配置編譯tensorflow1.14
unzip tensorflow-r1.14.zip cd tensorflow-r1.14/ ./configure
如需編譯GPU版本 CUDA support選擇Y,其他選項全部N;如需CPU版本全部N
// 有顯卡 bazel build --config=opt --config=cuda //tensorflow:libtensorflow_cc.so // 無顯卡 bazel build --config=opt //tensorflow:libtensorflow_cc.so
注意這里是要連外網下載依賴包的,最好掛代理,否則可能會一直報錯失敗,
網絡暢通的話請忽略掉下面這些操作
主要講一下無網情況下的處理方法!
修改目錄下的WORKSPACE文件和tensorflow/workspace.bzl文件
http_archive( name = "io_bazel_rules_closure", sha256 = "e0a111000aeed2051f29fcc7a3f83be3ad8c6c93c186e64beb1ad313f0c7f9f9", strip_prefix = "rules_closure-cf1e44edb908e9616030cc83d085989b8e6cd6df", urls = [
"file://///var/www/html/cf1e44edb908e9616030cc83d085989b8e6cd6df.tar.gz",
#注:所有類似下載地址的地方全都加上本地地址,並且自行先下載下來然后放到指定位置即可,
#需要下載的地方稍微有點多且不限於這兩個文件,所以要根據編譯時的報錯定位然后修改,
#有時通過鏈接下載的文件名需要修改,保證本地文件名能對的上即可
#將包直接放在/root/.cache/bazel/_bazel_root/*****/external/protobuf_archive/目錄下每次編譯都會直接被清空不可行
"http://mirror.tensorflow.org/github.com/bazelbuild/rules_closure/archive/cf1e44edb908e9616030cc83d085989b8e6cd6df.tar.gz",
"https://github.com/bazelbuild/rules_closure/archive/cf1e44edb908e9616030cc83d085989b8e6cd6df.tar.gz",], )
八、編譯第三方庫
cd ~/tensorflow-r1.14/tensorflow/contrib/makefile/ ./build_all_linux.sh
編譯Eigen3
cd tensorflow-r1.14/tensorflow/contrib/makefile/downloads/eigen mkdir build cd build cmake .. make sudo make install
usr/local/include目錄下會出現eigen3文件夾,可以移動到需要的地方
九、整理和打包庫環境:
sudo mkdir -p /usr/local/include/tf/tensorflow sudo cp -r bazel-genfiles/ /usr/local/include/tf sudo cp -r tensorflow/cc /usr/local/include/tf/tensorflow sudo cp -r tensorflow/core /usr/local/include/tf/tensorflow sudo cp -r /tensorflow/contrib /usr/local/include/tf/tensorflow sudo cp -r third_party /usr/local/include/tf sudo cp bazel-bin/tensorflow/libtensorflow_cc.so /usr/local/lib sudo cp bazel-bin/tensorflow/libtensorflow_cc.so.1 /usr/local/lib sudo cp bazel-bin/tensorflow/libtensorflow_framework.so /usr/local/lib sudo cp bazel-bin/tensorflow/libtensorflow_framework.so.1 /usr/local/lib
期間遇到過一個問題,libtensorflow_framework.so找不到,搜索/root/.cache/bazel里面也沒有
解決方法,將libtensorflow_framework.so.1 重命名成 libtensorflow_framework.so 可以用了
放到新系統上跑需要的文件:
/usr/local/include/tf /usr/local/lib (或者單獨拷出來那四個libtensorflow_****) protobuf_bin usr/local/include/eigen3
十、測試一下
編寫CMakeLists.txt 鏈接的位置改成實際的位置
#指定 cmake 的最小版本 cmake_minimum_required(VERSION 3.6.2) #項目名稱/工程名 project(cpptest) #設置c++編譯器 set(CMAKE_CXX_STANDARD 14) SET(CMAKE_BUILD_TYPE "Debug") SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb") SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") #aux_source_directory(./src DIR_SRCS) # 搜索當前目錄下的所有.cpp文件 #設置TENSORFLOW_DIR變量,變量內容為安裝的tensorflow文件夾路徑 set(TENSORFLOW_DIR *******************/tf) include_directories(${TENSORFLOW_DIR} ${TENSORFLOW_DIR}/bazel-genfiles ${TENSORFLOW_DIR}/tensorflow/contrib/makefile/downloads/absl ${TENSORFLOW_DIR}/tensorflow/contrib/makefile/downloads/nsync/public ${TENSORFLOW_DIR}/third_party/eigen3/unsupported *****************/eigen3 *****************/lib *****************/protobuf_bin/include) link_directories(${TENSORFLOW_DIR} ***************/lib) #動態鏈接庫目錄 #add_executable(cpptest ${DIR_SRCS}) ## 生成可執行文件 add_executable(cpptest main) #添加可執行文件所需要的庫,連接libtensorflow_cc.so和libtensorflow_framework庫,鏈接動態鏈接庫 target_link_libraries(cpptest tensorflow_cc tensorflow_framework)

#include <fstream> #include <iostream> #include <map> #include <tensorflow/core/platform/env.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/platform/logging.h" #include "tensorflow/core/platform/types.h" #include "tensorflow/core/public/session.h" using namespace std ; using namespace tensorflow; using tensorflow::Tensor; using tensorflow::Status; using tensorflow::string; using tensorflow::int32; //GraphDef graph_def; //graph::SetDefaultDevice("/gpu:1", &graph_def); //從文件名中讀取數據 Status ReadTensorFromImageFile(string file_name, const int input_height, const int input_width, vector<Tensor>* out_tensors) { auto root = Scope::NewRootScope(); using namespace ops; auto file_reader = ops::ReadFile(root.WithOpName("file_reader"),file_name); const int wanted_channels = 3; Output image_reader; std::size_t found = file_name.find(".png"); //判斷文件格式 if (found!=std::string::npos) { image_reader = DecodePng(root.WithOpName("png_reader"), file_reader,DecodePng::Channels(wanted_channels)); } else { image_reader = DecodeJpeg(root.WithOpName("jpeg_reader"), file_reader,DecodeJpeg::Channels(wanted_channels)); } // 下面幾步是讀取圖片並處理 auto float_caster =Cast(root.WithOpName("float_caster"), image_reader, DT_FLOAT); auto dims_expander = ExpandDims(root, float_caster, 0); auto resized = ResizeBilinear(root, dims_expander,Const(root.WithOpName("resize"), {input_height, input_width})); // Div(root.WithOpName(output_name), Sub(root, resized, {input_mean}),{input_std}); Transpose(root.WithOpName("transpose"),resized,{0,2,1,3}); GraphDef graph; root.ToGraphDef(&graph); unique_ptr<Session> session(NewSession(SessionOptions())); session->Create(graph); session->Run({}, {"transpose"}, {}, out_tensors);//Run,獲取圖片數據保存到Tensor中 return Status::OK(); } int main(int argc, char* argv[]) { string graph_path = "tf_model.pb"; GraphDef graph_def; graph::SetDefaultDevice("/gpu:1", &graph_def); //讀取模型文件 if (!ReadBinaryProto(Env::Default(), graph_path, &graph_def).ok()) { cout << "Read model .pb failed"<<endl; return -1; } cout << "Read model .pb AC"<<endl; //新建session unique_ptr<Session> session; SessionOptions sess_opt; sess_opt.config.mutable_gpu_options()->set_allow_growth(true); (&session)->reset(NewSession(sess_opt)); if (!session->Create(graph_def).ok()) { cout<<"Create graph failed"<<endl; return -1; } cout<<"Create graph AC"<<endl; //讀取圖像到inputs中 int input_height = 800; int input_width = 800; vector<Tensor> inputs; // string image_path(argv[1]); string image_path("test.jpg"); if (!ReadTensorFromImageFile(image_path, input_height, input_width,&inputs).ok()) { cout<<"Read image file failed"<<endl; return -1; } cout<<"Read image AC"<<endl; vector<Tensor> outputs; string input = "input_1"; string output = "segme_out/Sigmoid";//graph中的輸入節點和輸出節點,需要預先知道 pair<string,Tensor>img(input,inputs[0]); Status status = session->Run({img},{output}, {}, &outputs);//Run,得到運行結果,存到outputs中 if (!status.ok()) { cout<<"Running model failed"<<endl; cout<<status.ToString()<<endl; return -1; } cout<<"Running model AC"<<endl; //得到模型運行結果 Tensor t = outputs[0]; auto tmap = t.tensor<float, 4>(); int output_dim0 = t.shape().dim_size(0); int output_dim1 = t.shape().dim_size(1); int output_dim2 = t.shape().dim_size(2); int output_dim3 = t.shape().dim_size(3); cout<<typeid(tmap).name()<<endl; std::vector< vector<float> >feat(800,vector<float>(800,0)); ofstream outfile; outfile.open("out.txt"); for(int i=0;i<800;i++) { for(int j=0;j<800;j++) { feat[i][j]=tmap(0,i,j,0); outfile<<feat[i][j]<<endl; } } outfile.close(); return 0; }
可自行編寫調用模型代碼,然后
mkdir build cmake .. & make ./cpptest
ok
至此終於編譯完成,肝了好幾天