Tensorflow學習筆記(一)

因為博士研究方向主要集中在運籌優(yōu)化方向嗤疯,希望博士畢業(yè)之后工作轉(zhuǎn)向人工智能方向。因此決定在未來的半年內(nèi)逐漸豐富自己的AI相關(guān)技術(shù)棧闺兢,集中于深度學茂缚、GAN等非監(jiān)督學習技術(shù)、強化學習等方面屋谭。

Tensorflow作為google開源的一款優(yōu)秀的深度學習框架脚囊,吸引了很多關(guān)注,也成為和FB的pytorch并駕齊驅(qū)的框架桐磁。因此有必要對Tensorflow進行深入的研究悔耘。本學習筆記主要參考了《Tensorflow:實戰(zhàn)Google深度學習框架》這本書,其對于入門來說非常合適我擂,因此本系列文章主要是此書的最重要內(nèi)容的境界和個人的一些理解衬以。

Tensorflow的安裝和配置

如果是在個人PC上配置Tensorflow,推薦安裝pycharm破解版+anaconda的python環(huán)境校摩,很容易利用pycharm的包管理器添加Tensorflow的功能看峻。如果在服務器上,可以參考網(wǎng)上的配置教程衙吩,這不是本文的重點互妓,相關(guān)安裝可參考點我配置

Tensorflow的主要思想

  1. 張量和圖
    Tensorflow最重要的概念就是張量(tensor),一個張量可以理解為一個多維數(shù)組冯勉,如果是標量則定義為0維澈蚌。Tensorflow第一步需要做的事情就是定義一個圖(graph),圖的頂點由張量構(gòu)成珠闰,這些張量之間存在一些運算關(guān)系惜浅,這種運算關(guān)系則相當于頂點之間的邊。當定義好圖后伏嗜,就相當于定義好了所有張量的一個計算流坛悉。
    值得注意的是,定義好的張量其本質(zhì)是一個指針承绸,而不是具體數(shù)值裸影,直接打印定義好的張量,會打印出張量的數(shù)據(jù)結(jié)構(gòu)信息军熏,考慮如下代碼
import tensorflow as tf
a = tf.constant([1,0, 2.0], name='a')
print(a)

其輸出結(jié)果并不是預想的[1.0, 2.0]轩猩,而是

>>Tensor("a:0", shape=(3,), dtype=float32)
  1. 會話
    因此,Tensorflow的第三個重要的概念就是會話(session)荡澎,只有當圖運行在會話上時均践,才能使得張量計算得到具體值。如下代碼給出了一個最簡單的使用tensorflow計算加法的demo摩幔。
import tensorflow as tf
a = tf.constant([1.0, 2.0], name='a', dtype=tf.float32)
b = tf.constant([3.0, 4.0], name='b', dtype=tf.float32)
result = a + b
with tf.Session() as sess:
    print(sess.run(result))

上面的代碼with ... as 實際上是一個局部空間彤委,能夠保證tf.Session()在使用完后會話關(guān)閉,若tensor是某定義好的張量節(jié)點或衡,則運行sess.run(tensor)可以得到其具體值焦影。同時注意到tf.Session()會運行默認圖,只有當傳入tf.Session(graph=g1)才能保證該會話運行指定的圖g1封断∷钩剑可以按照如下方式定義圖且運行指定圖:

g1 = tf.Graph()
with g1.as_default():
    u = tf.Variable(initial_value=tf.random_normal(\
    shape=[200, 100], stddev=0.1), name='u')
with tf.Session(graph=g1) as sess:
    tf.initialize_all_variables().run()
    with tf.variable_scope("", reuse=True):
        print(sess.run(tf.get_variable('u')))   ##打印圖g1中張量u的計算結(jié)果

如果要定義默認會話,可以使用tf.InteractiveSession()坡疼,例如下面可以直接計算變量結(jié)果的代碼

