我們期待的TensorFlow 2.0還有哪些變化?
為提高 TensorFlow 的工作效率,TensorFlow 2.0 進行了多項更改,包括刪除了多餘的 API,使API 更加一致統一,例如統一的 RNNs (迴圈神經網路),統一的優化器,並且Python 執行時更好地集成了 Eager execution 。
許多 RFC 已經對 TensorFlow 2.0 的這些更改給出瞭解釋。本指南基於您對 TensorFlow 1.x 有一定的瞭解的前提,為您介紹在 TensorFlow 2.0 中的開發有什麼不同。
API 整理
在 TensorFlow 2.0 中,有許多 1.X 的 API 被刪除或移動 了。也有部分 1.X 的 API 被 2.0 版本的等價 API 所替代:tf.summary,tf.keras.metrics 和 tf.keras.optimizers。自動應用這些重新命名,最簡單的方法是使用 TensorFlow 2.0 升級指令碼。
Eager execution
TensorFlow 1.X 要求使用者通過呼叫 tf.* API 手動的將抽象語法樹(圖)拼接在一起。然後,它要求使用者將一組輸出張量和輸入張量傳遞給 session.run() 呼叫,來手動編譯抽象語法樹。相比之下,TensorFlow 2.0 executes eagerly(如正常使用 Python 一樣)在 2.0 的版本中,其 graphs(抽象語法樹)和 sessions 在實現的細節上應該是一樣的。
不再有全域性變數
TensorFlow 1.X 非常依賴於隱式全域性名稱空間。當你呼叫 tf.Variable 時,它會被放入預設圖中,即使你忘記了指向它的 Python 變數它也會留在那裡。這時,您可以恢復該 tf.Variable(),但前提是您得知道它已建立的名稱。如果您無法控制變數的建立,很難做到這一點。因此,各種機制以及尋找使用者建立變數的框架不斷湧現,試圖幫助使用者再次找到他們的變數。
TensorFlow 2.0 取消了所有這些機制(Variables 2.0 RFC),支援預設機制:跟蹤變數! 如果你不再用到某個 tf.Variable,它就會被回收。
Functions, not sessions
session.run() 的呼叫幾乎類似於函式呼叫:指定輸入和要呼叫的函式,然後返回一組輸出。在 TensorFlow 2.0 中,您可以使用 tf.function() 來修飾 Python 函式以將其標記為 JIT( Just-In-Time )編譯,以便 TensorFlow 將其作為單個圖執行(Functions 2.0 RFC)。
這種機制使得 TensorFlow 2.0 擁有圖模式的許多優點:
- 效能:該函式可以被優化,例如節點修剪,核心融合等
- 可移植性:該函式可以匯出 / 重新匯入(SavedModel 2.0 RFC),允許使用者重用和將 TensorFlow 函式作為模組共享
# TensorFlow 1.X
outputs = session.run(f(placeholder), feed_dict={placeholder: input})# TensorFlow 2.0
outputs = f(input)
由於能夠自由地穿插 Python 和 TensorFlow 程式碼,您能夠充分利用 Python 的表現力。而且,可移植的 TensorFlow 在沒有 Python 直譯器的情況下也可執行。比如:mobile,C ++ 和 JS。避免使用者在新增 @tf.function 時重寫程式碼,AutoGraph 會將 Python 構造的一個子集轉換成 TensorFlow 等價物。
TensorFlow 2.0 常用的建議
將程式碼重構為更小的函式
TensorFlow 1.X 中的常見使用模式是 “kitchen sink” 策略,即預先列出所有可能計算的並集,然後通過 session.run() 計算選定的張量。在 TensorFlow 2.0 中,使用者應該根據需求將程式碼重構為更小的函式。通常情況下,沒有必要用 tf.function 來修飾這些較小的函式;僅使用 tf.function 來修飾高階計算 — 例如,使用只有一個步驟的訓練或使用模型的正向傳遞,將程式碼重構為更小的函式。
使用 Keras 層和模型來管理變數
Keras 模型和層提供了方便的變數和 trainable_variables 屬性,以遞迴方式收集所有因變數。這使得本地化管理變數非常方便。
Keras 層 / 模型繼承自 tf.train.Checkpointable 並與 @ tf.function 整合,這使得直接檢查點或從 Keras 物件匯出 SavedModel 成為可能。您不一定要使用 Keras 的 fit() API 來整合。
結合 tf.data.Datasets 和 @tf.function
在迭代適合記憶體的訓練資料時,可以使用常規的 Python 迴圈。除此之外,tf.data.Dataset 則是從磁碟傳輸訓練資料的最好方法。資料集是可迭代的(不是迭代器),工作方式與其他 Python 迴圈類似。如果您想使用 AutoGraph 的等效圖操作替換 Python 迴圈,可以通過將程式碼包裝在 tf.function() 中,充分利用資料集非同步預取 / 流功能來實現。
@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.cond 和 tf.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
有關詳細資訊,請參閱文末連結:
https://github.com/tensorflow/docs/blob/master/site/en/r2/guide/effective_tf2.md