tensorflow的基本認識


  版權申明:本文為博主窗戶(Colin Cai)原創,歡迎轉帖。如要轉貼,必須注明原文網址

  http://www.cnblogs.com/Colin-Cai/p/10741013.html 

  作者:窗戶

  QQ/微信:6679072

  E-mail:6679072@qq.com

  tensorflow是一個很流行的計算框架,目前主要用來做深度學習。但實際上,tensorflow不僅僅可以做深度學習,理論上說任何算法都可以用tensorflow來描述,就在於它做了計算流圖這樣的抽象,而tensorflow這個名字實際上很自然流。其實提到計算流圖,這樣的抽象並不是tensorflow首作,計算模型中經常會有圖計算,編譯器中離開了這玩意玩不轉,乃至我們平時的工程涉及到大的規模乃至需要需求模板化的時候,可能都離不開計算流圖或者類似這樣的模型。所以,其實它對於我們每個人並不是什么新鮮的玩意。 

  以下代碼包括其注釋說明了計算流圖的建立以及使用,包含了對tensorflow的最基本概念認識。

#先要導入庫
import tensorflow as tf

#建立session才可以進行圖運算
#實際上session只需要在計算前建立即可
#但此處為了方便就先建立了
s = tf.Session()

 

  建立計算圖,包含了操作和張量。tensorflow內部帶有各種操作,甚至自己也可以用C++來添加新的操作。

  以下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,表示要臨時賦值的張量。

  以下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))}))

 

  一個計算圖中可以有多個placeholder

#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參數中定死了張量的形狀,實際上可以不定死維數

#甚至可以只指定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模型,但不知道是用什么實現的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM