帶你深入AI(6)- 詳解bazel
系列文章,請多關注
Tensorflow原始碼解析1 – 核心架構和原始碼結構
自然語言處理1 – 分詞
帶你深入AI(1) - 深度學習模型訓練痛點及解決方法
帶你深入AI(2)- 深度學習啟用函式,準確率,優化方法等總結
帶你深入AI(3)- 物體分類領域:AlexNet VGG Inception ResNet mobileNet
帶你深入AI(4)- 目標檢測領域:R-CNN,faster R-CNN,yolo,SSD, yoloV2
帶你深入AI(5)- 自然語言處理領域:RNN LSTM GRU
帶你深入AI(6)- 詳解bazel
帶你深入AI(7)- 深度學習重要Python庫
1 Bazel簡介
bazel是Google開源的一套編譯構建工具,廣泛應用於Google內部,包括TensorFlow專案。修改TensorFlow內部原始碼,需要使用bazel來編譯,故有必要了解下bazel。bazel優點很多,主要有
- 構建快。支援增量編譯。對依賴關係進行了優化,從而支援併發執行。
- 可構建多種語言。bazel可用來構建Java C++ Android ios等很多語言和框架,並支援mac windows linux等不同平臺
- 可伸縮。可處理任意大小的程式碼庫,可處理多個庫,也可以處理單個庫
- 可擴充套件。使用bazel擴充套件語言可支援新語言和新平臺。
2 Bazel專案結構
和Makefile一樣,使用bazel編譯也必須滿足它的專案結構要求。這也許是為什麼bazel還不夠普及的原因所在吧。bazel頂層,也就是根目錄下為工作區workspace,workspace下包含多個package,每個package又包含多個編譯目標target。
2.1 工作區workspace
要進行構建的檔案系統,根目錄下必須包含一個檔名為WORKSPACE的檔案,即使它內容為空。它指明瞭構建的根目錄。檔案系統中包括原始檔,標頭檔案,輸出目錄的符號連結等。WORKSPACE採用類似Python的語法,下面是TensorFlow原始碼根目錄下的WORKSPACE
workspace(name = "org_tensorflow")
http_archive(
name = "io_bazel_rules_closure",
sha256 = "6691c58a2cd30a86776dd9bb34898b041e37136f2dc7e24cadaeaf599c95c657",
strip_prefix = "rules_closure-08039ba8ca59f64248bb3b6ae016460fe9c9914f",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_closure/archive/08039ba8ca59f64248bb3b6ae016460fe9c9914f.tar.gz",
"https://github.com/bazelbuild/rules_closure/archive/08039ba8ca59f64248bb3b6ae016460fe9c9914f.tar.gz", # 2018-01-16
],
)
load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories")
closure_repositories()
load("//tensorflow:workspace.bzl", "tf_workspace")
# Uncomment and update the paths in these entries to build the Android demo.
android_sdk_repository(
name = "androidsdk",
api_level = 23,
# # Ensure that you have the build_tools_version below installed in the
# # SDK manager as it updates periodically.
build_tools_version = "26.0.1",
# # Replace with path to Android SDK on your system
path = "/Users/yangyixie/Library/Android/sdk",
)
#
android_ndk_repository(
name="androidndk",
path="/Users/yangyixie/Library/Android/sdk/ndk-bundle",
# # This needs to be 14 or higher to compile TensorFlow.
# # Please specify API level to >= 21 to build for 64-bit
# # archtectures or the Android NDK will automatically select biggest
# # API level that it supports without notice.
# # Note that the NDK version is not the API level.
api_level=14,
)
# Please add all new TensorFlow dependencies in workspace.bzl.
tf_workspace()
new_http_archive(
name = "inception_v1",
build_file = "models.BUILD",
sha256 = "7efe12a8363f09bc24d7b7a450304a15655a57a7751929b2c1593a71183bb105",
urls = [
"http://storage.googleapis.com/download.tensorflow.org/models/inception_v1.zip",
"http://download.tensorflow.org/models/inception_v1.zip",
],
)
new_http_archive(
name = "mobile_ssd",
build_file = "models.BUILD",
sha256 = "bddd81ea5c80a97adfac1c9f770e6f55cbafd7cce4d3bbe15fbeb041e6b8f3e8",
urls = [
"http://storage.googleapis.com/download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_android_export.zip",
"http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_android_export.zip",
],
)
new_http_archive(
name = "mobile_multibox",
build_file = "models.BUILD",
sha256 = "859edcddf84dddb974c36c36cfc1f74555148e9c9213dedacf1d6b613ad52b96",
urls = [
"http://storage.googleapis.com/download.tensorflow.org/models/mobile_multibox_v1a.zip",
"http://download.tensorflow.org/models/mobile_multibox_v1a.zip",
],
)
new_http_archive(
name = "stylize",
build_file = "models.BUILD",
sha256 = "3d374a730aef330424a356a8d4f04d8a54277c425e274ecb7d9c83aa912c6bfa",
urls = [
"http://storage.googleapis.com/download.tensorflow.org/models/stylize_v1.zip",
"http://download.tensorflow.org/models/stylize_v1.zip",
],
)
new_http_archive(
name = "speech_commands",
build_file = "models.BUILD",
sha256 = "c3ec4fea3158eb111f1d932336351edfe8bd515bb6e87aad4f25dbad0a600d0c",
urls = [
"http://storage.googleapis.com/download.tensorflow.org/models/speech_commands_v0.01.zip",
"http://download.tensorflow.org/models/speech_commands_v0.01.zip",
],
)
如上所示,語法類似Python,進行了多個方法呼叫,我們來看各個方法呼叫的含義。
http_archive:下載bazel檔案,然後解壓它,這個bazel 目錄檔案中必須包含BUILD檔案。上面的http_archive中指明瞭要下載io_bazel_rules_closure檔案,以及它的下載地址
new_http_archive: 下載檔案,然後解壓它,然後和其中包含的build_file一起建立bazel目錄
load:從.bzl檔案中載入一些內容,如上面從defs.bzl檔案中載入內容
android_sdk_repository:構建Android app時使用,指定Android sdk目錄
android_ndk_repository:構建Android app時使用,指定Android ndk目錄
2.2 包package
一個WORKSPACE工作區下可以包括多個包package,每個package可以實現一個子模組,從而讓各個模組進行解耦。每個package下必須包含一個BUILD檔案,它指定了package的編譯構建規則。由於TensorFlow原始碼是C++檔案,故本文只講解C++下的BUILD檔案,以及它的構建規則。
我們先列出TensorFlow原始碼中的一個BUILD檔案,然後講解BUILD檔案中的各個規則含義。
# Description:
# TensorFlow is a computational framework, primarily for use in machine
# learning applications.
# 通用方法,定義的值會作用到下面的每個子rule中。default_visibility指定了這個包的預設可見規則。可見的情況下才能被其他package呼叫。
package(
default_visibility = ["//visibility:public"],
)
# 預設的license
licenses(["notice"]) # Apache 2.0
# 通用方法,載入.bzl檔案
load(
"//tensorflow:tensorflow.bzl",
"tf_cc_test",
"tf_cc_binary",
"tf_copts",
"tf_gen_op_wrappers_cc",
"cc_library_with_android_deps",
)
# c++庫檔案,name指定了編譯為庫檔案後的檔名,srcs和hdrs指定原始檔和標頭檔案,deps指定需要依賴的其他檔案
cc_library(
name = "gradient_checker",
srcs = ["framework/gradient_checker.cc"],
hdrs = ["framework/gradient_checker.h"],
deps = [
":cc_ops",
":client_session",
":gradients",
":ops",
":scope",
"//tensorflow/core:framework",
"//tensorflow/core:lib",
"//tensorflow/core:lib_internal",
],
)
# c++測試檔案
tf_cc_test(
name = "gradients_array_grad_test",
srcs = ["gradients/array_grad_test.cc"],
deps = [
":array_grad",
":cc_ops",
":cc_ops_internal",
":grad_op_registry",
":grad_testutil",
":gradient_checker",
":testutil",
"//tensorflow/core:test",
"//tensorflow/core:test_main",
"//tensorflow/core:testlib",
],
)
# c++編譯目標檔案,為一個二進位制可執行檔案。name必須唯一,srcs指定了原始檔,linkopts指定了連結規則,deps指定了依賴檔案
tf_cc_binary(
name = "tutorials_example_trainer",
srcs = ["tutorials/example_trainer.cc"],
copts = tf_copts(),
linkopts = select({
"//tensorflow:windows": [],
"//tensorflow:windows_msvc": [],
"//tensorflow:darwin": [
"-lm",
"-lpthread",
],
"//tensorflow:ios": [
"-lm",
"-lpthread",
],
"//conditions:default": [
"-lm",
"-lpthread",
"-lrt",
],
}),
deps = [
":cc_ops",
"//tensorflow/core:core_cpu",
"//tensorflow/core:framework",
"//tensorflow/core:lib",
"//tensorflow/core:protos_all_cc",
"//tensorflow/core:tensorflow",
],
)
# 為多個編譯目標target指定一個名字,glob是一個幫助函式,指定了目錄中哪些檔案會include,哪些會exclude。visibility指定了target的可見性,也就是可以被哪些package呼叫
filegroup(
name = "all_files",
srcs = glob(
["**/*"],
exclude = [
"**/METADATA",
"**/OWNERS",
],
),
visibility = ["//tensorflow:__subpackages__"],
)
BUILD檔案也是採用的類似Python的語法,它定義了編譯規則,lib依賴等各項規則。其中有些命令專屬於BUILD檔案,有些則是bazel語法通用的,如WORKSPACE檔案中也可以使用。主要方法呼叫如下
tf_cc_binary:目標檔案編譯規則,為一個二進位制可執行檔案。name必須唯一,srcs指定了原始檔,linkopts指定了連結規則,deps指定了依賴檔案
cc_library:庫檔案編譯規則,name指定了編譯為庫檔案後的檔名,srcs和hdrs指定原始檔和標頭檔案,deps指定需要依賴的其他檔案
tf_cc_test:測試檔案規則
package:通用方法,定義的值會作用到下面的每個子rule中。default_visibility指定了這個包的預設可見規則。可見的情況下才能被其他package呼叫。
licenses:通用方法,預設的license
load:通用方法,載入.bzl檔案
filegroup:通用方法,為多個編譯目標target指定一個名字,glob是一個幫助函式,指定了目錄中哪些檔案會include,哪些會exclude。visibility指定了target的可見性,也就是可以被哪些package呼叫
其他一些常用方法可以參看bazel文件 https://docs.bazel.build/versions/master/be/c-cpp.html#cc_binary.linkopts
2.2.1 標籤
包的名稱叫做標籤,用來標識一個包package。標籤示例如下
//my/app/main:app_binary
標籤由兩部分組成,一部分為包名my/app/main, 一部分為包構建的目標名app_binary。每個標籤用來唯一標示包構建的目標,從而在被其他包使用時可以標識出來。同一個包下,標籤可以省略包名部分,如:app_binary表示同一個包下的目標。不同包之間,則千萬不能省略包名。
2.3 目標
包package是一個容器,組成它的元素稱為目標,分為檔案和規則。檔案分為兩種,一種為程式設計師寫的原始碼,一種為構建工具生成的檔案。規則定義瞭如何利用輸入來構建得到輸出,如上面的BUILD。輸入一般是原始檔,庫檔案等,輸出則一般是生成的構建目標檔案。
3 安裝和使用示例
bazel安裝參見 https://docs.bazel.build/versions/master/install.html
bazel的入門例項參見 https://docs.bazel.build/versions/master/tutorial/cpp.html#specify-multiple-build-targets
系列文章,請多關注
Tensorflow原始碼解析1 – 核心架構和原始碼結構
自然語言處理1 – 分詞
帶你深入AI(1) - 深度學習模型訓練痛點及解決方法
帶你深入AI(2)- 深度學習啟用函式,準確率,優化方法等總結
帶你深入AI(3)- 物體分類領域:AlexNet VGG Inception ResNet mobileNet
帶你深入AI(4)- 目標檢測領域:R-CNN,faster R-CNN,yolo,SSD, yoloV2
帶你深入AI(5)- 自然語言處理領域:RNN LSTM GRU
帶你深入AI(6)- 詳解bazel
帶你深入AI(7)- 深度學習重要Python庫