TensorFlow入門教程


簡介

  深度學習的框架有很多: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))
View Code

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)]
View Code

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]]
View Code

生成常數   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(),初始化為常數,這個非常有用,通常偏置項就是用它初始化的。

  由它衍生出的兩個初始化方法:

  1. tf.zeros_initializer(shape, dtype=tf.float32, partition_info=None)
  2. tf.ones_initializer(dtype=tf.float32, partition_info=None)
  3. 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_variabletf.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
View Code

區別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()
View Code

我們同時使用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()))
View Code

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()
View Code

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()
View Code

菜單欄多了 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)
    ...
View Code

關於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.]
View Code

運行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中文社區

【tensorflow】tf.train.get_checkpoint_state

TensorFlow中numpy與tensor數據相互轉化

 

作者:凌逆戰
歡迎任何形式的轉載,但請務必注明出處。
限於本人水平,如果文章和代碼有表述不當之處,還請不吝賜教。
本文章不做任何商業用途,僅作為自學所用,文章后面會有參考鏈接,我可能會復制原作者的話,如果介意,我會修改或者刪除。

 

 

 

出處:https://www.cnblogs.com/LXP-Never/p/10008693.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM