TensorFlow學習筆記1:graph、session和op

graph即tf.Graph(),session即tf.Session(),不少人常常將二者混淆,其實兩者徹底不是同一個東西。python

  • graph定義了計算方式,是一些加減乘除等運算的組合,相似於一個函數。它自己不會進行任何計算,也不保存任何中間計算結果。
  • session用來運行一個graph,或者運行graph的一部分。它相似於一個執行者,給graph灌入輸入數據,獲得輸出,並保存中間的計算結果。同時它也給graph分配計算資源(如內存、顯卡等)。

TensorFlow是一種符號式編程框架,首先要構造一個圖(graph),而後在這個圖上作運算。打個比方,graph就像一條生產線,session就像生產者。生產線具備一系列的加工步驟(加減乘除等運算),生產者把原料投進去,就能獲得產品。不一樣生產者均可以使用這條生產線,只要他們的加工步驟是同樣的就行。一樣的,一個graph能夠供多個session使用,而一個session不必定須要使用graph的所有,能夠只使用其中的一部分。編程

關於graph

定義一個圖:graph

g = tf.Graph()
a = tf.constant(2)
b = tf.constant(3)
x = tf.add(a, b)

上面就定義了一個graph。tensorflow會默認給咱們創建一個graph,因此g = tf.Graph()這句實際上是能夠省略的。上面的graph包含3個操做,即op,但凡是op,都須要經過session運行以後,才能獲得結果。若是你直接執行print(a),那麼輸出結果是:安全

Tensor("a:0", shape=(), dtype=int32)

是一個張量(Tensor)。若是你執行print(tf.Session().run(a)),才能獲得2.session

關於子圖:subgraph

你能夠定義多個graph,例如一個graph實現z = x + y,另外一個graph實現u = 2 * v框架

g1 = tf.Graph()
g2 = tf.Graph()
with g1.as_default():
    x = tf.constant(2)
    y = tf.constant(3)
    z = tf.add(x, y)
with g2.as_default():
    v = tf.constant(4)
    u = tf.mul(2, v)

但一般不建議這麼作,緣由以下:函數

  • 運行多個graph須要多個session,而每一個session會試圖耗盡全部的計算資源,開銷太大;
  • graph之間沒有數據通道,要人爲經過python/numpy傳數據;

事實上,你能夠把全部的op都定義在一個graph中:翻譯

x = tf.constant(2)
y = tf.constant(3)
z = tf.add(x, y)
v = tf.constant(4)
u = tf.mul(2, v)

從上面graph的定義能夠看到,x/y/z是一波,u/v是另外一波,兩者沒有任何交集。這至關於在一個graph裏有兩個獨立的subgraph。當你要計算z = x + y時,執行tf.Session().run(z);當你想計算u = 2 * v,就執行tf.Session().run(u),兩者徹底獨立。但更重要的是,兩者在同一個session上運行,系統會均衡地給兩個subgraph分配合適的計算資源。code

關於session

一般咱們會顯示地定義一個session來運行graph:orm

x = tf.constant(2)
y = tf.constant(3)
z = tf.add(x, y)

with tf.Session() as sess:
    result = sess.run(z)
    print(result)

輸出結果是5。內存

關於op

tensorflow是一個符號式編程的框架,首先要定義一個graph,而後用一個session來運行這個graph獲得結果。graph就是由一系列op構成的。上面的tf.constant()tf.add()tf.mul()都是op,都要現用session運行,才能獲得結果。

不少人會覺得tf.Variable()也是op,其實不是的。tensorflow裏,首字母大寫的類,首字母小寫的纔是op。tf.Variable()就是一個類,不過它包含了各類op,好比你定義了x = tf.Variable([2, 3], name = 'vector'),那麼x就具備以下op:

  • x.initializer # 對x作初始化,即賦值爲初始值[2, 3]
  • x.value() # 獲取x的值
  • x.assign(...) # 賦值操做
  • x.assign_add(...) # 加法操做

tf.Variable()必須先初始化,再作運算,不然會報錯。下面的寫法就不是很安全,容易致使錯誤:

W = tf.Variable(tf.truncated_normal([700, 10]))
U = tf.Variable(2 * W)

要把W賦值給U,必須現把W初始化。但不少人每每忘記初始化,從而出錯。保險起見,應該按照下面這樣寫:

W = tf.Variable(tf.truncated_normal([700, 10]))
U = tf.Variable(2 * W.intialized_value())

一個特殊的op: tf.placeholder()

placeholder,翻譯過來就是佔位符。其實它相似於函數裏的自變量。好比z = x + y,那麼x和y就能夠定義成佔位符。佔位符,顧名思義,就這是佔一個位子,平時不用關心它們的值,當你作運算的時候,你再把你的數據灌進去就好了。是否是和自變量很像?看下面的代碼:

a = tf.placeholder(tf.float32, shape=[3]) # a是一個3維向量
b = tf.constant([5, 5, 5], tf.float32)
c = a + b
with tf.Session() as sess:
    print sess.run(c, feed_dict = {a: [1, 2, 3]}) # 把[1, 2, 3]灌到a裏去

輸出結果是[6, 7, 8]。上面代碼中出現了feed_dict的概念,其實就是用[1, 2, 3]代替a的意思。至關於在本輪計算中,自變量a的取值爲[1, 2, 3]。其實不只僅是tf.placeholder才能夠用feed_dict,不少op均可以。只要tf.Graph.is_feedable(tensor)返回值是True,那麼這個tensor就可用用feed_dict來灌入數據。

tf.constant()是直接定義在graph裏的,它是graph的一部分,會隨着graph一塊兒加載。若是經過tf.constant()定義了一個維度很高的張量,那麼graph佔用的內存就會變大,加載也會變慢。而tf.placeholder就沒有這個問題,因此若是數據維度很高的話,定義成tf.placeholder是更好的選擇。

相關文章
相關標籤/搜索