1. 程式人生 > >TensorFlow學習筆記(1)—— MNIST手寫識別

TensorFlow學習筆記(1)—— MNIST手寫識別

1、初步學習

資料處理

xs:60000張圖片,28*28大小,將所有畫素點按一列排列,資料集變為了[60000, 784]的二維矩陣。

ys:60000張圖片,每個圖片有一個標籤標識圖片中數字,採用one-hot向量,資料集變為[60000, 10]的二維矩陣。

softmax函式
用來給不同的物件分配概率,一般放在分類網路最後一層。
這裡寫圖片描述
接下來,實現一個非常簡單的兩層全連線網路來完成MNIST資料分類的問題,輸入層784個神經元,對應每張圖片的784個畫素點;輸出層10個神經元,對應0-9這10個數字,實現分類。
這裡寫圖片描述

計算流程

1.資料準備
2.準備好placeholder
3.初始化引數/權重
4.計算預測結果
5.計算損失值
6.初始化optimizer
7.指定迭代次數,並在session執行graph

程式碼

# -*- coding:utf-8  -*-

# 安裝資料集,第一次執行可能需要下載
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)

import tensorflow as tf

# 載入資料集
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)

# 每個批次送100張圖片
batch_size = 100
# 計算一共有多少個批次 n_batch = mnist.train.num_examples // batch_size # 準備好placeholder x = tf.placeholder(tf.float32, [None, 784]) y = tf.placeholder(tf.float32,[None, 10]) # 初始化引數、權重 W = tf.Variable(tf.zeros([784, 10])) b = tf.Variable(tf.zeros([10])) # 計算預測結果 prediction = tf.nn.softmax(tf.matmul(x, W) + b) # 計算損失值
# 先使用二次代價函式 loss = tf.reduce_mean(tf.square(y - prediction)) # 初始化optimizer # 梯度下降優化器,學習率建議給的稍大些 learning_rate = 0.2 optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss) # 結果存放在一個布林型列表中 # tf.argmax(vector,1)意思是返回vector中最大值的索引號,如果vector是一個向量,那就返回一個值 # 如果是一個矩陣就返回一個向量,該向量每一維都是相應矩陣行的最大值元素的索引號 # 在這裡,argmax就是返回的就是向量中最大值(1)的位置,並進行比較,相同則返回1,反之為0 correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))# 這裡輸出的矩陣裡面是true和false # 準確率 # tf.cast 是型別轉換函式 accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) for epoch in range(21): for batch in range(n_batch): batch_xs, batch_ys = mnist.train.next_batch(batch_size) sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys}) acc = sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels}) if epoch % 2 == 0: print("Iter" + str(epoch) + ",Testing Accuracy" + str(acc))

結果如下

Iter0,Testing Accuracy8366.0
Iter2,Testing Accuracy8841.0
Iter4,Testing Accuracy8987.0
Iter6,Testing Accuracy9054.0
Iter8,Testing Accuracy9107.0
Iter10,Testing Accuracy9146.0
Iter12,Testing Accuracy9193.0
Iter14,Testing Accuracy9227.0
Iter16,Testing Accuracy9244.0
Iter18,Testing Accuracy9265.0
Iter20,Testing Accuracy9286.0

這個結果暫時不算很好,我們將逐漸對其進行改進

2、新增隱藏層

1、資料準備
2、準備好placeholder
3、初始化引數、權重
我們新增兩個隱藏層,分別有500和300個神經元,這樣包括輸入輸出層,總共4層神經網路
其中:
1)隱藏層初始化函式建議使用tf.truncated_normal()(截斷的隨機數)型別,而非前文的tf.zero()(初始化為0)型別
2)中間層的啟用函式,本文使用tanh(雙曲正切函式),建議使用ReLU函式或者Sigmoid函式,比較一個輸出結果
4、計算預測結果
5、計算損失值
6、初始化optimizer
7、指定迭代次數,並在session執行graph

程式碼如下

# -*- coding:utf-8  -*-

# 安裝資料集,第一次執行可能需要下載
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)

import tensorflow as tf

# 載入資料集
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)

# 每個批次送100張圖片
batch_size = 100
# 計算一共有多少個批次
n_batch = mnist.train.num_examples // batch_size

# 準備好placeholder
x = tf.placeholder(tf.float32, [None, 784])
y = tf.placeholder(tf.float32,[None, 10])

