簡介
深度學習的框架有很多:TensorFlow、Caffe、Theano、Torch...TensorFlow作為谷歌重要的開源項目,有非常火熱的開源的開源社區推動着開源項目的發展,它能讓項目有旺盛的生命力並在生命周期中不斷涌現新的功能並以較快的迭代來更新Bug修復。Keras是在TensorFlow基礎上構建的高層API,Keras在TensorFlow中。
Tensorflow中實現代碼可能跟我們python程序有那么一點不一樣,因為tensorflow有他自己的框架和體系,會用自己更加適配的方式來表達描述過程。
基本用法
tensorflow的程序通常被組織成兩個相互獨立的階段,一個構建計算圖(tf.Graph
)的階段,一個運行計算圖(tf.Session
)的階段
在構建計算圖階段:由張量與操作,張量Tensor主要保存了3個屬性: 名字(name)、維度(shape)、類型(type);操作OP,圖中的節點。
在運行計算圖階段:使用會話執行構建好的圖中的操作
TensorFlow圖描述了計算的過程。為了進行計算, 圖必須在會話
里被啟動。會話
將圖的OP分發到諸如CPU或GPU之類的設備
上, 同時提供執行OP的方法。這些方法執行后, 將產生的tensor返回。
import tensorflow as tf # 構建加法 計算圖 a = tf.constant(2.0, dtype=tf.float32) b = tf.constant(3.0) c = tf.add(a, b) print("a", a) # a Tensor("Const:0", shape=(), dtype=float32) print("b", b) # b Tensor("Const_1:0", shape=(), dtype=float32) print("c", c) # c Tensor("add:0", shape=(), dtype=int32) # 開啟會話,在會話中運行計算圖 with tf.Session() as sess: c_t = sess.run(c) # 把run之后的結果保存在c_t中 print(sess.run(b)) # 3.0 print("在會話中run后的加法結果", c_t) # 5
以上的圖中,有是三個節點,兩個constant節點,一個add節點,為了得到加法結果,再次強調我們必須在會話中run這個圖
計算圖(graph)
圖中包含了操作(tf.Operation)和數據(tf.Tensor)
默認圖
通常TensorFlow會默認幫我們創建一張圖,
查看默認圖有兩種方法:
1、default_g = tf.get_default_graph() # 創建一個默認圖的實例,綁定在default_g
2、op、sess都有graph屬性,默認在一張圖中
a.graph # <tensorflow.python.framework.ops.Graph object at 0x000001E3D5D12940>
sess.graph # <tensorflow.python.framework.ops.Graph object at 0x000001E3D5D12940>
創建圖
new_g = tf.Graph() 創建一張新的圖的實例,綁定在new_g
如果要在這張圖上定義數據和操作,可以使用new_g.as_default(),上下文管連器
要在tf.session(graph=new_g)選擇自定義的圖
# 自定義圖 new_g = tf.Graph() # 在自己的圖中定義數據和操作 with new_g.as_default(): a_new = tf.constant([[20]]) # 開啟new_g的會話 with tf.Session(graph=new_g) as new_sess: a_new_value = new_sess.run(a_new) print("新的圖的a的值", a_new_value)
會話(Session)
要評估張量,需要實例化一個tf.Session()對象,在會話中,調用 run 方法來運行圖節點以及查看張量,
sess.run(a) 和Tensor.eval(a) 返回與張量內容相同的numpy 數組
Tensor.eval方法和sess.run()僅在tf.Session處於活躍時才起作用。
with tf.Session() as sess: # 啟動默認圖 print(a.eval()) # 3 print(sess.run(a)) # 3
會話有兩種開啟的方式
1、tf.Session()
2、tf.InteractiveSession(),用於在交互模式中打開會話,ipython,shell,jupyter Notebook。
Session在使用完后需要釋放資源,除了使用sess.close()外,一般使用“with代碼塊”來自動關閉。
tf.Session(graph=None, config=None)
graph=new_graph # new_graph是自定義創建的新的圖的對象實例
config:清晰地顯示操作運行在哪些設備上 如果想要知道設備信息,把config設置成config = tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)
會話的run()
run(fetches, feed_dict=None, options=None, run_metadata=None)
fetches:單一的operation,或者元組operation、列表operation

