1 TensorFlow 計算模型一一計算圖node
1.1 計算圖的概念python
TensorFlow 是一個經過計算圖的形式來表述計算的編程系統 。計算圖是 TensorFlow 中最基本的一個概念, TensorFlow 中的全部計算都會被轉化爲計算圖上的節點 ,而節點之間的邊描述了計算之間的依賴關係。TensorFlow 的基本計算模型以下圖所示:git
1.2 計算圖的使用github
2 TensorFlow 數據模型一一張量正則表達式
2.1 張量的概念算法
2.2 張量的使用編程
3 TensorFlow 運行模型一一會話後端
4 TensorFlow變量api
4.1 TensorFlow中變量的概念數組
4.2 建立和使用變量
除了使用隨機數或者常數,TensorFlow 也支持經過其餘變量 的初始值來初始化新的變量。 如下代碼給出了具體的方法 。
w2 = tf.Variable(weights.initialized_value())
w3 = tf.Variable(weights.initialized_value()*2.0)
在 TensorFlow 中,一個變量的值在被使用以前,這個變量的初始化過程須要被明確地調用 ,即變量在使用以前須要初始化。 TensorFlow 提供了一種便捷的方式來完成變量初始化過程。如下程序展現了經過 tf.global_variables_initializer 函數實現初始化全部變量的過程 。
init_op = tf.global_variables_initializer()
sess.run(init_op)
4.3 TensorFlow目前支持的全部隨機數生成器
函數名稱 隨機數分佈 主要參數
tf.random_normal 正太分佈 平均值、標準差、取值類型·
tf.truncated_normal 正太分佈,但若是隨機出來的值偏離平均值超過 2個標準差,那麼這個數將會被從新隨機 平均值、標準差、取值類型
tf.random.uniform 均勻分佈 最小、最大取值、取值類型
tf.random_gamma Gamma 分佈 形狀參數 alpha、尺度參數 beta 、 取值類型
4.4 TensorFlow中經常使用的常量聲明方法
函數名稱 功能 樣例
tf.zeros 產生全0的數組 tf.zeros([2, 3), int32) > ([0, 0, 0], [0, 0, 0]]
tf.ones 產生全1的數組 tf.ones([2, 3], int32) -> [[1,1,1],[1,1,1]]
tf.fill 產生一個所有爲給定數字的數組 tf.fill([2, 3), 9) ->[ [9, 9, 9],[9, 9, 9]]
tf.constant 產生一個給定值的常量 tf.constant([1,2,3])—>[1,2,3]
4.5 案例:使用變量實現一個簡單的計數器.
# 建立一個變量爲計數器, 初始化爲標量 0. state = tf.Variable(0, name="counter") # 建立一個變量, 其做用是使state增長1 one = tf.constant(1) new_value = tf.add(state, one) # 更新計數器 update = tf.assign(state, new_value) # 啓動圖後, 變量必須先通過變量初始化, init_op = tf.global_variables_initializer() # 啓動圖, 運行會話 with tf.Session() as sess: # 運行變量初始化 sess.run(init_op) # 打印 'state' 的初始值 print sess.run(state) # 運行更新 'state', 並打印 'state' for _ in range(3): sess.run(update) print sess.run(state)
4.6 命名空間與共享變量
定義一個相同名字的變量
var = tf.Variable(name='var', initial_value=[4], dtype=tf.float32)
var_double = tf.Variable(name='var', initial_value=[4], dtype=tf.float32)
<tf.Variable 'var:0' shape=() dtype=float32_ref>
<tf.Variable 'var_1:0' shape=() dtype=float32_ref>
使用tf.variable_scope()修改OP命名空間
with tf.variable_scope("name"):
var = tf.Variable(name='var', initial_value=[4], dtype=tf.float32)
var_double = tf.Variable(name='var', initial_value=[4], dtype=tf.float32)
<tf.Variable 'name/var:0' shape=() dtype=float32_ref>
<tf.Variable 'name/var_1:0' shape=() dtype=float32_ref>
tf.get_variable共享變量
經過tf.get_variable的初始化與Variable參數同樣,可是要是實現共享須要打開tf.variable_scope("name")中的reuse=tf.AUTO_REUSE參數。
# 打開共享參數 # 或者 # with tf.variable_scope("name") as scope: # 在須要使用共享變量的前面定義: scope.reuse_variables() with tf.variable_scope("name", reuse=tf.AUTO_REUSE): var = tf.Variable(initial_value=4.0, name="var", dtype=tf.float32) var_double = tf.Variable(initial_value=4.0, name="var", dtype=tf.float32) var1 = tf.get_variable(initializer=tf.random_normal([2, 2], mean=0.0, stddev=1.0), name="var1", dtype=tf.float32) var1_double = tf.get_variable(initializer=tf.random_normal([2, 2], mean=0.0, stddev=1.0), name="var1", dtype=tf.float32) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) print(var1) print(var1_double)
5 TensorFlow模型的保存和恢復
5.1 什麼是Tensorflow模型?
5.2 爲何要保存Tensorflow模型:
例如,假設您能夠訪問通過訓練的 DNN,將圖片分爲 100 個不一樣的類別,包括動物,植物,車輛和平常物品。 您如今想要訓練一個 DNN 來對特定類型的車輛進行分類。 這些任務很是類似,所以您應該嘗試從新使用第一個網絡的一部分(請參見圖 11-4)。
5.3 如何保存Tensorflow模型:
若是咱們但願在迭代i次以後保存模型,能夠把當前的迭代步數傳進去:
# 每隔一百步保存一次模型
if i % 100 == 0:
saver.save(sess, 'my_test_model',global_step=i)
# 利用global_step參數能夠把迭代的步數追加到文件名中
5.4 如何導入已經保存的模型
若是想用別人的預先訓練好的模型做爲咱們的模型的一部分,那麼須要作兩件事情:
5.5 複用TensorFlow模型
若是原始模型使用 TensorFlow 進行訓練,則能夠簡單地將其恢復並在新任務上進行訓練:
[...] # 構建原始模型
with tf.Session() as sess: # 還原模型 saver.restore(sess, "./my_model_final.ckpt") # 在新任務中繼續訓練模型...
然而,一般咱們只想要重用原有模型的一部分(咱們立刻就會討論這種情況),一種簡單的解決方案就是配置Saver使之在還原原模型時只還原全部參數的一個子集。舉例來講,下面的代碼就只還原了隱藏層一、隱藏層2和隱藏層3:
"""
首先咱們創建新的模型,確保複製原始模型的隱藏層 1 到 3
"""
n_inputs = 28 * 28 # MNIST
n_hidden1 = 300 # reused
n_hidden2 = 50 # reused
n_hidden3 = 50 # reused
n_hidden4 = 20 # new!
n_outputs = 10 # new!
X = tf.placeholder(tf.float32, shape=(None, n_inputs), name="X") y = tf.placeholder(tf.int64, shape=(None), name="y") with tf.name_scope("dnn"): hidden1 = tf.layers.dense(X, n_hidden1, activation=tf.nn.relu, name="hidden1") # reused hidden2 = tf.layers.dense(hidden1, n_hidden2, activation=tf.nn.relu, name="hidden2") # reused hidden3 = tf.layers.dense(hidden2, n_hidden3, activation=tf.nn.relu, name="hidden3") # reused hidden4 = tf.layers.dense(hidden3, n_hidden4, activation=tf.nn.relu, name="hidden4") # new! logits = tf.layers.dense(hidden4, n_outputs, name="outputs") # new! with tf.name_scope("loss"): xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=logits) loss = tf.reduce_mean(xentropy, name="loss") with tf.name_scope("eval"): correct = tf.nn.in_top_k(logits, y, 1) accuracy = tf.reduce_mean(tf.cast(correct, tf.float32), name="accuracy") with tf.name_scope("train"): optimizer = tf.train.GradientDescentOptimizer(learning_rate) training_op = optimizer.minimize(loss) # 獲取保存的模型中用trainable = True(這是默認值)建立的全部變量的列表 reuse_vars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope="hidden[123]") # 咱們只保留那些範圍與正則表達式hidden [123]相匹配的變量(即,咱們獲得全部可訓練的隱藏層 1 到 3 中的變量)。 # 咱們建立一個字典,將原始模型中每一個變量的名稱映射到新模型中的名稱中(一般須要保持徹底相同的名稱) reuse_vars_dict = dict([(var.op.name, var) for var in reuse_vars]) # 建立一個SaverOP用來還原模型中的參數 restore_saver = tf.train.Saver(reuse_vars_dict) # to restore layers 1-3 init = tf.global_variables_initializer() # 建立一個新的SaverOP用來保存新模型 new_saver = tf.train.Saver() with tf.Session() as sess: init.run() # 從原始模型的層 1 到 3中恢復變量值 restore_saver.restore(sess, "./my_model_final.ckpt") for epoch in range(n_epochs): for iteration in range(mnist.train.num_examples // batch_size): X_batch, y_batch = mnist.train.next_batch(batch_size) sess.run(training_op, feed_dict={X: X_batch, y: y_batch}) accuracy_val = accuracy.eval(feed_dict={X: mnist.test.images, y: mnist.test.labels}) print(epoch, "Test accuracy:", accuracy_val) # 保存新模型 save_path = new_saver.save(sess, "./my_new_model_final.ckpt")
案例:識別手勢數據集
"""
一天下午,咱們和一些朋友決定教咱們的電腦破譯手語。咱們花了幾個小時在白色的牆壁前拍照,因而就有了瞭如下數據集。如今,你的任務是創建一個算法,使有語音障礙的人與不懂手語的人交流。
訓練集:有從0到5的數字的1080張圖片(64x64像素),每一個數字擁有180張圖片。
測試集:有從0到5的數字的120張圖片(64x64像素),每一個數字擁有5張圖片。
須要注意的是這是完整數據集的一個子集,完整的數據集包含更多的符號。
下面是每一個數字的樣本,以及咱們如何表示標籤的解釋。這些都是原始圖片,咱們實際上用的是64 * 64像素的圖片。
"""
import numpy as np
import h5py
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.python.framework import ops
import time
import math
from functools import partial
# %matplotlib inline #若是你使用的是jupyter notebook取消註釋
np.random.seed(1)
class GestureSymbolRecognition(object):
def init(self):
self.learning_rate = 0.0001
self.num_epochs = 1000
self.minibatch_size = 32
self.regularazion_rate = 0.001
self.n_inputs = 12288 self.n_hidden1 = 200 self.n_hidden2 = 100 self.n_hidden3 = 100 self.n_outputs = 6 self.batch_norm_momentum = 0.9 def load_data(self): """ 加載數據集 :return: """ # 從文件中讀取訓練集數據 train_dataset = h5py.File('datasets/train_signs.h5', "r") # 從訓練集數據中提取特徵值與標籤值數據 train_set_x_orig = np.array(train_dataset["train_set_x"][:]) train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # 從文件中讀取測試集數據 test_dataset = h5py.File('datasets/test_signs.h5', "r") # 從測試集數據中提取特徵值與標籤值數據 test_set_x_orig = np.array(test_dataset["test_set_x"][:]) test_set_y_orig = np.array(test_dataset["test_set_y"][:]) classes = np.array(test_dataset["list_classes"][:]) # 類別列表 classes_num = len(classes) # 數據集標籤分爲幾類 train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0])) test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0])) X_train_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1) # 每一列就是一個樣本 X_test_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1) # 歸一化數據 X_train = X_train_flatten / 255 X_test = X_test_flatten / 255 # 轉換爲one-hot編碼矩陣 Y_train = self.convert_to_one_hot(train_set_y_orig, len(classes)).T Y_test = self.convert_to_one_hot(test_set_y_orig, len(classes)).T return X_train, Y_train, X_test, Y_test, classes_num def convert_to_one_hot(self, Y, C): """ 實現one-hot編碼 :param Y:標籤矩陣 :param C:分類數量 :return:one_hot:one-hot矩陣 """ one_hot = np.eye(C)[Y.reshape(-1)].T return one_hot def random_mini_batches(self, X, Y, mini_batch_size, seed=0): """ 從數據集中建立一個隨機的mini-batch列表 :param X: 輸入數據,維度爲(輸入節點數量,樣本數量) :param Y: 對應的目標值,維度爲(1,樣本數量) :param mini_batch_size: 每一個mini-batch的樣本數量 :param seed: 隨機數種子 :return: mini_batches:一個同步列表,維度爲(mini_batch_X, mini_batch_Y) """ # 指定隨機數種子 np.random.seed(seed) # 獲取樣本數 m = X.shape[0] # print('樣本數量',m) # 建立一個同步列表 mini_batches = [] # 第一步:打亂樣本的順序 permutation = list(np.random.permutation(m)) # 返回一個長度爲m的隨機數組,且裏面的數是0到m-1 shuffled_X = X[permutation, :] # 將每一列特徵值數據按permutation的順序來從新排列 shuffled_Y = Y[permutation, :] # .reshape((Y.shape[0], m)) # 將每一列的目標值數據按permutation的順序來從新排列 # 第二步:分割訓練集數據 num_complete_minibatches = math.floor(m / mini_batch_size) # 迭代完成整個訓練集的次數 for k in range(0, num_complete_minibatches): mini_batch_X = shuffled_X[k * mini_batch_size:(k + 1) * mini_batch_size, :] mini_batch_Y = shuffled_Y[k * mini_batch_size:(k + 1) * mini_batch_size, :] mini_batch = (mini_batch_X, mini_batch_Y) mini_batches.append(mini_batch) # 若是訓練集的大小不是mini_batch_size的整數倍,那麼最後確定會剩下一些,取剩餘的數據 if m % mini_batch_size != 0: # 獲取剩餘部分的數據 mini_batch_X = shuffled_X[mini_batch_size * num_complete_minibatches:, :] mini_batch_Y = shuffled_Y[mini_batch_size * num_complete_minibatches:, :] mini_batch = (mini_batch_X, mini_batch_Y) mini_batches.append(mini_batch) # 返回同步列表 return mini_batches def train(self, print_cost=True, is_plot=True): """ 實現一個三層的TensorFlow神經網絡訓練邏輯:LINEAR->RELU->LINEAR->RELU->LINEAR->SOFTMAX 參數: print_cost - 是否打印成本,每100代打印一次 is_plot - 是否繪製曲線圖 """ # 加載數據集 x_train, y_train, x_test, y_test, label_classes_num = self.load_data() print("訓練集樣本數 = " + str(x_train.shape[0])) print("測試集樣本數 = " + str(x_test.shape[0])) print("X_train.shape: " + str(x_train.shape)) print("Y_train.shape: " + str(y_train.shape)) print("X_test.shape: " + str(x_test.shape)) print("Y_test.shape: " + str(y_test.shape)) # 設置圖級別的隨機數種子 tf.set_random_seed(1) # 設置操做級別的隨機數種子 seed = 3 # 獲取輸入節點數量和樣本數 (m, n_x) = x_train.shape # 成本函數值列表 costs = [] # 給X和Y建立佔位符節點 X = tf.placeholder(tf.float32, shape=(None, self.n_inputs), name="X") Y = tf.placeholder(tf.int32, shape=(None, label_classes_num), name="y") # 定義神經網絡全鏈接層 with tf.name_scope("dnn"): # 使用He權重初始化方法初始化權重 he_init = tf.contrib.layers.variance_scaling_initializer(mode='FAN_AVG') # 定義全鏈接層,使用elu激活函數 hidden1 = tf.layers.dense(X, self.n_hidden1, name="hidden1", activation=tf.nn.elu, kernel_initializer=he_init) hidden2 = tf.layers.dense(hidden1, self.n_hidden2, name="hidden2", activation=tf.nn.elu, kernel_initializer=he_init) hidden3 = tf.layers.dense(hidden2, self.n_hidden3, name="hidden3", activation=tf.nn.elu, kernel_initializer=he_init) outputs = tf.layers.dense(hidden3, self.n_outputs, name="outputs") # 輸出預測的類別 y_proba = tf.nn.softmax(outputs) # 定義損失函數計算損失 with tf.name_scope('loss'): # 前向傳播要在Z3處中止,由於在TensorFlow中最後的線性輸出層的輸出做爲計算損失函數的輸入,因此不須要A3. xentropy = tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=outputs) loss = tf.reduce_mean(xentropy, name="loss") # 定義優化器 with tf.name_scope("train_optimizer"): optimizer = tf.train.AdamOptimizer(self.learning_rate) training_op = optimizer.minimize(loss) # 評估模型,使用準確性做爲咱們的績效指標 with tf.name_scope("eval"): # 計算當前的預測結果 # 檢測使用了滑動平靜模型的神經網絡前向傳播是否正確。tf.argmax(average_y,1) # 計算每個樣例的預測答案。其中average_y是一個batch_size*10的二維數組,每 # 一行表示案例向前傳播的結果。tf.argmax的第二個參數爲1,表示選取最大值的 # 操做只在第一個維度上進行(x軸上),也就是說只在每一行選取最大值對應的下標 # 因而獲得的結果是一個長度爲batch的一維數組,這個一維數組中的值就表示了每 # 一個數字對應的樣例識別的結果.tf.equal()判斷每一個Tensor的每一維度是否相同 # 若是相等返回True,不然返回False. correct_prediction = tf.equal(tf.argmax(y_proba, 1), tf.argmax(Y, 1)) # 計算準確率 # 這個運算首先將一個布爾型的值轉換爲實數型,而後計算平均值。這一個平均值 # 就表明模型在這一組數據上的正確率 accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) """ 首先咱們創建新的模型,確保複製原始模型的隱藏層 1 到 2 """ # 獲取保存的模型中用trainable = True(這是默認值)建立的全部變量的列表 # 咱們只保留那些範圍與正則表達式hidden [123]相匹配的變量(即,咱們獲得全部可訓練的隱藏層 1 到 3 中的變量)。 reuse_vars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='hidden[12]') # 咱們建立一個字典,將原始模型中每一個變量的名稱映射到新模型中的名稱中(一般須要保持徹底相同的名稱) reuse_vars_dict = dict([(var.op.name, var) for var in reuse_vars]) # 建立一個SaverOP用來還原模型中的參數 restore_saver = tf.train.Saver(reuse_vars_dict) # 建立初始化全部變量的節點 init = tf.global_variables_initializer() # 建立一個新的SaverOP用來保存新模型 new_saver = tf.train.Saver(max_to_keep=1) # 開始會話並計算 with tf.Session() as sess: # 初始化全部變量 sess.run(init) # 加載模型,從模型中找出與當前訓練的模型代碼當中(名字同樣的OP操做),覆蓋原來的值 checkpoin = tf.train.latest_checkpoint('./ckpt/') # 若是模型已經保存則加載模型 if checkpoin: # 從原始模型恢復變量值 restore_saver.restore(sess, './ckpt/my_test1_model.ckpt') # 正常訓練模型 for epoch in range(self.num_epochs): epoch_cost = 0 # 每輪的成本函數值 num_minibatches = math.floor(m / self.minibatch_size) # 分紅多少個mini-batch組 seed = seed + 1 minibatches = self.random_mini_batches(x_train, y_train, self.minibatch_size, seed) for minibatch in minibatches: # 選擇一個minibatch (minibatch_X, minibatch_Y) = minibatch # 數據已經準備好了,開始運行session _, minibatch_cost = sess.run([training_op, loss], feed_dict={X: minibatch_X, Y: minibatch_Y}) # 計算這個minibatch在這一代中所佔的偏差 epoch_cost = epoch_cost + minibatch_cost / num_minibatches if epoch % 5 == 0: # 將每輪迭代的代價函數值存入列表 costs.append(epoch_cost) # 打印每輪迭代的代價函數值: if print_cost and epoch % 100 == 0: print("epoch = " + str(epoch) + " epoch_cost = " + str(epoch_cost)) # 保存學習後的參數 new_saver.save(sess, './ckpt/my_test1_model.ckpt') # 繪製代價函數值的學習曲線 if is_plot: plt.plot(np.squeeze(costs)) plt.ylabel('cost') plt.xlabel('iterations (per tens)') plt.title("Learning rate =" + str(self.learning_rate)) plt.show() # 計算模型學習完成後的訓練集及測試集準確率 train_acc = accuracy.eval({X: x_train, Y: y_train}) test_acc = accuracy.eval({X: x_test, Y: y_test}) print("訓練集的準確率:", train_acc) print("測試集的準確率:", test_acc)
if name == 'main':
# 開始時間
start_time = time.clock()
# 開始訓練
nn = GestureSymbolRecognition()
nn.train()
# 結束時間
end_time = time.clock()
# 計算時差
print("CPU的執行時間 = " + str(end_time - start_time) + " 秒")
5.6 凍結底層
5.7 緩存凍結層
由於凍結層不會變化,因此就有可能將每個訓練實例的最高凍結層的輸出緩存起來。因爲訓練會輪詢整個數據集不少次,因此你將得到巨大的速度提高,由於你只須要在一個訓練實例中遍歷一次凍結層(而不是每一個全數據集一次)。舉個例子,你能夠第一次在低層跑完整個訓練集(假設你有足夠的RAM):
hidden2_outputs = sess.run(hidden2, feed_dict={X: X_train})
而後在訓練中,你要作的不是構建批量的訓練實例,而是批量構建隱藏層2的輸出,而且將它們餵給訓練操做:
import numpy as np
n_epochs = 100
n_batches = 500
for epoch in range(n_epochs):
shuffled_idx = rnd.permutation(len(hidden2_outputs))
hidden2_batches = np.array_split(hidden2_outputs[shuffled_idx], n_batches)
y_batches = np.array_split(y_train[shuffled_idx], n_batches)
for hidden2_batch, y_batch in zip(hidden2_batches, y_batches):
sess.run(training_op, feed_dict={hidden2: hidden2_batch, y: y_batch})
5.8 調整、丟棄或替換層
5.9 模型動物園
5.10 無監督的預訓練
5.11 輔助任務中的預訓練
6 TensorBoard:可視化學習
注意:路徑不能出現中文,不然會打不開!!!
# 實現加法
con1 = tf.constant(11.0, name='input1')
con2 = tf.constant(12.0, name='input2')
sum_ = tf.add(con1, con2, name='add')
with tf.Session() as sess:
# 在會話中序列化events文件
file_writer = tf.summary.FileWriter('f:logs/', tf.get_default_graph())
file_writer.close()
7 Tensorflow案例—實現線性迴歸
7.1 線性迴歸原理複習
7.2 案例肯定
數據自己的分佈爲 y = 0.7 * x + 0.8
這裏將數據分佈的規律肯定,是爲了使咱們訓練出的參數跟真實的參數(即0.7和0.8)比較是否訓練準確。
7.3 使用的API
7.4 示例代碼
""" 使用Tensorflow實現線性迴歸 """ import tensorflow as tf class MyLinearRegression(object): """ 實現一個線性迴歸 """ def __init__(self, FLAGS): self.FLAGS = FLAGS # 定義學習率 self.learning_rate = 0.1 # 定義迭代次數 self.train_step = 1000 # 定義並初始化線性迴歸模型的權重與偏置參數,因爲權重與偏置須要被訓練與優化,所以需用使用變量OP定義 self.height = tf.Variable(tf.random_normal(shape=[1, 1], mean=0.0, stddev=1.0, name='height')) self.bais = tf.Variable(tf.random_normal(shape=[1], mean=0.0, stddev=1.0, name='bais')) def inputs(self): """ 獲取須要訓練的數據 :return: x_feature,y_target """ # 定義一個命名空間 with tf.variable_scope('get_inputs'): # 公式:y = x*0.7 + 0.8 # 生成符合正態分佈的特徵值 x_feature = tf.random_normal(shape=[100, 1], mean=0.0, stddev=1.0, name='x_feature') # 利用矩陣乘法計算得出目標值,注意矩陣相乘,維數要相同 y_target = tf.matmul(x_feature, [[0.7]]) + 0.8 return x_feature, y_target def inference(self, x_feature): """ 根據數據創建線性迴歸模型 :param x_feature: 特徵值 :return: y_predic:預測結果 """ # 定義一個命名空間 with tf.variable_scope('linear_model'): # 計算預測值 y_predict = tf.matmul(x_feature, self.height) + self.bais return y_predict def loss(self, y_predict, y_target): """ 由線性迴歸模型的損失函數計算損失值 :param y_predict: 預測值 :param y_target: 目標值 :return: 損失值 """ # 定義一個命名空間 with tf.variable_scope('get_loss'): # 損失函數使目標值與預測值的均方差公式 # 先用tf.square()計算差的平方 # 再用tf.reduce_mean()對列表數據求和後再求平均值 loss = tf.reduce_mean(tf.square(y_predict - y_target)) return loss def sgd_op(self, loss): """ 使用隨機梯度降低優化器來優化損失(優化模型參數) :param loss: 損失大小 :return: 梯度降低OP """ # 定義一個命名空間 with tf.variable_scope("sgd_op"): # 使用隨機梯度降低API得出優化結果 train_op = tf.train.GradientDescentOptimizer(learning_rate=self.learning_rate).minimize(loss) return train_op def merge_summary(self, loss): """ 增長變量顯示:在TensorBoard當中觀察模型的參數、損失值等變量值的變化 :param loss:損失 :return: merged:合併的變量 """ # 1. 收集變量 tf.summary.scalar('loss', loss) tf.summary.histogram('w', self.height) tf.summary.histogram('b', self.bais) # 2. 合併變量 merged = tf.summary.merge_all() return merged def train(self): """ 用於實現線性迴歸模型訓練邏輯 :return: """ # 開啓一個默認的圖 g = tf.get_default_graph() # 在默認的計算圖中進行操做 with g.as_default(): # 獲得輸入數據 x_feature, y_target = self.inputs() # 創建線性迴歸模型,獲得預測值 y_predict = self.inference(x_feature) # 根據損失函數求解損失值 loss = self.loss(y_predict, y_target) # 使用梯度降低優化器優化損失 train_op = self.sgd_op(loss) # 增長變量顯示:在TensorBoard當中觀察模型的參數、損失值等變量值的變化 merged = self.merge_summary(loss) # 定義一個保存模型的saveOP,設置要保留的最近檢測點的模型的數量 saver = tf.train.Saver(max_to_keep=5) # 開啓一個會話 with tf.Session() as sess: # 初始化變量,初始化後才能夠在會話中運行 sess.run(tf.global_variables_initializer()) # 生成事件文件觀察圖結構 file_writer = tf.summary.FileWriter('F:/tensorflow/logs', graph=sess.graph) print("模型隨機初始化的權重參數:{},偏置參數:{}".format(self.height.eval(), self.bais.eval())) # 加載模型,從模型當中找出與當前訓練的模型代碼當中(名字同樣的op操做),覆蓋原來的值 checkpoint = tf.train.latest_checkpoint('./ckpt/') # 判斷模型是否存在,若存在則提取保存的模型 if checkpoint: saver.restore(sess, checkpoint) print("第一次加載保存模型的權重參數:{},偏置參數:{}".format(self.height.eval(), self.bais.eval())) # 使用梯度降低優化損失 for i in range(1, self.FLAGS.train_step + 1): # 運行梯度降低OP與合併OP _, summary = sess.run([train_op, merged]) print("第{}步優化,損失爲{},權重參數:{},偏置參數:{}".format(i, loss.eval(), self.height.eval(), self.bais.eval())) # 將優化的變量寫入事件文件 file_writer.add_summary(summary, i) # 每隔一百步保存一次模型 if i % 100 == 0: saver.save(sess, self.FLAGS.model_dir, global_step=i) # './ckpt/myregression.ckpt' if __name__ == '__main__': # 定義命令行參數 tf.app.flags.DEFINE_integer('train_step', 0, '訓練步數') tf.app.flags.DEFINE_string('model_dir', '', "模型的保存路徑") # 定義獲取命令行的參數 FLAGS = tf.app.flags.FLAGS lr = MyLinearRegression(FLAGS) lr.train()
8 Tensorflow文件讀取
8.1 獲取數據到Tensorflow的方法
供給數據(Feeding): Python產生數據,再把數據餵給後端。
import tensorflow as tf
# 設計Graph
x1 = tf.placeholder(tf.int16)
x2 = tf.placeholder(tf.int16)
y = tf.add(x1, x2)
# 用Python產生數據
li1 = [2, 3, 4]
li2 = [4, 0, 1]
# 打開一個session --> 喂數據 --> 計算y
with tf.Session() as sess:
print sess.run(y, feed_dict={x1: li1, x2: li2})
""" 說明:在這裏x1, x2只是佔位符,沒有具體的值,那麼運行的時候去哪取值呢?這時候就要用到sess.run()中的feed_dict參數,將Python產生的數據餵給後端,並計算y。 """
預加載數據: 在TensorFlow圖中定義常量或變量來保存全部數據(僅適用於數據量比較小的狀況)。
import tensorflow as tf
# 設計Graph
x1 = tf.constant([2, 3, 4])
x2 = tf.constant([4, 0, 1])
y = tf.add(x1, x2)
# 打開一個session --> 計算y
with tf.Session() as sess:
print sess.run(y)
從文件讀取數據(QueueRunner):簡單來講就是將數據讀取模塊的圖搭好
8.2 TensorFlow文件讀取數據流程
8.3 TensorFlow讀取機制圖解
首先須要思考的一個問題是,什麼是數據讀取?以圖像數據爲例,讀取數據的過程能夠用下圖來表示: 假設咱們的硬盤中有一個圖片數據集0001.jpg,0002.jpg,0003.jpg……咱們只須要把它們讀取到內存中,而後提供給GPU或是CPU進行計算就能夠了。這聽起來很容易,但事實遠沒有那麼簡單。 事實上,咱們必需要把數據先讀入後才能進行計算,假設讀入用時0.1s,計算用時0.9s,那麼就意味着每過1s,GPU都會有0.1s無事可作,這就大大下降了運算的效率。
如何解決這個問題?方法就是將讀入數據和計算分別放在兩個線程中,將數據讀入內存的一個隊列,以下圖所示:
讀取線程源源不斷地將文件系統中的圖片讀入到一個內存的隊列中,而負責計算的是另外一個線程,計算須要數據時,直接從內存隊列中取就能夠了。這樣就能夠解決GPU由於IO而空閒的問題! 而在tensorflow中,爲了方便管理,在內存隊列前又添加了一層所謂的「文件名隊列」。 爲何要添加這一層文件名隊列?咱們首先得了解機器學習中的一個概念:epoch。對於一個數據集來說,運行一個epoch就是將這個數據集中的圖片所有計算一遍。如一個數據集中有三張圖片A.jpg、B.jpg、C.jpg,那麼跑一個epoch就是指對A、B、C三張圖片都計算了一遍。兩個epoch就是指先對A、B、C各計算一遍,而後再所有計算一遍,也就是說每張圖片都計算了兩遍。 tensorflow使用文件名隊列+內存隊列雙隊列的形式讀入文件,能夠很好地管理epoch。下面咱們用圖片的形式來講明這個機制的運行方式。以下圖,仍是以數據集A.jpg, B.jpg, C.jpg爲例,假定咱們要跑一個epoch,那麼咱們就在文件名隊列中把A、B、C各放入一次,並在以後標註隊列結束。
程序運行後,內存隊列首先讀入A(此時A從文件名隊列中出隊):
再依次讀入B和C:
此時,若是再嘗試讀入,系統因爲檢測到了「結束」,就會自動拋出一個異常(OutOfRange)。外部捕捉到這個異常後就能夠結束程序了。這就是tensorflow中讀取數據的基本機制。若是咱們要跑2個epoch而不是1個epoch,那隻要在文件名隊列中將A、B、C依次放入兩次再標記結束就能夠了。
8.4 TensorFlow讀取數據機制的對應函數
如何在tensorflow中建立文件名隊列與內存隊列呢?
對於文件名隊列,咱們使用tf.train.string_input_producer函數。這個函數須要傳入一個文件名list,系統會自動將它轉爲一個文件名隊列。 此外tf.train.string_input_producer還有兩個重要的參數,一個是num_epochs,它就是咱們上文中提到的epoch數。另一個就是shuffle,shuffle是指在一個epoch內文件的順序是否被打亂。若設置shuffle=False,以下圖,每一個epoch內,數據仍是按照A、B、C的順序進入文件名隊列,這個順序不會改變:
若是設置shuffle=True,那麼在一個epoch內,數據的先後順序就會被打亂,以下圖所示:
在tensorflow中,內存隊列不須要咱們本身創建,咱們只須要使用reader對象從文件名隊列中讀取數據就能夠了,具體實現能夠參考下面的實戰代碼。 除了tf.train.string_input_producer外,咱們還要額外介紹一個函數:tf.train.start_queue_runners。在咱們使用tf.train.string_input_producer建立文件名隊列後,整個系統其實仍是處於「停滯狀態」的,也就是說,咱們文件名並無真正被加入到隊列中(以下圖所示)。此時若是咱們開始計算,由於內存隊列中什麼也沒有,計算單元就會一直等待,致使整個系統被阻塞。
而使用tf.train.start_queue_runners以後,纔會啓動填充隊列的線程,這時系統就再也不「停滯」。此後計算單元就能夠拿到數據並進行計算,整個程序也就跑起來了,這就是函數tf.train.start_queue_runners的用處。
8.5 TensorFlow讀取數據的線程操做
8.6 TensorFlow讀取圖片數據
圖像基本知識
對於圖像文件,咱們怎麼進行轉換成機器學習可以理解的數據?對於圖片來說,組成圖片的最基本單位是像素,因此咱們獲取的是每張圖片的像素值。接觸的圖片有兩種,一種是黑白圖片,另外一種是彩色圖片。
案例:狗圖片讀取
代碼
"""
狗圖片讀取案例
"""
import tensorflow as tf
import os
def picture_read(file_list):
"""
讀取狗圖片數據到張量
:param file_list:路徑+文件名的列表
:return:
"""
# 1. 構造圖片文件名隊列
# 返回文件名隊列
file_queue = tf.train.string_input_producer(file_list)
# 2. 構造一個圖片讀取器,利用圖片讀取器去讀取隊列中的內容
reader = tf.WholeFileReader()
# 默認一次讀取一張圖片,沒有形狀
key, value = reader.read(file_queue)
# 3. 對讀取到的圖片內容進行解碼
# 數據類型從string---->unit8
# 形狀從()---->(???)
image = tf.image.decode_jpeg(value)
# 4. 圖片特徵值處理:對圖片進行批處理以前,進行形狀與大小的固定
# 把圖片固定成統一大小的目的是由於訓練的數據集的每一個樣本的特徵值應該相同。
# 設置成固定的大小
image_resized = tf.image.resize_images(image, size=[200, 200])
# 設置固定的通道數,使用靜態改變形狀的方法:set_shape()
image_resized.set_shape([200, 200, 3])
# 5. 對圖片數據進行批處理,批處理以前,每一個樣本的形狀必須固定
image_batch = tf.train.batch([image_resized], batch_size=10, num_threads=4, capacity=10)
# 在默認圖中進行會話操做 g = tf.get_default_graph() with g.as_default(): # 開啓會話 with tf.Session() as sess: # 1 手動開啓子線程去進行批處理讀取到隊列操做 # 1.1 建立用於線程回收的協調器 coord = tf.train.Coordinator() # 1.2 開啓子線程去讀取數據,返回子線程實例 threads = tf.train.start_queue_runners(sess=sess, coord=coord) # 2. 獲取樣本數據 pic_data = sess.run([image_batch]) print(pic_data) # 3. 回收子線程 coord.request_stop() coord.join(threads)
if name == 'main':
# 生成文件名列表
file_name_list = os.listdir('../data/dog/')
# 構造文件名+路徑列表
file_list = [os.path.join('../data/dog/', file) for file in file_name_list]
# 圖片文件讀取
picture_read(file_list)
8.7 TensorFlow利用二進制方式讀取CIFAR10數據集
<1×標籤> <3072×像素> ... <1×標籤> <3072×像素>
代碼
"""
CIFAR10數據集二進制版本的讀取
"""
import tensorflow as tf
import os
class CifarRead(object):
"""
CIFAR二進制文件的讀取
"""
def __init__(self, filename_list): """ 定義一些圖片的樣本屬性 :param filename_list: """ self.filename_list = filename_list self.height = 32 self.width = 32 self.channel = 3 self.label_bytes = 1 self.image_bytes = self.height * self.width * self.channel self.bytes = self.label_bytes + self.image_bytes def read_and_decode(self): """ 讀取二進制原始數據並解碼成張量 :return: """ # 1. 構造文件隊列 file_queue = tf.train.string_input_producer(self.filename_list) # 2. 使用二進制讀取器讀取內容 # 2.1 建立二進制讀取器實例,實在一次讀取的字節數 reader = tf.FixedLengthRecordReader(self.bytes) # 2.2 讀取內容,一共讀取1+3072=3073個字節,此時的value是某個文件的某個樣本 key, value = reader.read(file_queue) # 3. 對二進制數據進行解碼 decode_raw label_image = tf.decode_raw(value, tf.uint8) # 4. 切分圖片的特徵值與目標值:使用tf.slice(數據集,[起始下標],[結束下標])切片 label = tf.slice(label_image, [0], [self.label_bytes]) image = tf.slice(label_image, [self.label_bytes], [self.image_bytes]) # 5. 標籤、圖片的類型轉換、形狀轉換 # 5.1 標籤數據類型轉換 tf.cast() label_cast = tf.cast(label, tf.int32) image = tf.cast(image, tf.float32) # 5.2 固定圖片的特徵值形狀 # 5.2.1 shape:(3072,)--->[channel,height,width] depth_major = tf.reshape(image, [self.channel, self.height, self.width]) print(depth_major) # 5.2.2 tf.transpose:[channel,height,width]--->[heigt,width,channel] image_reshaped = tf.transpose(depth_major, [1, 2, 0]) print(image_reshaped) # 6.批處理圖片數據 image_batch, label_batch = tf.train.batch([image_reshaped, label_cast], batch_size=10, num_threads=4, capacity=10) print(image_batch) print(label_batch) return image_batch, label_batch def run(self): """ 執行文件讀取邏輯 :return: """ # 讀取二進制原始數據並解碼成張量,形狀固定於批處理 image_batch, label_batch = self.read_and_decode() # 開啓會話 with tf.Session() as sess: # 1. 手動開啓子線程去進行數據的批處理讀取到隊列的操做 # 1.1 建立用於線程回收的協調器 coord = tf.train.Coordinator() # 1.2 開啓子線程去讀取數據 threads = tf.train.start_queue_runners(sess=sess, coord=coord) # 2. 獲取樣本數據 pic_data = sess.run([image_batch, label_batch]) print(pic_data) # 3. 回收子線程 coord.request_stop() coord.join(threads)
if name == 'main':
# 生成文件名列表
filename_list = os.listdir('../data/cifar10/cifar-10-batches-bin/')
# 生成文件名加路徑列表
filename_list = [os.path.join('../data/cifar10/cifar-10-batches-bin/', file) for file in filename_list if
file[-3:] == 'bin']
# 實例化類
cr = CifarRead(filename_list)
cr.run()
In [7]: tf.reshape([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], [2, 2, 3]).eval()
Out[7]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9], [10, 11, 12]]], dtype=int32)
In [8]: tf.reshape([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], [3, 2, 2]).eval()
Out[8]:
array([[[ 1, 2],
[ 3, 4]],
[[ 5, 6], [ 7, 8]], [[ 9, 10], [11, 12]]], dtype=int32)
In [17]: tf.transpose(depth_major, [1, 2, 0]).eval()
Out[17]:
array([[[ 1, 5, 9],
[ 2, 6, 10]],
[[ 3, 7, 11], [ 4, 8, 12]]], dtype=int32)
8.8 CIFAR10類圖片的數據的TFRecords存儲和讀取
數據存入TFRecords文件
什麼是TFRecords文件
什麼是Example結構?
Feature字段中包含要寫入的數據、並指明數據類型。這是一個樣本的結構,批數據須要循環的存入這樣的結構。
example = tr.train.Example(features=tf.train.Features(feature={
"特徵值字段名":tf.train.Feature(特徵值數據類型列表=tf.train.特徵值數據類型列表類(value=[特徵值字段名])),
"標籤值字段名":tf.train.Feature(標籤值數據類型列表=tf.train.標籤值數據類型列表類(value=[標籤值字段名]))
}))
寫入數據到TFRecords中的主要步驟:
寫入數據到TFRecords中的示例代碼:
def wite_to_tfrecords(self, image_batch, label_batch): """ 將文件寫入到TFRecords文件中 :param image_batch: :param label_batch: :return: """ # 1. 創建TFRecords文件存儲器 writer = tf.python_io.TFRecordWriter('./1.tfrecords') # 設置路徑及文件名 # 2. 循環取出每一個樣本的值,構造example協議塊 for i in range(10): # 由於每批量有10個樣本數據 # 2.1 取出圖片的值 # 寫入文件的是值,而不是tensor類型,寫入example須要bytes類型數據,須要用tostring()來轉化 image = image_batch[i].eval().tostring() # 2.2 取出標籤值,寫入example中須要int類型,因此須要強制轉換成int類型 label = int(label_batch[i].eval()[0]) # 2.3 構造每一個樣本的example協議塊 feature = { "image": tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])), "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label])) } features = tf.train.Features(feature=feature) example = tf.train.Example(features=features) # 2.4 將example協議塊序列化 example_serialized = example.SerializeToString() # 2.5 寫入序列化後的值 writer.write(example_serialized) # 此處實際上是將其壓縮成一個二進制數據 # 3. 關閉文件存儲器 writer.close() return None
8.9 從TFRecords文件中讀取數據
解析example
feature = tr.parse_single_example(values,features={ "image":tf.FixedLenFeature([],tf.string), "label":tf.FixedLenFeature([],tf.int64) })
從TFRecords文件中讀取數據的主要步驟:
從TFRecords文件中讀取數據示例代碼:
def read_to_tfrecords(self): """ 從TFRecords文件中讀取圖片數據(解析example) :return: """ pass # 1. 構造文件隊列 file_queue = tf.train.string_input_producer(['./1.tfrecords']) # 參數爲文件名列表 # 2. 實例化TFRecords文件閱讀器 reader = tf.TFRecordReader() # 讀取數據 key, value = reader.read(file_queue) # 3. 解析example協議塊,返回值是字典 features = { "image": tf.FixedLenFeature([], tf.string), "label": tf.FixedLenFeature([], tf.int64) } feature = tf.parse_single_example(value, features=features) # 4. 處理標籤數據 # cast()只能在int和float之間進行轉換,將數據類型int64 轉換爲int32 label = tf.cast(feature["label"], tf.int32) # 處理圖片數據 # 因爲是一個string,要進行解碼, # 將字節轉換爲數字向量表示,字節爲一字符串類型的張量 # 若是以前用了tostring(),那麼必需要用decode_raw()轉換爲最初的int類型 # decode_raw()能夠將數據從string,bytes轉換爲int,float類型 image = tf.decode_raw(feature['image'], tf.uint8) # 5. 轉換圖片的形狀,此處須要用動態形狀進行轉換 image_tensor = tf.reshape(image, [self.height, self.width, self.channel]) # 6. 批處理 image_batch, label_batch = tf.train.batch([image_tensor, label], batch_size=10, num_threads=4, capacity=10) return image_batch, label_batch
CIFAR10類圖片的數據的TFRecords存儲和讀取示例代碼
import tensorflow as tf import os """ 讀取二進制文件轉換成張量,寫進TFRecords,同時讀取TFRcords """ # 命令行參數 FLAGS = tf.app.flags.FLAGS # 獲取值 tf.app.flags.DEFINE_string("tfrecord_dir", "./tmp/cifar10.tfrecords", "寫入圖片數據文件的文件名") # 讀取二進制轉換文件 class CifarRead(object): """ 讀取二進制文件轉換成張量,寫進TFRecords,同時讀取TFRcords """ def __init__(self, file_list): """ 初始化圖片參數 :param file_list:圖片的路徑名稱列表 """ # 文件列表 self.file_list = file_list # 圖片大小,二進制文件字節數 self.height = 32 self.width = 32 self.channel = 3 self.label_bytes = 1 self.image_bytes = self.height * self.width * self.channel self.bytes = self.label_bytes + self.image_bytes def read_and_decode(self): """ 解析二進制文件到張量 :return: 批處理的image,label張量 """ # 1.構造文件隊列 file_queue = tf.train.string_input_producer(self.file_list) # 2.閱讀器讀取內容 reader = tf.FixedLengthRecordReader(self.bytes) key, value = reader.read(file_queue) # key爲文件名,value爲元組 print(value) # 3.進行解碼,處理格式 label_image = tf.decode_raw(value, tf.uint8) print(label_image) # 處理格式,image,label # 進行切片處理,標籤值 # tf.cast()函數是轉換數據格式,此處是將label二進制數據轉換成int32格式 label = tf.cast(tf.slice(label_image, [0], [self.label_bytes]), tf.int32) # 處理圖片數據 image = tf.slice(label_image, [self.label_bytes], [self.image_bytes]) print(image) # 處理圖片的形狀,提供給批處理 # 由於image的形狀已經固定,此處形狀用動態形狀來改變 depth_major = tf.reshape(image, [self.channel, self.height, self.width]) image_tensor = tf.transpose(depth_major, [1, 2, 0]) print(image_tensor) # 批處理圖片數據 image_batch, label_batch = tf.train.batch([image_tensor, label], batch_size=10, num_threads=1, capacity=10) return image_batch, label_batch def write_to_tfrecords(self, image_batch, label_batch): """ 將文件寫入到TFRecords文件中 :param image_batch: :param label_batch: :return: """ # 創建TFRecords文件存儲器 writer = tf.python_io.TFRecordWriter('./1.tfrecords') # 傳進去命令行參數 # 循環取出每一個樣本的值,構造example協議塊 for i in range(10): # 取出圖片的值, #寫進去的是值,而不是tensor類型, # 寫入example須要bytes文件格式,將tensor轉化爲bytes用tostring()來轉化 image = image_batch[i].eval().tostring() # 取出標籤值,寫入example中須要使用int形式,因此須要強制轉換int label = int(label_batch[i].eval()[0]) # 構造每一個樣本的example協議塊 example = tf.train.Example(features=tf.train.Features(feature={ "image": tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])), "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label])) })) # 寫進去序列化後的值 writer.write(example.SerializeToString()) # 此處實際上是將其壓縮成一個二進制數據 writer.close() return None def read_from_tfrecords(self): """ 從TFRecords文件當中讀取圖片數據(解析example) :param self: :return: image_batch,label_batch """ # 1.構造文件隊列 file_queue = tf.train.string_input_producer(['./1.tfrecords']) # 參數爲文件名列表 # 2.構造閱讀器 reader = tf.TFRecordReader() key, value = reader.read(file_queue) # 3.解析協議塊,返回的值是字典 feature = tf.parse_single_example(value, features={ "image": tf.FixedLenFeature([], tf.string), "label": tf.FixedLenFeature([], tf.int64) }) # feature["image"],feature["label"] # 處理標籤數據 ,cast()只能在int和float之間進行轉換 label = tf.cast(feature["label"], tf.int32) # 將數據類型int64 轉換爲int32 # 處理圖片數據,因爲是一個string,要進行解碼, #將字節轉換爲數字向量表示,字節爲一字符串類型的張量 # 若是以前用了tostring(),那麼必需要用decode_raw()轉換爲最初的int類型 # decode_raw()能夠將數據從string,bytes轉換爲int,float類型的 image = tf.decode_raw(feature["image"], tf.uint8) # 轉換圖片的形狀,此處須要用動態形狀進行轉換 image_tensor = tf.reshape(image, [self.height, self.width, self.channel]) # 4.批處理 image_batch, label_batch = tf.train.batch([image_tensor, label], batch_size=10, num_threads=1, capacity=10) return image_batch, label_batch def run(self): """ 實現讀取數據的主邏輯 :return: """ # 讀取二進制文件 # image_batch,label_batch = self.read_and_decode() # 從已經存儲的TFRecords文件中解析出原始數據 image_batch, label_batch = self.read_from_tfrecords() with tf.Session() as sess: # 線程協調器 coord = tf.train.Coordinator() # 開啓線程 threads = tf.train.start_queue_runners(sess, coord=coord) print(sess.run([image_batch, label_batch])) print("存進TFRecords文件") # self.write_to_tfrecords(image_batch,label_batch) print("存進文件完畢") # 回收線程 coord.request_stop() coord.join(threads) if __name__ == '__main__': # 找到文件路徑,名字,構造路徑+文件名的列表,"A.csv"... # os.listdir() 方法用於返回指定的文件夾包含的文件或文件夾的名字的列表 filename = os.listdir('../data/cifar10/cifar-10-batches-bin/') # 加上路徑 file_list = [os.path.join('../data/cifar10/cifar-10-batches-bin/', file) for file in filename if file[-3:] == "bin"] # 建立一個文件讀取對象 cr = CifarRead(file_list) # 開始運行 cr.run()
9 Tensorflow中其它基礎API與高級API
9.1 基礎API
9.2 高級API
10 TensorFlow訓練稀疏模型
TensorFlow 中的 layers 模塊
TensorFlow 中的 layers 模塊提供用於深度學習的更高層次封裝的 API,利用它咱們能夠輕鬆地構建模型,這一節咱們就來看下這個模塊的 API 的具體用法。
11 TensorFlow中的layers模塊
11.1 概覽
layers 模塊的路徑寫法爲 tf.layers,這個模塊定義在 tensorflow/python/layers/layers.py,其官方文檔地址爲:https://www.tensorflow.org/api_docs/python/tf/layers,TensorFlow 版本爲 1.5。
這裏面提供了多個類和方法以供使用,下面咱們分別予以介紹。
11.2 方法
tf.layers 模塊提供的方法有:
11.2.1 tf.layers.Input
tf.layers.Input() 這個方法是用於輸入數據的方法,其實相似於 tf.placeholder,至關於一個佔位符的做用,固然也能夠經過傳入 tensor 參數來進行賦值。
Input( shape=None, batch_size=None, name=None, dtype=tf.float32, sparse=False, tensor=None )
參數說明以下:
返回值: 返回一個包含歷史 Meta Data 的 Tensor。
咱們用一個實例來感覺一下:
x = tf.layers.Input(shape=[32]) print(x) y = tf.layers.dense(x, 16, activation=tf.nn.softmax) print(y)
首先咱們用 Input() 方法初始化了一個 placeholder,這時咱們沒有傳入 tensor 參數,而後調用了 dense() 方法構建了一個全鏈接網絡,激活函數使用 softmax,而後將兩者輸出,結果以下:
Tensor("input_layer_1:0", shape=(?, 32), dtype=float32) Tensor("dense/Softmax:0", shape=(?, 16), dtype=float32)
這時咱們發現,shape 它給咱們作了轉化,原本是 [32],結果它給轉化成了 [?, 32],即第一維表明 batch_size,因此咱們須要注意,在調用此方法的時候不須要去關心 batch_size 這一維。
若是咱們在初始化的時候傳入一個已有 Tensor,例如:
data = tf.constant([1, 2, 3]) x = tf.layers.Input(tensor=data) print(x)
結果以下:
data = tf.constant([1, 2, 3]) x = tf.layers.Input(tensor=data) print(x)
能夠看到它能夠自動計算出其 shape 和 dtype。
11.2.2 tf.layers.batch_normalization
此方法是批量標準化的方法,通過處理以後能夠加速訓練速度,其定義在 tensorflow/python/layers/normalization.py,論文能夠參考:http://arxiv.org/abs/1502.03167 「Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift」。
batch_normalization( inputs, axis=-1, momentum=0.99, epsilon=0.001, center=True, scale=True, beta_initializer=tf.zeros_initializer(), gamma_initializer=tf.ones_initializer(), moving_mean_initializer=tf.zeros_initializer(), moving_variance_initializer=tf.ones_initializer(), beta_regularizer=None, gamma_regularizer=None, beta_constraint=None, gamma_constraint=None, training=False, trainable=True, name=None, reuse=None, renorm=False, renorm_clipping=None, renorm_momentum=0.99, fused=None, virtual_batch_size=None, adjustment=None )
參數說明以下:
最後的一些參數說明不夠詳盡,更詳細的用法參考:https://www.tensorflow.org/api_docs/python/tf/layers/batch_normalization。
其用法很簡單,在輸入數據後面加一層 batch_normalization() 便可:
x = tf.layers.Input(shape=[32]) x = tf.layers.batch_normalization(x) y = tf.layers.dense(x, 20)
11.2.3 tf.layers.dense
dense,即全鏈接網絡,layers 模塊提供了一個 dense() 方法來實現此操做,定義在 tensorflow/python/layers/core.py 中,下面咱們來講明一下它的用法。
dense( inputs, units, activation=None, use_bias=True, kernel_initializer=None, bias_initializer=tf.zeros_initializer(), kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None, trainable=True, name=None, reuse=None )
參數說明以下:
返回值: 全鏈接網絡處理後的 Tensor。
下面咱們用一個實例來感覺一下它的用法:
x = tf.layers.Input(shape=[32]) print(x) y1 = tf.layers.dense(x, 16, activation=tf.nn.relu) print(y1) y2 = tf.layers.dense(y1, 5, activation=tf.nn.sigmoid) print(y2)
首先咱們用 Input 定義了 [?, 32] 的輸入數據,而後通過第一層全鏈接網絡,此時指定了神經元個數爲 16,激活函數爲 relu,接着輸出結果通過第二層全鏈接網絡,此時指定了神經元個數爲 5,激活函數爲 sigmoid,最後輸出,結果以下:
x = tf.layers.Input(shape=[32]) print(x) y1 = tf.layers.dense(x, 16, activation=tf.nn.relu) print(y1) y2 = tf.layers.dense(y1, 5, activation=tf.nn.sigmoid) print(y2)
能夠看到輸出結果的最後一維度就等於神經元的個數,這是很是容易理解的。
11.2.4 tf.layers.convolution
convolution,即卷積,這裏提供了多個卷積方法,如 conv1d()、conv2d()、conv3d(),分別表明一維、二維、三維卷積,另外還有 conv2d_transpose()、conv3d_transpose(),分別表明二維和三維反捲積,還有 separable_conv2d() 方法表明二維深度可分離卷積。它們定義在 tensorflow/python/layers/convolutional.py 中,其用法都是相似的,在這裏以 conv2d() 方法爲例進行說明。
conv2d( inputs, filters, kernel_size, strides=(1, 1), padding='valid', data_format='channels_last', dilation_rate=(1, 1), activation=None, use_bias=True, kernel_initializer=None, bias_initializer=tf.zeros_initializer(), kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None, trainable=True, name=None, reuse=None )
參數說明以下:
返回值: 卷積後的 Tensor。
下面咱們用實例感覺一下它的用法:
x = tf.layers.Input(shape=[20, 20, 3]) y = tf.layers.conv2d(x, filters=6, kernel_size=2, padding='same') print(y) 這裏咱們首先聲明瞭一個 [?, 20, 20, 3] 的輸入 x,而後將其傳給 conv2d() 方法,filters 設定爲 6,即輸出通道爲 6,kernel_size 爲 2,即卷積核大小爲 2 x 2,padding 方式設置爲 same,那麼輸出結果的寬高和原來必定是相同的,可是輸出通道就變成了 6,結果以下: Tensor("conv2d/BiasAdd:0", shape=(?, 20, 20, 6), dtype=float32)
但若是咱們將 padding 方式不傳入,使用默認的 valid 模式,代碼改寫以下:
x = tf.layers.Input(shape=[20, 20, 3]) y = tf.layers.conv2d(x, filters=6, kernel_size=2) print(y)
結果以下:
Tensor("conv2d/BiasAdd:0", shape=(?, 19, 19, 6), dtype=float32)
結果就變成了 [?, 19, 19, 6],這是由於步長默認爲 1,卷積核大小爲 2 x 2,因此獲得的結果的高寬即爲 (20 – (2 – 1)) x (20 – (2 – 1)) = 19 x 19。
固然卷積核咱們也能夠變換大小,傳入一個列表形式:
x = tf.layers.Input(shape=[20, 20, 3]) y = tf.layers.conv2d(x, filters=6, kernel_size=[2, 3]) print(y)
這時咱們的卷積核大小變成了 2 x 3,即高爲 2,寬爲 3,結果就變成了 [?, 19, 18, 6],這是由於步長默認爲 1,卷積核大小爲 2 x 2,因此獲得的結果的高寬即爲 (20 – (2 – 1)) x (20 – (3 – 1)) = 19 x 18。
若是咱們將步長也設置一下,也傳入列表形式:
x = tf.layers.Input(shape=[20, 20, 3]) y = tf.layers.conv2d(x, filters=6, kernel_size=[2, 3], strides=[2, 2]) print(y)
這時卷積核大小變成了 2 x 3,步長變成了 2 x 2,因此結果的高寬爲 ceil(20 – (2- 1)) / 2 x ceil(20 – (3- 1)) / 2 = 10 x 9,獲得的結果即爲 [?, 10, 9, 6]。
運行結果以下:
Tensor("conv2d_4/BiasAdd:0", shape=(?, 10, 9, 6), dtype=float32)
另外咱們還能夠傳入激活函數,或者禁用 bias 等操做,實例以下:
x = tf.layers.Input(shape=[20, 20, 3]) y = tf.layers.conv2d(x, filters=6, kernel_size=2, activation=tf.nn.relu, use_bias=False) print(y)
這樣咱們就將激活函數改爲了 relu,同時禁用了 bias,運行結果以下:
Tensor("conv2d_5/Relu:0", shape=(?, 19, 19, 6), dtype=float32)
另外還有反捲積操做,反捲積顧名思義即卷積的反向操做,即輸入卷積的結果,獲得卷積前的結果,其參數用法是徹底同樣的,例如:
x = tf.layers.Input(shape=[20, 20, 3]) y = tf.layers.conv2d_transpose(x, filters=6, kernel_size=2, strides=2) print(y)
例如此處輸入的圖像高寬爲 20 x 20,通過卷積核爲 2,步長爲 2 的反捲積處理,獲得的結果高寬就變爲了 40 x 40,結果以下:
Tensor("conv2d_transpose/BiasAdd:0", shape=(?, 40, 40, 6), dtype=float32)
11.2.5 tf.layers.pooling
pooling,即池化,layers 模塊提供了多個池化方法,這幾個池化方法都是相似的,包括 max_pooling1d()、max_pooling2d()、max_pooling3d()、average_pooling1d()、average_pooling2d()、average_pooling3d(),分別表明一維二維三維最大和平均池化方法,它們都定義在 tensorflow/python/layers/pooling.py 中,這裏以 max_pooling2d() 方法爲例進行介紹。
max_pooling2d( inputs, pool_size, strides, padding='valid', data_format='channels_last', name=None )
參數說明以下:
返回值: 通過池化處理後的 Tensor。
下面咱們用一個實例來感覺一下:
x = tf.layers.Input(shape=[20, 20, 3]) print(x) y = tf.layers.conv2d(x, filters=6, kernel_size=3, padding='same') print(y) p = tf.layers.max_pooling2d(y, pool_size=2, strides=2) print(p)
在這裏咱們首先指定了輸入 x,shape 爲 [20, 20, 3],而後對其進行了卷積計算,而後池化,最後獲得池化後的結果。結果以下:
Tensor("input_layer_1:0", shape=(?, 20, 20, 3), dtype=float32) Tensor("conv2d/BiasAdd:0", shape=(?, 20, 20, 6), dtype=float32) Tensor("max_pooling2d/MaxPool:0", shape=(?, 10, 10, 6), dtype=float32)
能夠看到這裏池化窗口用的是 2,步長也是 2,因此本來卷積後 shape 爲 [?, 20, 20, 6] 的結果就變成了 [?, 10, 10, 6]。
11.2.6 tf.layers.dropout
dropout 是指在深度學習網絡的訓練過程當中,對於神經網絡單元,按照必定的機率將其暫時從網絡中丟棄,能夠用來防止過擬合,layers 模塊中提供了 dropout() 方法來實現這一操做,定義在 tensorflow/python/layers/core.py。下面咱們來講明一下它的用法。
dropout( inputs, rate=0.5, noise_shape=None, seed=None, training=False, name=None )
參數說明以下:
返回: 通過 dropout 層以後的 Tensor。
咱們用一個實例來感覺一下:
x = tf.layers.Input(shape=[32]) print(x) y = tf.layers.dense(x, 16, activation=tf.nn.softmax) print(y) d = tf.layers.dropout(y, rate=0.2) print(d)
運行結果:
Tensor("input_layer_1:0", shape=(?, 32), dtype=float32) Tensor("dense/Softmax:0", shape=(?, 16), dtype=float32) Tensor("dropout/Identity:0", shape=(?, 16), dtype=float32)
在這裏咱們使用 dropout() 方法實現了 droput 操做,並制定 dropout rate 爲 0.2,最後輸出結果的 shape 和原來是一致的。
11.2.7 tf.layers.flatten
flatten() 方法能夠對 Tensor 進行展平操做,定義在 tensorflow/python/layers/core.py。
flatten( inputs, name=None )
參數說明以下:
返回結果: 展平後的 Tensor。
下面咱們用一個實例來感覺一下:
x = tf.layers.Input(shape=[5, 6]) print(x) y = tf.layers.flatten(x) print(y)
運行結果:
Tensor("input_layer_1:0", shape=(?, 5, 6), dtype=float32) Tensor("flatten/Reshape:0", shape=(?, 30), dtype=float32)
這裏輸入數據的 shape 爲 [?, 5, 6],通過 flatten 層以後,就會變成 [?, 30],即將除了第一維的數據維度相乘,對原 Tensor 進行展平。
假如第一維是一個已知的數的話,它依然仍是一樣的處理,示例以下:
Tensor("input_layer_1:0", shape=(?, 5, 6), dtype=float32) Tensor("flatten/Reshape:0", shape=(?, 30), dtype=float32)
結果以下:
Tensor("input_layer_1:0", shape=(?, 5, 6), dtype=float32) Tensor("flatten/Reshape:0", shape=(?, 30), dtype=float32)
12 TensorFlow 計算交叉熵錯誤問題解決
sparse_softmax_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, name=None)
在使用tf.nn.sparse_softmax_cross_entropy_with_logits(logits, labels)語句時產生以下錯誤:
import tensorflow as tf labels = [[0.2,0.3,0.5], [0.1,0.6,0.3]] logits = [[2,0.5,1], [0.1,1,3]]result1 = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=labels, logits=logits)若是這樣用就會報這個錯ValueError: Rank mismatch: Rank of labels (received 2) should equal rank of logits minus 1 (received 2).
下面演示一下,兩個方法的正確用法:
import tensorflow as tf labels = [[0.2,0.3,0.5], [0.1,0.6,0.3]] logits = [[2,0.5,1], [0.1,1,3]]result1 = tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits) import tensorflow as tf labels = [0,2] logits = [[2,0.5,1], [0.1,1,3]] result1 = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=labels, logits=logits)
總結:
tf.nn.in_top_k函數的用法
'''
predictions: 你的預測結果(通常也就是你的網絡輸出值)大小是預測樣本的數量乘以輸出的維度
target: 實際樣本類別的標籤,大小是樣本數量的個數
k: 每一個樣本中前K個最大的數裏面(序號)是否包含對應target中的值
'''
import tensorflow as tf
A = tf.Variable([[0.8, 0.4, 0.5, 0.6],[0.1, 0.9, 0.2, 0.4],[0.1, 0.9, 0.4, 0.2]])
B = tf.Variable([1, 1, 2])
result = tf.nn.in_top_k(A, B, 2)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run(A))
print(sess.run(B))
print(sess.run(result))
'''
解釋:
k取1的時候:
由於A中第一個元素的最大值爲0.8,索引(序號)是0,而B是1,不包含B,因此返回False.
A中第二個元素的最大值爲0.9,索引(序號)是1,而B是1,包含B,因此返回True.
A中第三個元素的最大值爲0.9,索引(序號)是1,而B是2,不包含B,因此返回False.
k取2的時候:
由於A中前兩個元素的最大值爲0.8,0.6,索引(序號)是0,3,而B是1,不包含B,因此返回False.
A中前兩個元素的最大值爲0.9,0.4,索引(序號)是1,3,而B是1,包含B,因此返回True.
A中前兩個元素的最大值爲0.9,0.4,索引(序號)是1,2,而B是2,包含B,因此返回True.
'''
案例:TensorFlow1實現全鏈接神經網絡識別手勢數據集
""" 一天下午,咱們和一些朋友決定教咱們的電腦破譯手語。咱們花了幾個小時在白色的牆壁前拍照,因而就有了瞭如下數據集。如今,你的任務是創建一個算法,使有語音障礙的人與不懂手語的人交流。 訓練集:有從0到5的數字的1080張圖片(64x64像素),每一個數字擁有180張圖片。 測試集:有從0到5的數字的120張圖片(64x64像素),每一個數字擁有5張圖片。 須要注意的是這是完整數據集的一個子集,完整的數據集包含更多的符號。 下面是每一個數字的樣本,以及咱們如何表示標籤的解釋。這些都是原始圖片,咱們實際上用的是64 * 64像素的圖片。 """ import numpy as np import h5py import matplotlib.pyplot as plt import time import math import tensorflow as tf # %matplotlib inline #若是你使用的是jupyter notebook取消註釋 np.random.seed(1) class GestureSymbolRecognition(object): def __init__(self): self.learning_rate = 0.0001 self.num_epochs = 1500 self.minibatch_size = 32 self.regularazion_rate = 0.001 self.n_inputs = 12288 self.n_hidden1 = 100 self.n_hidden2 = 100 self.n_hidden3 = 100 self.n_outputs = 6 self.batch_norm_momentum = 0.9 def load_data(self): """ 加載數據集 :return: """ # 從文件中讀取訓練集數據 train_dataset = h5py.File('datasets/train_signs.h5', "r") # 從訓練集數據中提取特徵值與標籤值數據 train_set_x_orig = np.array(train_dataset["train_set_x"][:]) train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # 從文件中讀取測試集數據 test_dataset = h5py.File('datasets/test_signs.h5', "r") # 從測試集數據中提取特徵值與標籤值數據 test_set_x_orig = np.array(test_dataset["test_set_x"][:]) test_set_y_orig = np.array(test_dataset["test_set_y"][:]) classes = np.array(test_dataset["list_classes"][:]) # 類別列表 classes_num = len(classes) # 數據集標籤分爲幾類 train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0])) test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0])) X_train_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1) # 每一列就是一個樣本 X_test_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1) # 歸一化數據 X_train = X_train_flatten / 255 X_test = X_test_flatten / 255 # 轉換爲one-hot編碼矩陣 Y_train = self.convert_to_one_hot(train_set_y_orig, len(classes)).T Y_test = self.convert_to_one_hot(test_set_y_orig, len(classes)).T return X_train, Y_train, X_test, Y_test, classes_num def convert_to_one_hot(self, Y, C): """ 實現one-hot編碼 :param Y:標籤矩陣 :param C:分類數量 :return:one_hot:one-hot矩陣 """ one_hot = np.eye(C)[Y.reshape(-1)].T return one_hot def random_mini_batches(self, X, Y, mini_batch_size, seed=0): """ 從數據集中建立一個隨機的mini-batch列表 :param X: 輸入數據,維度爲(輸入節點數量,樣本數量) :param Y: 對應的目標值,維度爲(1,樣本數量) :param mini_batch_size: 每一個mini-batch的樣本數量 :param seed: 隨機數種子 :return: mini_batches:一個同步列表,維度爲(mini_batch_X, mini_batch_Y) """ # 指定隨機數種子 np.random.seed(seed) # 獲取樣本數 m = X.shape[0] # print('樣本數量',m) # 建立一個同步列表 mini_batches = [] # 第一步:打亂樣本的順序 permutation = list(np.random.permutation(m)) # 返回一個長度爲m的隨機數組,且裏面的數是0到m-1 shuffled_X = X[permutation, :] # 將每一列特徵值數據按permutation的順序來從新排列 shuffled_Y = Y[permutation, :] # .reshape((Y.shape[0], m)) # 將每一列的目標值數據按permutation的順序來從新排列 # 第二步:分割訓練集數據 num_complete_minibatches = math.floor(m / mini_batch_size) # 迭代完成整個訓練集的次數 for k in range(0, num_complete_minibatches): mini_batch_X = shuffled_X[k * mini_batch_size:(k + 1) * mini_batch_size, :] mini_batch_Y = shuffled_Y[k * mini_batch_size:(k + 1) * mini_batch_size, :] mini_batch = (mini_batch_X, mini_batch_Y) mini_batches.append(mini_batch) # 若是訓練集的大小不是mini_batch_size的整數倍,那麼最後確定會剩下一些,取剩餘的數據 if m % mini_batch_size != 0: # 獲取剩餘部分的數據 mini_batch_X = shuffled_X[mini_batch_size * num_complete_minibatches:, :] mini_batch_Y = shuffled_Y[mini_batch_size * num_complete_minibatches:, :] mini_batch = (mini_batch_X, mini_batch_Y) mini_batches.append(mini_batch) # 返回同步列表 return mini_batches def train(self, print_cost=True, is_plot=True): """ 實現一個三層的TensorFlow神經網絡訓練邏輯:LINEAR->RELU->LINEAR->RELU->LINEAR->SOFTMAX 參數: print_cost - 是否打印成本,每100代打印一次 is_plot - 是否繪製曲線圖 """ # 加載數據集 x_train, y_train, x_test, y_test, label_classes_num = self.load_data() print("訓練集樣本數 = " + str(x_train.shape[0])) print("測試集樣本數 = " + str(x_test.shape[0])) print("X_train.shape: " + str(x_train.shape)) print("Y_train.shape: " + str(y_train.shape)) print("X_test.shape: " + str(x_test.shape)) print("Y_test.shape: " + str(y_test.shape)) # 設置圖級別的隨機數種子 tf.set_random_seed(1) # 設置操做級別的隨機數種子 seed = 3 # 獲取輸入節點數量和樣本數 (m, n_x) = x_train.shape # 成本函數值列表 costs = [] # 給X和Y建立佔位符節點 X = tf.placeholder(tf.float32, shape=(None, self.n_inputs), name="X") Y = tf.placeholder(tf.int32, shape=(None, label_classes_num), name="y") # 定義神經網絡全鏈接層 with tf.name_scope("dnn"): # 使用He權重初始化方法初始化權重 he_init = tf.variance_scaling_initializer(mode="fan_avg") # 定義全鏈接層,使用elu激活函數 hidden1 = tf.layers.dense(X, self.n_hidden1, name="hidden1", kernel_initializer=he_init, activation=tf.nn.elu, ) hidden2 = tf.layers.dense(hidden1, self.n_hidden2, name="hidden2", kernel_initializer=he_init, activation=tf.nn.elu) hidden3 = tf.layers.dense(hidden2, self.n_hidden3, name="hidden3", kernel_initializer=he_init, activation=tf.nn.elu) outputs = tf.layers.dense(hidden3, self.n_outputs, name="outputs") # 輸出預測的類別 y_proba = tf.nn.softmax(outputs) # 定義損失函數計算損失 with tf.name_scope('loss'): # 前向傳播要在Z3處中止,由於在TensorFlow中最後的線性輸出層的輸出做爲計算損失函數的輸入,因此不須要A3. xentropy = tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=outputs) loss = tf.reduce_mean(xentropy, name="loss") # 定義優化器 with tf.name_scope("train_optimizer"): optimizer = tf.train.AdamOptimizer(self.learning_rate) training_op = optimizer.minimize(loss) # # 使用梯度裁剪 # threshold = 1.0 # 設置梯度閾值 # # 定義優化器 # optimizer = tf.train.AdamOptimizer(self.learning_rate) # # 調用優化器的compute_gradients()方法計算梯度 # grads_and_vars = optimizer.compute_gradients(loss) # # 使用tf.clip_by_value()函數建立一個裁剪梯度的操做 # capped_gvs = [(tf.clip_by_value(grad, -threshold, threshold), var) for grad, var in grads_and_vars] # # 建立一個節點使用優化器的apply_gradients()函數應用裁剪的梯度 # training_op = optimizer.apply_gradients(capped_gvs) # 評估模型,使用準確性做爲咱們的績效指標 with tf.name_scope("eval"): # 計算當前的預測結果 # 檢測使用了滑動平靜模型的神經網絡前向傳播是否正確。tf.argmax(average_y,1) # 計算每個樣例的預測答案。其中average_y是一個batch_size*10的二維數組,每 # 一行表示案例向前傳播的結果。tf.argmax的第二個參數爲1,表示選取最大值的 # 操做只在第一個維度上進行(x軸上),也就是說只在每一行選取最大值對應的下標 # 因而獲得的結果是一個長度爲batch的一維數組,這個一維數組中的值就表示了每 # 一個數字對應的樣例識別的結果.tf.equal()判斷每一個Tensor的每一維度是否相同 # 若是相等返回True,不然返回False. correct_prediction = tf.equal(tf.argmax(y_proba, 1), tf.argmax(Y, 1)) # 計算準確率 # 這個運算首先將一個布爾型的值轉換爲實數型,而後計算平均值。這一個平均值 # 就表明模型在這一組數據上的正確率 accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) # 建立初始化全部變量的節點 init = tf.global_variables_initializer() # 建立一個保存模型的saveOP,設置要保留的最近檢測點的模型的數量 saver = tf.train.Saver(max_to_keep=1) # 開始會話並計算 with tf.Session() as sess: # 初始化全部變量 sess.run(init) # 加載模型,從模型中找出與當前訓練的模型代碼當中(名字同樣的OP操做),覆蓋原來的值 checkpoin = tf.train.latest_checkpoint('./ckpt/') # 若是模型已經保存則加載模型 if checkpoin: saver.restore(sess, checkpoin) # 計算模型預測的準確率 train_acc = accuracy.eval({X: x_train[100:200], Y: y_train[100:200]}) test_acc = accuracy.eval({X: x_test[100:200], Y: y_test[100:200]}) print("訓練集的準確率:", train_acc) print("測試集的準確率:", test_acc) else: # 模型未保存,則開始訓練模型 # 正常訓練模型 for epoch in range(self.num_epochs): epoch_cost = 0 # 每輪的成本函數值 num_minibatches = math.floor(m / self.minibatch_size) # 分紅多少個mini-batch組 seed = seed + 1 minibatches = self.random_mini_batches(x_train, y_train, self.minibatch_size, seed) for minibatch in minibatches: # 選擇一個minibatch (minibatch_X, minibatch_Y) = minibatch # 數據已經準備好了,開始運行session _, minibatch_cost = sess.run([training_op, loss], feed_dict={X: minibatch_X, Y: minibatch_Y}) # 計算這個minibatch在這一代中所佔的偏差 epoch_cost = epoch_cost + minibatch_cost / num_minibatches if epoch % 5 == 0: # 將每輪迭代的代價函數值存入列表 costs.append(epoch_cost) # 打印每輪迭代的代價函數值: if print_cost and epoch % 100 == 0: print("epoch = " + str(epoch) + " epoch_cost = " + str(epoch_cost)) # 保存學習後的參數 saver.save(sess, './ckpt/my_test1_model.ckpt') # 繪製代價函數值的學習曲線 if is_plot: plt.plot(np.squeeze(costs)) plt.ylabel('cost') plt.xlabel('iterations (per tens)') plt.title("Learning rate =" + str(self.learning_rate)) plt.show() # 計算模型學習完成後的訓練集及測試集準確率 train_acc = accuracy.eval({X: x_train, Y: y_train}) test_acc = accuracy.eval({X: x_test, Y: y_test}) print("訓練集的準確率:", train_acc) print("測試集的準確率:", test_acc) if __name__ == '__main__': # 開始時間 start_time = time.clock() # 開始訓練 nn = GestureSymbolRecognition() nn.train() # 結束時間 end_time = time.clock() # 計算時差 print("CPU的執行時間 = " + str(end_time - start_time) + " 秒")