本篇中介紹一下TensorFlow的安裝。TensorFlow的安裝分為安裝包安裝和編譯安裝.
一般的用戶使用安裝包安裝就可以了弱判,并且安裝包的方式簡(jiǎn)單方便慧耍,具體又分為基于pip安裝履因、基于docker安裝类咧、基于VirtualEnv的安裝和基于Anaconda的安裝馒铃,基本的過(guò)程都是先準(zhǔn)備好Python環(huán)境,然后直接通過(guò)Pip(python的包管理器)直接下載安裝TensorFlow的Python包痕惋,比較簡(jiǎn)單区宇,這里就不再贅述了,可自行g(shù)oogle或參考這兩篇文章值戳,寫的十分的詳細(xì):wiki议谷, doc
基于編譯源碼的安裝方式在用戶找不到自己平臺(tái)合適的安裝包、或則是想要深入學(xué)習(xí)TensorFlow實(shí)現(xiàn)的情況下使用堕虹。這里我們?cè)敿?xì)介紹一下基于源碼的安裝方式卧晓。
TensorFlow官網(wǎng)也有一篇講解源碼安裝的文章,也值得參考一下:源碼安裝鲫凶。
那么本文跟這些文章的區(qū)別在哪呢禀崖?本人力求做到跟官網(wǎng)的手冊(cè)互補(bǔ)衩辟,本文中我會(huì)將重點(diǎn)放在原理的講解上螟炫,而這些參考資料的重點(diǎn)都是在實(shí)際動(dòng)手操作上。
至于閱讀順序完全在于讀者的喜好艺晴,可以對(duì)照這些操作手冊(cè)先實(shí)踐一遍昼钻,然后回過(guò)頭來(lái)看這篇講解;也可以先看我這偏講解封寞,然后再實(shí)踐然评。
環(huán)境準(zhǔn)備
編譯TensorFlow工程的時(shí)候,有很多可選功能可以選擇是否開啟狈究,有是否需要GPU支持碗淌,還有是否需要支持HDFS,是否需要OpenGL抖锥,Google Cloud亿眠,XLA優(yōu)化等等。用戶選擇的開啟的功能越多磅废,TensorFlow的依賴項(xiàng)就越多纳像,環(huán)境準(zhǔn)備就越復(fù)雜些。
1拯勉、首先我們需要選擇平臺(tái)和操作系統(tǒng):
Ubuntu和max OS X是官方推薦的兩個(gè)平臺(tái)竟趾,本篇中我們選擇Ubuntu 16.04 64位作為編譯平臺(tái)憔购。
2、安裝構(gòu)建工具Bazel:
Bazel是一個(gè)開源的構(gòu)建系統(tǒng)岔帽,同樣來(lái)自于google玫鸟,在google內(nèi)部使用的也比較廣泛。
構(gòu)建系統(tǒng)的需求是隨著軟件規(guī)模的增大而提出的犀勒。在軟件規(guī)模很小的時(shí)候鞋邑,我們可以手動(dòng)調(diào)用gcc編譯和鏈接生成目標(biāo)文件。但是隨著軟件規(guī)模的增大账蓉,這種方式顯然很低效枚碗,于是出現(xiàn)的構(gòu)建工具,我們可以定義構(gòu)建目標(biāo)的規(guī)則文件铸本,然后由構(gòu)建工具來(lái)解析這個(gè)規(guī)則文件肮雨,調(diào)用gcc來(lái)編譯何生成目標(biāo)文件。隨著軟件規(guī)模的進(jìn)一步擴(kuò)大箱玷,出現(xiàn)了跨平臺(tái)的需求怨规。這時(shí)候構(gòu)建工具也提供了根據(jù)不同的平臺(tái)定義不同的構(gòu)建規(guī)則的功能。
類似的構(gòu)建工具還有Make, Maven, Gradle, GPY锡足,GN(chromium目前采用的構(gòu)建工具)等等波丰。
現(xiàn)代構(gòu)建工具的功能越來(lái)越強(qiáng)大,很多都支持多平臺(tái)舶得,多語(yǔ)言掰烟,遠(yuǎn)程依賴等等。
Bazel的安裝也很簡(jiǎn)單沐批,詳細(xì)參考:安裝Bazel
我們通過(guò)一個(gè)例子來(lái)測(cè)試和熟悉一下Bazel的使用纫骑,例子是Bazel官方提供的。
首先來(lái)獲取例子代碼:
git clone https://github.com/bazelbuild/examples/
可以看到目錄 examples/cpp-tutorial 結(jié)構(gòu)如下:
examples
└── cpp-tutorial
├──stage1
│ ├── main
│ │ ├── BUILD
│ │ └── hello-world.cc
│ └── WORKSPACE
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── WORKSPACE
└──stage3
├── main
│ ├── BUILD
│ ├── hello-world.cc
│ ├── hello-greet.cc
│ └── hello-greet.h
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
└── WORKSPACE
來(lái)看一下BUILD文件的內(nèi)容九孩,cpp-tutorial/stage1/main/BUILD如下:
# 通過(guò)cc_binary規(guī)則定義了一個(gè)binary目標(biāo)先馆,
# 目標(biāo)名稱為 hello-world,源文件是 hello-world.cc.
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
構(gòu)建hello-world的方式也簡(jiǎn)單,執(zhí)行如下命令:
bazel build //main:hello-world
cpp-tutorial/stage2/main/BUILD內(nèi)容如下:
# 通過(guò)cc_library規(guī)則定義了一個(gè)library目標(biāo)躺彬,
# 目標(biāo)名稱為 hello-greet煤墙,源文件是 hello-greet.cc,
# hello-greet.h
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
)
# 通過(guò)cc_binary規(guī)則定義了一個(gè)binary目標(biāo),
# 目標(biāo)名稱為 hello-world宪拥,源文件是 hello-world.cc.
# 并且依賴包內(nèi)目標(biāo)hello-greet
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [
":hello-greet",
],
)
構(gòu)建方式?jīng)]變化:
bazel build //main:hello-world
cpp-tutorial/stage3/main/BUILD內(nèi)容如下:
# 通過(guò)cc_library規(guī)則定義了一個(gè)library目標(biāo)仿野,
# 目標(biāo)名稱為 hello-greet,源文件是 hello-greet.cc,
# hello-greet.h
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
)
# 通過(guò)cc_binary規(guī)則定義了一個(gè)binary目標(biāo)江解,
# 目標(biāo)名稱為 hello-world设预,源文件是 hello-world.cc.
# 并且依賴包內(nèi)目標(biāo)hello-greet和包lib下的目標(biāo)//lib:hello-time
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [
":hello-greet",
"http://lib:hello-time",
],
)
在看一下包lib下的BUILD文件:
# 通過(guò)cc_library規(guī)則定義了一個(gè)library目標(biāo),
# 目標(biāo)名稱為 hello-time犁河,源文件是 hello-time.cc,
# hello-time.h
cc_library(
name = "hello-time",
srcs = ["hello-time.cc"],
hdrs = ["hello-time.h"],
visibility = ["http://main:__pkg__"],
)
的確定義了一個(gè)目標(biāo)hello-time鳖枕,并且設(shè)置了main包可見魄梯。
構(gòu)建方式依然沒變:
bazel build //main:hello-world
3、安裝Python以及依賴項(xiàng):
主要的Python依賴有這幾項(xiàng)
numpy:這是 Python 中常用的科學(xué)計(jì)算包宾符,支持很多矩陣運(yùn)算酿秸,并提供了高緯運(yùn)算的優(yōu)化算法。
dev:這是 Python 開發(fā)包魏烫,用于向 Python 添加擴(kuò)展程序辣苏;其中包括了一些用C/Java/C#等語(yǔ)言編寫的python擴(kuò)展在編譯的時(shí)候依賴的頭文件,靜態(tài)庫(kù)等文件哄褒。TensorFlow不完全由Python寫成稀蟋,核心執(zhí)行模塊是有C++,CUDA寫成的呐赡,因此需要此包退客。
pip:Python 軟件包管理器;提供了對(duì) Python 包的查找链嘀、下載萌狂、安裝、卸載的功能怀泊。
wheel:用于管理 wheel (.whl) 格式的 Python 壓縮包茫藏。
根據(jù)你的Python版本,安裝方式稍有不同霹琼,詳細(xì)安裝方式务傲,參考:安裝python依賴
4、安裝GPU依賴:
Nvidia顯卡
Nvidia顯卡驅(qū)動(dòng)
Cuda ToolKit : 是Nvidia推出的使用GPU資源進(jìn)行通用計(jì)算的SDK碧囊,TensorFlow的核心計(jì)算層通過(guò)cuda接口树灶,驅(qū)動(dòng)顯卡的GPU進(jìn)行計(jì)算。CUDA安裝包一般會(huì)集成了顯卡驅(qū)動(dòng)糯而。
cuDNN: 是Nvidia推出的深度學(xué)習(xí)中CNN和RNN的高度優(yōu)化的實(shí)現(xiàn)。因?yàn)榈讓邮褂昧撕芏嘞冗M(jìn)的技術(shù)何接口沒有對(duì)外開源泊窘,因此性能高很多熄驼。
安裝方式不再贅述,參考:安裝GPU依賴
從源碼安裝
目前為止烘豹,我們的準(zhǔn)備工作就完成了瓜贾,可以開始編譯工程了。接下來(lái)的工作就比較簡(jiǎn)單了携悯,基本流程是 git clone 獲取源碼祭芦、執(zhí)行 configure 腳本配置編譯選項(xiàng)、執(zhí)行bazel build命令構(gòu)建目標(biāo)憔鬼、執(zhí)行目標(biāo)腳本生成TensorFlow安裝包龟劲、pip安裝目標(biāo)TensorFlow安裝包胃夏,具體操作不再贅述,參考官網(wǎng)手冊(cè):編譯TensorFlow昌跌,我們來(lái)重點(diǎn)理解一下這幾個(gè)問(wèn)題:
1仰禀、configure腳本是如何配置編譯選項(xiàng)?
編譯之前蚕愤,需要執(zhí)行configure腳本答恶,腳本會(huì)提示用戶配置一些編譯選項(xiàng),例如是否支持CUDA萍诱,OpenGL悬嗓,HDFS,Google Cloud等等裕坊。那么這些配置選項(xiàng)是如果一項(xiàng)后續(xù)的編譯的呢烫扼?
以python環(huán)境配置為例看一下配置的原理;我們來(lái)看一下腳本configure中setup_python函數(shù):
function setup_python {
## Set up python-related environment settings:
##
## 這個(gè)while循環(huán)用來(lái)設(shè)置Python可執(zhí)行文件的路徑PYTHON_BIN_PATH碍庵,
## 使用which命令自動(dòng)查找python的路徑作為可選項(xiàng)映企,用戶可以自己指定路徑
##
while true; do
fromuser=""
if [ -z "$PYTHON_BIN_PATH" ]; then
default_python_bin_path=$(which python || which python3 || true)
read -p "Please specify the location of python. [Default is $default_python_bin_path]: " PYTHON_BIN_PATH
fromuser="1"
if [ -z "$PYTHON_BIN_PATH" ]; then
PYTHON_BIN_PATH=$default_python_bin_path
fi
fi
if [ -e "$PYTHON_BIN_PATH" ]; then
break
fi
echo "Invalid python path. ${PYTHON_BIN_PATH} cannot be found" 1>&2
if [ -z "$fromuser" ]; then
exit 1
fi
PYTHON_BIN_PATH=""
# Retry
done
##
## 下面的if邏輯用來(lái)設(shè)置PYTHON_LIB_PATH
##
if [ -z "$PYTHON_LIB_PATH" ]; then
# Split python_path into an array of paths, this allows path containing spaces
IFS=',' read -r -a python_lib_path <<< "$(python_path)"
if [ 1 = "$USE_DEFAULT_PYTHON_LIB_PATH" ]; then
PYTHON_LIB_PATH=${python_lib_path[0]}
echo "Using python library path: $PYTHON_LIB_PATH"
else
echo "Found possible Python library paths:"
for x in "${python_lib_path[@]}"; do
echo " $x"
done
set -- "${python_lib_path[@]}"
echo "Please input the desired Python library path to use. Default is [$1]"
read b || true
if [ "$b" == "" ]; then
PYTHON_LIB_PATH=${python_lib_path[0]}
echo "Using python library path: $PYTHON_LIB_PATH"
else
PYTHON_LIB_PATH="$b"
fi
fi
fi
##
## 檢查PYTHON_BIN_PATH路徑是否有效,無(wú)效則結(jié)束配置腳本
##
if [ ! -x "$PYTHON_BIN_PATH" ] || [ -d "$PYTHON_BIN_PATH" ]; then
echo "PYTHON_BIN_PATH is not executable. Is it the python binary?"
exit 1
fi
local python_major_version
python_major_version=$("${PYTHON_BIN_PATH}" -c 'from __future__ import print_function; import sys; print(sys.version_info[0]);' | head -c1)
if [ -z "$python_major_version" ]; then
echo -e "\n\nERROR: Problem getting python version. Is $PYTHON_BIN_PATH the correct python binary?"
exit 1
fi
# Convert python path to Windows style before writing into bazel.rc
if is_windows; then
PYTHON_BIN_PATH="$(cygpath -m "$PYTHON_BIN_PATH")"
PYTHON_LIB_PATH="$(cygpath -m "$PYTHON_LIB_PATH")"
fi
##
## 接下來(lái)的邏輯是將配置固化到磁盤静浴,涉及兩個(gè)磁盤文件.tf_configure.bazelrc和
## tools/python_bin_path.sh堰氓,后面我們講介紹這兩個(gè)文件的作用。
##
# Set-up env variables used by python_configure.bzl
write_action_env_to_bazelrc "PYTHON_BIN_PATH" "$PYTHON_BIN_PATH"
write_action_env_to_bazelrc "PYTHON_LIB_PATH" "$PYTHON_LIB_PATH"
write_to_bazelrc "build --define PYTHON_BIN_PATH=\"$PYTHON_BIN_PATH\""
write_to_bazelrc "build --define PYTHON_LIB_PATH=\"$PYTHON_LIB_PATH\""
write_to_bazelrc "build --force_python=py$python_major_version"
write_to_bazelrc "build --host_force_python=py$python_major_version"
write_to_bazelrc "build --python${python_major_version}_path=\"$PYTHON_BIN_PATH\""
write_to_bazelrc "test --force_python=py$python_major_version"
write_to_bazelrc "test --host_force_python=py$python_major_version"
write_to_bazelrc "test --define PYTHON_BIN_PATH=\"$PYTHON_BIN_PATH\""
write_to_bazelrc "test --define PYTHON_LIB_PATH=\"$PYTHON_LIB_PATH\""
write_to_bazelrc "run --define PYTHON_BIN_PATH=\"$PYTHON_BIN_PATH\""
write_to_bazelrc "run --define PYTHON_LIB_PATH=\"$PYTHON_LIB_PATH\""
# Write tools/python_bin_path.sh
echo "export PYTHON_BIN_PATH=\"$PYTHON_BIN_PATH\"" > tools/python_bin_path.sh
}
這里面使用了兩個(gè)函數(shù)來(lái)保存配置苹享,如下:
function write_to_bazelrc() {
echo "$1" >> .tf_configure.bazelrc
}
function write_action_env_to_bazelrc() {
write_to_bazelrc "build --action_env $1=\"$2\""
}
如果執(zhí)行成功双絮,會(huì)生成文件.tf_configure.bazelrc,內(nèi)容如下:
build --action_env PYTHON_BIN_PATH="/usr/bin/python"
build --action_env PYTHON_LIB_PATH="/usr/local/lib/python2.7/dist-packages"
build --define PYTHON_BIN_PATH="/usr/bin/python"
build --define PYTHON_LIB_PATH="/usr/local/lib/python2.7/dist-packages"
build --force_python=py2
build --host_force_python=py2
build --python2_path="/usr/bin/python"
test --force_python=py2
test --host_force_python=py2
test --define PYTHON_BIN_PATH="/usr/bin/python"
test --define PYTHON_LIB_PATH="/usr/local/lib/python2.7/dist-packages"
run --define PYTHON_BIN_PATH="/usr/bin/python"
run --define PYTHON_LIB_PATH="/usr/local/lib/python2.7/dist-packages"
build:opt --cxxopt=-march=native --copt=-march=native
build --action_env TF_NEED_CUDA="0"
build --action_env TF_NEED_OPENCL="0"
這個(gè)文件在后面的bazel編譯中會(huì)用到得问《谂剩可以看出,這其中記錄的是編譯時(shí)期需要傳遞給bazel的參數(shù)信息宫纬。根據(jù)配置的不同焚挠,用戶自己機(jī)器上的文件內(nèi)容可以會(huì)差異,屬于正忱焐В現(xiàn)象蝌衔。
2、編譯目標(biāo)是什么蝌蹂?又是如何構(gòu)建的呢噩斟?
僅支持 CPU 的情況下,構(gòu)建的目標(biāo)的命令如下:
$ bazel build --config=opt //tensorflow/tools/pip_package:build_pip_package
支持 GPU 的情況下,構(gòu)建的目標(biāo)的命令如下:
$ bazel build --config=opt --config=cuda //tensorflow/tools/pip_package:build_pip_package
我們來(lái)看一下構(gòu)建的目標(biāo)build_pip_package,回憶前面bazel的例子孤个,找到定義它的BUILD文件 tensorflow/tools/pip_package/BUILD, 目標(biāo)的定義如下:
sh_binary(
name = "build_pip_package",
srcs = ["build_pip_package.sh"],
data = select({
"http://tensorflow:windows": [":simple_console_for_windows"],
"http://tensorflow:windows_msvc": [":simple_console_for_windows"],
"http://conditions:default": [
":licenses",
"MANIFEST.in",
"README",
"setup.py",
":included_headers",
":simple_console",
"http://tensorflow:tensorflow_py",
"http://tensorflow/contrib/graph_editor:graph_editor_pip",
"http://tensorflow/contrib/keras:keras",
"http://tensorflow/contrib/labeled_tensor:labeled_tensor_pip",
"http://tensorflow/contrib/ndlstm:ndlstm",
"http://tensorflow/contrib/nn:nn_py",
"http://tensorflow/contrib/session_bundle:session_bundle_pip",
"http://tensorflow/contrib/signal:signal_py",
"http://tensorflow/contrib/slim:slim",
"http://tensorflow/contrib/slim/python/slim/data:data_pip",
"http://tensorflow/contrib/slim/python/slim/nets:nets_pip",
"http://tensorflow/contrib/tpu:tpu_estimator",
"http://tensorflow/contrib/tpu:tpu_helper_library",
"http://tensorflow/contrib/tpu:tpu_py",
"http://tensorflow/contrib/specs:specs",
"http://tensorflow/contrib/tensor_forest:init_py",
"http://tensorflow/contrib/tensor_forest/hybrid:hybrid_pip",
"http://tensorflow/contrib/predictor:predictor_pip",
"http://tensorflow/examples/tutorials/mnist:package",
"http://tensorflow/python:distributed_framework_test_lib",
"http://tensorflow/python:meta_graph_testdata",
"http://tensorflow/python:util_example_parser_configuration",
"http://tensorflow/python/debug:debug_pip",
"http://tensorflow/python/saved_model:saved_model",
"http://tensorflow/python/tools:tools_pip",
],
}) + if_mkl(["http://third_party/mkl:intel_binary_blob"]),
)
我們遇到了bazel的新的規(guī)則sh_binary以及一個(gè)select函數(shù)剃允,我們來(lái)一下它們的定義:
sh_bianry用來(lái)定義一個(gè)可執(zhí)行的Bourne Shell腳本目標(biāo),name表示目標(biāo)的名字,srcs是腳本文件斥废,必須是可執(zhí)行的腳本椒楣,腳本運(yùn)行時(shí)需要的其他文件由data屬性定義,目標(biāo)構(gòu)建完成后营袜,這些被依賴項(xiàng)都會(huì)在目標(biāo)的runfiles目錄內(nèi)撒顿。
select函數(shù)根據(jù)bazel的command-line的參數(shù)返回不同的結(jié)果。
綜合起來(lái)看荚板,目標(biāo) build_pip_package 的可執(zhí)行腳本是build_pip_package.sh凤壁,data 的屬性值取決于bazel的命令行參數(shù)。我們先忽略windows平臺(tái)下的取值跪另,看到 build_pip_package 目標(biāo)依賴 //tensorflow:tensorflow_py拧抖、//tensorflow/contrib/graph_editor:graph_editor_pip 等眾多目標(biāo),這里暫時(shí)先不去一一細(xì)看這些被依賴項(xiàng)目免绿。在構(gòu)建 build_pip_package 目標(biāo)的時(shí)候唧席,bazel會(huì)遞歸的構(gòu)建所有的被依賴目標(biāo)。
接下來(lái)嘲驾,我們來(lái)看下shell腳本build_pip_package.sh淌哟,它的主要工作在main函數(shù)里完成:
function main() {
##
## 下面的代碼做參數(shù)檢查,用戶執(zhí)行此腳本的時(shí)候需要提供一個(gè)目標(biāo)文件夾路徑辽故,
## 作為最后whl安裝包生成的路徑
##
if [ $# -lt 1 ] ; then
echo "No destination dir provided"
exit 1
fi
DEST=$1
TMPDIR=$(mktemp -d -t tmp.XXXXXXXXXX)
GPU_FLAG=""
while true; do
if [[ "$1" == "--gpu" ]]; then
GPU_FLAG="--project_name tensorflow_gpu"
fi
shift
if [[ -z "$1" ]]; then
break
fi
done
echo $(date) : "=== Using tmpdir: ${TMPDIR}"
if [ ! -d bazel-bin/tensorflow ]; then
echo "Could not find bazel-bin. Did you run from the root of the build tree?"
exit 1
fi
##
## 下面的代碼是在做文件拷貝徒仓,將編譯生成的文件拷貝到目標(biāo)路徑中。
## 不同系統(tǒng)可能源目錄的結(jié)構(gòu)不一樣誊垢,再有就是bazel的版本更新掉弛,也導(dǎo)致
## 新舊版本的源路徑結(jié)構(gòu)不太一樣,等等原因喂走;這里的代碼兼容了各種源目
## 錄的結(jié)構(gòu)殃饿。runfiles目錄中就是之前所有依賴生成文件會(huì)出現(xiàn)的位置。
##
if is_windows; then
rm -rf ./bazel-bin/tensorflow/tools/pip_package/simple_console_for_window_unzip
mkdir -p ./bazel-bin/tensorflow/tools/pip_package/simple_console_for_window_unzip
echo "Unzipping simple_console_for_windows.zip to create runfiles tree..."
unzip -o -q ./bazel-bin/tensorflow/tools/pip_package/simple_console_for_windows.zip -d ./bazel-bin/tensorflow/tools/pip_package/simple_console_for_window_unzip
echo "Unzip finished."
# runfiles structure after unzip the python binary
cp -R \
bazel-bin/tensorflow/tools/pip_package/simple_console_for_window_unzip/runfiles/org_tensorflow/tensorflow \
"${TMPDIR}"
mkdir "${TMPDIR}/external"
# Note: this makes an extra copy of org_tensorflow.
cp_external \
bazel-bin/tensorflow/tools/pip_package/simple_console_for_window_unzip/runfiles \
"${TMPDIR}/external"
RUNFILES=bazel-bin/tensorflow/tools/pip_package/simple_console_for_window_unzip/runfiles/org_tensorflow
elif [ ! -d bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow ]; then
# Really old (0.2.1-) runfiles, without workspace name.
cp -R \
bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/tensorflow \
"${TMPDIR}"
mkdir "${TMPDIR}/external"
cp_external \
bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/external \
"${TMPDIR}/external"
RUNFILES=bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles
# Copy MKL libs over so they can be loaded at runtime
if [ -d bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow/_solib_k8/_U_S_Sthird_Uparty_Smkl_Cintel_Ubinary_Ublob___Uthird_Uparty_Smkl ]; then
mkdir "${TMPDIR}/_solib_k8"
cp -R \
bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow/_solib_k8/_U_S_Sthird_Uparty_Smkl_Cintel_Ubinary_Ublob___Uthird_Uparty_Smkl \
"${TMPDIR}/_solib_k8"
fi
else
if [ -d bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow/external ]; then
# Old-style runfiles structure (--legacy_external_runfiles).
cp -R \
bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow/tensorflow \
"${TMPDIR}"
mkdir "${TMPDIR}/external"
cp_external \
bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow/external \
"${TMPDIR}/external"
# Copy MKL libs over so they can be loaded at runtime
if [ -d bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow/_solib_k8/_U_S_Sthird_Uparty_Smkl_Cintel_Ubinary_Ublob___Uthird_Uparty_Smkl ]; then
mkdir "${TMPDIR}/_solib_k8"
cp -R \
bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow/_solib_k8/_U_S_Sthird_Uparty_Smkl_Cintel_Ubinary_Ublob___Uthird_Uparty_Smkl \
"${TMPDIR}/_solib_k8"
fi
else
# New-style runfiles structure (--nolegacy_external_runfiles).
cp -R \
bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow/tensorflow \
"${TMPDIR}"
mkdir "${TMPDIR}/external"
# Note: this makes an extra copy of org_tensorflow.
cp_external \
bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles \
"${TMPDIR}/external"
# Copy MKL libs over so they can be loaded at runtime
if [ -d bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow/_solib_k8/_U_S_Sthird_Uparty_Smkl_Cintel_Ubinary_Ublob___Uthird_Uparty_Smkl ]; then
mkdir "${TMPDIR}/_solib_k8"
cp -R \
bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow/_solib_k8/_U_S_Sthird_Uparty_Smkl_Cintel_Ubinary_Ublob___Uthird_Uparty_Smkl \
"${TMPDIR}/_solib_k8"
fi
fi
RUNFILES=bazel-bin/tensorflow/tools/pip_package/build_pip_package.runfiles/org_tensorflow
fi
# protobuf pip package doesn't ship with header files. Copy the headers
# over so user defined ops can be compiled.
mkdir -p ${TMPDIR}/google
mkdir -p ${TMPDIR}/third_party
pushd ${RUNFILES%org_tensorflow}
for header in $(find protobuf -name \*.h); do
mkdir -p "${TMPDIR}/google/$(dirname ${header})"
cp "$header" "${TMPDIR}/google/$(dirname ${header})/"
done
popd
cp -R $RUNFILES/third_party/eigen3 ${TMPDIR}/third_party
#
# 下面的代碼拷貝Python的whl格式的安裝包
# 的幾個(gè)必須文件芋肠,MANIFEST.in, README, setup.py
#
cp tensorflow/tools/pip_package/MANIFEST.in ${TMPDIR}
cp tensorflow/tools/pip_package/README ${TMPDIR}
cp tensorflow/tools/pip_package/setup.py ${TMPDIR}
# Before we leave the top-level directory, make sure we know how to
# call python.
source tools/python_bin_path.sh
#
# 最后乎芳,下面的代碼調(diào)用Python生成whl格式的包文件
#
pushd ${TMPDIR}
rm -f MANIFEST
echo $(date) : "=== Building wheel"
"${PYTHON_BIN_PATH:-python}" setup.py bdist_wheel ${GPU_FLAG} >/dev/null
mkdir -p ${DEST}
cp dist/* ${DEST}
popd
rm -rf ${TMPDIR}
echo $(date) : "=== Output wheel file is in: ${DEST}"
}
看得出來(lái),build_pip_package.sh的腳本就是將我們的編譯結(jié)果打包成一個(gè)wheel格式的python包业栅。
前面構(gòu)建完腳本目標(biāo)后秒咐,就可以執(zhí)行腳本生成wheel包:
$ bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
最后我們可以用pip安裝生成的wheel包:
$ sudo pip install /tmp/tensorflow_pkg/tensorflow-1.6.0-py2-none-any.whl
安裝完測(cè)試
為了檢查安轉(zhuǎn)是否完成,可以執(zhí)行一些測(cè)試代碼碘裕,下面的測(cè)試用例來(lái)自官網(wǎng),來(lái)看一下:
調(diào)用 Python:
$ python
在 Python 交互式 shell 中輸入以下幾行簡(jiǎn)短的程序代碼:
# Python
import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
print(sess.run(hello))
如果系統(tǒng)輸出以下內(nèi)容攒钳,則說(shuō)明順利完成:
Hello, TensorFlow!