result = tf.constant(1,name='result')
sess=tf.InteractiveSession()
print(result.eval())
sess.close()
---------------------
>>1
  1. 變量
    變量是tensorflow重要的一種張量彬呻,在深度學習訓練中,變量可用來存儲可迭代更新的待優(yōu)化的參數(shù)柄瑰。常見的兩種聲明變量的方法包括
w1 = tf.Variable(initial_value=tf.random(\
shape[1,1],stddev=0.1), name='weights')
w2 =  tf.get_variable(name = 'weights', shape=[1, 1],\
initializer=tf.random_normal_initializer(stddev=0.1))

采用這兩種方式定義變量是等價的闸氮。tf.Variable需要傳入初始值,而tf.get_variable則要求傳入一個initializer的初始化器狱意。在run session的之前init這些變量將會按照代碼中的方式進行初始化。tf.Variable和tf.get_variable存在一些細微的差別:

  • tf.Variable在出現(xiàn)變量的name沖突時會系統(tǒng)自動處理加上后綴拯欧,而tf.get_variable則會系統(tǒng)報錯详囤,不允許重名。
import tensorflow as tf
w_1 = tf.Variable(1,name="w_1")
w_2 = tf.Variable(2,name="w_1")
print(w_1.name)
print(w_2.name)
#輸出
>>w_1:0
>>w_1_1:0
-----------------------------------
import tensorflow as tf
w_1 = tf.get_variable(name="w_1",initializer=1)
w_2 = tf.get_variable(name="w_1",initializer=2)
#錯誤信息
#ValueError: Variable w_1 already exists, disallowed. Did
#you mean to set reuse=True in VarScope?
  • 當需要共享變量的時候,需要使用tf.get_variable()藏姐。為了方便變量管理隆箩,tensorflow有一個變量管理器,叫做tf.variable_scope羔杨,類似于C++中的命名空間捌臊,在不同命名空間內(nèi),tf.get_variable()可以重名兜材。但tf.get_variable()在同一個命名空間內(nèi)共享一個變量的時候需要聲明reuse理澎,否則報錯,reuse代表是指向同一個變量曙寡。如下為例:
import tensorflow as tf
with tf.variable_scope("scope1"): # scopename is scope1
    w1 = tf.get_variable("w1", shape=[])
    w2 = tf.Variable(0.0, name="w2")
with tf.variable_scope("scope1", reuse=True):
    w1_p = tf.get_variable("w1", shape=[])
    w2_p = tf.Variable(1.0, name="w2")
with tf.variable_scope("scope2"):
    w1_pp = tf.get_variable("w1", shape=[])
print(w1 is w1_p, w2 is w2_p, w1 is w1_pp)  # True False False

最后再簡單說一下變量的初始化糠爬,如果已經(jīng)聲明了兩個變量w1和w2,那么下面幾種初始化方式等價:

sess.run(w1.initializer)
sess.run(w2.initializer)
-----------------------------
sess.run(tf.initialize_all_variables())
-----------------------------
tf.initialize_all_variables().run()

值得注意的是举庶,在最新版本的python和tensorflow中执隧,函數(shù)tf.initialize_all_variables被替換成了tf.global_variables_initializer,但前者還可以兼容使用户侥,只不過會報警告镀琉。

  1. 賦值操作
    tensorflow為張量節(jié)點提供了賦值運算的操作tf.assign,可以將一個變量賦給另外一個變量蕊唐,但是要求變量的dtype是一樣的屋摔,維數(shù)shape不同的時候還需要聲明validate_shape=False。舉例如下