a = tf.constant(2.) b = tf.constant(3.) c = a+b sess = tf.Session() s = sess.run(c) print(s) print(c.eval(session=sess))
feed_dict:參數允許調用者覆蓋圖中張量的值,運行時賦值。
與tf.placeholder()配合使用,則會檢測值的形狀是否與占位符匹配。
我們可以通過sess.run取回多個tensor

input1 = tf.constant(3.0) input2 = tf.constant(2.0) input3 = tf.constant(5.0) intermed = tf.add(input2, input3) mul = tf.mul(input1, intermed) with tf.Session(): result = sess.run([mul, intermed]) print result # 輸出: # [array([ 21.], dtype=float32), array([ 7.], dtype=float32)]
feed操作
使用 tf.placeholder() 為這些操作創建占位符,run時候通過feed_dict指定參數替換占位符。
a = tf.placeholder(tf.float32) b = tf.placeholder(tf.float32) c = tf.add(a,b) with tf.Session() as sess: re = sess.run(c, feed_dict={a:1, b:2.5}) print(re) # 3.5 print(sess.run(c, feed_dict={a:[1., 3.], b:[2., 3.]})) # [3. 6.]
Tensor 張量
張量Tensor有3個屬性: 名字(name)、維度(shape)、類型(type);
0 階張量
一個數字的大小
mammal = tf.Variable("Elephant", tf.string) ignition = tf.Variable(451, tf.int16) floating = tf.Variable(3.14159265359, tf.float64) its_complicated = tf.Variable(12.3 - 4.85j, tf.complex64)
1 階張量
mystr = tf.Variable(["Hello"], tf.string) cool_numbers = tf.Variable([3.14159, 2.71828], tf.float32) first_primes = tf.Variable([2, 3, 5, 7, 11], tf.int32) its_very_complicated = tf.Variable([12.3 - 4.85j, 7.5 - 6.23j], tf.complex64)
2 階張量
mymat = tf.Variable([[7],[11]], tf.int16) myxor = tf.Variable([[False, True],[True, False]], tf.bool) linear = tf.Variable([[4], [9], [16], [25]], tf.int32) squarish = tf.Variable([ [4, 9], [16, 25] ], tf.int32) rank = tf.rank(squarish_squares)
在圖像處理的過程中,會使用許多4階張量,維度對應批次大小、圖像寬度、圖像高度和顏色通道。
my_image = tf.zeros([10, 299, 299, 3]) # batch x height x width x color
改變形狀:tf.reshape(x, shape)
three = tf.ones([3, 4, 5]) matrix = tf.reshape(three, [6, 10]) #重塑成 6*10 matrixB = tf.reshape(matrix, [3, -1]) # 重塑成 3x20
切片索引的時候[3, -1]列表示重塑成3行任意列。
constant 常量 Tensor
生成0的張量函數 tf.zeros(shape=[2,2], dtypt=tf.float32, namhanghe=None)
生成1的張量函數 tf.ones(shape=[2,2], dtypt=tf.float32, namhanghe=None)
生成都是value值的dims形狀的張量 tf.fill(dims, value, name=None)

