iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 4
1
AI & Data

深度學習裡的冰與火之歌 : Tensorflow vs PyTorch系列 第 4

Day 4 偽動態計算圖: Tensorflow 的 Eager Mode

在上一篇中我們介紹了 Tensorflow 在建置靜態計算圖的兩個主要類別:tf.Variabletf.Graph。今天我們會先花一點時間來舉說 tf.Session 物件。這個 tf.Session 可以看作是靜態計算圖和 runtime 之間的媒介。靜態計算圖在建置的過程中,特別為資料預留了型態和空間,再藉著 tf.Sessionrun 的方法將資料餵入,並取回計算結果。

More about tf.Session

A tf.Sessions 會使用 Tensorflow C++ backend 評估計算圖的計算結果。

使用實例方法 tf.Session().run() 來提供數據,然後獲取計算結果。有以下四種 scenarios 啟動 tf.Session()

  • 透過類別 factory 方法建立互動式的 tf.InteractiveSession() 並將操作置於 default 設備(應為 CPU)
  • 透過類別 factory 方法建立非互動式的 tf.Session()tf.Session() 早將操作置於 default 設備(應為 CPU)
  • 透過類別 factory 方法建立非互動式的 tf.Session()並將某些操作置於特定設備,如 GPU(需要關於 GPU 的配置知識)
  • 通過指定一個 tf.train.ClusterSpec 到類別 factory 方法的 cluster_def參數,啟動分散式叢集 Session

現就單線程(single thread),CPU 的方式來 demosrate 如何使用 tf.Session 作資料的餵入和擷取(Feed and fetch)。例子由 tensorflow 官方網站提供

import tensorflow as tf
import numpy as np

x = tf.placeholder(tf.float32, shape=(1024, 1024)) # use symbolic placeholder for data
y = tf.matmul(x, x)

with tf.Session() as sess: # using tf.Session within its active context 
    # print(sess.run(y))  # ERROR: will fail because x was not fed.
    rand_array = np.random.rand(1024, 1024)
    print(sess.run(y, feed_dict={x: rand_array}))  # Will succeed.

然而,由於使用 Python 的使用者相當廣泛,雖然靜態計算圖有許多優點,但就是不包括 Python 使用者最希望擁有的優點,那就是可以使用 Python 圈子裡常被使用的函式庫,包括了 numpy 和 pandas 等等。同時,靜態計算圖也無法再建置時除錯,這對研究者經常要建置許多不同的網路架構,甚至得實驗不同網路架構間的特性,就顯得非常重要。PyTorch 的這項優點,恰巧搓中了 Tensorflow 的痛處,也讓 Tensorflow 引入了:

Eager execution:

Eager execution 又被稱為 Eager mode:可以使用者在建置模型時,就評估每個操作。而根據官方文件Eager execution 有下列設計目標:

  1. 直覺性的介面:使用 Python 建立資料結構,執行環境可以依 Python 使用者常用函式庫建置,適合在小型資料和簡單的迴圈中使用。
    • keras 類別和物件,如 tf.keras.layers 皆可以在 Eager mode 中使用
  2. 更容易除錯:可使用 Python 標準函式庫的 debugger 除錯或檢查一個運算元的輸入和輸出
  3. 更自然的程式碼 flow control:直接用 Python 的 if...else 即可
    • 使用 tf.GradientTape() context 來記錄正向的運算過程,並記錄到一個 "tape" 物件上。待該物件呼叫自身的 gradient 即可反向計算

下面是一個官方提供使用的tf.GradientTape() 例子。這是和 PyTroch 很相近的設計,除了在 Eager mode 是用 with tf.GradientTape() 來納入正向傳播的運算,而 PyTroch 則是 with torch.no_grad() 的方法 exclude 正向傳播的運算。

import tensorflow as tf
tf.enable_eager_execution() # must enable eager mode immedately after importing 

w = tf.Variable([[1.0]])
with tf.GradientTape() as tape:
  loss = w * w

grad = tape.gradient(loss, w)
print(grad)  # => tf.Tensor([[ 2.]], shape=(1, 1), dtype=float32)

Eager modeGraph mode