## 嘗試賦不同類型
w1 = tf.Variable(tf.random_normal([2,3], stddev=1), name='w1')
w2 = tf.Variable(tf.random_normal([3,4], dtype=tf.float64, stddev=1), name='w2')
w1.assign(w2)
>>TypeError: Input 'value' of 'Assign' Op has type float64 that does not match type float32 of argument 'ref'.
## 賦不同shape
w1 = tf.Variable(tf.zeros([2,2]), name='w1')
w2 = tf.Variable(tf.zeros([2,3]), name='w2')
tf.assign(w1, w2)
>> ValueError: Dimension 1 in both shapes must be equal, but are 2 and 3. Shapes are [2,2] and [2,3]. for 'Assign' (op: 'Assign') with input shapes: [2,2], [2,3].
# 這一句可以成功執(zhí)行
tf.assign(w1, w2, validate_shape=False)
  1. 占位張量(placeholder)
    通常而言刃泌,定義一個計算圖會使用常量tf.constant凡壤,但是頻繁使用tf.constant會增大網(wǎng)絡圖的規(guī)模,帶來急速的計算膨脹耙替。因此亚侠,tensorflow里面引入了placeholder占位符用來在循環(huán)結(jié)構(gòu)中不斷接收常量。例如在前向傳播算法中一次迭代用多個樣本(一個batch)來計算輸出值俗扇,迭代1000次硝烂,如果不用placeholder去接收batch,而改成聲明常量的方法铜幽,必然導致計算圖的規(guī)模急劇膨脹滞谢。因此做法是為每個batch聲明一個固定的placeholder作為占位張量節(jié)點,然后每次迭代將具體的樣本數(shù)據(jù)feed進去除抛。placeholder必須要有固定的數(shù)據(jù)類型狮杨,但是維度可以是變化的,比如可設定shape=(none, 2)到忽,則第一維可以變化橄教。在sess.run()的時候需要將所有必須的placeholder都填上具體的數(shù)據(jù)清寇,例如
x = tf.placeholder(shape=[1,2], dtype=tf.float32, name='x-input')
y = tf.const([0.5,0.5])
result = x+y
with tf.Session() as sess:
    print(sess.run(result, feed_dict={x:[0.5,0.5]}))
>> [1.0, 1.0]

使用tensorflow編寫最簡單的神經(jīng)網(wǎng)絡

熟悉了上一節(jié)介紹的tensorflow思想,我們就可以寫一個最簡單的神經(jīng)網(wǎng)絡的代碼了

import tensorflow as tf
#Numpy是一個科學計算的工具包护蝶,這里通過Numpy工具包生成模擬數(shù)據(jù)集
from numpy.random import RandomState
 
#定義訓練數(shù)據(jù)batch的大小
batch_size = 8
 
#定義神經(jīng)網(wǎng)絡的參數(shù)
w1 = tf.Variable(tf.random_normal([2, 3], stddev = 1, seed = 1))
w2 = tf.Variable(tf.random_normal([3, 1], stddev = 1, seed = 1))
 
'''
在shape的一個維度上使用None可以方便的使用不同的batch大小华烟。在訓練時把數(shù)據(jù)分成
比較小的batch,但是在測試時持灰,可以一次性使用全部的數(shù)據(jù)盔夜。當數(shù)據(jù)集比較小時這樣比較
方便測試。但是數(shù)據(jù)集比較大時堤魁,將大量數(shù)據(jù)放入一個batch可能造成內(nèi)存溢出喂链。
'''
x = tf.placeholder(tf.float32, shape=(None, 2), name='x-input')
y_ = tf.placeholder(tf.float32, shape=(None, 1), name='y-input')
 
#定義神經(jīng)網(wǎng)絡的前向傳播結(jié)構(gòu)
a = tf.matmul(x, w1)
y = tf.matmul(a, w2)
 
#定義損失函數(shù)和反向傳播算法
y = tf.sigmoid(y)
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0))
                                + (1-y)*tf.log(tf.clip_by_value(1-y, 1e-10, 1.0)))
train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)
 
#通過隨機數(shù)生成一個模擬數(shù)據(jù)集
rdm = RandomState(1)
dataset_size = 128
X = rdm.rand(dataset_size, 2)
 
