致遠行的人,自編TensorFlow教程(2)

在上一篇文章中,我們介紹了使用TensorFlow框架有兩部分組成:構建計算圖,用會話啓動計算圖。今天我們來介紹 tf.placeholder,feed_dict,實現一個 Wx+b 的函數。本文章仍然保持不夠專業的傳統,只求達到效果,可以實現一些東西;或者說“路子比較野”。同時確實不一定保證章節與章節之間條理清晰。

首先還是上一段可執行的代碼。

import tensorflow as tf

# 開始構建計算圖

W = tf.constant(
    [[1.0, 2.0, 3.0],
     [4.0, 5.0, 6.0]]
)

# 注意 x 和 b 是列向量
x = tf.placeholder(tf.float32, shape=[3, 1])

b = tf.constant([[1.0], [2.0]])

result1 = tf.matmul(W, x) + b

result2 = result1 + b

# 結束構建計算圖

init = tf.global_variables_initializer()

with tf.Session() as sess:
    # get_result1 = sess.run(result1, feed_dict={x: [[3.0], [4.0], [5.0]]})
    get_result1, get_result2 = sess.run([result1, result2], feed_dict={x: [[3.0], [4.0], [5.0]]})
    print(get_result1)
    print(get_result2)

這段代碼中構建計算圖的部分比較長,我仍然會細緻地講解。

首先是W矩陣,我把它設爲 2 × 3 的矩陣。根據上一節的講解,它是一個常量。在TensorFlow裏,需要特別注意矩陣和向量的shape,即線性代數裏學的,2 × 3 的矩陣只能和 3 × n 的矩陣相乘,如果在報錯信息裏面看到“shape”的字樣,十有八九是矩陣的大小搞錯了。

講真,我真的很佩服那些學數學的,是如何記住那些矩陣的shape,保證寫出來是對的,當然我確實也記不住大寫的是矩陣,小寫的是向量這樣的規則(Is it right?)。我看公式時總是會想着shape是多少,這樣代碼跑出來是怎樣的效果。

x = tf.placeholder(tf.float32, shape=[3, 1])
b = tf.constant([[1.0], [2.0]])

聲明 x 是一個placeholder,就是說假設這裏有一個矩陣,矩陣的大小是shape決定的。在運行計算圖的時候, x 會被填入相應的數據,這個在稍後會說明。總之它是一個 3 × 1 的列向量。同樣 b 也是一個 2 × 1 的列向量。

如果你需要 b 是行向量呢?如下所示,自行注意其中的差別。記不住的話,寫代碼的時候多試幾次,調試到正確爲止。

b = tf.constant([1.0, 2.0])

然後關於我們希望獲得的結果:

result1 = tf.matmul(W, x) + b
result2 = result1 + b

其實寫result1這一行就可以了,result2只是爲了說明一個技巧。tf.matmul是TensorFlow中的矩陣乘法運算。爲什麼不直接用“*”呢?我也是寫到這邊的時候剛剛想到的,然後測試了一下,“*”好像是向量乘法(就是,[1, 2, 3] * [4, 5, 6] = [4, 10, 18]),沒有嚴格測試,歡迎指正。

總之result1就是Wx+b在計算圖中的結果。注意計算圖中的變量類型都是tensor,必須依靠會話啓動計算圖才能得到結果。(不信可以試試直接print,啥也看不到)

get_result1, get_result2 = sess.run([result1, result2], feed_dict={x: [[3.0], [4.0], [5.0]]})

我們剛剛說了,構建計算圖時假設 x 是一個矩陣,因爲我們也沒告訴它實際的數值。在這行代碼中,我們使用feed_dict這個參數,給 x 傳入一個列向量。這樣可以一次性得到result1和result2的結果。可以使用構建一個帶tensor的list在一行代碼中獲取所有的tensor在計算後對應的值。這裏還有個細節,result2是以來result1的。在獲取result2的時候,我覺得,只是個人覺得,計算圖只會被計算一次。就是說,獲取result2的時候,計算圖不會從頭計算。(我們能想到的這麼簡單的優化,TensorFlow團隊應該也想得到,除非不可爲)只計算一次的好處就是,如果你的計算圖流程特別長,那麼只計算一次的話可以大大提高計算速度,節約計算資源。雖然只是個人猜測,有機會可以測試一下,但直接寫在一行代碼裏會合適一些。

今天就講到這兒吧,建議把代碼手敲一遍,然後嘗試各種改動,調戲一下代碼,下一節我們將講變量和優化器。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章