前言

本文梳理了TensorFlow的基本概念:數據流圖、Tensor、Operation、Variable、Placeholder、Session、Optimizer、minimize。並對每個概念進行了詳細的講解和擴展。

閱讀本文需要對深度學習有一定了解,並知道tensorflow是做什麼的。

一. 編程範式:數據流圖

聲明式編程和命令式編程

聲明式編程:做什麼

命令式編程:怎麼做

TensorFlow採用了聲明式編程範式。

聲明式編程的優點:

1.代碼可讀性強:以目標而非過程為導向。2.支持引用透明:函數的調用語句可以由它的返回值取代。3.提供預編譯優化能力:先構建出數據流圖,無依賴邏輯的並行化計算、無效邏輯去除、公共邏輯提取等。

tensorflow數據流圖

數據流圖定義:用節點和有向邊描述數學運算的有向無環圖。

數據流圖中的節點代表各類操作,包括數學運算、數據填充、結果輸出和變數讀寫等等,每個節點的操作都需要分配到具體的物理設備(cpu、gpu)上執行。有向邊描述了節點間的輸入輸出關係。

1.節點

前向圖中的節點有:

  • 數學函數或表達式
  • 存儲模型參數的變數(variable)
  • 佔位符(placeholder)

後向圖中的節點有:

  • 梯度值
  • 更新模型參數的操作
  • 更新後的模型參數

2.有向邊

多數用來傳輸數據,少數用來控制依賴。

3.執行原理

數據流圖執行順序的實現參考了拓撲排序的設計思想。

當我們使用tensorflow執行指定數據流圖時,其執行過程可分為以下4個步驟
  • a.以節點名稱作為關鍵字,其所依賴的個數為值,創建一個散列表,將所有節點放入這個散列表。
  • b.為此數據流圖創建一個可執行隊列,將三列表中依賴個數為0的節點加入隊列,並在散列表中刪除它們。
  • c.一次執行隊列中的每個一節點,執行成功後將此節點輸出項的節點的依賴數減1,更新散列表。
  • d.重複b和c,直到執行隊列為空。

二. 數據載體:張量

在tensorflow中,張量(Tensor)是數據流圖上的數據載體,通常是多維數組。還有一種叫SpareseTensor,存放稀疏數據(0的數量遠多於非0元素),旨在減少稀疏數據的內存佔用。

在物理實現時,它含有指向張量數據的內存緩衝區的指針,當它不被任何操作依賴時,會釋放該內存緩衝區。

1.創建

一般tensor都不是直接創建的,而是定義常量和代數計算操作而間接創建的。

import tensorflow as tf
a = tf.constant(1, name="a", dtype=tf.int32)
b = tf.constant(2, name="b", dtype=tf.int32)
c = tf.add(a, b, name="c")
print(a)
print(b)
print(c)
Tensor("a:0", shape=(), dtype=int32)
Tensor("b:0", shape=(), dtype=int32)
Tensor("c:0", shape=(), dtype=int32)

2.求解

如果想要求解某個張量的值,則需要創建會話,然後執行張量的eval方法或會話的run方法。

with tf.Session() as sess:
print(c.eval())
print(sess.run(c))
3
3

3.成員方法

張量公共成員方法:

import tensorflow as tf
a = tf.constant(1, name="a", dtype=tf.int32)
b = tf.constant(2, name="b", dtype=tf.int32)
c = tf.add(a, b, name="c")

print(a.consumers())
[<tf.Operation c type=Add>] # 可以看出c這個操作依賴tensora

4.操作

tensorflow提供了大量操作,以便構建數據流圖,實現演算法模型。

三. 模型載體:操作

數據流圖由節點和郵箱邊組成,每個節點代表一種操作,因此操作是模型功能的實際載體。數據流圖中的節點按功能不同可以分為以下三種:

  1. 計算節點:計算或控制操作。
  2. 存儲節點:變數,一般用來存儲模型參數。
  3. 數據節點:佔位符操作,描述待輸入數據的屬性。

計算節點:Operation

計算操作的基本屬性:

並不需要直接定義計算節點,只要你用了類似tf.add這種操作,它就自動構造了Operation實例。下面整理了TensorFlow Python API提供的典型操作:

存儲節點:Variable

作用:多次執行數據流圖時存儲特定的參數。

構建變數時必須給定一個值。

變數值要初始化tf.global_variables_initializer()之後才能看到。

# 清空圖
import tensorflow as tf
aa = tf.Variable([1,2,3], name="aa")
print(aa.dtype) # 輸出其數據類型
print(aa.initial_value) # 輸出初始化值
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(aa)) # 輸出初始化之後的變數值
<dtype: int32_ref>
Tensor("aa/initial_value:0", shape=(3,), dtype=int32)
[1 2 3]

數據節點:Placeholder

數據流圖在填充數據之前不會執行任何計算,通常,我們在定義模型之前就已經明確了輸入數據的類型和形狀等屬性,而模型的第一步計算很可能就要用到這些輸入數據。數據節點Placeholder的作用就是定義好待輸入數據的類型和形狀,先完成模型的構建,最後數據流圖要執行的時候再把數據填充(feed)到Placehoder中來。

import tensorflow as tf
a = tf.constant([[1,2],[3,4]], dtype=tf.int32, name="a")
b = tf.placeholder(shape=[2,2], dtype=tf.int32, name="b")
c = a + b
with tf.Session() as sess:
print(sess.run(c, feed_dict={b:[[1,1],[1,1]]}))
[[2 3]
[4 5]]

四. 運行環境:會話

tensorflow數據流圖描述了要計算的拓撲結構和所需的數據屬性,但它僅僅是個殼。還需要向圖中填充數據、選擇待求解的張量、執行各種操作才能得到結果。而tensorflow的會話提供了這個計算過程的運行環境,它的本質是維護一段運行時間的上下文。

會話通過提取和切分數據流圖、調度並執行操作節點,來將數據流圖在計算機上執行。

流程:創建會話、運行會話、關閉會話。

sess = tf.Session() # 創建會話
sess.run(...) # 運行會話
sess.close() # 關閉會話

# 或者:
with tf.Session() as sess:# 自動關閉
sess.run(...)

target在執行單機任務時不用管它。

graph指向默認圖,當有多個數據流圖時需要顯式指定。config描述會話的配置信息。配置的內容可以包括並行線程數、GPU分配策略、運算超時時間等參數,最常用的幾個參數:

用法:

# minimize的參數:
minimize(self, loss, global_step=None, var_list=None,
gate_gradients=GATE_OP, aggregation_method=None,
colocate_gradients_with_ops=False, name=None,
grad_loss=None)

五. 訓練工具:優化器

優化器是tensorflow實現優化演算法的載體,它實現了自動求梯度並更新參數的功能。優化器根據模型結構和損失函數,利用鏈式求導法則求出每個參數的梯度並更新它們,以完成一次完整的訓練。

tensorflow提供了很多種Optimizer,定義在tf.train中。

使用minimize方法訓練模型

# minimize的參數:
minimize(self, loss, global_step=None, var_list=None,
gate_gradients=GATE_OP, aggregation_method=None,
colocate_gradients_with_ops=False, name=None,
grad_loss=None)

實現原理參見 源碼:tensorflow/python/training/optimizer.py

其中常用的參數:

訓練模型實例:

# 定義模型
...
# 定義損失函數
loss = ...
# 優化器
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01) # 選擇優化方法,給定學習率
golbal_step = tf.Variable(0, name=global_step, trainable=False)
train = optimizer.minimize(loss, global_step=global_step)

with tf.Session() as sess:
sess.run(global_variables_initializer()) # 初始化參數
for step in 10000:
sess.run(train, feed_dict={...}) # 一步訓練

References:

[1] 深入理解TensorFlow框架設計與實現原理 第三章


推薦閱讀:
相關文章