本篇中介紹一下TensorFlow的安裝。TensorFlow的安裝分為安裝包安裝和編譯安裝.
一般的用戶使用安裝包安裝就可以了,并且安裝包的方式簡單方便,具體又分為基于pip安裝、基于docker安裝、基于VirtualEnv的安裝和基于Anaconda的安裝,基本的過程都是先準(zhǔn)備好Python環(huán)境,然后直接通過Pip(python的包管理器)直接下載安裝TensorFlow的Python包,比較簡單,這里就不再贅述了,可自行g(shù)oogle或參考這兩篇文章,寫的十分的詳細(xì):wiki, doc
基于編譯源碼的安裝方式在用戶找不到自己平臺合適的安裝包、或則是想要深入學(xué)習(xí)TensorFlow實現(xiàn)的情況下使用。這里我們詳細(xì)介紹一下基于源碼的安裝方式。
TensorFlow官網(wǎng)也有一篇講解源碼安裝的文章,也值得參考一下:源碼安裝。
那么本文跟這些文章的區(qū)別在哪呢?本人力求做到跟官網(wǎng)的手冊互補,本文中我會將重點放在原理的講解上,而這些參考資料的重點都是在實際動手操作上。
至于閱讀順序完全在于讀者的喜好,可以對照這些操作手冊先實踐一遍,然后回過頭來看這篇講解;也可以先看我這偏講解,然后再實踐。
環(huán)境準(zhǔn)備
編譯TensorFlow工程的時候,有很多可選功能可以選擇是否開啟,有是否需要GPU支持,還有是否需要支持HDFS,是否需要OpenGL,Google Cloud,XLA優(yōu)化等等。用戶選擇的開啟的功能越多,TensorFlow的依賴項就越多,環(huán)境準(zhǔn)備就越復(fù)雜些。
1、首先我們需要選擇平臺和操作系統(tǒng):
Ubuntu和max OS X是官方推薦的兩個平臺,本篇中我們選擇Ubuntu 16.04 64位作為編譯平臺。
2、安裝構(gòu)建工具Bazel:
Bazel是一個開源的構(gòu)建系統(tǒng),同樣來自于google,在google內(nèi)部使用的也比較廣泛。
構(gòu)建系統(tǒng)的需求是隨著軟件規(guī)模的增大而提出的。在軟件規(guī)模很小的時候,我們可以手動調(diào)用gcc編譯和鏈接生成目標(biāo)文件。但是隨著軟件規(guī)模的增大,這種方式顯然很低效,于是出現(xiàn)的構(gòu)建工具,我們可以定義構(gòu)建目標(biāo)的規(guī)則文件,然后由構(gòu)建工具來解析這個規(guī)則文件,調(diào)用gcc來編譯何生成目標(biāo)文件。隨著軟件規(guī)模的進(jìn)一步擴(kuò)大,出現(xiàn)了跨平臺的需求。這時候構(gòu)建工具也提供了根據(jù)不同的平臺定義不同的構(gòu)建規(guī)則的功能。
類似的構(gòu)建工具還有Make, Maven, Gradle, GPY,GN(chromium目前采用的構(gòu)建工具)等等。
現(xiàn)代構(gòu)建工具的功能越來越強(qiáng)大,很多都支持多平臺,多語言,遠(yuǎn)程依賴等等。
Bazel的安裝也很簡單,詳細(xì)參考:安裝Bazel
我們通過一個例子來測試和熟悉一下Bazel的使用,例子是Bazel官方提供的。
首先來獲取例子代碼:
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
來看一下BUILD文件的內(nèi)容,cpp-tutorial/stage1/main/BUILD如下:
# 通過cc_binary規(guī)則定義了一個binary目標(biāo),
# 目標(biāo)名稱為 hello-world,源文件是 hello-world.cc.
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
構(gòu)建hello-world的方式也簡單,執(zhí)行如下命令:
bazel build //main:hello-world
cpp-tutorial/stage2/main/BUILD內(nèi)容如下:
# 通過cc_library規(guī)則定義了一個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"],
)
# 通過cc_binary規(guī)則定義了一個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)容如下:
# 通過cc_library規(guī)則定義了一個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"],
)
# 通過cc_binary規(guī)則定義了一個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文件:
# 通過cc_library規(guī)則定義了一個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__"],
)
的確定義了一個目標(biāo)hello-time,并且設(shè)置了main包可見。
構(gòu)建方式依然沒變:
bazel build //main:hello-world
3、安裝Python以及依賴項:
主要的Python依賴有這幾項
numpy:這是 Python 中常用的科學(xué)計算包,支持很多矩陣運算,并提供了高緯運算的優(yōu)化算法。
dev:這是 Python 開發(fā)包,用于向 Python 添加擴(kuò)展程序;其中包括了一些用C/Java/C#等語言編寫的python擴(kuò)展在編譯的時候依賴的頭文件,靜態(tài)庫等文件。TensorFlow不完全由Python寫成,核心執(zhí)行模塊是有C++,CUDA寫成的,因此需要此包。
pip:Python 軟件包管理器;提供了對 Python 包的查找、下載、安裝、卸載的功能。
wheel:用于管理 wheel (.whl) 格式的 Python 壓縮包。
根據(jù)你的Python版本,安裝方式稍有不同,詳細(xì)安裝方式,參考:安裝python依賴
4、安裝GPU依賴:
Nvidia顯卡
Nvidia顯卡驅(qū)動
Cuda ToolKit : 是Nvidia推出的使用GPU資源進(jìn)行通用計算的SDK,TensorFlow的核心計算層通過cuda接口,驅(qū)動顯卡的GPU進(jìn)行計算。CUDA安裝包一般會集成了顯卡驅(qū)動。
cuDNN: 是Nvidia推出的深度學(xué)習(xí)中CNN和RNN的高度優(yōu)化的實現(xiàn)。因為底層使用了很多先進(jìn)的技術(shù)何接口沒有對外開源,因此性能高很多。
安裝方式不再贅述,參考:安裝GPU依賴
從源碼安裝
目前為止,我們的準(zhǔn)備工作就完成了,可以開始編譯工程了。接下來的工作就比較簡單了,基本流程是 git clone 獲取源碼、執(zhí)行 configure 腳本配置編譯選項、執(zhí)行bazel build命令構(gòu)建目標(biāo)、執(zhí)行目標(biāo)腳本生成TensorFlow安裝包、pip安裝目標(biāo)TensorFlow安裝包,具體操作不再贅述,參考官網(wǎng)手冊:編譯TensorFlow,我們來重點理解一下這幾個問題:
1、configure腳本是如何配置編譯選項?
編譯之前,需要執(zhí)行configure腳本,腳本會提示用戶配置一些編譯選項,例如是否支持CUDA,OpenGL,HDFS,Google Cloud等等。那么這些配置選項是如果一項后續(xù)的編譯的呢?
以python環(huán)境配置為例看一下配置的原理;我們來看一下腳本configure中setup_python函數(shù):
function setup_python {
## Set up python-related environment settings:
##
## 這個while循環(huán)用來設(shè)置Python可執(zhí)行文件的路徑PYTHON_BIN_PATH,
## 使用which命令自動查找python的路徑作為可選項,用戶可以自己指定路徑
##
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邏輯用來設(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路徑是否有效,無效則結(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
##
## 接下來的邏輯是將配置固化到磁盤,涉及兩個磁盤文件.tf_configure.bazelrc和
## tools/python_bin_path.sh,后面我們講介紹這兩個文件的作用。
##
# 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
}
這里面使用了兩個函數(shù)來保存配置,如下:
function write_to_bazelrc() {
echo "$1" >> .tf_configure.bazelrc
}
function write_action_env_to_bazelrc() {
write_to_bazelrc "build --action_env $1=\"$2\""
}
如果執(zhí)行成功,會生成文件.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"
這個文件在后面的bazel編譯中會用到??梢钥闯?,這其中記錄的是編譯時期需要傳遞給bazel的參數(shù)信息。根據(jù)配置的不同,用戶自己機(jī)器上的文件內(nèi)容可以會差異,屬于正?,F(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
我們來看一下構(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以及一個select函數(shù),我們來一下它們的定義:
sh_bianry用來定義一個可執(zhí)行的Bourne Shell腳本目標(biāo),name表示目標(biāo)的名字,srcs是腳本文件,必須是可執(zhí)行的腳本,腳本運行時需要的其他文件由data屬性定義,目標(biāo)構(gòu)建完成后,這些被依賴項都會在目標(biāo)的runfiles目錄內(nèi)。
select函數(shù)根據(jù)bazel的command-line的參數(shù)返回不同的結(jié)果。
綜合起來看,目標(biāo) build_pip_package 的可執(zhí)行腳本是build_pip_package.sh,data 的屬性值取決于bazel的命令行參數(shù)。我們先忽略windows平臺下的取值,看到 build_pip_package 目標(biāo)依賴 //tensorflow:tensorflow_py、//tensorflow/contrib/graph_editor:graph_editor_pip 等眾多目標(biāo),這里暫時先不去一一細(xì)看這些被依賴項目。在構(gòu)建 build_pip_package 目標(biāo)的時候,bazel會遞歸的構(gòu)建所有的被依賴目標(biāo)。
接下來,我們來看下shell腳本build_pip_package.sh,它的主要工作在main函數(shù)里完成:
function main() {
##
## 下面的代碼做參數(shù)檢查,用戶執(zhí)行此腳本的時候需要提供一個目標(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目錄中就是之前所有依賴生成文件會出現(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格式的安裝包
# 的幾個必須文件,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}"
}
看得出來,build_pip_package.sh的腳本就是將我們的編譯結(jié)果打包成一個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
安裝完測試
為了檢查安轉(zhuǎn)是否完成,可以執(zhí)行一些測試代碼,下面的測試用例來自官網(wǎng),來看一下:
調(diào)用 Python:
$ python
在 Python 交互式 shell 中輸入以下幾行簡短的程序代碼:
# Python
import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
print(sess.run(hello))
如果系統(tǒng)輸出以下內(nèi)容,則說明順利完成:
Hello, TensorFlow!