[Tensorflow 實戰] TensorFlow 入門

TensorFlow 的計算模型、數據模型和運行模型。

TensorFlow 計算模型 — — 計算圖

TensorFlow:
* Tensor:張量,可以被簡單地理解為多維度數組。
* Flow:流,表達張量之間通過計算相互轉化的過程。

計算圖Computational Graph
1. 構造計算圖
2. 運行計算圖

計算圖是什麼?

通過 tf.get_default_graph() 函數就可以獲得當前默認的計算圖。

Tensorflow 數據模型 — — 張量

張量可以被簡單理解為多維數組。
* 零階張量表示標量(Scalar),也就是一個數。
* 一階張量表示向量(Vector),也就是一個一維數組
* n 階張量可以理解為一個 n 維數組。

在張量中並沒有真正保存數字,它保存的是如何得到這些數字的計算過程。

a = tf.constant([1.0, 2.0], name=’a’)
b = tf.constant([2.0, 3.0], name=’b’)
result = tf.add(a, b, name=’add’)
print(result)

Result:

Tensor(“add_1:0”, shape=(2,), dtype=float32)

Tensorflow 計算的結果不是一個具體的數字,而是一個張量的結構。
張量主要保存三個屬性:
1. 名字(name)
2. 維度(shape)
3. 類型(type)

張量的第三個屬性是類型(type),每一個張量會有一個唯一的類型。TensorFlow 會對參與運算的所有張量進行類型的檢查,當發現類型不匹配時會報錯。

a = tf.constant([1, 2], name=’a’)
b = tf.constant([2.0, 3.0], name=’b’)
result = tf.add(a, b, name=’add’)

Error:

ValueError: Tensor conversion requested dtype int32 for Tensor with dtype float32: ‘Tensor(“b_2:0”, shape=(2,), dtype=float32)’

不帶小數點被默認為 int32,帶小數點會默認為 float32。

在張量有一個小技巧是 result.get_shpae(),通過張量來儲存中間結果可以方便獲取中間結果。比如在 CNN 中,convolution layer 或是 max pooling layer有可能改變張量的維度,通過 result.get_shape() 來獲取結果的維度訊息可以免去人工計算的麻煩。

result.get_shape()

Result:

TensorShape([Dimension(2)])

TensorFlow 運行模型 — — 會話()

Session 擁有管理 TensorFlow 程式運行時的所有資源。所有計算完成之後需要關閉 Session 來幫助系統回收資源,否則就可能出現資源洩漏的問題。

sess = tf.Session()print(sess.run(result))sess.close()

Result:

[3. 5.]

在 python 中可以通過上下文管理器來使用 Session。

with tf.Session() as sess:
print(sess.run(result))

Result:

[3. 5.]

以下兩種寫法會有相同的結果:

with tf.Session() as sess:
print(sess.run(result))
print(result.eval())

tf.constant

在 TensorFlow 中計算圖的運算相當嚴謹,如果節點中的數值型態不一樣就會報錯。

node1 = tf.constant(3.0, tf.float32)
node2 = tf.constant(4)
tf.add(node1, node2)

Error:

Input ‘y’ of ‘Add’ Op has type int32 that does not match type float32 of argument ‘x’.

tf.placeholder

我們可以利用 tf.placeholder 在計算圖中建立空的 node,在運行計算圖時,可以將資料餵進去 tf.placeholder

# 建構計算圖
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
add_node = a + b

輸出看看 add_node 長什麼樣子:

print(add_node)
# 運行計算圖
print(sess.run(add_node, feed_dict={a: 1, b: 3}))
print(sess.run(add_node, feed_dict={a: [1, 2], b: [3, 4]}))

輸出結果:

<tf.Tensor ‘add:0’ shape=<unknown> dtype=float32>
4.0
[4. 6.]

我們可以添加一個操作,使計算圖更加複雜:

add_and_triple = add_node * 3
add_and_triple
# 運行計算圖
print(sess.run(add_and_triple, feed_dict={a: [1, 2], b: [3, 4]}))

輸出結果:

<tf.Tensor ‘mul:0’ shape=<unknown> dtype=float32>
[12. 18.]

所以我們可以利用 tf.placeholder 來定義網路結構,後續只要在運行計算圖時,將資料餵進去 node 後,就可以運行網路。

tf.Variable

在 Machine Learning 中,需要模型可以任意輸入,為了模型具有可訓練能力,需要修正計算圖,使對於同樣的輸入得到新的輸出。tf.Variable 允許我們為計算圖添加訓練參數。

我們來建構 Variable,提供型態 (type) 和初始值:

n1 = tf.Variable(3.0, tf.float32)

常數節點在調用 tf.constant 時就被初始化,而 variable node 在調用 tf.Variable 時並不初始化,必須顯性的執行如下操作:

init = tf.global_variables_initializer()
sess.run(init)

意識到 init 對像是 Tensorflow 子圖初始化所有 global variable 是重要的,在調用 sess.run(init) 方法之前,所有 Variable 都是未初始化的。

sess.run(n1)

輸出結果:

3.0

重點來了,我們來用 tf.Variable 和 tf.placeholder 建立線型模型 (linear model):

W = tf.Variable([1., 3, 5.])
b = tf.Variable([1.], dtype=tf.float32)
X = tf.placeholder(dtype=tf.float32, shape=(3,))
net = W * X + b
init = tf.global_variables_initializer()
sess.run(init)
sess.run(net, feed_dict={X: [1., 2., 3]})

這邊要特別注意的是,在定義完 tf.Variable 時,要重新初始化 Variable。

輸出結果:

array([ 2., 7., 16.], dtype=float32)

tf.train

Tensorflow提供了優化器 Optimizer 慢慢改變每個參數來最小化損失函數。最簡單的Optimizer是梯度下降gradient descent,它根據損失函數相對於該變量的導數大小來修改參數值,一般來講,手動計算導數是乏味且易出錯的,Tensorflow可以使用方法tf.gradients自動的為給定模型計算導數。優化器通常做這個工作。

# optimizer
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train = optimizer.minimize(loss)
# training
epoch = 1000
for _ in range(epoch):
sess.run(train, feed_dict={X: [1., 2., 3.], y: [3., 6., 15.]})

以下是完整的程式碼:

W = tf.Variable([1., 3, 5.])
b = tf.Variable([1.], dtype=tf.float32)
X = tf.placeholder(dtype=tf.float32, shape=(3,))
net = W * X + b
init = tf.global_variables_initializer()
sess.run(init)
# label
y = tf.placeholder(dtype=tf.float32)
# loss function
square_errors = tf.square(net-y)
loss = tf.reduce_sum(square_errors)
# optimizer
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train = optimizer.minimize(loss)
# training
epoch = 1000
for _ in range(epoch):
sess.run(train, feed_dict={X: [1., 2., 3.], y: [3., 6., 15.]})
curr_W, curr_b, curr_loss = sess.run([W, b, loss],{X:[ 1 , 2 , 3], y: [3., 6., 15.]})
print ( “W: {} b: {} loss: {}”.format(curr_W, curr_b, curr_loss))

輸出結果:

W: [1.7294136 2.3647099 4.576473 ] b: [1.2705834] loss: 2.4556356947869062e-11

Reference:

  1. https://blog.csdn.net/WuyZhen_CSDN/article/details/64516733

每天進步一點點,在終點遇見更好的自己。

Love podcasts or audiobooks? Learn on the go with our new app.