# 初始化引數、權重
# 1)隱藏層初始化函式建議使用tf.truncated_normal()(截斷的隨機數)型別,而非前文的tf.zero()(初始化為0)型別
# 2)中間層的啟用函式,本文使用tanh(雙曲正切函式),建議使用ReLU函式或者Sigmoid函式,比較一個輸出結果
# tf.truncated_normal() 函式從階段的正態分佈中輸出隨機值
# 函式原型為tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
# 其中stddev是正態分佈標準差,seed是一個生成隨機數的種子,那麼是操作的名字
W1 = tf.Variable(tf.truncated_normal([784, 500], stddev=0.1), name="W1")
b1 = tf.Variable(tf.zeros([500]) + 0.1, name='b1')
L1 = tf.nn.relu(tf.matmul(x, W1) + b1, name='L1')

W2 = tf.Variable(tf.truncated_normal([500, 300], stddev=0.1),name='W2')
b2 = tf.Variable(tf.zeros([300]) + 0.1, name='b2')
L2 = tf.nn.relu(tf.matmul(L1, W2) + b2, name='L2')

W3 = tf.Variable(tf.truncated_normal([300, 10], stddev=0.1), name='W3')
b3 = tf.Variable(tf.zeros([10]) + 0.1, name='b3')
# 計算預測結果
prediction = tf.nn.softmax(tf.matmul(L2,W3) + b3)

# 計算損失值
# 先使用二次代價函式
loss = tf.reduce_mean(tf.square(y - prediction))

# 初始化optimizer
# 梯度下降優化器,學習率建議給的稍大些
learning_rate = 0.2
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)

# 結果存放在一個布林型列表中
# tf.argmax(vector,1)意思是返回vector中最大值的索引號,如果vector是一個向量,那就返回一個值
# 如果是一個矩陣就返回一個向量,該向量每一維都是相應矩陣行的最大值元素的索引號
# 在這裡,argmax就是返回的就是向量中最大值(1)的位置,並進行比較,相同則返回1,反之為0
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))# 這裡輸出的矩陣裡面是truefalse
# 準確率
# tf.cast 是型別轉換函式
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    for epoch in range(21):
        for batch in range(n_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys})

        acc = sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels})
        if epoch % 2 == 0:
            print("Iter" + str(epoch) + ",Testing Accuracy" + str(acc))

經測試,使用relu函式的效果最好,能達到96左右的正確率;其次tanh,能達到95;最差是sigmoid。

3、進一步改進——方差代價函式&交叉熵代價函式

C表示代價函式,為簡便起見,以一個樣本為例,此時二次代價函式為:
這裡寫圖片描述
其中,y是我們期望的輸出,a是神經元實際的輸出:a = σ(z),z = wx + b
假如我們使用梯度下降法來調整權值引數大小,權值w和 偏置b 的梯度推導如下:
這裡寫圖片描述
其中,z表示神經元的輸入,σ表示啟用函式。w和b的梯度跟啟用函式的梯度成正比,啟用函式的梯度越大,w和b的大小調整得越快, 訓練收斂得越快。
假設我們的啟用函式是sigmoid函式:
這裡寫圖片描述
因為sigmoid的性質,導致σ·(z) 在z 取大部分值的時候會很小,這樣會使得w和b 的更新很慢.

為了克服這個問題,我們換個思路,在不改變啟用函式的情況下,改變代價函式,改為交叉熵代價函式:
這裡寫圖片描述
其中,y為期望的輸出,a為神經元實際輸出:a = σ(z), z = ∑Wj*Xj+b
同樣,權重w 和 偏置 b 的梯度如下:
這裡寫圖片描述
從上式可知,w、b的調整與σ·(z)無關,σ(z)-y 表示輸出值與實際值的誤差,當其誤差越大時,梯度越大,w、b調整的越快,訓練速度也越快,反之,則亦然,這正是我們想要的。

此外,交叉熵函式一般與s型函式(即sigmoid函式和tanh函式)組合適用。

步驟

1.資料準備
2.準備placeholder
3.初始化引數/權重
4.計算預測結果
5.計算損失值
這裡我們使用交叉熵函式替代二次代價函式

# 計算損失值
# 先使用二次代價函式
# loss = tf.reduce_mean(tf.square(y - prediction))
# 這裡我們使用交叉熵函式替代二次代價函式
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))

6.初始化optimizer
全域性程式碼

# -*- coding:utf-8  -*-

# 安裝資料集,第一次執行可能需要下載
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)

