幾篇值得參考的博文:
[1] https://blog.csdn.net/robothn/article/details/86157724
[2] https://blog.csdn.net/yz2zcx/article/details/83106669
[3] https://blog.csdn.net/yuejisuo1948/article/details/84197534
[4] https://zhuanlan.zhihu.com/p/34942873
[5] https://www.cnblogs.com/hrlnw/p/7383951.html
[6] http://www.cnblogs.com/hrlnw/p/7007648.html
[7] https://blog.csdn.net/gzt940726/article/details/81053378
[8] https://blog.csdn.net/luoyexuge/article/details/80399265
[9] https://joe-antognini.github.io/machine-learning/windows-tf-project
形式上基本雷同,這裏主要參考的還是
[1] https://blog.csdn.net/robothn/article/details/86157724
接下來,進入正文:
一、使用CMake + VS2015 IDE編譯(失敗,結果導向看Bazel編譯)
1.準備工作(參考[3]:環境準備)
歡迎趟坑,如果珍惜所謂效率的,請直接看Bazel編譯!
2.下載源碼(https://github.com/tensorflow/tensorflow)
3.修改*.CMAKE文件
運行cmake-gui,configure出錯如下:
tf_core_ops.cmake報錯:clustering_ops.cc文件沒有找到,解決方法:cmake文件中修改路徑
tf.core_kernels.cmake報錯:clustering_ops.cc文件沒有找到,解決方法:cmake文件中修改路徑
接下來是,abseil_cpp.cmake文件的修改
(你自己創建的build文件)\abseil_cpp\src\abseil_cpp_build\absl下所有lib文件包含進來,
不然VS編譯abseil_cpp項目和後面所有*gen_cc項目都會出錯
if(WIN32)
if(${CMAKE_GENERATOR} MATCHES "Visual Studio.*")
set(abseil_cpp_STATIC_LIBRARIES
${abseil_cpp_BUILD}/absl/base/Release/absl_base.lib
${abseil_cpp_BUILD}/absl/base/Release/absl_internal_spinlock_wait.lib
${abseil_cpp_BUILD}/absl/base/Release/absl_dynamic_annotations.lib
${abseil_cpp_BUILD}/absl/base/Release/absl_internal_malloc_internal.lib
${abseil_cpp_BUILD}/absl/base/Release/absl_internal_throw_delegate.lib
${abseil_cpp_BUILD}/absl/container/Release/absl_internal_hashtablez_sampler.lib
${abseil_cpp_BUILD}/absl/container/Release/absl_raw_hash_set.lib
${abseil_cpp_BUILD}/absl/debugging/Release/absl_demangle_internal.lib
${abseil_cpp_BUILD}/absl/debugging/Release/absl_failure_signal_handler.lib
${abseil_cpp_BUILD}/absl/debugging/Release/absl_internal_debugging_internal.lib
${abseil_cpp_BUILD}/absl/debugging/Release/absl_internal_examine_stack.lib
${abseil_cpp_BUILD}/absl/debugging/Release/absl_leak_check.lib
${abseil_cpp_BUILD}/absl/debugging/Release/absl_leak_check_disable.lib
${abseil_cpp_BUILD}/absl/debugging/Release/absl_stacktrace.lib
${abseil_cpp_BUILD}/absl/debugging/Release/absl_symbolize.lib
${abseil_cpp_BUILD}/absl/hash/Release/absl_hash.lib
${abseil_cpp_BUILD}/absl/hash/Release/absl_internal_city.lib
${abseil_cpp_BUILD}/absl/numeric/Release/absl_int128.lib
${abseil_cpp_BUILD}/absl/strings/Release/absl_strings.lib
${abseil_cpp_BUILD}/absl/strings/Release/absl_internal_str_format_internal.lib
${abseil_cpp_BUILD}/absl/strings/Release/absl_internal_strings_internal.lib
${abseil_cpp_BUILD}/absl/synchronization/Release/absl_internal_graphcycles_internal.lib
${abseil_cpp_BUILD}/absl/synchronization/Release/absl_synchronization.lib
${abseil_cpp_BUILD}/absl/time/Release/absl_time.lib
${abseil_cpp_BUILD}/absl/time/Release/absl_internal_time_zone.lib
${abseil_cpp_BUILD}/absl/time/Release/absl_internal_civil_time.lib
${abseil_cpp_BUILD}/absl/types/Release/absl_bad_optional_access.lib
${abseil_cpp_BUILD}/absl/types/Release/absl_bad_variant_access.lib
${abseil_cpp_BUILD}/absl/types/Release/absl_internal_bad_any_cast_impl.lib
${abseil_cpp_BUILD}/absl/types/Release/absl_optional.lib)
4.添加version_info.cc
鏈接:https://pan.baidu.com/s/1fPH88RVbDhjEn5sBoR8LDQ
提取碼:33wu
添加至tensorflow-master\tensorflow\core\util\
5.tensorflow-master\tensorflow\core\kernels\unicode_ops.cc
tensorflow-master\tensorflow\core\kernels\unicode_ops.cc(65): error C2440: “初始化”: 無法從“const UChar *”轉換爲“const char16_t *”
解決方法:強制轉換類型,const char16_t* buf = (char16_t*)in.getBuffer();
6.tensorflow-master\tensorflow\cc\gradients\nn_grad.cc
報錯:auto squeeze_result = Squeeze(scope, matmul_result, Squeeze::Axis(axis));
解決方法:auto squeeze_result = Squeeze(scope, matmul_result, Squeeze::SqueezeDims(axis));
7.使用 CMake GUI 生成 solution(參考[1]:使用 cmake GUI 生成 solution)
打開cmake-gui
配置項目:
生成項目:
接下來就是,用VS2015(管理員)打開tensorflow.sln文件
8.Eigen項目編譯問題
每一次編譯都要重新下載downloads文件裏面的文件
鏈接:https://pan.baidu.com/s/1mB7Wpp8Uw8OSpdJVqJSDog (下載downloads文件夾裏面的文件)
提取碼:tk4t
但是這還不夠,編譯eigen這個項目,下載和解壓文件的動作主要由
download-eigen.cmake和extract-eigen.cmake,這兩個文件執行的
如此的話,就進去cmake文件裏面對應位置進行修改
比如download-eigen.cmake
這一段就是download-eigen.cmake中判斷是否重新下載的語段,但是不知道爲什麼has_hash這個值每次都是0(具體原因我也沒有深究),所以每一次都會出現
File already exists but no hash specified (use URL_HASH):
file='E:/tensorflow-master/vs14_project/downloads/ad3bcd81cc49.tar.gz'
Old file will be removed and new file downloaded from URL.
所以,就在這句message後面,加上return(),
並且註釋掉file(REMOVE "E:/tensorflow-master/vs14_project/downloads/ad3bcd81cc49.tar.gz")
同時,修改extract-eigen.cmake,爲啥要修改呢?
因爲解壓出來的eigen文件夾中的CMakeLists文件有錯誤,只有阻止解壓,然後修改CMakeLists,具體後面再講
其實阻止解壓很簡單,加上return()就可以了
(你自己創建的build文件)\eigen\src\eigen\CMakeLists.txt文件修改:註釋掉紅框中的語句
不知道爲啥,報錯的原因居然是cmake沒有add_subdirectory()這條語句,好在這個語句沒啥用,註釋掉就好了
鏈接:https://pan.baidu.com/s/1PxNVZCgTyE0GHOfZFF3tcg (修改好的eigen文件夾,直接替換對應文件和文件夾就好了)
提取碼:fh3n
9.tf_core_kernels編譯
tf_core_kernels編譯確實很久
而且有幾個地方會出錯,
比如,fatal error C1060: 編譯器的堆空間不足,是因爲VS2015的 cl.exe 是並行編譯多個源文件的,每個分配了單獨線程,所以需要減少並行數來減少內存佔用,在編譯此項目時,需要把藍色處改爲 1
有成功編譯的,但是再編譯tensorflow、grpc_tensorflow_server、summarize_graph等項目又出了很多奇怪的錯誤
心疼自己1秒(冷漠)
此時,我已經花了4天在這個玩意上了,因爲編譯要好久,都是晚上搞,隔天回來看結果,
每次看到滿屏的錯誤,真是懷疑人生。。。。
二、使用 Bazel 編譯(成功)
1.準備工作(參考[1]:使用 Bazel 編譯Tensorflow1.13)
[1]中的 VS2015 x64 命令行,指的就是 vs2015 x64本機工具命令提示符(管理員)
2.下載並編譯 tensorflow(參考[6]:編譯源碼,生成so庫)
其實可以簡單到你不敢相信
1)啓動 VS2015 x64 命令行,激活Anaconda環境,在命令行內執行
cmd.exe "/K" D:\Users\Leon_PC\Anaconda3\Scripts\activate.bat
2)切換虛擬環境
conda activate tensorflow_gpu
3)配置項目
cd /d D:\lib\tensorflow(tensorflow_master目錄)
python configure.py
4)編譯項目:libtensorflow_cc.so、libtensorflow_framework.so和install_headers
編譯之前,去到\tensorflow-master\tensorflow\BUILD文件裏面好好看清楚
需要編譯的是libtensorflow_cc.so、libtensorflow_framework.so和install_headers三個項目
install_headers項目會把所有H文件彙總,方便後面引用
cd tensorflow
bazel build :libtensorflow_cc.so(BUILD文件tf_cc_shared_object(name="libtensorflow_cc.so"))
bazel build :libtensorflow_framework.so(BUILD文件tf_cc_shared_object(name="libtensorflow_framework.so"))
bazel build :install_headers(BUILD文件tf_cc_shared_object(name="install_headers"))
這是後面編譯好了之後再編譯一次的結果,因爲沒有改動,所以沒有彈出特別多信息
libtensorflow_cc.so第一次編譯成功的結果如下:
最後看到
滿滿的成就感有木有
順便提一句,bazel-bin文件夾是要你運行bazel build命令後自動生成的
3.運行一個小栗子
本來以爲我就可以輕鬆愉快地走向人生巔峯了,沒想到後面的幾個問題讓我又搞了2天
果然,成年人的世界裏,沒有容易二字
1)H文件引用問題
這個比較好解決,只要前面記得編譯install_headers
後面,C/C++->常規->附加包含目錄,加上以下幾句,就基本沒有問題了
D:\\lib\\tensorflow\\bazel-genfiles\\tensorflow\\include
D:\\lib\\tensorflow\\bazel-genfiles
D:\\lib\\tensorflow\\bazel-bin\\tensorflow
D:\\lib\\tensorflow\\bazel-genfiles\\tensorflow\\include\\external\\com_google_absl
D:\\lib\\tensorflow\\bazel-genfiles\\tensorflow\\include\\external\\protobuf_archive\\src
2)lib文件的鏈接問題(參考[9]:Additional Command Line Options)
首先,你要bazel-bin中所有*.lib文件都列出來,這需要寫一個批量處理程序
鏈接:https://pan.baidu.com/s/15dhDeolpapzMH7lGOjAblg (這裏我都列出來了,自取吧)
提取碼:s1fx
然後,鏈接器->輸入->附加依賴項添加*.lib,鏈接器->常規->附加庫目錄添加lib路徑
最後,鏈接器->命令行->其他選項添加/WHOLEARCHIVE:*.lib,
這裏的*.lib是指bazel-bin\tensorflow\core\文件下所有lib文件以及子目錄下的所有lib文件
鏈接:https://pan.baidu.com/s/1LlnnbfuzkzuIxDsHrePnnA (WHOLEARCHIVE格式文件)
提取碼:puyg
不然的話,你會遇到
錯誤:Non-OK-status: status status: Not found: Op type not registered ‘NoOp’ in binary running on .
3)運行結果
隨便跑了一個程序,
#include<iostream>
#include "tensorflow/cc/client/client_session.h"
#include "tensorflow/cc/ops/standard_ops.h"
#include "tensorflow/core/framework/tensor.h"
int main()
{
using namespace tensorflow;
using namespace tensorflow::ops;
Scope root = Scope::NewRootScope();
//Matrix A = [3 2; -1 0]
auto A = Const(root, { { 3.f, 2.f },{ -1.f, 0.f } });
//Vector b = [3 5]
auto b = Const(root, { { 3.f, 5.f } });
//v = Ab^T
auto v = MatMul(root.WithOpName("v"), A, b, MatMul::TransposeB(true));
std::vector<Tensor> outputs;
ClientSession session(root);
//Run and fetch v
TF_CHECK_OK(session.Run({ v }, &outputs));
//Expect outputs[0] == [19; -3]
LOG(INFO) << outputs[0].matrix<float>();
return 0;
}
啓動vs2015 x64本機工具命令提示符(管理員)
打開*.sln,配置好環境之後編譯
之所以使用vs2015 x64本機工具命令提示符,是因爲vs默認的是32位的link.exe,
鑑於我們這個牛逼的TensorFlow需要鏈接非常非常多庫纔可以運行起來,所以要用64位的link.exe
不然會出現錯誤:鏈接器堆空間不足
解決方法:VS2015 x64 本機工具命令提示符,打開xxx.sln,再編譯;
參考:https://blog.csdn.net/andr0id/article/details/83899973
最後,運行結果如下。
不容易啊