版權申明:本文爲博主窗戶(Colin Cai)原創,歡迎轉帖。如要轉貼,必須註明原文網址 http://www.cnblogs.com/Colin-Cai/p/10741013.html 做者:窗戶 QQ/微信:6679072 E-mail:6679072@qq.com
tensorflow是一個很流行的計算框架,目前主要用來作深度學習。但實際上,tensorflow不只僅能夠作深度學習,理論上說任何算法均可以用tensorflow來描述,就在於它作了計算流圖這樣的抽象,而tensorflow這個名字實際上很天然流。其實提到計算流圖,這樣的抽象並非tensorflow首做,計算模型中常常會有圖計算,編譯器中離開了這玩意玩不轉,乃至咱們平時的工程涉及到大的規模乃至須要需求模板化的時候,可能都離不開計算流圖或者相似這樣的模型。因此,其實它對於咱們每一個人並非什麼新鮮的玩意。 html
如下代碼包括其註釋說明了計算流圖的創建以及使用,包含了對tensorflow的最基本概念認識。算法
#先要導入庫 import tensorflow as tf #創建session才能夠進行圖運算 #實際上session只須要在計算前創建便可 #但此處爲了方便就先創建了 s = tf.Session()
創建計算圖,包含了操做和張量。tensorflow內部帶有各類操做,甚至本身也能夠用C++來添加新的操做。sql
如下multipy和reduce_sum都是操做,其實constant也被當作是操做。微信
#如下是創建計算圖,tensorflow創建計算圖 #只是定義各個tensor之間的計算關係,並未開始計算 #每一個操做均可以帶一個名字,操做和張量之間是一對一的關係 #如下是兩個常量 a = tf.constant(list(range(1,5)), name="a") b = tf.constant(list(range(11,15)), name="b") #將兩個形狀同樣的張量依次按相同位置相乘 #獲得一個形狀同樣的張量 c = tf.multiply(a, b, name="c") #將張量裏全部元素累和 d = tf.reduce_sum(c, name="d")
不要被名字所誤導,以上並不產生計算,只是佈置流圖,或許tf.place(tf.multiply, a, b)這樣的名字可能更好一點^_^網絡
在session裏使用run方法纔會產生真實的計算,run帶有兩個參數,一個是fetches,表示要計算的張量,一個是feed_dict,表示要臨時賦值的張量。session
如下s.run(d)其實等同於s.run(fetches=d)框架
#使用Session的方法run能夠根據計算圖計算須要的tensor #1*11+2*12+3*13+4*14=130 #輸出130 print(s.run(d)) #能夠選擇一組tensor #輸出[array([1, 2, 3, 4], dtype=int32), array([11, 12, 13, 14], dtype=int32), array([11, 24, 39, 56], dtype=int32), 130] print(s.run([a,b,c,d])) #feed_dict能夠修改任何想傳入的tensor,此處但願修改a的傳入 #31*11+32*12+33*13+34*14=1630 #輸出1630 print(s.run(d, feed_dict={a:list(range(31,35))})) #feed_dict能夠一次修改多個tensor #41*51+42*52+43*53+44*54=8930 #輸出8930 print(s.run(d, feed_dict={a:list(range(41,45)), b:list(range(51,55))})) #不是constant同樣能夠修改傳入 #此時計算c不依賴於a和b #1+2+3+4+5=10 #輸出10 print(s.run(d, feed_dict={c:list(range(1,5))})) #流圖中d依賴於c更短,因此a的傳入不影響計算 #輸出10 print(s.run(d, feed_dict={a:list(range(11,15)), c:list(range(1,5))}))
實際上,大多狀況下,老是會有一些張量要在計算開始指定的,那麼這些張量爲constant已經失去意義,從而引入placeholder。學習
#引入placeholder,這樣此處不須要constant #如下創建的張量爲一階張量,也就是向量,維度爲4 e = tf.placeholder(tf.int32, shape=[4], name="e") f = tf.constant(list(range(1,5)), name="f") g = tf.multiply(e, f, name="g") h = tf.reduce_sum(g, name="h") #h的計算最終依賴於e這個placeholder #而若是依賴的placeholder若是不傳值,則不可運算 #如下會產生異常 try: print(s.run(h)) except: print("EROR HERE!") #給placeholder傳值 #輸出10 print(s.run(h, feed_dict={e:list(range(1,5))})) #a,b,c,d的計算和h的計算是兩ge獨立的計算連通圖 #但依然能夠一塊兒計算 #輸出[array([1, 2, 3, 4], dtype=int32), array([11, 12, 13, 14], dtype=int32), array([11, 24, 39, 56], dtype=int32), 130, 30] print(s.run([a,b,c,d,h], feed_dict={e:list(range(1,5))}))
一個計算圖中能夠有多個placeholderfetch
#placeholder能夠創建多個 e2 = tf.placeholder(tf.int32, shape=[4], name="e2") f2 = tf.placeholder(tf.int32, shape=[4], name="f2") g2 = tf.multiply(e2, f2, name="g2") h2 = tf.reduce_sum(g2, name="h2") #要計算h2,依賴的兩個placeholder必須都傳值 #輸出30 print(s.run(h2, feed_dict={e2:list(range(1,5)), f2:list(range(1,5))}))
上面placeholder在shape參數中定死了張量的形狀,實際上能夠不定死維數spa
#甚至能夠只指定placeholder是幾階張量,而不指定維度數 e3 = tf.placeholder(tf.int32, shape=[None], name="e3") f3 = tf.placeholder(tf.int32, shape=[None], name="f3") g3 = tf.multiply(e3, f3, name="g3") h3 = tf.reduce_sum(g3, name="h3") #輸出30 print(s.run(h3, feed_dict={e3:list(range(1,5)), f3:list(range(1,5))})) #元組固然沒有問題 #輸出5 print(s.run(h3, feed_dict={e3:(1,2), f3:(1,2)}))
二階張量固然也能夠,同理三階、四階...都是能夠得
#一階張量能夠,二階張量固然沒有問題 e4 = tf.placeholder(tf.int32, shape=[None, None], name="e4") f4 = tf.placeholder(tf.int32, shape=[None, None], name="f4") g4 = tf.multiply(e4, f4, name="g4") h4 = tf.reduce_sum(g4, name="h4") #輸出30 print(s.run(h4, feed_dict={e4:[[1,2],[3,4]], f4:[[1,2],[3,4]]})) #經過名字也能夠找到張量 _e4 = tf.get_default_graph().get_tensor_by_name("e4:0") _f4 = tf.get_default_graph().get_tensor_by_name("f4:0") _g4 = tf.get_default_graph().get_tensor_by_name("g4:0") _h4 = tf.get_default_graph().get_tensor_by_name("h4:0") #輸出[array([[ 100, 400],[ 900, 1600]], dtype=int32), 3000] print(s.run([_g4, _h4], feed_dict={_e4:[[10,20],[30,40]], _f4:[[10,20],[30,40]]}))
甚至,placeholder不指定張量階數也是沒有問題的。
x = tf.placeholder(tf.int32) y = tf.reduce_sum(x) #輸出10 s.run(y,feed_dict={x:[[1,2],[3,4]]}) #輸出36 s.run(y,feed_dict={x:[[[1,2],[3,4]], [[5,6],[7,8]]]})
以上提到的計算圖自己不帶有記憶,從而能夠引入帶有記憶的計算圖,那就是須要引入變量(variable)概念,也就是能夠把一些張量定義爲變量。
#引入變量,從而但願在內存中常駐,以便修改 m=tf.Variable(list(range(1,3)), name="m") n=tf.reduce_sum(m, name="n") p=tf.add(m, n, name="p") #把p賦值給變量m q=tf.assign(m, p, name="q") #當使用變量的時候,須要利用這個將變量初始化一下 s.run(tf.global_variables_initializer()) #[1,2]求和爲3,[1,2]加3獲得[4,5],賦值給m #輸出[4 5] print(s.run(q)) #[4,5]求和爲9,[4,5]加9獲得[13,14],賦值給m #輸出[13 14] print(s.run(q))
變量一旦形狀肯定,是不能進行調整的。
try: #concat是把兩個張量拼接,從而張量的維度發生了變化 #而m2做爲變量,一開始形狀就被肯定,assign是不能對形狀金勳哥調整的 #從而這裏會發生異常 m2=tf.Variable([1,2], expected_shape=[None],dtype=tf.int32) n2=tf.reduce_sum(m2) p2=tf.add(m2,n2) r2=tf.concat([m2,p2],0) q2=tf.assign(m2,r2) s.run(tf.global_variables_initializer()) s.run(q2) except: print("ERROR HERE!")
或許只能用如下方法?
#我能想到的只好用如下方法來實現改變形狀 m3=tf.placeholder(tf.int32, shape=[None], name="m3") n3=tf.reduce_sum(m3, name="n3") p3=tf.add(m3, n3, name="p2") r3=tf.concat([m3,p3], 0, name="r3") #輸出[1 2 4 5] x=s.run(r3, feed_dict={m3:[1,2]}) print(x) #輸出[1 2 4 5 13 14 16 17] x=s.run(r3, feed_dict={m3:x}) print(x)
關於以上變量的維度一旦肯定,就沒法改變,多是由於tensorflow一開始就分配好了內存。我就想,若是將來出現那種結構不斷調整的AI模型該怎麼辦,彷佛前段時間據說了已經出現了不斷在調整尺寸的基於神經網絡的AI模型,但不知道是用什麼實現的。