import tensorflow as tf

# 載入資料集
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)

# 每個批次送100張圖片
batch_size = 100
# 計算一共有多少個批次
n_batch = mnist.train.num_examples // batch_size

# 準備好placeholder
x = tf.placeholder(tf.float32, [None, 784])
y = tf.placeholder(tf.float32,[None, 10])

# 初始化引數、權重
# 1)隱藏層初始化函式建議使用tf.truncated_normal()(截斷的隨機數)型別,而非前文的tf.zero()(初始化為0)型別
# 2)中間層的啟用函式,本文使用tanh(雙曲正切函式),建議使用ReLU函式或者Sigmoid函式,比較一個輸出結果
# tf.truncated_normal() 函式從階段的正態分佈中輸出隨機值
# 函式原型為tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
# 其中stddev是正態分佈標準差,seed是一個生成隨機數的種子,那麼是操作的名字
W1 = tf.Variable(tf.truncated_normal([784, 500], stddev=0.1), name="W1")
b1 = tf.Variable(tf.zeros([500]) + 0.1, name='b1')
L1 = tf.nn.relu(tf.matmul(x, W1) + b1, name='L1')

W2 = tf.Variable(tf.truncated_normal([500, 300], stddev=0.1),name='W2')
b2 = tf.Variable(tf.zeros([300]) + 0.1, name='b2')
L2 = tf.nn.relu(tf.matmul(L1, W2) + b2, name='L2')

W3 = tf.Variable(tf.truncated_normal([300, 10], stddev=0.1), name='W3')
b3 = tf.Variable(tf.zeros([10]) + 0.1, name='b3')
# 計算預測結果
prediction = tf.nn.softmax(tf.matmul(L2,W3) + b3)

# 計算損失值
# 先使用二次代價函式
# loss = tf.reduce_mean(tf.square(y - prediction))
# 這裡我們使用交叉熵函式替代二次代價函式
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))

# 初始化optimizer
# 梯度下降優化器,學習率建議給的稍大些
learning_rate = 0.2
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)

# 結果存放在一個布林型列表中
# tf.argmax(vector,1)意思是返回vector中最大值的索引號,如果vector是一個向量,那就返回一個值
# 如果是一個矩陣就返回一個向量,該向量每一維都是相應矩陣行的最大值元素的索引號
# 在這裡,argmax就是返回的就是向量中最大值(1)的位置,並進行比較,相同則返回1,反之為0
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))# 這裡輸出的矩陣裡面是truefalse
# 準確率
# tf.cast 是型別轉換函式
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    for epoch in range(21):
        for batch in range(n_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys})

        acc = sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels})
        if epoch % 2 == 0:
            print("Iter" + str(epoch) + ",Testing Accuracy" + str(acc))

4、Optimizer優化器和Tensorboard

——前文中,我們將三層全連線神經網路的方差代價函式(二次代價函式)替換成交叉熵函式來完成MNIST資料的分類問題,最終迭代計算20次,準確率接近0.97,離我們預期的0.98甚至0.99還有差距。
這次主要做兩個修改:
1)選用合適的優化器進行梯度下降(參考
2)學習使用tensorboard

TensorFlow的優化器
Tensorflow中包含如下幾個優化器:
tf.train.GradientDescentOptimizer
tf.train.AdadeltaOptimizer
tf.train.AdagradOptimizer
tf.train.AdagradDAOptimizer
tf.train.MomentumOptimizer
tf.train.AdamOptimizer
tf.train.FtrlOptimizer
tf.train.ProximalGradientDescentOptimizer
tf.train.ProximalAdagradOptimizer
tf.train.RMSPropOptimizer

其中,
Momerntum:當前權值的改變受到上一次權值改變的影響,類似於小球向下滾動時帶上了慣性。這樣可以加快小球向下的速度。

NAG:在TF中跟Momentum合併在同一個函式tf.train.MomentumOptimizer中,可以通過引數配置啟用。在Momentun中小球會盲目地跟從下坡的梯度,容易發生錯誤,所以我們需要一個更聰明的小球,這個小球提取知道它要去哪兒,它還要知道走到坡地的時候熟讀慢下來而不是又衝上另一個坡,知道下一個位置大概在哪裡。從而我們可以提前計算下一個位置的梯度,然後使用到當前位置。

