前一篇主要對(duì)TensorFlow的常量挤巡,如簡(jiǎn)單的scalar, vector, matrix等Tensor盏求,以及線性序列(Sequence)啥么,基本的抽樣函數(shù)做了介紹驻啤,本篇主要介紹TensorFlow中的變量蝌矛,數(shù)據(jù)類型道批,基本的數(shù)學(xué)操作,并結(jié)合TensorBoard,來(lái)介紹一些變量依賴的組織入撒。
搞機(jī)器學(xué)習(xí)或是數(shù)值計(jì)算程序的人估計(jì)都了解NumPy隆豹,或者整個(gè)python-based的數(shù)理科學(xué)計(jì)算的生態(tài)系統(tǒng),SciPy。
數(shù)據(jù)類型
TensorFlow的基本數(shù)據(jù)類型在借鑒NumPy(且當(dāng)前對(duì)NumPy的類型幾乎完全兼容)的基礎(chǔ)上茅逮,也有些自己原生的一些數(shù)據(jù)類型璃赡,完整的數(shù)據(jù)類型列表可以參見(jiàn)官網(wǎng),下表給出一些基本的數(shù)據(jù)類型:
Data Type | Python type | Description |
---|---|---|
DT_FLOAT | tf.float32 | 32 bits floating point |
DT_DOUBLE | tf.float64 | 64 bits floating point |
DT_INT32 | tf.int32 | 32 bits signed int |
DT_INT64 | tf.int64 | 64 bits signed int |
DT_STRING | tf.string | Variable length byte array |
DT_BOOL | tf.bool | Boolean |
因?yàn)門ensorFlow數(shù)據(jù)類型保持了跟NumPy的無(wú)縫集成献雅,大多數(shù)時(shí)候你可以把NumPy的數(shù)據(jù)類型當(dāng)成TensorFlow的來(lái)用鉴吹,但通常的practice是如果可以用TensorFlow原生數(shù)據(jù)類型的地方,我們就直接用原生的惩琉。一方面是誰(shuí)也不知道現(xiàn)在的版本是兼容的豆励,以后會(huì)不會(huì)久不兼容了呢?最重要的是瞒渠,原生的數(shù)據(jù)類型對(duì)TensorFlow的build-in函數(shù)良蒸,求導(dǎo)優(yōu)化計(jì)算等都有天然的優(yōu)勢(shì)。
變量
前一篇我們介紹了常量伍玖,常量跟變量的區(qū)別自然不必贅述嫩痰,就跟任何語(yǔ)言類似。其存儲(chǔ)的地方也不同窍箍,比如Java中的常量是放在堆區(qū)串纺,而變量是在棧區(qū)丽旅。在TensorFlow里,常量和變量也是分開(kāi)存儲(chǔ)的纺棺。常量的值是放在graph的definition里的榄笙,在分布式環(huán)境下,每個(gè)節(jié)點(diǎn)上整個(gè)graph都是replicated的祷蝌,相應(yīng)的常量也會(huì)replicated一份茅撞。對(duì)于TensorFlow而言,Graph的definition用protocol buffer來(lái)表述:
import tensorflow as tf
vector = tf.constant([2.0, 8], name="vector")
print tf.get_default_graph().as_graph_def()
而變量則不同巨朦,往往是放在一些獨(dú)立的集群上<label for="sn-1" class="margin-toggle sidenote-number" style="box-sizing: border-box; margin: 0px 0px 5px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 700; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; display: inline; max-width: 100%; counter-increment: sidenote-counter 1;"></label>
即我們通常所說(shuō)的Parameter Server米丘,是目前主流的分布式機(jī)器學(xué)習(xí)框架,原始論文參見(jiàn)
糊啡,其需要和worker節(jié)點(diǎn)進(jìn)行跨網(wǎng)絡(luò)或者RPC通信拄查。
變量聲明
和一般的面向?qū)ο笳Z(yǔ)言一樣,聲明一個(gè)變量就是創(chuàng)建一個(gè)tf.Variable
類的實(shí)例棚蓄。和常量不同的是堕扶,我們用tf.constant
來(lái)聲明一個(gè)常量。前者是一個(gè)Class癣疟,而后者是一個(gè)operator(可以看作是一個(gè)類里的方法),一個(gè)tf.Variable
類里可以有多個(gè)operator潮酒。
import tensorflow as tf
# use InteractiveSession
sess = tf.InteractiveSession()
cons = tf.constant(8, name="consant")
var = tf.Variable(8, name="Variable")
# ==> Tensor("consant:0", shape=(), dtype=int32)
print cons
# ==> <tf.Variable 'Variable:0' shape=() dtype=int32_ref>
print var
變量初始化
在使用一個(gè)變量之前睛挚,必須先初始化變量,如果使用了一個(gè)未初始化的變量急黎,會(huì)報(bào)一個(gè)FailedPreconditionError
的錯(cuò)誤扎狱,如下所示。值得注意的時(shí)勃教,和一般的面向?qū)ο笳Z(yǔ)言不同的是淤击,第3行中,tf.Variable(8, name="Variable")
故源,雖然第一個(gè)參數(shù)是8污抬,似乎是做了初始化,其實(shí)不然绳军。前面我們說(shuō)過(guò)印机,TensorFlow作為一門工具語(yǔ)言,一個(gè)鮮明的特點(diǎn)便是函數(shù)(這里是Graph)的定義和執(zhí)行是分開(kāi)的门驾。初始化函數(shù)也需要顯示的聲明和執(zhí)行射赛。
全局初始化函數(shù)
import tensorflow as tf
cons = tf.constant(8, name="consant")
var = tf.Variable(8, name="Variable")
init = tf.global_variables_initializer() ## 全局初始化函數(shù)聲明
with tf.Session() as sess:
sess.run(init) # 執(zhí)行全局初始化
print sess.run(cons) # OK, result is 8
# 未初始化: FailedPreconditionError: Attempting to use uninitialized value Variable_2
# 初始化:result is 8.
print sess.run(var)
選擇性初始化
import tensorflow as tf
var1 = tf.Variable(8, name="var1")
var2 = tf.Variable(8, name="var2")
init = tf.variables_initializer([var1]) ## 初始化var1
with tf.Session() as sess:
sess.run(init) # 執(zhí)行全局初始化
# OK, result is 8
print sess.run(var1)
# 未初始化: FailedPreconditionError: Attempting to use uninitialized value var2_2
print sess.run(var2)
單個(gè)變量初始化
import tensorflow as tf
var2 = tf.Variable(8, name="var1")
with tf.Session() as sess:
sess.run(var2.initializer)
print sess.run(var2) # OK, result is 8.
變量評(píng)估和賦值
賦值函數(shù)assign()
變量聲明之后,我們可以通過(guò)在Session中的sess.run()
來(lái)查看一個(gè)變量的值奶是,還有一個(gè)eval()
函數(shù)也可以實(shí)現(xiàn)該功能楣责。變量的賦值則是通過(guò)assign()
函數(shù)來(lái)實(shí)現(xiàn)竣灌,值得注意的是這里的賦值是非引用式的,函數(shù)返回賦值后的值秆麸,但該變量的值不會(huì)改變初嘹。
import tensorflow as tf
var1 = tf.Variable(8, name="var1")
var1.assign(100) # 變量賦值,var1 任然是8
init = tf.variables_initializer([var1])
with tf.Session() as sess:
print var1.eval() # OK, result is 8.
值得注意的是在使用了賦值函數(shù)后蛔屹,我們并沒(méi)有對(duì)var2
進(jìn)行初始化卻可以正確使用削樊。
查看源碼會(huì)發(fā)現(xiàn),其實(shí)是assign()
函數(shù)替我們做了兔毒。當(dāng)我們通過(guò)賦值函數(shù)聲明一個(gè)變量漫贞,但這個(gè)變量依賴于另外一個(gè)變量時(shí),情況便變得很有趣了育叁。如下所示:
import tensorflow as tf
var1 = tf.Variable(8, name="var1")
var2 = var1.assign(var1*2)
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(var1.initializer)
print var2.eval() # result is 16
print var2.eval() # result is 32
print var2.eval() # result is 64
var2被assign的不是一個(gè)值迅脐,而是一個(gè)assign
的operator,因此在Session里豪嗽,每次run時(shí)就會(huì)做一次評(píng)估谴蔑,這就好比C語(yǔ)言中的宏擴(kuò)展。
自增和自減函數(shù)
TensorFlow提供了assign_add()
和assgin_sub()
函數(shù)來(lái)實(shí)現(xiàn)函數(shù)的自增自減功能龟梦。和assign()函數(shù)會(huì)自動(dòng)幫你初始化變量不同隐锭,自增、自減函數(shù)并不會(huì)幫你賦值计贰,你需要自己賦值
原因其均依賴于當(dāng)前的值做assign钦睡,因此需要對(duì)var1
和var2
都要做初始化。
TensorBoard
數(shù)據(jù)可視化在ML里一直是被忽視但又非常重要的一部分躁倒。記得Andrew Ng最常說(shuō)的一句話便是在做任何數(shù)據(jù)分析處理之前一定要對(duì)數(shù)據(jù)有個(gè)直觀的sense荞怒,數(shù)據(jù)可視化便是重要的方法,因?yàn)槠鋵?duì)模型秧秉,參數(shù)選擇都至關(guān)重要褐桌。TensorFlow Dev Summit 2017中用很大的篇幅介紹了TensorBoard,如MNIST手寫(xiě)辨識(shí)的demo中長(zhǎng)這樣
用Google自己的話說(shuō)象迎,
"The computations you'll use TensorFlow for -like training a massive deep neural network - can be complex and confusing. To make it easier to understand, debug, and optimize TensorFlow programs, we've included a suite of visualization tools call TensorBoard".
更詳盡的介紹和使用將根據(jù)具體的的機(jī)器學(xué)習(xí)的例子來(lái)介紹更具有直觀性荧嵌。最簡(jiǎn)單的使用僅兩步:首先在Session里首行加上,
writer = tf.summary.FileWriter('./graphs', sess.graph)
然后在shell里run如下命令砾淌。打開(kāi)瀏覽器完丽,http://localhost:6006
,就可以看見(jiàn)針對(duì)當(dāng)前Session的TensorFlow可視化效果拇舀。
$ tensorboard --logdir="./graphs"
參考
[2]