1. 程式人生 > 實用技巧 >Windows下編譯TensorFlow1.3 C++ library及建立一個簡單的TensorFlow C++程式

Windows下編譯TensorFlow1.3 C++ library及建立一個簡單的TensorFlow C++程式

由於最近比較忙,一直到假期才有空,因此將自己學到的知識進行分享。如果有不對的地方,請指出,謝謝!目前深度學習越來越火,學習、使用tensorflow的相關工作者也越來越多。最近在研究tensorflow線下采用 python 指令碼訓練出模型, 利用freeze_graph工具輸出.pb圖檔案,之後再線上生產環境windows平臺上用C++程式碼直接呼叫預先訓練好的模型完成預測的工作。因為目前tensorflow提供的C++的API比較少,所以參考了以上幾篇已有的日誌,做個總結。這裡編譯出TensorFlow C++ library,遇到的坑進行填埋。之後的呼叫C++library相對比較簡單,可以參考連結部分。

Step1:Windows 10必備環境準備

1.1安裝VS2015

1.2安裝Swigwin-3.0.12,其可執行檔案地址為D:/lib/swigwin-3.0.12/swig.exe

1.4安裝python3.5,安裝時注意選擇將路徑新增到環境變數。

1.5安裝CMake-3.8.0,安裝時注意選擇將路徑新增到環境變數。

1.6安裝Git,用於在編譯過程中從GitHub上下載依賴項。

1.7 將GitHub上TensorFlow的master分支下載並解壓到資料夾D:\tf中,編輯檔案tensorflow/tensorflow/contrib/cmake/CMakeLists.txt,將第87行至93行修改如下:

1 2 3 4 5 6 7 8 9 10 11 12 if(tensorflow_OPTIMIZE_FOR_NATIVE_ARCH) include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-march=native"COMPILER_OPT_ARCH_NATIVE_SUPPORTED) if(COMPILER_OPT_ARCH_NATIVE_SUPPORTED) set(CMAKE_CXX_FLAGS"${CMAKE_CXX_FLAGS} -march=native") else() CHECK_CXX_COMPILER_FLAG(
"/arch:AVX"COMPILER_OPT_ARCH_AVX_SUPPORTED) if(COMPILER_OPT_ARCH_AVX_SUPPORTED) set(CMAKE_CXX_FLAGS"${CMAKE_CXX_FLAGS} /arch:AVX") endif() endif() endif()

總結下這一部分的三個重要地址:

Python可執行檔案地址為:D:/lib/Python35/python.exe;
Python庫檔案地址為:D:/lib/Python35/libs/python35.lib(release版本), D:/lib/Python35/libs/python35_d.lib(Debug版本);
Swigwin可執行檔案地址:D:/lib/swigwin-3.0.12/swig.exe。

Step2:編譯 TensorFlow shared lib

2.1開啟資料夾D:\tf\tensorflow-master\tensorflow\contrib\cmake, 新建資料夾\build。以管理員身份執行開始 \ 所有程式 \ Visual Studio 2015\Visual Studio Tools\ Developer Command Prompt for VS 2015,輸入powershell,使用命令切換到新建的build資料夾下。使用指令1用於build編譯專案。可以看到,使用的就是上一部分儲存的三個路徑。當命令列中出現Generating done,說明build成功。

1 2 3 4 5 # 指令1(release) cmake .. -A x64 -DCMAKE_BUILD_TYPE=Release -DSWIG_EXECUTABLE=D:/lib/swigwin-3.0.12/swig.exe-DPYTHON_EXECUTABLE=D:/lib/Python35/python.exe -DPYTHON_LIBRARIES=D:/lib/Python35/libs/python35.lib -Dtensorflow_BUILD_SHARED_LIB=ON # 指令1(debug) cmake .. -A x64 -DCMAKE_BUILD_TYPE=Debug -DSWIG_EXECUTABLE=D:/lib/swigwin-3.0.12/swig.exe-DPYTHON_EXECUTABLE=D:/lib/Python35/python.exe -DPYTHON_LIBRARIES=D:/lib/Python35/libs/python35_d.lib-Dtensorflow_BUILD_SHARED_LIB=ON