import tensorflow as tf t1 = tf.fill([2,3], 3) sess = tf.Session() print(sess.run(t1)) # [[3 3 3] # [3 3 3]]
生成常數 tf.constant(value, dtype=None, Shape=None, name="Const")
numpy數據轉換為tensorflow數據:data_tensor= tf.convert_to_tensor(data_numpy)
tensorflow數據轉換為numpy數據:data_numpy = data_tesor.eval()在會話中運行
random 隨機 Tensor
tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
生成標准正太分布的隨機張量
tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
shape表示生成張量的維度,mean是均值,stddev是標准差。這個函數產生截斷的正太分布,就是說產生正太分布的值與均值的差值大於兩倍的標准差,那就重新生成。和一般的正太分布的產生隨機數據比起來,這個函數產生的隨機數與均值的差距不會超過兩倍的標准差,但是一般的別的函數是可能的。
tf.random_uniform(shape, minval=0, maxval=None, dtype=tf.float32, seed=None, name=None)
從均勻分布中返回隨機值,shape形狀、minval最小值、maxval最大值
tf.random_shuffle(value, seed=None, name=None)
沿着要被洗牌的張量的第一個維度,隨機打亂。value要洗牌的張量
initialize 初始化Tensor
tf.constant_initializer(value=0, dtype=tf.float32)
也可以簡寫為tf.Constant(),初始化為常數,這個非常有用,通常偏置項就是用它初始化的。
由它衍生出的兩個初始化方法:
- tf.zeros_initializer(shape, dtype=tf.float32, partition_info=None)
- tf.ones_initializer(dtype=tf.float32, partition_info=None)
- tf.constant_initializer(0),tf.Constant(0)
tf.truncated_normal_initializer(mean=0.0, stddev=1.0, seed=None, dtype=tf.float32)
也可簡寫為tf.TruncatedNormal(),生成截斷正態分布的隨機數,這個初始化方法好像在tf中用得比較多。
tf.random_normal_initializer(mean=0.0, stddev=1.0, seed=None, dtype=tf.float32)
用正態分布產生張量的初始化器,mean均值、stddev方差、seed隨機種子、dtype數據類型。
tf.random_uniform_initializer(minval=0, maxval=None, seed=None, dtype=tf.float32)
初始化均勻分布的隨機Tensor,參數分別用於指定minval最小值、maxval最大值、seed隨機數種子、dtype類型。
tf.cast(x, dtype, name=None) # 把張量x,變成任何的dtype
變量
變量也是張量的一種
創建變量 variable;get_variable
tensorflow中創建變量的函數有tf.get_variable;tf.Variable
tf.get_variable(name, validate_shape=True, dtype=None, initializer=None, trainable=True, collections=None, caching_device=None, regularizer=None, partitioner=None, custom_getter=None, shape=None)
- name: 變量名(必須設置)
- initializer: 初始化的值
- trainable: 是否能被訓練
- shape: 形狀
例如:創建一個名為“my_variable”的變量,shape為[1,2,3]的三維張量。默認情況下dtype=tf.float32
my_int_variable = tf.get_variable("my_int_variable", shape=[1, 2, 3], dtype=tf.int32, initializer=tf.zeros_initializer)
我們還可以將Tensor變量作為初始化對象,但此時我們不能初始化形狀,而需要使用初始化張量的形狀
other_variable = tf.get_variable("other_variable", dtype=tf.int32, initializer=tf.constant([23, 42]))
使用tf.Varizble 創建變量
tf.Variable(name=None, validate_shape=True, dtype=None, initial_value=None, trainable=True, collections=None, caching_device=None, variable_def=None, expected_shape=None, import_scope=None)
- dtype: 數據類型
- initial_value: 初始化的值
- trainable: 是否能被訓練
v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer()) w = v + 1 # 這樣一來w也是tf.Tensor
我們可以使用assign、assign_add方法為變量tf.Variable賦值

