2.1 Tensorflow的計(jì)算模型——計(jì)算圖
??根據(jù)lesson1中所講,Tensorflow實(shí)際原理是張量的流動(dòng),講述輸入的多維數(shù)組(張量)通過(guò)不同節(jié)點(diǎn)進(jìn)行不同的運(yùn)算進(jìn)行轉(zhuǎn)化的一個(gè)過(guò)程,Tensorflow的每一個(gè)計(jì)算都是計(jì)算圖的一個(gè)節(jié)點(diǎn),涉及到一次張量的轉(zhuǎn)化。多個(gè)節(jié)點(diǎn)構(gòu)成一個(gè)神經(jīng)元。Tensorflow如果不定義計(jì)算圖,會(huì)自動(dòng)生成一個(gè)默認(rèn)的計(jì)算圖,并將定義的計(jì)算全部加入默認(rèn)圖。
??如果說(shuō)類比的話,計(jì)算圖就像是我們?cè)诿嫦驅(qū)ο缶幊汤锏念悾聪率龃a可以理解),在一個(gè)計(jì)算圖里,每個(gè)數(shù)據(jù)都像是類中的變量,每個(gè)計(jì)算節(jié)點(diǎn)都像是一個(gè)成員函數(shù),兩個(gè)圖里的變量名字可以相同但是在指定運(yùn)行不同的圖時(shí),得到結(jié)果根據(jù)各自圖運(yùn)算過(guò)程而定。
??計(jì)算圖有隔離張量和計(jì)算的作用,并對(duì)張量和計(jì)算進(jìn)行管理,例如限定計(jì)算所使用的GPU等,這個(gè)后續(xù)學(xué)到再說(shuō),我現(xiàn)在也不太會(huì)??,而且我前面介紹的安裝是CPU版本。自定義圖的示例代碼如下(python 的縮進(jìn)很重要,不要漏掉):
import tensorflow as tf
g1 = tf.Graph()
with g1.as_default():
# 在計(jì)算圖g1中定義變量“v”,初始化為0
v = tf.get_variable("v",initializer=tf.zeros_initializer(shape=[1]))
g2 = tf.Graph()
with g2.as_default():
# 在計(jì)算圖g2中定義變量“v”,初始化為1
v = tf.get_variable("v",initializer=tf.ones_initializer(shape=[1]))
# 在計(jì)算圖g1中讀取變量“v”的值
with tf.Session(graph = g1) as sess:
tf.initialize_all_variables().run()
with tf.variable_scope("",reuse=True):
# 在計(jì)算圖g1中,“v”為0,所以下述語(yǔ)句應(yīng)該輸出0
print(sets.run(tf.get_variable("v")))
# 在計(jì)算圖g2中讀取變量“v”的值
with tf.Session(graph = g2) as sess:
tf.initialize_all_variables().run()
with tf.variable_scope("",reuse=True):
# 在計(jì)算圖g1中,“v”為1,所以下述語(yǔ)句應(yīng)該輸出1
print(sets.run(tf.get_variable("v")))
??使用圖限定計(jì)算用的GPU
g = tf.Graph()
# 指定計(jì)算運(yùn)行的設(shè)備
with g.device('/gpu:0'):
result = a + b
2.2 Tensorflow的數(shù)據(jù)模型——張量
2.2.1 概念
??張量是Tensorflow管理數(shù)據(jù)的形式,可以簡(jiǎn)單理解為多維數(shù)組,不過(guò)Tensor的存儲(chǔ)和Numpy的多維數(shù)組有所不同,Numpy簡(jiǎn)介參見(jiàn)這里,觀察如下代碼:
import tensorflow as tf
#. td.constant 是一個(gè)計(jì)算,個(gè)人感覺(jué)和申請(qǐng)const變量差不多,不過(guò)結(jié)果是一個(gè)張量,存儲(chǔ)在變量a中
a = tf.constant([1.0,2.0],name="a")
b = tf.constant([2.0,3.0],name="b")
c = tf.constant([2.0,3.0])
d = tf.constant([2.0,3.0])
result = tf.add(a,b,name="add")
print(result) # output : Tensor("add:0",shape=(2,),dtype=float32)
print(a) # output: Tensor("a:0", shape=(2,), dtype=float32)
print(c) # output: Tensor("Const:0", shape=(2,), dtype=float32)
print(d) # output: Tensor("Const_1:0", shape=(2,), dtype=float32)
sess = tf.Session()
sess.run(result) # output : array([3., 5.], dtype=float32)
less.run(a) # output : array([1., 2.], dtype=float32)
??從上述代碼可以發(fā)現(xiàn)張量中主要保存了三個(gè)屬性:名字(name),維度(shape)和類型(type),其中名字遵循“node:src_output”,比如result為add計(jì)算節(jié)點(diǎn)的第0個(gè)輸出,所以命名為add:0,因?yàn)橛械挠?jì)算節(jié)點(diǎn)并不一定輸出一個(gè)張量,所以src_output為輸出序號(hào),node為計(jì)算節(jié)點(diǎn)名稱,tf.constant()和tf.add()均為計(jì)算,所以a為a:0,其中節(jié)點(diǎn)的名稱可以由我們定義,如果我們不自己定義,Tensorflow有自己的默認(rèn)命名,比如c的"Const:0" 以及d的“Const_1:0”
??所以,我感覺(jué)Tensor不能單純的理解為多維數(shù)組,它包含了他是從哪個(gè)計(jì)算節(jié)點(diǎn)計(jì)算而來(lái)的,以及它的大小,我們可以理解為T(mén)ensorflow分為兩部分工作,第一部分工作是定義計(jì)算圖,也就是定義張量是如何流動(dòng)的,但是每一步運(yùn)算都并沒(méi)有實(shí)質(zhì)上的運(yùn)行,張量就是這樣而存在的。第二部分是對(duì)計(jì)算圖進(jìn)行實(shí)質(zhì)上的通過(guò)CPU或者GPU進(jìn)行計(jì)算,這就需要運(yùn)行Session,Session的使用會(huì)在后面小節(jié)具體描述,從上述代碼可以看到運(yùn)行sess.run()就會(huì)輸出運(yùn)算結(jié)果
2.2.2 張量的使用
??觀察下列代碼的運(yùn)行
import tensorflow as tf
a = tf.constant([1,2],name="a")
b = tf.constant([2.0,3.0],name="b")
c = tf.constant([1,2],name="c",dtype=tf.float32)
result = a + b # Get ERROR bellow
# ValueError: Tensor conversion requested dtype int32 for Tensor with dtype float32: 'Tensor("b:0", shape=(2,), dtype=float32)'
result = b+c # no error
??對(duì)于Tensorflow,如果不聲明類型dtype,那么沒(méi)有小數(shù)點(diǎn)默認(rèn)類型為int32,有小數(shù)點(diǎn)默認(rèn)為float32,這個(gè)和我們編程不一樣,不存在強(qiáng)制類型轉(zhuǎn)換,需要注意。Tensorflow所支持的數(shù)據(jù)類型:
- 浮點(diǎn)數(shù)(tf.float32、tf.float64)
- 整數(shù)(tf.int8、tf.int16、tf.int32、tf.int64、 tf.unit8)
- 布爾型(tf.bool)
- 復(fù)數(shù)(tf.complex64、tf.complex128)
import tensorflow as tf
a = tf.constant([1.0,2.0],name="a")
b = tf.constant([2.0,3.0],name="b")
result = a + b; # 和tf.add()效果相同,根據(jù)需要選擇,使用tf.add()可以自定義節(jié)點(diǎn)的其他屬性,比如計(jì)算節(jié)點(diǎn)的名字
# 和上述代碼效果一樣,但可讀性差
result_1 = tf.constant([1.0,2.0],name="a") +
tf.constant([2.0,3.0],name="b")
??從上述代碼可以看到,中間變量a和b只是為了存儲(chǔ)中間張量,可以不寫(xiě),但是為了可讀性應(yīng)該使用類似的中間變量增加代碼可讀性,優(yōu)點(diǎn)如下:
- 對(duì)于python:由于python的靈活的類型轉(zhuǎn)化無(wú)需聲明數(shù)據(jù)類型,設(shè)置必要中間變量方便調(diào)試
- 對(duì)于Tensorflow: 由于有的網(wǎng)絡(luò)巨大,在設(shè)計(jì)計(jì)算圖時(shí)需要考慮張量的大小問(wèn)題,設(shè)置中間變量可以方便的獲取中間步驟張量的大小,省去人為計(jì)算
2.3 Tensorflow運(yùn)行模型——會(huì)話
??前面兩節(jié)介紹了Tensorflow如何組織數(shù)據(jù)和運(yùn)算,可以認(rèn)為是計(jì)算圖的設(shè)計(jì)部分,而會(huì)話(session)是對(duì)前面兩個(gè)部分設(shè)計(jì)結(jié)果的執(zhí)行。會(huì)話可以管理Tensorflow程序運(yùn)行時(shí)的所有資源。計(jì)算完成后需要關(guān)閉繪畫(huà)幫助系統(tǒng)回收資源,可以理解為一個(gè)指針,這個(gè)指針指向計(jì)算圖的某個(gè)節(jié)點(diǎn),該節(jié)點(diǎn)就被激活并執(zhí)行計(jì)算,當(dāng)所有運(yùn)算執(zhí)行完,關(guān)閉會(huì)話,類似于指針的free。
??Tensorflow的會(huì)話的使用一般有兩種,如下所示,所有計(jì)算完成后關(guān)閉資源,但是這種方法有一個(gè)問(wèn)題就是當(dāng)在session.close()執(zhí)行之前,程序出現(xiàn)異常而退出,那么會(huì)造成資源泄漏。不過(guò)我喜歡。。??
# 創(chuàng)建一個(gè)會(huì)話
sess = tf.Session()
# 使用這個(gè)會(huì)話得到關(guān)心的運(yùn)算結(jié)果,比如上節(jié)使用的sess.run(result)
session.run(...)
#關(guān)閉會(huì)話釋放資源
session.close()
??還有一種寫(xiě)法如下,不會(huì)泄漏資源,但是我感覺(jué)寫(xiě)起來(lái)很麻煩
# 創(chuàng)建一個(gè)會(huì)話,通過(guò)Python的上下文管理器來(lái)管理這個(gè)會(huì)話。
with tf.Session() as session:
# 使用創(chuàng)建的會(huì)話計(jì)算關(guān)心的結(jié)果
session.run(...)
# 不需要調(diào)用Session.close()函數(shù)
# 當(dāng)上下文退出后會(huì)話關(guān)閉并進(jìn)行資源釋放
??以上兩種介紹的是Session的簡(jiǎn)單的也是常用的寫(xiě)法,其實(shí)會(huì)話的使用很靈活,主要表現(xiàn)在默認(rèn)會(huì)話的設(shè)置和使用上。Session和計(jì)算圖Graph類似存在默認(rèn)會(huì)話,在默認(rèn)的會(huì)話下,無(wú)需調(diào)用sess.run(),使用方法如下所示
sess = tf.Session()
#設(shè)置為默認(rèn)會(huì)話
with sess.as_default():
print(result.eval())
??同樣效果的等價(jià)寫(xiě)法還有如下兩種:
sess = tf.Session()
# 如下兩行等價(jià),均未設(shè)置默認(rèn)會(huì)話
print(sess.run(result))
print(result.eval(session=sess))
??如果Session設(shè)置為每一步計(jì)算節(jié)點(diǎn)的默認(rèn)會(huì)話,僅需調(diào)用運(yùn)算節(jié)點(diǎn)的eval()成員函數(shù)即可得到運(yùn)算結(jié)果,Tensorflow提供一個(gè)將自動(dòng)生成的會(huì)話直接注冊(cè)為默認(rèn)會(huì)話的函數(shù),作用于全局,用法如下:
# 生成一個(gè)注冊(cè)為默認(rèn)會(huì)話的會(huì)話sess
sess = tf.InteractiveSession()
print(result.eval())
sess.close()
??至此,Tensorflow的基本思想已經(jīng)簡(jiǎn)單介紹完畢,下一部分將根據(jù)一些網(wǎng)絡(luò)的設(shè)計(jì)和使用展開(kāi)對(duì)Tensorflow展開(kāi)進(jìn)階介紹