Adagrad:它是基於SGD(隨機最速下降法)的一種演算法,它的核心思想是對比較常見的資料基於它比較小的學習率去調整引數,對於比較罕見的資料基於它比較大的學習率去調整引數。它很適合應用於稀疏的資料集(比如一個圖片資料集,有10000張狗和貓的圖片,但只有100張大象的)。Adagrad主要優勢在於不需要人為調節學習率,它可以自動調節。但是其缺點在於當迭代次數增多,學習率將會越來越低最終趨於0.

RMSprop:借鑑了一些Adagrad的思想,不過這裡RMSprop只用到了前t-1次 梯度平方的均值加上當前梯度的平方的和再開方作為學習率的分母。這樣就不會出現學習率越來越低的問題,而且還能自己調節學習率,可以有一個比較好的效果。

Adadelta:我們甚至不需要設定一個預設學習率,在Adadelta不需要使用學習率也可以達到一個非常好的效果。

Adam:像Adadelta和RMSprop一樣,Adam會儲存之前衰減的平方梯度,同時它也會儲存之前衰減的梯度。經過一些處理之後再使用類似Adadelta和RMSprop的方式更新引數。

本文采用的AdamOptimizer,同時會控制學習率的衰減,一開始速度很快,當越接近終點速度越慢。

TensorFlow
——視覺化是深度學習神經網路開發、除錯。應用中極為重要的手段。當我們使用TensorFlow搭建深層神經網路時,我們希望能夠了解整個網路的結構,資訊是如何傳遞的,想了解每次訓練後權重值W與偏置值b是如何變化的,損失值、準確率的變化趨勢等待。
——使用Google的視覺化工具Tensorboard可以幫我們實現上述功能,它可以將模型訓練過程中的各種資料彙總起來儲存在日誌檔案裡,然後在指定的web端視覺化地展現這些資訊。

步驟

1、資料準備
2、準備placeholder
這次我們在placeholder中加入了name這項引數,這是為Tensorboard做準備
這裡為了剛才說的,實現學習率逐漸衰減的AdamOptimizer,這裡我們建一個lr變數,命名為learning_rate,初始值設為0.001

x = tf.placeholder(tf.float32, [None, 784], name='x_input')
y = tf.placeholder(tf.float32, [None, 10], name='y_input')
lr = tf.Variable(0.001, dtype=tf.float32, name='learning_rate')

3、初始化引數/權重

這裡對所有的權重和偏置也都命上名。

W1 = tf.Variable(tf.truncated_normal([784, 500], stddev=0.1), name='W1')
b1 = tf.Variable(tf.zeros([500]) + 0.1, name='b1')
L1 = tf.nn.tanh(tf.matmul(x, W1) + b1, name='L1')

W2 = tf.Variable(tf.truncated_normal([500, 300], stddev=0.1), name='W2')
b2 = tf.Variable(tf.zeros([300]) + 0.1, name='b2')
L2 = tf.nn.tanh(tf.matmul(L1, W2) + b2, name='L2')

W3 = tf.Variable(tf.truncated_normal([300, 10], stddev=0.1), name='W3')
b3 = tf.Variable(tf.zeros([10]) + 0.1, name='b3')

4、計算預測結果
5、計算損失值
6、初始化optimizer
這裡我們用 tf.train.AdamOptimizer() 替代 tf.train.GradientDescentOptimizer()

# learning_rate = 0.2
# optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimizer(loss)
optimizer = tf.train.AdamOptimizer(lr).minimize(loss)

# 結果存放在一個布林型列表中
correct_prediction = tf.equai(tf.argmax(y, 1), tf.argmax(prediction, 1))

# 求準確率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

7、指定迭代次數,並在session中執行graph
Tensorboard的視覺化需要建立一個graph,你想從這個graph中獲取某些資料的資訊,之後,我們使用tf.summary.FileWriter()將執行後輸出的資料檔案都儲存到本地磁碟(自己設定的檔案路徑)中。這裡選擇這個程式檔案的同目錄下,生成一個graph資料夾,其中又有個名為mnist的資料夾,生成的資料檔案將儲存在mnist資料夾中。

init = tf.global_variables_initializer()

with tf.Session() as sess:
     sess.run(init)
     writer = tf.summary.FileWriter('/graphs/mnist',sess.graph)

     for epoch in rage(21):
         sess.run(tf.assign(lr, 0.001 * (0.95 ** epoch)))
         # 這句話是說在實現每次迭代後,學習率逐漸衰減,在最初開始的0.001基礎上
         # 乘以0.95的迭代次數epoch次冪
         for batch in range(n_batch):
             batch_xs, batch_ys = mnist.train.next_batch(batch_size)
             sess.run(optimizer, feed_dict={x:batch_xs, y:batch_ys})

         rest_acc = sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels})
         learning_rate = sess.run(lr)
         if epoch % 2 ==0:
              print("Iter" + str(epoch) + ", Testing accuracy:" + str(test_acc) + ", Learning rate:" + str(learning_rate))
              # 每次輸出準確率和學習率

      writer.close() # 最後記得將寫入檔案操作關閉            

完整程式碼

# -*- coding:utf-8  -*-

# 安裝資料集,第一次執行可能需要下載
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)

import tensorflow as tf

# 載入資料集
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)

# 每個批次送100張圖片
batch_size = 100
# 計算一共有多少個批次
n_batch = mnist.train.num_examples // batch_size

# 準備好placeholder
x = tf.placeholder(tf.float32, [None, 784], name='x_input')
y = tf.placeholder(tf.float32,[None, 10], name='y_input')
lr = tf.Variable(0.001, dtype=tf.float32, name='learning_rate')

# 初始化引數、權重
# 1)隱藏層初始化函式建議使用tf.truncated_normal()(截斷的隨機數)型別,而非前文的tf.zero()(初始化為0)型別
# 2)中間層的啟用函式,本文使用tanh(雙曲正切函式),建議使用ReLU函式或者Sigmoid函式,比較一個輸出結果
# tf.truncated_normal() 函式從階段的正態分佈中輸出隨機值
# 函式原型為tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
# 其中stddev是正態分佈標準差,seed是一個生成隨機數的種子,那麼是操作的名字
W1 = tf.Variable(tf.truncated_normal([784, 500], stddev=0.1), name="W1")
b1 = tf.Variable(tf.zeros([500]) + 0.1, name='b1')
L1 = tf.nn.tanh(tf.matmul(x, W1) + b1, name='L1')

W2 = tf.Variable(tf.truncated_normal([500, 300], stddev=0.1),name='W2')
b2 = tf.Variable(tf.zeros([300]) + 0.1, name='b2')
L2 = tf.nn.tanh(tf.matmul(L1, W2) + b2, name='L2')

W3 = tf.Variable(tf.truncated_normal([300, 10], stddev=0.1), name='W3')
b3 = tf.Variable(tf.zeros([10]) + 0.1, name='b3')
# 計算預測結果
prediction = tf.nn.softmax(tf.matmul(L2,W3) + b3)

# 計算損失值
# 先使用二次代價函式
# loss = tf.reduce_mean(tf.square(y - prediction))
# 這裡我們使用交叉熵函式替代二次代價函式
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))

# 初始化optimizer
# 梯度下降優化器,學習率建議給的稍大些
# learning_rate = 0.2
# optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
optimizer = tf.train.AdamOptimizer(lr).minimize(loss)

# 結果存放在一個布林型列表中
# tf.argmax(vector,1)意思是返回vector中最大值的索引號,如果vector是一個向量,那就返回一個值
# 如果是一個矩陣就返回一個向量,該向量每一維都是相應矩陣行的最大值元素的索引號
# 在這裡,argmax就是返回的就是向量中最大值(1)的位置,並進行比較,相同則返回1,反之為0
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))# 這裡輸出的矩陣裡面是truefalse
# 準確率
# tf.cast 是型別轉換函式
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    writer = tf.summary.FileWriter('graphs/mnist/', sess.graph)

    for epoch in range(21):
        sess.run(tf.assign(lr, 0.001 * (0.95 ** epoch)))
        # 這句話是說在實現每次迭代後,學習率逐漸衰減,在最初開始的0.01基礎上
        # 乘以0.95的迭代次數epoch次冪
        for batch in range(n_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            sess.run(optimizer, feed_dict={x: batch_xs, y:batch_ys})

        test_acc = sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels})
        learning_rate = sess.run(lr)
        if epoch % 2 == 0:
            print("Iter" + str(epoch) + ",Testing Accuracy" + str(test_acc) + ", Learning rate:" + str(learning_rate))

    writer.close() # 最後記得關閉寫入檔案操作

執行結果