import tensorflow as tf # 創建一個變量, 初始化為標量 0. state = tf.Variable(0, name="counter") one = tf.constant(1) v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer()) assignment = v.assign_add(1) # 變量加1 new_value = tf.add(state, one) # new_value = state + 1 update = tf.assign(state, new_value) # state = new_value 只是在描繪圖,並不會真正的執行 # 啟動圖后, 變量必須先經過'初始化'(init) init = tf.global_variables_initializer() # 啟動圖, 運行 op with tf.Session() as sess: sess.run(init) # 運行 'init' print(sess.run(state)) # 打印'state'的初始值 0 print(sess.run(assignment)) # assignment.eval() # 運行 op, 更新 'state', 並打印 'state' for _ in range(3): sess.run(update) print(sess.run(state)) # 0 # 1 # 2 # 3
區別1、使用tf.Variable時候,如果檢測到命名沖突,系統會自己處理。使用tf.get_variable()時,系統不會處理相同變量名的沖突,而會報錯。
tf.Variable() 創建變量
w_1 = tf.Variable(3, name="w_1") w_2 = tf.Variable(1, name="w_1") print(w_1.name) # w_1:0 print(w_2.name) # w_1:0
tf.get_variable() 創建變量
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?
區別2、tf.Variable()每次都在創建新對象,所以reuse=True和它沒有什么關系,對於get_vatiable(),如果是一個已經創建的變量對象,就把那個對象返回,如果是之前沒有創建的變量對象的話,就創建一個新的。
with tf.variable_scope("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") print(w1 is w1_p) # True w1和w1_p 指向同一個對象 print(w2 is w2_p) # False w2和w2_p 指向不同對象
代碼中創建了變量的,“變量”必須經過初始化,然后在會話中運行下面一段進行初始化,一次性初始化所有變量,初始化后,才能調用與顯示。
a = tf.Variable(initial_value=50) b = tf.Variable(initial_value=50) c = tf.add(a, b) init = tf.global_variables_initializer() # 初始化變量 with tf.Session() as sess: # 開啟會話 sess.run(init) # 允許初始化 a_value, b_value, c_value = sess.run([a,b,c]) print("a_value",a_value) print("b_value", b_value) print("c_value", c_value)
tf.global_variables_initializer不會指定變量的初始化順序,因此如果變量的初始值取決另一個變量的值,那么很有可能出現錯誤,所以我們最好使用variable.initialized_value(),而非veriable,也就是在創建變量的時候給變量初始化。
v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer()) w = tf.get_variable("w", initializer=v.initialized_value() + 1)
當然我們也可以自行初始化變量
session.run(my_variable.initializer)
my_variable.initializer.run()
tf.add_to_collection:把變量放入一個集合,把很多變量變成一個列表
tf.get_collection:從一個列表中取出全部變量,是一個列表
tf.add_n:把一個列表的東西都依次加起來
import tensorflow as tf v1 = tf.get_variable(name='v1', shape=[1], initializer=tf.constant_initializer(0)) tf.add_to_collection('loss', v1) v2 = tf.get_variable(name='v2', shape=[1], initializer=tf.constant_initializer(2)) tf.add_to_collection('loss', v2) init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) print(tf.get_collection("loss")) # [<tf.Variable 'v1:0' shape=(1,) dtype=float32_ref>, # <tf.Variable 'v2:0' shape=(1,) dtype=float32_ref>] print(sess.run(tf.add_n(tf.get_collection("loss")))) # [2.]
變量命名空間 variable_scope;tf.name_scope
tensorflow中創建變量命名空間域的函數有 tf.name_scope;tf.variable_scope
使用tf.variable_scope()修改變量的命名空間,使得代碼的結構更加清晰,還能夠使得TensorBoard更加整潔。同時給變量取名name也可以使得TensorBoard更加整潔。
首先看看比較簡單的tf.name_scope("scope_name")
tf.name_scope主要結合tf.Variable()來使用,它的主要目的是為了方便管理參數命名。
import tensorflow as tf with tf.name_scope('conv1'): weights1 = tf.Variable([1.0, 2.0], name='weights') bias1 = tf.Variable([0.3], name='bias') # 下面是在另外一個命名空間來定義變量的 with tf.name_scope('conv2'): weights2 = tf.Variable([4.0, 2.0], name='weights') bias2 = tf.Variable([0.33], name='bias') # 所以,實際上weights1 和 weights2 這兩個引用名指向了不同的空間,不會沖突 print(weights1.name) # conv1/weights:0 print(weights2.name) # conv2/weights:0 # 這時候如果再次執行上面的代碼,就會再生成其他命名空間 with tf.name_scope('conv1'): weights1 = tf.Variable([1.0, 2.0], name='weights') bias1 = tf.Variable([0.3], name='bias') with tf.name_scope('conv2'): weights2 = tf.Variable([4.0, 2.0], name='weights') bias2 = tf.Variable([0.33], name='bias') print(weights1.name) # conv1_1/weights:0 print(weights2.name) # conv2_1/weights:0
我們再來看看tf.variable_scope("scope_name")
tf.variable_scope()主要結合tf.get_variable()來使用,實現 變量共享。
with tf.variable_scope('v_scope'): Weights1 = tf.get_variable('Weights', shape=[2,3]) bias1 = tf.get_variable('bias', shape=[3]) # 下面來共享上面已經定義好的變量 # 在下面的 scope 中的get_variable()變量必須經過get_variable()定義過了,才能設置 reuse=True,否則會報錯reuse=True,否則會報錯 with tf.variable_scope('v_scope', reuse=True): Weights2 = tf.get_variable('Weights') print(Weights1.name) # v_scope/Weights:0 print(Weights2.name) # v_scope/Weights:0
我們可以看到這兩個變量命名空間名都是 v_scope,reuse=True只是讓后一個v_scope重用上一個v_scope的所有變量。在后一個v_scope中定義的變量,必須是已經在上一個v_scope中經過get_variable定義過的,否則會報錯。tf.Variable()每次都在創建新對象,而tf.get_variable()如果變量存在,則使用以前創建的變量,如果不存在,則新創建一個變量。
從輸出我們可以看出來,這兩個引用名稱指向的是同一個內存對象
共享變量有兩種方法

