Tensorflow中的圖(tf.Graph)和會話(tf.Session)的實現
Tensorflow程式設計系統
Tensorflow工具或者說深度學習本身就是一個連貫緊密的系統。一般的系統是一個自治獨立的、能實現複雜功能的整體。系統的主要任務是對輸入進行處理,以得到想要的輸出結果。我們之前見過的很多系統都是線性的,就像汽車生產工廠的流水線一樣,輸入->系統處理->輸出。系統內部由很多單一的基本部件構成,這些單一部件具有特定的功能,且需要穩定的特性;系統設計者通過特殊的連線方式,讓這些簡單部件進行連線,以使它們之間可以進行資料交流和資訊互換,來達到相互配合而完成具體工作的目的。
對於任何一個系統來說,都應該擁有穩定、獨立、能處理特殊任務的單一部件;且擁有一套良好的內部溝通機制,以讓系統可以健康安全的執行。
現實中的很多系統都是線性的,被設計好的、不能進行更改的,比如工廠的流水線,這樣的系統並不具備自我調整的能力,無法對外界的環境做出反應,因此也就不具備“智慧”。
深度學習(神經網路)之所以具備智慧,就是因為它具有反饋機制。深度學習具有一套對輸出所做的評價函式(損失函式),損失函式在對神經網路做出評價後,會通過某種方式(梯度下降法)更新網路的組成引數,以期望系統得到更好的輸出資料。
由此可見,神經網路的系統主要由以下幾個方面組成:
- 輸入
- 系統本身(神經網路結構),以及涉及到系統本身構建的問題:如網路構建方式、網路執行方式、變數維護、模型儲存和恢復等等問題
- 損失函式
- 反饋方式:訓練方式
定義好以上的組成部分,我們就可以用流程化的方式將其組合起來,讓系統對輸入進行學習,調整引數。因為該系統的反饋機制,所以,組成的方式肯定需要迴圈。
而對於Tensorflow來說,其設計理念肯定離不開神經網路本身。所以,學習Tensorflow之前,對神經網路有一個整體、深刻的理解也是必須的。如下圖:Tensorflow的執行示意。
那麼對於以上所列的幾點,什麼才是最重要的呢?我想肯定是有關係統本身所涉及到的問題。即如何構建、執行一個神經網路?在Tensorflow中,用計算圖來構建網路,用會話來具體執行網路。深入理解了這兩點,我想,對於Tensorflow的設計思路,以及執行機制,也就略知一二了。
圖(tf.Graph):計算圖,主要用於構建網路,本身不進行任何實際的計算。計算圖的設計啟發是高等數學裡面的鏈式求導法則的圖。我們可以將計算圖理解為是一個計算模板或者計劃書。
會話(tf.session):會話,主要用於執行網路。所有關於神經網路的計算都在這裡進行,它執行的依據是計算圖或者計算圖的一部分,同時,會話也會負責分配計算資源和變數存放,以及維護執行過程中的變數。
接下來,我們主要從計算圖開始,看一看Tensorflow是如何構建、執行網路的。
計算圖
在開始之前,我們先複習一下Tensorflow的幾種基本資料型別:
tf.constant(value,dtype=None,shape=None,name='Const',verify_shape=False) tf.Variable(initializer,name) tf.placeholder(dtype,name=None)
複習完畢。
graph = tf.Graph() with graph.as_default(): img = tf.constant(1.0,shape=[1,5,3])
以上程式碼中定義了一個計算圖,在該計算圖中定義了一個常量。Tensorflow預設會建立一張計算圖。所以上面程式碼中的前兩行,可以省略。預設情況下,計算圖是空的。
在執行完img = tf.constant(1.0,3])以後,計算圖中生成了一個node,一個node結點由name,op,input,attrs組成,即結點名稱、操作、輸入以及一系列的屬性(型別、形狀、值)等組成,計算圖就是由這樣一個個的node組成的。對於tf.constant()函式,只會生成一個node,但對於有的函式,如tf.Variable(initializer,name)(注意其第一個引數是初始化器)就會生成多個node結點(後面會講到)。
那麼執行完img = tf.constant(1.0,3])後,計算圖中就多一個node結點。(因為每個node的屬性很多,我只表示name,op,input屬性)
繼續新增程式碼:
img = tf.constant(1.0,3]) k = tf.constant(1.0,shape=[3,3,1])
程式碼執行後的計算圖如下:
需要注意的是,如果沒有對結點進行命名,Tensorflow自動會將其命名為:Const、Const_1、const_2......。其他型別的結點類同。
現在,我們新增一個變數:
img = tf.constant(1.0,1]) kernel = tf.Variable(k)
該變數用一個常量作為初始化器。我們先看一下計算圖:
如圖所示:
執行完tf.Variable()函式後,一共產生了三個結點:
- Variable:變數維護(不存放實際的值)
- Variable/Assign:變數分配
- Variable/read:變數使用
圖中只是完成了操作的定義,但並沒有執行操作(如Variable/Assign結點的Assign操作,所以,此時候變數依然不可以使用,這就是為什麼要在會話中初始化的原因)。
我們繼續新增程式碼:
img = tf.constant(1.0,1]) kernel = tf.Variable(k) y = tf.nn.conv2d(img,kernel,strides=[1,2,1],padding="SAME")
得到的計算圖如下:
可以看出,變數讀取是通過Variable/read來進行的。
如果在這裡我們直接開啟會話,並執行計算圖中的卷積操作,系統就會報錯。
img = tf.constant(1.0,1]) kernel = tf.Variable(k) y2 = tf.nn.conv2d(img,padding="SAME") with tf.Session() as sess: sess.run(y2)
這段程式碼錯誤的原因在於,變數並沒有初始化就被使用,而從圖中清晰的可以看到,直接執行卷積,是回溯不到變數的值(Const_1)的(箭頭方向)。
所以,在執行之前,要進行初始化,程式碼如下:
img = tf.constant(1.0,padding="SAME") init = tf.global_variables_initializer()
執行完tf.global_variables_initializer()函式以後,計算圖如下:
tf.global_variables_initializer()產生了一個名為init的node,該結點將所有的Variable/Assign結點作為輸入,以達到對整張計算圖中的變數進行初始化。
所以,在開啟會話後,執行的第一步操作,就是變數初始化(當然變數初始化的方式有很多種,我們也可以顯示呼叫tf.assign()來完成對單個結點的初始化)。
完整程式碼如下:
img = tf.constant(1.0,padding="SAME") init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) # do someting....
會話
在上述程式碼中,我已經使用會話(tf.session())來執行計算圖了。在tf.session()中,我們重點掌握無所不能的sess.run()。
一個session()中包含了Operation被執行,以及Tensor被evaluated的環境。
tf.Session().run()函式的定義:
run( fetches,feed_dict=None,options=None,run_metadata=None )
tf.Session().run()函式的功能為:執行fetches引數所提供的operation操作或計算其所提供的Tensor。
run()函式每執行一步,都會執行與fetches有關的圖中的所有結點的計算,以完成fetches中的任務。其中,feed_dict提供了部分資料輸入的功能。(和tf.Placeholder()搭配使用,很舒服)
引數說明:
- fetches:可以是圖中的一個結點,也可以是一個List或者字典,此時候返回值與fetches格式一致;該引數還可以是一個Operation,此時候返回值為None。
- feed_dict:字典格式。給模型輸入其計算過程中所需要的值。
當我們把模型的計算圖構建好以後,就可以利用會話來進行執行訓練了。
在明白了計算圖是如何構建的,以及如何被會話正確的執行以後,我們就可以愉快的開始Tensorflow之旅啦。
參考連結
https://jacobbuckman.com/
https://danijar.com/what-is-a-tensorflow-session/
http://looop.cn/?p=3365
到此這篇關於Tensorflow中的圖(tf.Graph)和會話(tf.Session)的實現的文章就介紹到這了,更多相關Tensorflow tf.Graph tf.Session內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!