Iter0,Testing Accuracy9513.0, Learning rate:0.001
Iter2,Testing Accuracy9653.0, Learning rate:0.0009025
Iter4,Testing Accuracy9750.0, Learning rate:0.00081450626
Iter6,Testing Accuracy9754.0, Learning rate:0.0007350919
Iter8,Testing Accuracy9778.0, Learning rate:0.0006634204
Iter10,Testing Accuracy9795.0, Learning rate:0.0005987369
Iter12,Testing Accuracy9797.0, Learning rate:0.0005403601
Iter14,Testing Accuracy9804.0, Learning rate:0.000487675
Iter16,Testing Accuracy9814.0, Learning rate:0.00044012666
Iter18,Testing Accuracy9807.0, Learning rate:0.00039721432
Iter20,Testing Accuracy9816.0, Learning rate:0.00035848594

可以看到準確率已經升到了98.

記得中間我們做了一些使用tensorboard的準備工作。接下來我們就講下怎麼使用tensorboard。
這裡有個坑,就是在開啟tensorboard的時候,網上的方法一般是:
先在命令列輸入

tensorboard --logdir= D:/TensorFlow/graphs/mnist/ (這裡是存放資料的路徑,程式中定義的,不加引號)

然後過一會兒會生成一個埠,用谷歌會火狐開啟就可以看到圖
但實際上這樣操作只會顯示當前目錄沒有圖。
找了好多攻略,都不管用,最後發現一個辦法可以。
先在命令列中cd到你存放資料的資料夾的上一級資料夾。然後在這個目錄(比如說在D:/TensorFlow/graphs) 裡輸入

tensorboard --logdir= mnist/

再開啟他給的地址,就可以看到圖了。

5、 TensorBoard視覺化介面

前面我們在三層全連線神經網路中使用了學習率隨迭代次數增加而衰減的AdamOptimizer優化器來完成MN IST資料的分類問題,最終跌打計算20次,準確率超過0.98,同時掌握瞭如何寫入Graph資料檔案,並在Tensorboard檢視。

Tensorboard的資料形式

Tensorboard可以記錄與展示一下資料形式:
1)標量Scalar
2)圖片Imags
3)音訊Audio
4)計算圖Graph
5)資料分佈Distribution
6)直方圖Histograms
7)嵌入向量Embeddings

Tensorboard的視覺化過程

1)建立一個graph,你想從這個graph中獲取某些資料的資訊
2)確定要在graph中的那些節點放置summary operations以記錄資訊
使用 tf.summary.scallar記錄標量
使用tf.summary.histogram記錄資料的直方圖
使用tf.summary.distributuion記錄資料的的分佈圖
使用tf.summary.image記錄影象資料
。。。。
3)operations並不會去真的執行計算,除非你告訴他們需要去run,或者它被其他的需要run’的operation所依賴。而我們上一步建立的這些summary operations其實並不被其他節點依賴,因此,我們需要特地去執行所有的summary節點。但是一份程式很多這種節點一個個執行很麻煩,就可用tf.summary.merge_all去將所有summary節點合併成一個節點,只要執行這個節點,就能產生所有我們之前設定的summary data。
4)使用tf.summary.FileWriter將執行後輸出的資料都儲存到本地磁碟中
5)執行整個程式,並在命令列輸入執行tensorboard的指令,之後開啟web端可檢視視覺化的結果

tf.name_scope()函式

複雜的TensorFlow一般由數以千計的節點所構成的,所以難以以下全部看到,甚至無法用標準圖表工具來展示。為簡單起見,我們為op/tensor名劃定範圍,並且視覺化把該資訊用於在圖表中的節點上定義一個層級。預設情況下,只有頂層節點會顯示。

程式碼示例

1、資料準備

今天程式上來第一部分就發生變化,出現了新面孔,那就是定義了一個variable_summaries()函式,傳遞引數為var。
這個函式的作用是:
1)將傳遞過來的引數var進行求均值(mean)、標準差(stddev)、最大最小值(max、min)
2)用tf.summary.scalar()函式,分別對上述的幾個統計量(標量)進行記錄,同時記錄引數var的直方圖(tf.summary.histogram()函式實現)

在這裡大家發現了我用的tf.name_scope()函式,我在這裡建立一個名叫summaries的視覺化節點的層級,之後在Tensorboard中將會找到它。

# 安裝資料集,第一次執行可能需要下載
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)

import tensorflow as tf

# 載入資料集
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)

# 每個批次送100張圖片
batch_size = 100
# 計算一共有多少個批次
n_batch = mnist.train.num_examples // batch_size