# 方法一 with tf.variable_scope("name") as scope: scope.reuse_variables() # 方法二 with tf.variable_scope("name", reuse=True): scope.reuse_variables()
我們同時使用Variable和get_variable看看輸出結果:
with tf.variable_scope('v_scope') as scope1: Weights1 = tf.get_variable('Weights', shape=[2,3]) bias1 = tf.Variable([0.52], name='bias') # 下面來共享上面已經定義好的變量 with tf.variable_scope('v_scope', reuse=True) as scope2: Weights2 = tf.get_variable('Weights') bias2 = tf.Variable([0.52], name='bias') print(Weights1.name) # v_scope/Weights:0 print(Weights2.name) # v_scope/Weights:0 print(bias1.name) # v_scope/bias:0 print(bias2.name) # v_scope_1/bias:0
如果reuse=True的scope中的變量沒有經過get_variable定義,則會報錯。
with tf.variable_scope('v_scope') as scope1: Weights1 = tf.get_variable('Weights', shape=[2,3]) bias1 = tf.Variable([0.52], name='bias') # bias1 的定義方式是使用Variable print(Weights1.name) # v_scope/Weights:0 print(bias1.name) # v_scope/bias:0 # 下面來共享上面已經定義好的變量 # 在下面的 scope 中的get_variable()變量必須經過get_variable()定義過了,才能設置 reuse=True,否則會報錯 with tf.variable_scope('v_scope', reuse=True) as scope2: Weights2 = tf.get_variable('Weights') bias2 = tf.get_variable('bias', [1]) # ‘bias print(Weights2.name) print(bias2.name) # Variable v_scope/bias does not exist, or was not created with tf.get_variable()
總結:如果我們使用tf.variable_scope定義變量命名空間,盡量使用tf.get_variable創建變量。
TensorFlow里面的變量OP
常見的tensorflow的OP
類型 |
實例 |
標量運算 |
add、sub、mul、div、exp、log、greater、less、equal |
向量運算 |
concat、slice、splot、constant、rank、spape、shuffle、 |
矩陣運算 |
matmul、matrixinverse、matrixdateminant |
帶狀態的運算 |
Variable、assgin、assginadd |
神經元組件 |
softmax、sigmoid、relu、convolution、max_pool |
存儲、恢復 |
Save、Restroe |
隊列與同步運算 |
Equeue、Dequeue、MutexAxquire、MutexRelease |
控制流 |
Merge、Switch、Enter、Leave、Nextiteration |
用tensorflow做一個簡單的線性回歸

import tensorflow as tf # .rand生成一個[0~1]之間2行100列的數組 # .randn生成服從正態分布的數組 x_data = tf.random_normal(shape=[100,1]) y_data = tf.matmul(x_data, [[0.4]]) + 5 # 構造一個線性模型 b = tf.Variable(initial_value=tf.random_normal(shape=[1, 1])) W = tf.Variable(initial_value=tf.random_normal(shape=[1, 1])) y = tf.matmul(x_data, W) + b # 最小化方差 loss = tf.reduce_mean(tf.square(y - y_data)) # 設置學習率0.5的梯度下降算法,求最小值 optimizer = tf.train.GradientDescentOptimizer(0.01).minimize(loss) init = tf.global_variables_initializer() # 初始化變量 # 開啟會話 with tf.Session() as sess: sess.run(init) print("訓練前的w: %f 和b:%f" % (W.eval(), b.eval())) for i in range(0, 1000): sess.run(optimizer) if i % 20 == 0: # 每20次打印一次 print("第 %d 次訓練前的w: %f 和b:%f 損失值%f" % (i, W.eval(), b.eval(), loss.eval()))
TensorBoard:可視化學習
TensorFlow是tensorflow的可視化工具,實現程序可視化的過程
1、數據序列化-events文件
在會話中寫入事件文件,然后在path路徑創建一個even文件
tf.summary.FileWriter("path", graph=sess.graph)
- path 事件文件的寫入地址
- graph 選擇描繪的計算圖,graph=sess.graph 或者 graph=tf.get_default_graph() 選擇的都是默認圖
import tensorflow as tf a = tf.constant(20, name="a") b = tf.constant(30, name="b") c = a + b with tf.Session() as sess: c = sess.run(c) writer = tf.summary.FileWriter("./", sess.graph) # 寫入事件文件 writer.close() # 寫完之后最后要記得關閉
2、啟動TensorBoard
在cmd中或者Git Bash中運行 tensorboard --logdir="path"
然后在谷歌瀏覽器中 localhost:6006 就可以看到圖了
我們來看一個更復雜的TensorBoard圖,代碼如下