或者,這裡我用cmake-gui介面進行cmake編譯出release和debug版本,如下圖所示:

2.2命令列中輸入指令2開始編譯,在編譯過程中保持網路暢通,有15個依賴庫需要下載。編譯過程中可能出現一些警告,不用擔心,只要沒有錯誤編譯就可以通過。

# 指令2(release)
MSBuild /p:Configuration=Release ALL_BUILD.vcxproj
# 指令2(debug)
MSBuild /p:Configuration=Debug ALL_BUILD.vcxproj

2.3但是,我在自己的電腦上編譯失敗,並出現了90個錯誤,這些錯誤都指向了兩檔案:

D:\tf\tensorflow-master\tensorflow\contrib\cmake\build\re2\src\re2\re2\testing\re2_test.cc
D:\tf\tensorflow-master\tensorflow\contrib\cmake\build\re2\src\re2\re2\testing\search_test.cc

re2包提供了正則表示式的功能,資料夾testing中是測試檔案,在TensorFlow執行過程中其實不需要這些測試功能,所以可以通過禁止編譯re2的測試部分來移除這些錯誤。

Step3:排除錯誤

3.1對出錯的工程資料夾下,修改檔案D:\tf\tensorflow-master\tensorflow\contrib\cmake\build\re2\src\re2\CMakeLists.txt(一定要翻牆下載到),將第16行修改為:

option(RE2_BUILD_TESTING “enable testing for RE2” OFF)

,並儲存。

3.2 重新進行編譯(步驟2.2)。在編譯過程中,會出現錯誤:

C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Microsoft.CppCommon.targets(171,5): error MSB6006: “cmd.exe”已退
出,程式碼為 1。 [D:\tensorflow-master\tensorflow\contrib\cmake\build\grpc.vcxproj]

這個應該是沒有成功下載grpc,這個應該是個bug,給的連結不對(多次編譯都編不過去),百度了下grpc對我現在的應用暫時用不多(不瞭解可以百度gprc)因此,暫時不需要grpc,也就不下載,編輯檔案tensorflow/tensorflow/contrib/cmake/CMakeLists.txt,將第23行修改如下:

option(tensorflow_ENABLE_GRPC_SUPPORT "Enable gRPC support" OFF)

3.3重新cmake 和Build編譯專案,並重新進行編譯,重複步驟2.1,2.2和3.1。可能會出現錯誤:

fatal error C1060: compiler is out of heap space

這應該是跟自己的硬體相關,我自己的電腦配置不太好。出現這個錯誤,首先等待編譯過程的完成,然後重複執行指令2。大概重複執行兩三次這個問題就沒有了。每次重複執行前,需等待整個編譯過程完成。

也可能會出現這樣的錯誤(Debug編譯出現這樣的錯誤):

這可能在實際中編譯採用的是x86,並沒有真正採用x64的環境進行編譯,因此開啟命令視窗Developer Command Prompt for VS 2015,輸入powershell,使用命令切換到新建的build資料夾下,輸入指令3,然後在輸入指令2。

# 指令3
set PreferredToolArchitecture=x64

3.4 編譯到最後會出現錯誤(debug版本比較嚴格)符號過載的錯誤,如下圖所示:

error C2678: binary '<': no operator found which takes a left-hand operand of type IndicesRowIterator

修改對應的資料夾下的檔案,我這裡是D:\tf\tensorflow-master-ngrpc\tensorflow\contrib\boosted_trees\lib\utils\sparse_column_iterable.cc,增加到檔案中,增加的內容如下所示:

bool operator<( const IndicesRowIterator& other ) const {
QCHECK_LT( iter_, other.iter_ );
return ( row_idx_ < other.row_idx_ );
}

最終編譯成功。出現需要的相應的release和debug版本的lib和動態連結庫