def variable_summaries(var):
    with tf.name_scope('summaries'):
        mean = tf.reduce_mean(var)
        tf.summary.scalar('mean',mean)
        with tf.name_scope('stddev'):
            stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
        tf.summary.scalar('stddev',stddev)
        tf.summary.scalar('max', tf.reduce_max(var))
        tf.summary.scalar('min', tf.reduce_min(var))
        tf.summary.histogram('histogram', var)# 直方圖

2.準備好placeh

同樣,我用tf.name_scope()函式,建立了一個名叫input的視覺化節點的層級,這個節點層下包含x_input/y_input、learning_rate 三個子節點。

with tf.name_scope('input'):
    x = tf.placeholder(tf.float32, [None, 784], name='x_input')
    y = tf.placeholder(tf.float32,[None, 10], name='y_input')
    lr = tf.Variable(0.001, dtype=tf.float32, name='learning_rate')

3.初始化引數/權重
這裡對每個變數都做了同樣的操作,只不過這裡命名了3個層級的節點,同時對權重W1,W2,W3,偏置值b1,b2,b3進行variable_summaries()函式的呼叫,想具體瞭解這些引數在模型訓練中是如何變化的。

with tf.name_scope('layer'):
    with tf.name_scope('Input_layer'):
        with tf.name_scope('W1'):
            W1 = tf.Variable(tf.truncated_normal([784, 500], stddev=0.1), name="W1")
            variable_summaries(W1)
        with tf.name_scope('b1'):
            b1 = tf.Variable(tf.zeros([500]) + 0.1, name='b1')
            variable_summaries((b1))
        with tf.name_scope('L1'):
            L1 = tf.nn.tanh(tf.matmul(x, W1) + b1, name='L1')
    with tf.name_scope('Hidden layer'):
        with tf.name_scope('W2'):
            W2 = tf.Variable(tf.truncated_normal([500, 300], stddev=0.1),name='W2')
        with tf.name_scope('b2'):
            b2 = tf.Variable(tf.zeros([300]) + 0.1, name='b2')
        with tf.name_scope('L2'):
            L2 = tf.nn.tanh(tf.matmul(L1, W2) + b2, name='L2')
    with tf.name_scope('Output_layer'):
        with tf.name_scope('W3'):
            W3 = tf.Variable(tf.truncated_normal([300, 10], stddev=0.1), name='W3')
        with tf.name_scope('b3'):
            b3 = tf.Variable(tf.zeros([10]) + 0.1, name='b3')
        # 計算預測結果
        prediction = tf.nn.softmax(tf.matmul(L2,W3) + b3)

4.計算預測結果
5.計算損失值

with tf.name_scope('loss'):
    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))
    tf.summary.scalar('loss',loss)

6.初始化optimizer

with tf.name_scope('optimizer'):
    optimizer = tf.train.AdamOptimizer(lr).minimize(loss)

with tf.name_scope('train'):
    with tf.name_scope('correct_prediction'):
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))# 這裡輸出的矩陣裡面是truefalse

    with tf.name_scope('accuracy'):
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
        tf.summary.scalar('accuracy', accuracy)

7、指定迭代次數,並在session中執行graph

init = tf.global_variables_initializer()
merged = tf.summary.merge_all()
# 將所有的summary節點合併成一個節點,只要執行這個節點,就能產生所有我們之間設定的summary data

with tf.Session() as sess:
    sess.run(init)
    writer = tf.summary.FileWriter('graphs/mnist/', sess.graph)
    # 這個寫法是針對mac的,在win下生成的檔案讀不了?
    # writer = tf.summary.FileWriter('graphs/mnist/', tf.get_default_graph())

    for epoch in range(21):
        sess.run(tf.assign(lr, 0.001 * (0.95 ** epoch)))
        # 這句話是說在實現每次迭代後,學習率逐漸衰減,在最初開始的0.01基礎上
        # 乘以0.95的迭代次數epoch次冪
        for batch in range(n_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            # sess.run(optimizer, feed_dict={x: batch_xs, y:batch_ys})
            summary,_ = sess.run([merged, optimizer], feed_dict={x:batch_xs, y:batch_ys})
            # 這裡我們在tun的時候增加了merged,說明了之前我們設定的節點都不會執行
            # 在這裡run以後才會把結果反饋給summary
        writer.add_summary(summary, epoch)
        # 將每次迭代產生的summary寫入graph的資料檔案中,以便我們在tensorboard中顯示出
        test_acc = sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels})
        learning_rate = sess.run(lr)
        if epoch % 2 == 0:
            print("Iter" + str(epoch) + ",Testing Accuracy" + str(test_acc) + ", Learning rate:" + str(learning_rate))

    writer.close() # 最後記得關閉寫入檔案操作

