目錄
from tensorflow.examples.tutorials.mnist import input_data
tf.nn.sparse_softmax_cross_entropy_with_logits()
tf.contrib.layers.l2_regularizer()
tf.control_dependencies()/tf.no_op()
Ch5:MNIST數字識別問題
from tensorflow.examples.tutorials.mnist import input_data
#將數據集提取爲三個部分:mnist.train、mnist.test和mnist.validation,每個部分包含有images和labels。train、test和validation中樣本的數量分別爲55000、10000和5000。
mnist = input_data.read_data_sets("../../datasets/MNIST_data/", one_hot=True)
batch_size = 100
xs, ys = mnist.train.next_batch(batch_size) # 從train的集合中選取batch_size個訓練數據。
tf.nn.relu()
線性整流函數(Rectified Linear Unit, ReLU),又稱修正線性單元。等同於max(0,x),將輸入小於0的值賦值爲0,輸入大於0的值不變。
import tensorflow as tf
a = tf.constant([-1.0, 2.0,-3.6])
with tf.Session() as sess:
b = tf.nn.relu(a)
print(sess.run(b))
#實際上是上一章調用ema的average接口,來獲取當前時序數據的指數滑動平均值
avg_class.average(weights2)
tf.truncated_normal()
tf.truncated_normal(shape, mean, stddev) :shape表示生成張量的維度,mean是均值,stddev是標準差。這個函數產生正態分佈,均值和標準差自己設定。這是一個截斷的產生正態分佈的函數,就是說產生正態分佈的值如果與均值的差值大於兩倍的標準差,那就重新生成。和一般的正態分佈的產生隨機數據比起來,這個函數產生的隨機數與均值的差距不會超過兩倍的標準差,但是一般的別的函數是可能的。
tf.argmax()
tf.argmax(vector, 1):返回的是vector中的最大值的索引號,如果vector是一個向量,那就返回一個值,如果是一個矩陣,那就返回一個向量,這個向量的每一個維度都是相對應矩陣行的最大值元素的索引號。
import tensorflow as tf
import numpy as np
A = [[1,3,4,5,6]]
B = [[1,3,4], [2,4,1]]
with tf.Session() as sess:
print(sess.run(tf.argmax(A, 1)))
print(sess.run(tf.argmax(B, 1)))
輸出:
[4]
[2 1]
tf.nn.sparse_softmax_cross_entropy_with_logits()
注意與tf.nn.sigmoid_cross_entropy_with_logits以及tf.nn.softmax_cross_entropy_with_logits的區別和聯繫。首先顧名思義,tf.nn.sparse_softmax_cross_entropy_with_logits和tf.nn.softmax_cross_entropy_with_logits都是將輸入送到softmax層,再利用softmax層的輸入和實際的標籤數據,來計算交叉熵,交叉熵是分類問題中常見的損失函數。二者的區別主要在於二者使用的標籤真值形式是不同的。
- sparse_softmax_cross_entropy_with_logits:
使用的是實數來表示類別,數據類型爲int16,int32,或者 int64,標籤大小範圍爲[0,num_classes-1],標籤的維度爲[batch_size]大小
- softmax_cross_entropy_with_logits
使用的是one-hot二進制碼來表示類別,數據類型爲float16,float32,或者float64,維度爲[batch_size, num_classes]。這裏需要說明一下的時,標籤數據類型並不是Bool型的。這是因爲實際上在tensorflow中,softmax_cross_entropy_with_logits中的每一個類別是一個概率分佈,tensorflow中對該模塊的說明中明確指出了這一點,Each row labels[i] must be a valid probability distribution。很顯然,one-hot的二進碼也可以看是一個有效的概率分佈。
import tensorflow as tf
sess = tf.InteractiveSession()
logits = tf.constant([[1.0, 2.0, 3.0], [1.0, 2.0, 3.0], [1.0, 2.0, 3.0]])
labels = tf.constant([[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]])
softmax = tf.nn.softmax(logits)
sparse_labels = tf.argmax(labels, 1)
cross_entropy = -tf.reduce_sum(labels * tf.log(softmax))
cross_entropy2 = tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=labels))
cross_entropy3 = tf.reduce_sum(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=sparse_labels))
print("sparse_labels : {}".format(sparse_labels.eval()))
print("cross entropy by tf : %.4f" % cross_entropy.eval())
print("cross entropy by softmax_cross : %.4f" % cross_entropy2.eval())
print("cross entropy by sparse_softmax_cross: %.4f" % cross_entropy3.eval())
注意:tf.nn.softmax函數默認(dim=-1)是對張量最後一維的shape=(p,)向量進行softmax計算,得到一個概率向量。不同的是,tf.nn.sigmoid函數對一個張量的每一個標量元素求得一個概率。也就是說tf.nn.softmax默認針對1階張量進行運算,可以通過指定dim來針對1階以上的張量進行運算,但不能對0階張量進行運算。而tf.nn.sigmoid是針對0階張量,。
下面說說tf.nn.sigmoid_cross_entropy_with_logits:不同於softmax系列函數是張量中向量與向量間的運算。sigmoid_cross_entropy_with_logits函數則是張量中標量與標量間的運算。
z = 0.8
x = 1.3
cross_entropy4 = tf.nn.sigmoid_cross_entropy_with_logits(labels=z, logits=x)
# tf.nn.sigmoid_cross_entropy_with_logits的具體實現:
cross_entropy5 = - z * tf.log(tf.nn.sigmoid(x)) \
- (1-z) * tf.log(1-tf.nn.sigmoid(x))
sess = tf.InteractiveSession()
print(sess.run(cross_entropy4))
print(sess.run(cross_entropy5))
cross_entropy4 與cross_entropy5 的值是相等的。sigmoid_cross_entropy_with_logits的具體實現就是
如果sigmoid_cross_entropy_with_logits的labels和logits是相同shape的張量,輸出結果則是與labels和logits有相同shape的張量。張量的每個元素都是labels和logits相對的值捉對按上述方法計算出來的交叉熵。
tf.contrib.layers.l2_regularizer()
創建一個L2正則化方法
tf.control_dependencies()/tf.no_op()
在有些機器學習程序中我們想要指定某些操作執行的依賴關係,這時我們可以使用tf.control_dependencies()來實現。control_dependencies(control_inputs)返回一個控制依賴的上下文管理器,使用with關鍵字可以讓在這個上下文環境中的操作都在control_inputs 執行。
with g.control_dependencies([a, b, c]):
# `d` and `e` will only run after `a`, `b`, and `c` have executed.
d = ...
e = ...
可以嵌套control_dependencies 使用
with g.control_dependencies([a, b]):
# Ops constructed here run after `a` and `b`.
with g.control_dependencies([c, d]):
# Ops constructed here run after `a`, `b`, `c`, and `d`.
可以傳入None 來消除依賴:
with g.control_dependencies([a, b]):
# Ops constructed here run after `a` and `b`.
with g.control_dependencies(None):
# Ops constructed here run normally, not waiting for either `a` or `b`.
with g.control_dependencies([c, d]):
# Ops constructed here run after `c` and `d`, also not waiting
# for either `a` or `b`.
在訓練模型時,我們每步訓練可能要執行兩種操作,op a,b這時我們就可以使用如下代碼
with tf.control_dependencies([a, b]):
c= tf.no_op(name='train') # tf.no_op;什麼也不做
sess.run(c)
# 也可以將其替換爲
c= tf.group([a, b])
sess.run(c)
tf.cast()
tf.cast()函數的作用是執行 tensorflow 中張量數據類型轉換,比如讀入的圖片如果是int8類型的,一般在要在訓練前把圖像的數據格式轉換爲float32。
cast定義:
cast(x, dtype, name=None)
第一個參數 x: 待轉換的數據(張量)
第二個參數 dtype: 目標數據類型
第三個參數 name: 可選參數,定義操作的名稱
tf.train.Saver()
模型保存,先要創建一個Saver對象:如
saver = tf.train.Saver(max_to_keep=0)
這裏的max_keep參數代表的是保存模型的個數,默認爲5。
TensorFlow中的Saver對象是用於參數保存和恢復的。其實 創建 saver對象時使用的鍵值對就是表達了一種對應關係:
save時, 表示:variable的值應該保存到 checkpoint文件中的哪個 key下
restore時,表示:checkpoint文件中key對應的值,應該restore到哪個variable
參數會保存到 checkpoint 文件中,通過鍵值對的形式在 checkpoint中存放着。如果 Saver 的構造函數中傳的是 dict,那麼在 save 的時候,checkpoint文件中存放的就是對應的 key-value。如下:
import tensorflow as tf
# Create some variables.
v1 = tf.Variable(1.0, name="v1")
v2 = tf.Variable(2.0, name="v2")
saver = tf.train.Saver({"variable_1":v1, "variable_2": v2})
# Use the saver object normally after that.
with tf.Session() as sess:
tf.global_variables_initializer().run()
saver.save(sess, 'test-ckpt/model-2')
我們利用官方提供的工具來查看一下checkpoint中保存了什麼
from tensorflow.python.tools.inspect_checkpoint import print_tensors_in_checkpoint_file
print_tensors_in_checkpoint_file("test-ckpt/model-2", None, True)
# 輸出:
#tensor_name: variable_1
#1.0
#tensor_name: variable_2
#2.0
如果構建saver對象的時候,我們傳入的是 list, 那麼將會用對應 Variable 的 variable.op.name 作爲 key。
import tensorflow as tf
# Create some variables.
v1 = tf.Variable(1.0, name="v1")
v2 = tf.Variable(2.0, name="v2")
saver = tf.train.Saver([v1, v2])
# Use the saver object normally after that.
with tf.Session() as sess:
tf.global_variables_initializer().run()
saver.save(sess, 'test-ckpt/model-2')
我們再使用官方工具打印出 checkpoint 中的數據,得到
tensor_name: v1
1.0
tensor_name: v2
2.0
如果我們現在想將 checkpoint 中v2的值restore到v1 中,v1的值restore到v2中,我們該怎麼做?
這時,我們只能採用基於 dict 的 saver
import tensorflow as tf
# Create some variables.
v1 = tf.Variable(1.0, name="v1")
v2 = tf.Variable(2.0, name="v2")
saver = tf.train.Saver({"variable_1":v1, "variable_2": v2})
# Use the saver object normally after that.
with tf.Session() as sess:
tf.global_variables_initializer().run()
saver.save(sess, 'test-ckpt/model-2')
restore的代碼和save的代碼有所不同
import tensorflow as tf
# Create some variables.
v1 = tf.Variable(1.0, name="v1")
v2 = tf.Variable(2.0, name="v2")
#restore的時候,variable_1對應到v2,variable_2對應到v1,就可以實現目的了。
saver = tf.train.Saver({"variable_1":v2, "variable_2": v1})
# Use the saver object normally after that.
with tf.Session() as sess:
tf.global_variables_initializer().run()
saver.restore(sess, 'test-ckpt/model-2')
print(sess.run(v1), sess.run(v2))
# 輸出的結果是 2.0 1.0,如我們所期望的那樣
回顧總結:
save時, 表示:variable的值應該保存到 checkpoint文件中的哪個 key下;restore時,表示:checkpoint文件中key對應的值,應該restore到哪個variable。
tf.train.import_meta_graph()
import_meta_graph將定義在.meta的網絡導入到當前圖中。所以,這會替你創造圖/網絡,但我們仍然需要導入在這張圖上訓練好的參數。一般來說加載完成模型之後,會需要手動加載參數,所以會和saver.restore()api聯合使用。
with tf.Session() as sess:
new_saver = tf.train.import_meta_graph('my_test_model-1000.meta')
new_saver.restore(sess, tf.train.latest_checkpoint('./'))
tf.assign()
tf.assign(A, new_number): 這個函數的功能主要是把A的值變爲new_number
直接在保存模型時保存時序數據的ema值
v = tf.Variable(0, dtype = tf.float32, name="v")
ema = tf.train.ExponentialMovingAverage(0.99)
print(ema.variables_to_restore())
saver = tf.train.Saver(ema.variables_to_restore())
with tf.Session() as sess:
saver.restore(sess, "Saved_model/model2.ckpt")
其它
tf.get_default_graph().as_graph_def():得到當前圖的計算節點信息
graph_util.convert_variables_to_constants():將相關節點的values固定
tf.gfile.GFile(): # 保存模型
graph_def.ParseFromString(f.read())通過得到模型中的圖和變量數據
tf.import_graph_def()加載目前的圖
gfile.FastGFile()
tf.gfile.FastGFile(path,decodestyle)
函數功能:實現對圖片的讀取。
函數參數:(1)path:圖片所在路徑 (2)decodestyle:圖片的解碼方式。(‘r’:UTF-8編碼; ‘rb’:非UTF-8編碼)
saver.export_meta_graph():詳見https://zhuanlan.zhihu.com/p/31308381
tf.train.NewCheckpointReader() 用於創建一個reader對象,進而導出持久化模型的所有變量
reader = tf.train.NewCheckpointReader("/home/penglu/Desktop/lp/model.ckpt")
variables = reader.get_variable_to_shape_map()
for ele in variables:
print(ele)
reader.get_tensor(key) 用於查看ckpt模型文件中的變量