# 實現一個線性回歸 import tensorflow as tf # 准備數據 X = tf.random_normal(shape=[100, 1]) y_true = tf.matmul(X, [[0.8]]) + 0.7 # 構建線性模型的tensor變量Weight, bias Weight = tf.Variable(initial_value=tf.random_normal(shape=[1, 1])) bias = tf.Variable(initial_value=tf.random_normal(shape=[1, 1])) y_predict = tf.matmul(X, Weight) + bias # 構建損失方程,優化器及訓練模型操作train loss = tf.reduce_mean(tf.square(y_predict - y_true)) optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.5) train = optimizer.minimize(loss) init = tf.initialize_all_variables() # 構建變量初始化操作init with tf.Session() as sess: sess.run(init) writer = tf.summary.FileWriter("./", sess.graph) for step in range(1000): sess.run(train) if step % 20 == 0: # 每20次打印一次 print(step, sess.run(Weight), sess.run(bias)) writer.close()
3、增加變量顯示功能
目的:在TensorBoard中觀察模型參數、損失值等變量的變化
步驟:
1、收集變量
tf.summary.scalar(name="", tensor) # 收集對於對於損失函數和准確率等單值變量,tensor為要收集的tnesor對象
tf.summary.histogram(name="", tensor) # 收集高維度的變量
tf.summaty.image(name="", tensor) # 收集輸入的圖片張量
2、合並變量並寫入事件文件
1、合並變量:merged = tf.summary.merge_all()
2、在會話中創建事件文件:event_file = tf.summary.FileWriter("./", sess.graph) # 創建事件文件
3、在會話中運行合並操作:summary = sess.run(merged) # 每次迭代都需要運行
4、將每次迭代后的變量寫入事件文件:event_file.add_summary(summary, step) # step表示第幾次運行
5、最后記得關閉事件文件:event_file.close()

