一、基礎概念
1. 從Hello World開始
import tensorflow as tf
#創建一個常量運算,將作為一個節點加入到默認計算圖中
hello = tf.constant("Hello, World!")
#創建一個TF對話
sess = tf.Session()
#運行并獲得結果
print(sess.run(hello))
# b'Hello, World!'
#輸出前面的'b'表示Bytes literals(字節文字)
2. TensorFlow的概念
- Tensor 張量
數據結構:多維數組 - Flow 流
計算模型:張量之間通過計算而轉換的過程
TensorFlow是一個通過計算圖的形式表述計算的編程系統
每一個計算都是計算圖上的一個節點,節點之間的邊描述了計算之間的關系
3. 計算圖(數據流圖)的概念
計算圖是一個有向圖,由以下內容構成
- 一組節點,每個節點都代表一個操作,是一種運算
- 一組有向邊,每條邊代表節點之間的關系( 數據傳遞和控制依賴 )
TensorFlow有兩種邊
- 常規邊(實線):代表數據依賴關系。一個節點的運算輸出成為另一個節點的輸入,兩個節點之間有tensor流動( 值傳遞 )
- 特殊邊(虛線):不攜帶值,表示兩個節點之間的控制相關性。比如,happens-before關系,源節點必須在目的節點執行前完成執行
4. 計算圖的實例
計算圖節點輸出的結果不是一個具體的數字,而是一個張量的結構
#一個簡單計算圖
node1 = tf.constant(3.0, tf.float32, name = "node1")
node2 = tf.constant(4.0, tf.float32, name = "node2")
node3 = tf.add(node1, node2)
print(node3)
# Tensor("Add:0", shape=(), dtype=float32)
創建計算圖就是建立計算模型,執行對話才能提供數據并獲得結果
#建立對話并顯示運行結果
sess = tf.Session()
#更新變量并返回計算結果
print("運行sess.run(node3)的結果:", sess.run(node3))
#關閉session
sess.close()
# 運行sess.run(node3)的結果: 7.0
5. 張量的概念
- 在TensorFlow中,所有的數據都通過張量的形式來表示
- 從功能的角度,張量可以簡單理解為多維數組
零階張量表示標量(scalar),也就是一個數;
一階張量為向量(vector),也就是 一維數組;
n階張量可以理解為一個n維數組; - 張量并沒有真正保存數字,它保存的是計算過程
6. 張量的屬性
Tensor("Add:0", shape=(), dtype=float32)
-
名字(name)
"node:src_output":node 節點名稱,src_output 來自節點的第幾個輸出 -
形狀(shape)
張量的維度信息,shape=(),表示是標量 -
類型(type)
每一個張量會有一個唯一的類型
TensorFlow會對參與運算的所有張量進行類型檢查,發現類型不匹配時會報錯
7. 張量的形狀
三個術語描述張量的維度,階(rank)、形狀(shape)、維數(dimension number)
階 | 形狀 | 維數 | 例子 |
---|---|---|---|
0 | () | 0-D | 4 |
1 | (D0) | 1-D | [2,3,5] |
2 | (D0,D1) | 2-D | [[2,3],[3,4]] |
3 | (D0,D1,D2) | 3-D | [[[7],[3]],[[2],[4]]] |
N | (D0,D1,...,Dn-1) | n-D | 形為(D0,D1,...,Dn-1的張量) |
tens1 = tf.constant([[[1,2,2],[2,2,3]],
[[3,5,6],[5,4,3]],
[[7,0,1],[9,1,9]],
[[11,12,7],[1,3,14]]], name="tens1")
print(tens1)
#Tensor("tens1:0", shape=(4, 2, 3), dtype=int32)
#shape,4表示最外維有4個元素,2表示中間維度有2個元素,3表示最里維有3個元素
#查看張量的形狀
scalar = tf.constant(100)
vector = tf.constant([1, 2, 3, 4, 5])
matrix = tf.constant([[1, 2, 3],[4, 5, 6]])
cube_matrix = tf.constant([[[1],[2],[3]], [[4],[5],[6]], [[7],[8],[9]]])
print(scalar.get_shape())
print(vector.get_shape())
print(matrix.get_shape())
print(cube_matrix.get_shape())
# ()
# (5,)
# (2, 3)
# (3, 3, 1)
8. 獲取張量的元素
- 階為1的張量等價于向量
- 階為2的張量等價于矩陣,通過t[i, j]獲取元素
- 階為3的張量,通過t[i, j, k]獲取元素
tens2 = tf.constant([[[1,2],[2,3]],[[3,4],[5,6]]])
sess = tf.Session()
print(sess.run(tens2)[1, 1, 0])
sess.close()
# 5
9. 張量的類型
TensorFlow支持14種不同的類型
- 實數 tf.float32, tf.float64
- 整數 tf.int8, tf.int16, tf.int32, tf.int64, tf.uint8
- 布爾 tf.bool
- 復數 tf.complex64, tf.complex128
默認類型: - 不帶小數點的數會被默認為int32
- 帶小數點的會被默認為float32
import tensorflow as tf
a = tf.constant([1, 2], name = "a")
b = tf.constant([2.0, 3.0], name = "b")
result = a + b
# 類型不匹配而報錯:Tensor conversion requested dtype int32 for Tensor with dtype float32: 'Tensor("b:0", shape=(2,), dtype=float32)'
10. 操作
- 計算圖中的節點就是操作
加減乘除運算、變量初始賦值都是操作 - 每個運算操作都有屬性,它在構建圖的時候需要確定下來
- 操作可以和計算設備綁定,指定操作在某個設備上執行
- 操作之間存在順序關系,這些操作之間的依賴就是“邊”
- 如果操作A的輸入是操作B執行的結果,那么這個操作A就依賴于操作B
import tensorflow as tf
tf.reset_default_graph() #清除default graph和不斷增加的節點
#定義變量a
a = tf.Variable(1, name = "a")
b= tf.add(a, 1, name = "b")
c = tf.multiply(b, 4, name = "c")
d = tf.subtract(c, b, name = "d")
logdir = 'D:\ForPython\log'
#生成一個寫日志的writer,并將當前的TensorFlow計算圖寫入日志
writer = tf.summary.FileWriter(logdir, tf.get_default_graph())
writer.close()
二、基本運算
1. TensorFlow運行模型——會話
會話擁有并管理TensorFlow程序運行時的所有資源,當所有計算完成后需要關閉會話幫助系統回收資源
- 會話的典型模式1
#定義計算圖
tens1 = tf.constant([1, 2, 3])
#創建一個會話
sess = tf.Session()
try:
#使用這個創建好的會話來得到關心的運算的結果,比如盜用 sess.run(result)
#來得到張量result的值
print(sess.run(tens1))
except:
print("Exception")
finally:
#關閉會話使得本次運行中使用到的資源可以被釋放
sess.close()
# [1 2 3]
- 會話的典型模式2
node1 = tf.constant(3.0, tf.float32, name = "node1")
node2 = tf.constant(4.0, tf.float32, name = "node2")
result = tf.add(node1, node2)
#創建一個會話,并通過Python中的上下文管理器來管理這個會話
with tf.Session() as sess:
#使用這創建好的會話來計算關心的結果
print(sess.run(result))
#不需要再調用Session.close()函數來關閉會話
#當上下文退出時會話關閉和資源釋放也自動完成了
# 7.0
- 指定默認的會話
node1 = tf.constant(3.0, tf.float32, name = "node1")
node2 = tf.constant(4.0, tf.float32, name = "node2")
result = tf.add(node1, node2)
sess = tf.Session()
with sess.as_default(): #指定sess為默認的會話,故可直接調用result.eval()
print(result.eval())
# 7.0
#未指定時,result.eval()必須說明會話參數
print(result.eval(session = sess)
# 7.0
#用sess.run()同樣可以完成相同功能
print(sess.run(result))
# 7.0
-
交互式環境下設置默認會話
交互式環境下,Python腳本或者Jupyter編輯器下,通過設置默認會話來獲取張量的取值更加方便,tf.InteractiveSession 使用這個函數會自動將生成的會話注冊為默認會話
node1 = tf.constant(3.0, tf.float32, name = "node1")
node2 = tf.constant(4.0, tf.float32, name = "node2")
result = tf.add(node1, node2)
#定義交互式的session,同時注冊為默認會話
sess = tf.InteractiveSession()
print(result.eval())
sess.close()
# 7.0
2. 常量與變量
常量:在運行過程中不會改變的單元,在TensorFlow中無須進行初始化操作
#創建語句
constant_name = tf.constant(value)
#示例
a = tf.constant(1.0, name = "a")
變量:在運行過程中值會改變的單元,在TensorFlow中須進行初始化操作
#創建語句
name_variable = tf.Variable(value, name) #注意V是大寫字母
#個別變量初始化
init_op = name_variable.initializer()
#所有變量初始化
init_op = tf.global_variables_initializer()
#示例
node1 = tf.Variable(3.0, tf.float32, name = "node1")
node2 = tf.Variable(4.0, tf.float32, name = "node2")
result = tf.add(node1, node2, name = "add")
sess = tf.Session()
#變量初始化
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(result))
# 7.0
3. 變量賦值
與傳統編程語言不同,TensorFlow中的變量定義后,一般無需人工賦值,系統會根據算法模型,訓練優化過程中自動調整變量對應的數值。
#如果需要人工賦值,并且不希望訓練模型自動更改它
epoch = tf.Variable(0, name = 'epoch', trainable = False) #指明不參加訓練
#特殊情況需要人工更新,可用變量賦值語句
update_op = tf.assign(variable_to_be_updated, new_value) #被更新變量,新值
#示例:通過變量賦值1、2、3...5
import TensorFlow as tf
value = tf.Variable(0, name = "value")
one = tf.constant(1)
new_value = tf.add(value, one)
update_value = tf.assign(value, new_value)
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
for _ in range(5): #執行5次
sess.run(update_value) #每一次更新值(+1)
print(sess.run(value))
# 1
# 2
# 3
# 4
# 5
4. 占位符、Feed數據填充和Fetch數據獲取
TensorFlow中的Variable變量類型,在定義時需要初始化,但有些變量定義時并不知道其數值,只有當真正開始運行程序時,才由外部輸入,比如訓練數據,這時候需要用到占位符。
tf.placeholder占位符,是TensorFlow中特有的一種數據結構,類似動態變量,函數的參數、或者C語言或者Python語言中格式化輸出的“%”占位符。
- 占位符 placeholder
#函數接口:先定義一種數據,參數為數據的 Type和 Shape
tf.placeholder(dtype, shape = None, name = None)
x = tf.placeholder(tf.float32, [2, 3], name = 'tx')
#生成一個2x3的二維數組,矩陣中每個元素類型為tf.float32,內部對應的符號名稱是tx
- Feed數據填充
如果構建了一個包含placeholder操作的計算圖,當在session中調用run方法時,placeholder占用的變量必須通過feed_dict參數傳遞進去
#定義變量a、b
a = tf.placeholder(tf.float32, name = 'a')
b = tf.placeholder(tf.float32, name = 'b')
#定義a*b的操作 c
c = tf.multiply(a, b, name ='c')
#定義初始化所有變量的操作init
init = tf.global_variables_initializer()
#創建一個會話,并通過Python中的上下文管理器來管理這個會話
with tf.Session() as sess:
sess.run(init) #使用的是占位符,因此這里不進行變量初始化也可以
#通過feed_dict 的參數傳遞,按字典格式
result = sess.run(c, feed_dict = {a : 8.0, b : 3.5})
print(result)
# 28.0
- 多個操作可以通過一次Feed完成執行
#定義變量 a、b
a = tf.placeholder(tf.float32, name = "a")
b = tf.placeholder(tf.float32, name = "b")
#定義操作 c、d
c = tf.multiply(a, b, name ="c")
d = tf.subtract(a, b, name = 'd')
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
result = sess.run([c,d],feed_dict = {a:[8.0, 2.0, 3.5], b:[1.5, 2.0, 4.]})
print(result)
#取結果中的第一個
print(result[0])
# [array([ 12., 4., 14.], dtype=float32), array([ 6.5, 0. , -0.5], dtype=float32)]
# [ 12. 4. 14.]
#一次返回多個值分別賦給多個變量
rc, rd = sess.run([c,d],feed_dict = {a:[8.0, 2.0, 3.5], b:[1.5, 2.0, 4.]})
print("value of c = ", rc, "value of d = ", rd)
# value of c = [ 12. 4. 14.] value of d = [ 6.5 0. -0.5]
三、TensorBoard 可視化初步
TensorBoard是TensorFlow的可視化工具,通過TensorFlow程序運行過程中輸出的日志文件可視化TensorFlow程序的運行狀態,TensorBoard和TensorFlow程序跑在不同的進程中。
import tensorflow as tf
#清除default graph 和不斷增加的節點
tf.reset_default_graph()
#日志
logdir = 'D:\ForPython\log'
#定義一個簡單的計算圖,實現向量加法的操作
input1 = tf.constant([1.0, 2.0, 3.0], name = "input1")
input2 = tf.Variable(tf.random_uniform([3]), name = "input2")
output = tf.add_n([input1, input2], name = "add")
#生成一個寫日志的writer, 并將當前的TensorFlow計算圖寫入日志
writer = tf.summary.FileWriter(logdir, tf.get_default_graph())
writer.close()
啟動TensorBoard
- 在Anaconda Prompt 中先進入日志存放的目錄
- 再運行TensorBoard,并將日志的地址指向程序日志輸出的地址
- 命令:tensorboard --logdir=D:\ForPython\log
- 啟動服務的端口默認為6006,使用 --port 參數可以改編啟動服務的端口
- 在瀏覽器中訪問網址:http://miaoxingren:6006(若打不開-> http://127.0.0.1:6006)