[譯]高效的TensorFlow 2.0:應用最佳實踐以及有什麼變化

雲水木石發表於2019-03-11

Tensorflow團隊早早就放出了風聲,Tensorflow 2.0就快來了,這是一個重要的里程碑版本,重點放在簡單和易用性上。我對Tensorflow 2.0的到來充滿期待,因此翻譯了這篇Tensorflow團隊釋出的文件:Effective TensorFlow 2.0: Best Practices and What’s Changed。原文地址:https://medium.com/tensorflow/effective-tensorflow-2-0-best-practices-and-whats-changed-a0ca48767aff ,略有刪減。點選閱讀原文可以跳轉到該文章,需要翻牆哦!

最近的一篇文章中,我們提到,TensorFlow 2.0經過重新設計,重點關注開發人員的工作效率、簡單性和易用性。

要深入瞭解所改變的內容及應用最佳實踐,請檢視新的Effective TensorFlow 2.0指南(釋出在GitHub上)。本文簡要概述那份指南里的內容。如果您對這些主題感興趣,請前往指南瞭解更多資訊!

主要變化概述

TensorFlow 2.0中有許多變化可以提高使用者的工作效率,包括刪除冗餘API、使API更加一致(統一的RNN統一的優化器),以及Python執行時更好地整合Eager執行

許多RFC(如果您對它們感到陌生,請檢視它們!)已經解釋了制定TensorFlow 2.0的變化和思考。本指南展現了在TensorFlow 2.0中開發應該是什麼樣的。前提假設您對TensorFlow 1.x有一定的瞭解。

API清理

許多API在TF 2.0中消失或改變位置,有些則被替換為等效的2.0版本 -- tf.summary、tf.keras.metrics和tf.keras.optimizers。自動替換為新方法的最簡單方法是使用v2升級指令碼

Eager執行

TensorFlow 1.X要求使用者呼叫tf.* API手動將抽象語法樹(圖)拼接在一起。 然後,使用者需要通過將一組輸出張量和輸入張量傳遞給 session.run() 函式呼叫來手動編譯抽象語法樹。相比之下,TensorFlow 2.0立即執行(就像Python通常做的那樣),在tf 2.0中,圖形和會話感覺更像實現細節。

減少全域性變數

TensorFlow 1.X嚴重依賴於隱式全域性名稱空間。呼叫 tf.Variable() 時,它會被放入預設圖形中,它會保留在那裡,即使忘記了指向它的Python變數。然後,您可以恢復該 tf.Variable ,但前提是您知道它已建立的名稱。如果變數的建立不由您掌控,這就很難做到。結果,各種機制激增,試圖幫助使用者再次找到他們的變數。

TensorFlow 2.0取消了所有這些機制(Variables 2.0 RFC),啟用預設機制:跟蹤變數! 如果您失去了對 tf.Variable 的追蹤,就會被垃圾回收。

函式,而不是會話

session.run() 呼叫幾乎就像一個函式呼叫:指定輸入和要呼叫的函式,然後返回一組輸出。在TensorFlow 2.0中,您可以使用 tf.function() 來修飾Python函式以將其標記為JIT編譯,使得TensorFlow將其作為單個圖執行(Functions 2.0 RFC)。

這種機制允許TensorFlow 2.0獲得圖形模式的所有好處:

  • 效能:可以優化函式(節點修剪、核心融合等)
  • 可移植性:函式可以匯出/重新匯入(SavedModel 2.0 RFC),允許使用者重用和共享模組化TensorFlow函式。

憑藉自由分發Python和TensorFlow程式碼的能力,您可以充分利用Python的表現力。但是,行動式TensorFlow在沒有Python直譯器上下文時執行 - 移動、C++和JS。為了幫助使用者避免在新增@tf.function時重寫程式碼,* AutoGraph *會將部分Python構造轉換為他們的TensorFlow等價物。

TensorFlow 2.0約定建議

將程式碼重構為更小的函式

TensorFlow 1.X中的常見使用模式是“水槽”策略,其中所有可能的計算的合集被預先排列,然後通過 session.run() 評估選擇的張量。在TensorFlow 2.0中,使用者應將其程式碼重構為較小的函式,這些函式根據需要呼叫。通常,沒有必要用 tf.function 來修飾這些較小的函式,僅使用 tf.function 來修飾高階計算 - 例如,訓練的一個步驟或模型的正向傳遞。

使用Keras圖層和模型來管理變數

Keras模型和圖層提供方便的變數和 trainable_variables 屬性,以遞迴方式收集所有關聯變數,這樣可以輕鬆地將變數本地管理到它們的使用位置。

Keras層/模型繼承自tf.train.Checkpointable並與@ tf.function整合,這使得直接獲得檢查點或從Keras物件匯出SavedModel成為可能。您不一定要使用Keras's.fit()API來進行這些整合。

組合tf.data.Datasets和@tf.function

迭代載入到記憶體的訓練資料時,可以隨意使用常規的Python迭代。否則,tf.data.Dataset是從磁碟傳輸訓練資料的最佳方式。資料集是可迭代的(不是迭代器),在Eager模式下和其他Python迭代一樣工作。您可以通過將程式碼包裝在tf.function()中來充分利用資料集非同步預取/流特性,它會將Python迭代替換為使用AutoGraph的等效圖形操作。

@tf.function
def train(model, dataset, optimizer):
 for x, y in dataset:
  with tf.GradientTape() as tape:
   prediction = model(x)
   loss = loss_fn(prediction, y)
  gradients = tape.gradients(loss, model.trainable_variables)
  optimizer.apply_gradients(gradients, model.trainable_variables)
複製程式碼

如果您使用 Keras.fit() API,則無需考慮資料集迭代。

model.compile(optimizer=optimizer, loss=loss_fn)
model.fit(dataset)
複製程式碼

利用AutoGraph和Python控制流程

AutoGraph提供了一種將依賴於資料的控制流轉換為等價圖形模式的方法,如 tf.condtf.while_loop

資料相關控制流通常出現在序列模型。tf.keras.layers.RNN 封裝了RNN單元格,允許您靜態或動態地展開迴圈。處於演示目的,您可以重新實現動態展開,如下所示:

class DynamicRNN(tf.keras.Model):

  def __init__(self, rnn_cell):
    super(DynamicRNN, self).__init__(self)
    self.cell = rnn_cell
 
  def call(self, input_data):
    # [batch, time, features] -> [time, batch, features]
    input_data = tf.transpose(input_data, [1, 0, 2])
    outputs = tf.TensorArray(tf.float32, input_data.shape[0])
    state = self.cell.zero_state(input_data.shape[1], dtype=tf.float32)
    for i in tf.range(input_data.shape[0]):
      output, state = self.cell(input_data[i], state)
      outputs = outputs.write(i, output)
    return tf.transpose(outputs.stack(), [1, 0, 2]), state
複製程式碼

使用tf.metrics聚合資料並用tf.summary來記錄日誌

最後,一套完整的 tf.summary 符號即將推出。您可以使用以下命令訪問 tf.summary 的2.0版本:

from tensorflow.python.ops import summary_ops_v2
複製程式碼

下一步

本文提供了Effective TF 2.0指南的簡要(如果您對這些主題感興趣,請到那裡瞭解更多!)要了解有關TensorFlow 2.0的更多資訊,我們還推薦這些近期文章:

相關文章