'''
定義規(guī)則來給出樣本的標簽。在這里所有x1+x2<1的樣例都被認為是正樣本(比如零件合格)姨涡,
而其他為負樣本(比如零件不合格)衩藤。和tensorflow游樂場中的表示法不太一樣的地方是,
在這里使用0表示負樣本涛漂,1表示正樣本赏表。大部分解決分類問題的神經(jīng)網(wǎng)絡都會采用0和1表示法。
'''
Y = [[int(x1+x2<1)] for (x1, x2) in X]
 
#創(chuàng)建一個會話來運行tensorflow程序
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    #初始化變量
    sess.run(init_op)
 
    #打印訓練前神經(jīng)網(wǎng)絡參數(shù)的值
    print(sess.run(w1))
    print(sess.run(w2))
 
    #設定訓練的輪數(shù)
    STEPS = 5000
    for i in range(STEPS):
        #每次選取batch個樣本進行訓練
        start = (i * batch_size) % dataset_size
        end = min(start+batch_size, dataset_size)
 
        #通過選取的樣本訓練神經(jīng)網(wǎng)絡并更新參數(shù)
        sess.run(train_step, feed_dict={x:X[start:end], y_:Y[start:end]})
        if i % 1000 == 0:
            #每隔一段時間計算所在數(shù)據(jù)上的交叉熵并輸出
            total_cross_entropy = sess.run(cross_entropy, feed_dict={x:X, y_:Y})
            print("After %d training steps(s), cross entropy on all data is %g" %
                  (i, total_cross_entropy))
    print(sess.run(w1))
    print(sess.run(w2))

可以總結(jié)撰寫神經(jīng)網(wǎng)絡的大致步驟 :

  1. placeholder用于傳入樣本數(shù)據(jù)匈仗,作為神經(jīng)網(wǎng)絡的輸入瓢剿;(trainable)variables用于作為待訓練參數(shù)
  2. 定義神經(jīng)網(wǎng)絡結(jié)構(gòu)圖和前向傳播算法的輸出結(jié)果
  3. 定義損失函數(shù)及反向傳播的優(yōu)化算法,形成一個完整的train_step
  4. 定義一個會話tf.Session()悠轩,多次執(zhí)行train_step(核心是反響傳播算法)间狂,不斷更新variables
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市火架,隨后出現(xiàn)的幾起案子鉴象,更是在濱河造成了極大的恐慌,老刑警劉巖何鸡,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纺弊,死亡現(xiàn)場離奇詭異,居然都是意外死亡骡男,警方通過查閱死者的電腦和手機淆游,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來隔盛,“玉大人犹菱,你說我怎么就攤上這事∷笨唬” “怎么了腊脱?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長龙亲。 經(jīng)常有香客問我陕凹,道長震鹉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任捆姜,我火速辦了婚禮,結(jié)果婚禮上迎膜,老公的妹妹穿的比我還像新娘泥技。我一直安慰自己,他們只是感情好磕仅,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布珊豹。 她就那樣靜靜地躺著,像睡著了一般榕订。 火紅的嫁衣襯著肌膚如雪店茶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天劫恒,我揣著相機與錄音贩幻,去河邊找鬼。 笑死两嘴,一個胖子當著我的面吹牛丛楚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播憔辫,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼趣些,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贰您?” 一聲冷哼從身側(cè)響起坏平,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锦亦,沒想到半個月后舶替,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡孽亲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年坎穿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片返劲。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡玲昧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出篮绿,到底是詐尸還是另有隱情孵延,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布亲配,位于F島的核電站尘应,受9級特大地震影響惶凝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜犬钢,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一苍鲜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧玷犹,春花似錦混滔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至巍扛,卻和暖如春领跛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撤奸。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 正文 我出身青樓怎诫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親贷痪。 傳聞我的和親對象是個殘疾皇子幻妓,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容