背景
本文檔旨在為那些想要用其他編程語言創建或開發 TensorFlow 功能的人員提供指導。本文介紹了 TensorFlow 的功能以及在其他編程語言中實現相同功能應采取的推薦步驟。
Python 是 TensorFlow 支持的第一種客戶端語言,目前支持的功能最多。該功能正逐步移植到 TensorFlow 的核心(用 C++ 實現)并通過 C API 公開。客戶端語言應使用該語言的外部函數接口 (FFI) 調用此 C API 以提供 TensorFlow 功能。
通過某個編程語言提供 TensorFlow 功能可分為幾大類別:
運行預定義圖:給定 GraphDef(或 MetaGraphDef)協議消息,能夠創建會話,運行查詢并獲得張量結果。這對于想要在預訓練模型上進行推斷的移動應用或服務器來說已足夠
圖構造:每個定義的 TensorFlow 操作至少有一個向圖添加操作的函數。理想情況下,這些函數會自動生成,因此在修改操作定義時它們會保持同步
梯度(亦稱為自動微分):給定圖及輸入和輸出操作列表,向圖添加計算輸入相對于輸出的偏導數(梯度)的操作。允許針對圖中的特定操作自定義梯度函數
函數:定義可在主 GraphDef 中的多個位置調用的子圖。在包含在 GraphDef 中的 FunctionDefLibrary 內定義 FunctionDef
控制流:使用用戶指定的子圖構造 If 和 While 循環。理想情況下,這些控制流支持梯度(參見上文)
神經網絡庫:一些組件,它們共同支持神經網絡模型的創建和訓練(可能在分布式設置中)。雖然以其他語言提供此功能會很方便,但目前還沒有用除 Python 以外的語言支持此功能的計劃。這些庫通常是上述功能的封裝容器
語言綁定至少應支持運行預定義的圖,但大多數還應支持圖構造。TensorFlow Python API 提供了所有這些功能。
當前狀態
應該在 C API 基礎之上構建新的語言支持。但是,正如您在下表中所看到的,部分功能尚未在 C 中提供。在 C API 中提供更多功能是一個長期項目。
推薦方法
運行預定義的圖
語言綁定應該定義以下類:
Graph:表示 TensorFlow 計算的圖。包含操作(在客戶端語言中由 Operation 表示)并且對應于 C API 中的 TF_Graph。主要在創建新的 Operation 對象和啟動 Session 時用作參數。還支持遍歷圖中的操作 (TF_GraphNextOperation),按名稱查詢操作 (TF_GraphOperationByName),以及轉換為 GraphDef 協議消息或對其進行轉換(C API 中的 TF_GraphToGraphDef 和 TF_GraphImportGraphDef)
Operation:表示圖中的計算節點。對應于 C API 中的 TF_Operation
Output:表示圖中某個操作的一個輸出。具有 DataType(最終是一個形狀)。可以作為輸入參數傳遞給函數以向圖添加操作,或傳遞給 Session 的 Run() 方法以將該輸出提取為張量。對應于 C API 中的 TF_Output
Session:表示 TensorFlow 運行時的特定實例的客戶端。它的主要任務是使用 Graph 和一些選項進行構建,然后進行字段調用以對圖執行 Run() 操作。對應于 C API 中的 TF_Session
Tensor:表示所有元素都具有相同 DataType 的 N 維(矩形)數組。向 Session 的 Run() 調用提供數據或從中獲取數據。對應于 C API 中的 TF_Tensor
DataType:包含受 TensorFlow 支持的所有可能張量類型的枚舉。對應于 C API 中的 TF_DataType,在 Python API 中通常稱為 dtype
圖構造
TensorFlow 有很多操作,并且操作列表不是靜態的,因此我們建議生成用于將操作添加到圖中的函數,而不是手動逐個編寫這些函數(但手動編寫一些函數不失為確定生成器應該生成哪些內容的不錯方法)。生成函數所需的信息包含在 OpDef 協議消息中。
您可以通過以下幾種方法獲取已注冊操作的 OpDef 列表:
C API 中的 TF_GetAllOpList 會檢索所有已注冊的 OpDef 協議消息。它可以用于以客戶端語言編寫生成器。這就要求客戶端語言支持協議緩沖區,以便解釋 OpDef 消息
C++ 函數 OpRegistry::Global()->GetRegisteredOps() 會返回所有已注冊 OpDef(在 tensorflow/core/framework/op.h 中定義)的相同列表。它可以用于以 C++ 編寫生成器(對于不支持協議緩沖區的語言特別有用)
該列表的 ASCII 序列化版本通過自動化流程定期檢入tensorflow/core/ops/ops.pbtxt
OpDef 會指定以下內容:
駝峰命名法 (CamelCase) 的操作名稱。對于生成的函數,請遵循相應語言的慣例。例如,如果該語言使用蛇形命名法 (snake_case),則使用該命名法而不是駝峰命名法表示此操作的函數名稱
輸入和輸出列表。這些內容的類型可以通過引用屬性實現多態,如添加操作的輸入和輸出部分所述
屬性列表及其默認值(如果有)。請注意,系統會推斷其中一些屬性(如果它們由輸入確定),一些屬性是可選屬性(如果它們具有默認值),另一些屬性是必需屬性(無默認值)
一般操作以及輸入、輸出和非推斷屬性的文檔
運行時使用的其他一些字段,可以被代碼生成器忽略
可以將 OpDef 轉換為函數的文本,該函數使用 TF_OperationDescription C API(封裝在相應語言的 FFI 中)將該操作添加到圖中:
從 TF_NewOperation() 開始創建 TF_OperationDescription*。
每個輸入調用 TF_AddInput() 或 TF_AddInputList() 一次(取決于輸入是否具有列表類型)。
調用 TF_SetAttr*() 函數來設置非推斷屬性。如果您不想替換默認值,可以跳過具有默認值的屬性。
根據需要設置選填字段:
TF_SetDevice():強制在特定設備上執行操作。
TF_AddControlInput():添加要求以說明在此操作開始運行之前完成另一個操作
TF_SetAttrString("_kernel"):設置內核標簽(很少使用)
TF_ColocateWith():將一個操作與另一個操作共置到一起
完成后調用 TF_FinishOperation()。這樣會將操作添加到圖中,之后便無法修改。
現有示例會在編譯流程中運行代碼生成器(使用 Bazel genrule)。或者,代碼生成器可以由自動化 cron 進程運行,并可能檢入結果中。這可能會導致生成的代碼與檢入代碼庫中的 OpDef 之間產生分歧,但對于會提前生成代碼的語言(例如適用于 Go 的 go get 和適用于 Rust 的 cargo ops)很有用。另一方面,對于某些語言,代碼可以從 tensorflow/core/ops/ops.pbtxt 動態生成。
處理常量
如果用戶可以為輸入參數提供常量,則調用代碼將更加簡潔。生成的代碼應該將這些常量轉換為以下操作:添加到圖中并用作正在實例化的操作的輸入。
可選參數
如果語言允許函數具有可選參數(如 Python 中具有默認值的關鍵字參數),則將它們用于可選屬性、操作名稱、設備、控制輸入等。在某些語言中,可以使用動態作用域設置這些可選參數(如 Python 中的 “with” 塊)。如果沒有這些功能,庫可能會依靠 “編譯器模式”,就像在 TensorFlow API 的 C++ 版本中所做的那樣。
名稱作用域
建議您使用某種作用域層次結構支持命名圖操作,特別是考慮到 TensorBoard 依靠它以合理的方式顯示大圖這一事實。現有的 Python 和 C++ API 采用不同的方法:在 Python 中,名稱的 “目錄” 部分(最后一個 “/” 前面的所有內容)來自 with塊。實際上,有一個線程局部堆棧,其中的作用域定義了名稱層次結構。名稱的最后一個組成部分由用戶顯式提供(使用可選的 name 關鍵字參數),或者默認為要添加的操作的類型名稱。在 C++ 中,名稱的 “目錄” 部分存儲在顯式 Scope 對象中。NewSubScope() 方法附加到名稱的該部分并返回一個新的 Scope。名稱的最后一個組成部分是使用 WithOpName() 方法設置的,并且像 Python 一樣默認為要添加的操作的類型名稱。系統會顯式傳遞 Scope 對象以指定上下文的名稱。
封裝容器
可以保留生成的函數專用于某些操作,這樣可以改用執行一些額外工作的封裝容器函數。這也為支持所生成代碼作用域之外的功能提供了一個應急路徑。
封裝容器的一個用途是支持 SparseTensor 輸入和輸出。SparseTensor 是一個包含 3 個密集張量(索引、值和形狀)的元組。值是向量大小 [n],形狀是向量大小 [秩],索引是矩陣大小 [n, 秩]。有一些稀疏操作使用此三元組表示單個稀疏張量。
使用封裝容器的另一個原因是用于保留狀態的操作。有一些此類操作(例如變量)有幾個用于處理該狀態的伴隨操作。Python API 為這些操作提供了類,其中構造函數會創建操作,并且此類上的方法會向處理該狀態的圖添加操作。
其他注意事項
最好添加一個關鍵字列表,用于重命名與語言關鍵字沖突的操作函數和參數(或其他會導致問題的符號,如生成的代碼中引用的庫函數或變量的名稱)。
用于向圖添加 Const 操作的函數通常是封裝容器,因為生成的函數通常具有冗余的 DataType 輸入。
梯度、函數和控制流
目前,對梯度、函數和控制流操作(“if” 和 “while”)的支持并未在除 Python 以外的其他語言中提供。當 C API 提供必要的支持時,將會更新這方面的功能。
-
編程語言
+關注
關注
10文章
1950瀏覽量
34988 -
函數
+關注
關注
3文章
4346瀏覽量
62974
原文標題:采用其他編程語言的 TensorFlow
文章出處:【微信號:tensorflowers,微信公眾號:Tensorflowers】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論