Step4:在Windows上編譯和執行一個簡單的TensorFlowC++ 程式

4.1在vs2015中建立一個新的工程solution,並在對應的檔案中輸入如下:

#include <vector>
#include <eigen/Dense>

#include "matmul.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/cc/ops/standard_ops.h"

using namespace tensorflow;

// Build a computation graph that takes a tensor of shape [?, 2] and
// multiplies it by a hard-coded matrix.
GraphDef CreateGraphDef()
{
  Scope root = Scope::NewRootScope();

  auto X = ops::Placeholder(root.WithOpName("x"), DT_FLOAT, 
                            ops::Placeholder::Shape({ -1, 2 }));
  auto A = ops::Const(root, { { 3.f, 2.f },{ -1.f, 0.f } });

  auto Y = ops::MatMul(root.WithOpName("y"), A, X, 
                       ops::MatMul::TransposeB(true));

  GraphDef def;
  TF_CHECK_OK(root.ToGraphDef(&def));

  return def;
}

int main()
{
  GraphDef graph_def = CreateGraphDef();

  // Start up the session
  SessionOptions options;
  std::unique_ptr<Session> session(NewSession(options));
  TF_CHECK_OK(session->Create(graph_def));

  // Define some data.  This needs to be converted to an Eigen Tensor to be
  // fed into the placeholder.  Note that this will be broken up into two
  // separate vectors of length 2: [1, 2] and [3, 4], which will separately
  // be multiplied by the matrix.
  std::vector<float> data = { 1, 2, 3, 4 };
  auto mapped_X_ = Eigen::TensorMap<Eigen::Tensor<float, 2, Eigen::RowMajor>>
                     (&data[0], 2, 2);
  auto eigen_X_ = Eigen::Tensor<float, 2, Eigen::RowMajor>(mapped_X_);

  Tensor X_(DT_FLOAT, TensorShape({ 2, 2 }));
  X_.tensor<float, 2>() = eigen_X_;

  std::vector<Tensor> outputs;
  TF_CHECK_OK(session->Run({ { "x", X_ } }, { "y" }, {}, &outputs));

  // Get the result and print it out
  Tensor Y_ = outputs[0];
  std::cout << Y_.tensor<float, 2>() << std::endl;
  
  session->Close();
  getchar();
}

4.2在對應的標頭檔案中輸入如下:

#pragma once

#define COMPILER_MSVC
#define NOMINMAX

4.3在vs2015中,屬性配置介面中,includeDirectories:

D:\tf\tensorflow-master-ngrpc\tensorflow\contrib\cmake\build\Debug
D:\tf\tensorflow-master-ngrpc\tensorflow\contrib\cmake\build\external\nsync\public
D:\tf\tensorflow-master-ngrpc\tensorflow\contrib\cmake\build\protobuf\src\protobuf\src
D:\tf\tensorflow-master-ngrpc\tensorflow\contrib\cmake\build\external\eigen_archive
D:\tf\tensorflow-master-ngrpc\tensorflow\contrib\cmake\build
D:\tf\tensorflow-master-ngrpc
D:\tf\tensorflow-master-ngrpc\third_party\eigen3

4.4在vs2015中,屬性配置介面中,Additional Library Directories(release版本):

D:\tf\tensorflow-master-ngrpc\tensorflow\contrib\cmake\build\Release

4.5在vs2015中,屬性配置介面中,Linker Settings(release版本):

tensorflow.lib

4.6編譯和執行程式,執行結果如下所示:

 7 17
-1 -3

參考:

https://joe-antognini.github.io/machine-learning/build-windows-tf

http://quqixun.com/?p=785

http://blog.csdn.net/longji/article/details/72760409

http://blog.csdn.net/rockingdingo/article/details/75452711

https://github.com/tensorflow/tensorflow/issues

https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/cmake

https://stackoverflow.com/questions/42603407/how-to-compile-tensor-flow-with-sse-and-and-avx-instructions-on-windows