Eager mode 可執行有狀態(如任何運行在 tf.Variable 的運算)和非有狀態操作。若在 Graph mode 則需要 tf.Session() 來提供資料計算。

Eager mode

  • 必須要先初始化數據,可以使用 numpy.ndarraytf.data API(如:tf.data.Dataset.from_tensor_slices
  • Graph mode 預設是用 CPU 設備計算的,若要在 GPU上運行,需要手動指定 tf.device('/ gpu:0'
  • Eager mode 的目標是在研發 prototype 設計階段時使用,若在生產階段,則需要在圖形模式下運行
  • Eager mode 下生成的模型,可以 export 儲存並以在 Graph mode 導入。

numpy.ndarray and tf.Tensor:

  1. numpy.ndarray and tf.Tensor 的不同
    • numpy.ndarray 只能在 CPU 中運行,於主記憶體中
    • tf.Tensor 可以在 CPU 或 GPU 運行。
  2. tf.Tensornumpy.ndarray 間轉換:
    • 直接將 numpy.ndarray 傳入 tensorflow 的運算元,如 tf.add
    • 直接將 tf.Tensor 傳入 numpy 的運算元,如 np.add。該 tf.Tensor 必須已有 numpy.ndarray 填滿
  3. 想要知道已用 numpy.ndarray 填滿的 tf.Tensor,其 numpy.ndarray 的值為何,可以使用 tf.Tensor().numpy 屬性。

下面的原始碼是一個使用 eager execution 的例子,可以看到在例子裡,numpy.ndarraytf.Tensor 混合運算無障礙。

import tensorflow as tf

tf.enable_eager_execution() # must enable eager mode immedately after importing 
print(tf.executing_eagerly()) #outputing True

a = tf.constant([[1, 2],
                 [3, 4]])
print(a)  # creat an usual Tensor object with numpy.ndarray
# => tf.Tensor(
# [[1 2]
# [3 4]], shape=(2, 2), dtype=int32)

b = tf.add(a, 1) # creat another Tensor object by broadcast adding 1
print(b) # => tf.Tensor(
         #[[2 3]
         #[4 5]], shape=(2, 2), dtype=int32)

import numpy as np

c = np.multiply(a, b)
print(c) # => <class 'numpy.ndarray'> [[ 2  6]
         # [12 20]]

使用 Eager Execution 常見的錯誤:

不支持 tf.placeholder:當在 Eager mode 使用 tf.placeholder,會出現以下錯誤訊息

Problem: RuntimeError: tf.placeholder() is not compatible with eager execution.

這是 tf.placeholder 是為運算元的輸入先建置一個符號,並預留空間,待資料流入計算圖時使用。這樣的需求和 eager execution 的設計不合,因為 eager execution 在實例化 tf.Tensor 物件需要使用者立即提供資料

Reference:

[1] A Brief Guide to Tensorflow Eager Execution: introduces 1.7 release


上一篇
Day 3 靜態計算圖:Tensorflow
下一篇
Day 5 Jax 來拯救:numpy-based 的動態計算圖
系列文
深度學習裡的冰與火之歌 : Tensorflow vs PyTorch31

1 則留言

0
Capillary J
iT邦新手 5 級 ‧ 2019-09-20 01:11:22

之前一直好奇用Eager mode 做出來的模型效率不是很差嗎?
原來真正使用是要轉成graph mode,請問能分享轉成graph mode的相關介紹嗎@@?

renewang iT邦新手 5 級 ‧ 2019-09-20 22:09:51 檢舉

謝謝你的留言!我很希望目前我能夠很詳細的回應你。可是,
因為其實他不是要轉成 graph mode,而是在 eager mode 利用 tf.Saver 存成 checkpoint 格式後,在 graph mode 中讀入。你可以先看看我附上 Tensorflow r1.13 的 tf.contrib.eager.CheckpointableSaver,裡頭有 API 文件解釋該怎麼使用。往後,我若有機會再來細談!Good Luck! https://www.tensorflow.org/versions/r1.13/api_docs/python/tf/contrib/eager/CheckpointableSaver

我要留言

立即登入留言