後面就是和前面講的一樣,開啟tensorboard,可以看到自己的資料走勢圖,直方圖,等等。注意Graph 的變化,不再是前面看到的一大堆節點很混亂的樣子,而變成了簡單的幾個元件。將其開啟後還可以看到裡面的組織結構。

完整程式碼

# 安裝資料集,第一次執行可能需要下載
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)

import tensorflow as tf

# 載入資料集
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)

# 每個批次送100張圖片
batch_size = 100
# 計算一共有多少個批次
n_batch = mnist.train.num_examples // batch_size

def variable_summaries(var):
    with tf.name_scope('summaries'):
        mean = tf.reduce_mean(var)
        tf.summary.scalar('mean',mean)
        with tf.name_scope('stddev'):
            stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
        tf.summary.scalar('stddev',stddev)
        tf.summary.scalar('max', tf.reduce_max(var))
        tf.summary.scalar('min', tf.reduce_min(var))
        tf.summary.histogram('histogram', var)# 直方圖

# 準備好placeholder
with tf.name_scope('input'):
    x = tf.placeholder(tf.float32, [None, 784], name='x_input')
    y = tf.placeholder(tf.float32,[None, 10], name='y_input')
    lr = tf.Variable(0.001, dtype=tf.float32, name='learning_rate')

# 初始化引數、權重
# 1)隱藏層初始化函式建議使用tf.truncated_normal()(截斷的隨機數)型別,而非前文的tf.zero()(初始化為0)型別
# 2)中間層的啟用函式,本文使用tanh(雙曲正切函式),建議使用ReLU函式或者Sigmoid函式,比較一個輸出結果
# tf.truncated_normal() 函式從階段的正態分佈中輸出隨機值
# 函式原型為tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)
# 其中stddev是正態分佈標準差,seed是一個生成隨機數的種子,那麼是操作的名字
with tf.name_scope('layer'):
    with tf.name_scope('Input_layer'):
        with tf.name_scope('W1'):
            W1 = tf.Variable(tf.truncated_normal([784, 500], stddev=0.1), name="W1")
            variable_summaries(W1)
        with tf.name_scope('b1'):
            b1 = tf.Variable(tf.zeros([500]) + 0.1, name='b1')
            variable_summaries(b1)
        with tf.name_scope('L1'):
            L1 = tf.nn.tanh(tf.matmul(x, W1) + b1, name='L1')
    with tf.name_scope('Hidden_layer'):
        with tf.name_scope('W2'):
            W2 = tf.Variable(tf.truncated_normal([500, 300], stddev=0.1),name='W2')
            variable_summaries(W2)
        with tf.name_scope('b2'):
            b2 = tf.Variable(tf.zeros([300]) + 0.1, name='b2')
            variable_summaries(b2)
        with tf.name_scope('L2'):
            L2 = tf.nn.tanh(tf.matmul(L1, W2) + b2, name='L2')
    with tf.name_scope('Output_layer'):
        with tf.name_scope('W3'):
            W3 = tf.Variable(tf.truncated_normal([300, 10], stddev=0.1), name='W3')
            variable_summaries(W3)
        with tf.name_scope('b3'):
            b3 = tf.Variable(tf.zeros([10]) + 0.1, name='b3')
            variable_summaries(b3)
        # 計算預測結果
        prediction = tf.nn.softmax(tf.matmul(L2,W3) + b3)

# 計算損失值
# 先使用二次代價函式
# loss = tf.reduce_mean(tf.square(y - prediction))
# 這裡我們使用交叉熵函式替代二次代價函式
with tf.name_scope('loss'):
    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))
    tf.summary.scalar('loss',loss)

# 初始化optimizer
# 梯度下降優化器,學習率建議給的稍大些
# learning_rate = 0.2
# optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
with tf.name_scope('optimizer'):
    optimizer = tf.train.AdamOptimizer(lr).minimize(loss)

# 結果存放在一個布林型列表中
# tf.argmax(vector,1)意思是返回vector中最大值的索引號,如果vector是一個向量,那就返回一個值
# 如果是一個矩陣就返回一個向量,該向量每一維都是相應矩陣行的最大值元素的索引號