# 實現一個線性回歸 import tensorflow as tf # 准備數據 X = tf.random_normal(shape=[100, 1]) y_true = tf.matmul(X, [[0.8]]) + 0.7 # 構建線性模型的tensor變量Weight, bias Weight = tf.Variable(initial_value=tf.random_normal(shape=[1, 1])) bias = tf.Variable(initial_value=tf.random_normal(shape=[1, 1])) y_predict = tf.matmul(X, Weight) + bias # 構建損失方程,優化器及訓練模型操作train loss = tf.reduce_mean(tf.square(y_predict - y_true)) optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01) train = optimizer.minimize(loss) # 收集變量 tf.summary.scalar("error", loss) # 收集標量 tf.summary.histogram("Weight", Weight) # 收集高維變量 tf.summary.histogram("bias", bias) merged = tf.summary.merge_all() # 合並變量 init = tf.initialize_all_variables() # 變量初始化操作 with tf.Session() as sess: sess.run(init) event_file = tf.summary.FileWriter("./", sess.graph) # 創建事件文件 for step in range(100): sess.run(train) if step % 20 == 0: # 每20次打印一次 print(step, sess.run(Weight), sess.run(bias)) summary = sess.run(merged) # 運行合並變量操作 event_file.add_summary(summary, step) # 將每次迭代后的變量寫入事件文件 event_file.close()
菜單欄多了 scalars(標量)、distributions(分布圖)、histogram(直方圖)
我們先來看看scalars
我們再來看看 distributions和histogram
我們可以看到,我們所看到的grapth圖結構是比較亂的,我們添加變量命名空間讓圖結構顯示的更整齊。
模型的保存與加載
模型保存
saver = tf.train.Saver(var_list=None, max_to_keep=5) 保存和加載模型(保存文件格式:checkpoint文件)
- var_list:指定要保存的變量,可以作為一個dict或列表傳遞,如果為None,就是保存所有變量。
- max_to_keep:保留檢查點文件的數量,創建新文件時會刪除舊的文件
saver.save(sess, save_path="./liner.ckpt", global_step=step) 保存模型
- sess:會話名字
- save_path:設定權重參數保存的路徑和文件名;
- global_step=step:將訓練的次數作為后綴加入到模型名字中。
一次 saver.save() 后可以在文件夾中看到新增的四個文件,
checkpoint 記錄最新的模型
***.meta 存儲網絡結構
***.data/***.index 存儲訓練好的參數
import tensorflow as tf v1 = tf.get_variable("v1", shape=[3], initializer=tf.zeros_initializer) v2 = tf.get_variable("v2", shape=[5], initializer=tf.zeros_initializer) inc_v1 = v1.assign(v1+1) # v1變量+1 dec_v2 = v2.assign(v2-1) # v2變量-1 init = tf.global_variables_initializer() saver = tf.train.Saver() # 創建Saver對象 with tf.Session() as sess: sess.run(init) inc_v1.op.run() dec_v2.op.run() for epoch in range(300): if epoch % 10 ==0: # 在會話中保存模型 save_path = saver.save(sess, "./model/model.ckpt", global_step=epoch) print("Model saved in path: %s" % save_path)
下圖是訓練過程中生成的幾個模型文件列表
模型加載
加載模型:saver.restore(sess, "./liner.ckpt")
獲取最新的模型:checkpoint = tf.train.latest_checkpoint("./model/")
import tensorflow as tf import os v1 = tf.get_variable("v1", shape=[3]) v2 = tf.get_variable("v2", shape=[5]) tf.add_to_collection("variable", v1) tf.add_to_collection("variable", v2) def load_model(sess, ckpt): # ckpt是模型路徑 if os.path.isdir(ckpt): # 獲取最新的模型 checkpoint = tf.train.latest_checkpoint(ckpt) # ./model/model.ckpt-290 else: checkpoint = ckpt print(checkpoint) meta = checkpoint + '.meta' # './model/model.ckpt-290.meta' saver = tf.train.import_meta_graph(meta) # 加載graph圖結構 saver.restore(sess, checkpoint) # 加載模型參數 with tf.Session() as sess: sess.run(tf.global_variables_initializer()) model_dir = "./model/" load_model(sess, model_dir) # 從變量集和名為"variable"的集和中取出變量 a, b = tf.get_collection('variable') print(a,b) print("模型恢復....") print("v1 : %s" % v1.eval()) print("v2 : %s" % v2.eval())
sv = tf.train.Supervisor(logdir="./my_dir", init_op=init)
一般我們在訓練模型之前,都會檢查本地是否有之前已經訓練好並保存了的模型,所以會做一次if判斷,但是Supervisor可以節省這一步,sv = tf.train.Supervisor(logdir=log_path, init_op=init)會判斷模型是否存在.如果存在,會自動讀取模型.不用顯式地調用restore,具體如下:
log_path = "./Source/model/supervisor" log_name = "linear.ckpt" saver = tf.train.Saver() # 創建saver init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) if len(os.listdir(log_path)) != 0: # 如果已經有模型,則直接讀取 saver.restore(sess, os.path.join(log_path, log_name)) for step in range(201): sess.run(train) if step % 20 == 0: print(step, sess.run(W), sess.run(b)) saver.save(sess, os.path.join(log_path, log_name))
用Supervisor
log_path = "./Source/model/supervisor" log_name = "linear.ckpt" init = tf.global_variables_initializer() sv = tf.train.Supervisor(logdir=log_path, init_op=init) # logdir用來保存checkpoint和summary saver = sv.saver # 創建saver sess = sv.managed_session() # 會自動去logdir中去找checkpoint,如果沒有的話,自動執行初始化 for i in range(201): sess.run(train) if i % 20 == 0: print(i, sess.run(W), sess.run(b)) saver.save(sess, os.path.join(log_path, log_name))
通過checkpoint找到模型文件名
tf.train.get_checkpoint_state(checkpoint_dir,latest_filename=None)
參數:
- checkpoint_dir:checkpoint文件的路徑
- latest_filename:指定checkpoint的名字
返回的是CheckpointState proto對象,CheckpointState proto對象有兩個可用屬性。
- model_checkpoint_path:最新的chechpoint路徑
- all_model_checkpoint_paths:文件中所有的checkpoints路徑列表
ckpt = tf.train.get_checkpoint_state('./model/') if ckpt and ckpt.model_checkpoint_path: print(ckpt.model_checkpoint_path) # ./model/model.ckpt-1000(1000是訓練步數) print(ckpt.all_model_checkpoint_paths) # ['./model/model.ckpt-500', './model/model.ckpt-1000']
global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
得到了global_step之后,就可以恢復模型,繼續在原來的模型基礎上,訓練后面的步驟了。
命令行參數的使用
tensorflow支持程序從命令行接受參數,即使用tf.app.flag,tf.app.flag可以定義各種參數類型
tf.app.flag.DEFINE_integer(參數名, 默認值, 參數說明文檔 字符串)
整形參數 tf.app.flag.DEFINE_integer(flag_name, default, docstring)
字符串參數 tf.app.flag.DEFINE_string(flag_name, default, docstring)
布爾值參數 tf.app.flag.DEFINE_boolean(flag_name, default, docstring)
浮點值參數 tf.app.flag.DEFINE_float(flag_name, default, docstring)
...
2、tf.app.flags,flags有一個FLAGS標志,可以調用到我們前面具體定義的參數名flag_name。
import tensorflow as tf # 定義命令行參數 tf.app.flags.DEFINE_integer("step", 100, "訓練模型的步數") tf.app.flags.DEFINE_string("model_dir", "Unknown", "模型保存的路徑") FLAGS = tf.app.flags.FLAGS # 簡化變量名 print("step:", FLAGS.step) # step: 100 print("model_dir:", FLAGS.model_dir) # model_dir: Unknown
tf.app.run()可以自動運行腳本中的main(argv)函數,如果腳本沒有main(argv)函數,會報錯。
main函數中的argv參數打印出來是腳本的地址
import tensorflow as tf def main(argv): print(argv) # ['C:\\Users\\Never\\Desktop\\temp\\temp.py'] tf.app.run() # 自動調用腳本中的main(argv)函數
關於多個GPU的分類使用
TensorFlow一般你不需要顯式指定使用CPU還是GPU,TensorFlow能自動檢測。如果檢測到 GPU,TensorFlow會盡可能地利用找到的第一個GPU來執行操作。
如果你的電腦有兩個GPU,tensorflow默認是不會使用的,為了讓 TensorFlow 使用這些 GPU, 你必須將 op 明確指派給它們執行. with.Device
語句用來指派特定的 CPU 或 GPU 執行操作:

with tf.Session() as sess: with tf.device("/gpu:1"): matrix1 = tf.constant([[3., 3.]]) matrix2 = tf.constant([[2.],[2.]]) product = tf.matmul(matrix1, matrix2) ...
關於IPython的tensorflow的使用
為了便於使用諸如IPython之類的Python交互環境,比如jupyter notebook。可以使用InteractiveSession
代替Session
類,使用Tensor.eval()
和Operation.run()
方法代替Session.run()。
這樣可以避免使用一個變量來持有會話。

# 進入一個交互式 TensorFlow 會話. import tensorflow as tf sess = tf.InteractiveSession() x = tf.Variable([1.0, 2.0]) a = tf.constant([3.0, 3.0]) # 使用初始化器 initializer op 的 run() 方法初始化 'x' x.initializer.run() # 增加一個減法 sub op, 從 'x' 減去 'a'. 運行減法 op, 輸出結果 sub = tf.subtract(x, a) print(sub.eval()) # [-2. -1.]
運行tensorflow的時候,會出現紅色警告I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
如果不想看到這個,在腳本開始的時候,加
import os os.environ["TF_CPP_MIN_LOG_LEVEL"]= "2" # 或者 import os os.environ["KERAS_BACKEND"] = "tensorflow"
參考文獻:
【tensorflow】tf.train.get_checkpoint_state
作者:凌逆戰
歡迎任何形式的轉載,但請務必注明出處。
限於本人水平,如果文章和代碼有表述不當之處,還請不吝賜教。
本文章不做任何商業用途,僅作為自學所用,文章后面會有參考鏈接,我可能會復制原作者的話,如果介意,我會修改或者刪除。