純乾貨-手把手優化神經網路—MNIST數字識別進階
這一章我們把前兩章介紹的優化方法應用在我們的訓練模型V1上(參考機器學習實戰—MNIST手寫體數字識別 ),看看如何使用簡單的單隱藏層全連線神經網路提高準確率。話不多說直接開幹。
載入TensorFlow和MNIST資料集
import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
訓練主程式
隨著工程量的上升,我們儘量把需要重複使用以及功能獨立的部分分開存放,以便於增加程式碼的可讀性,方便debug,以及今後的維護。
def main_train(mnist): x = tf.placeholder(tf.float32, [None, INPUT_NODE]) y_ = tf.placeholder(tf.float32, [None, OUTPUT_NODE]) ...
同樣的,我們需要宣告一些變數,來代表經常使用的引數,比如:我們用INPUT_NODE代表輸入資料的大小784,OUTPUT_NODE代表輸出結果的大小10。比較好的習慣是儘量不要在程式碼中直接使用具體的數字,字串等,而是通過預先宣告的變數來賦值。這有利於增加程式碼的可讀性,同時幫助避免不小心的疏忽導致這些值在編寫時出差錯。
INPUT_NODE = 784# 輸入節點數 OUTPUT_NODE = 10# 輸出節點數 LAYER1_NODE = 500# 隱藏層節點數
隱藏層引數初始化
利用tf.truncated_normal 生成截斷正態分佈的隨機值,標準差為0.1,作為權重
利用tf.constant生成值為0.1的常數引數作為變差值
weights1 = tf.Variable(tf.truncated_normal([INPUT_NODE, LAYER1_NODE], stddev=0.1)) biases1 = tf.Variable(tf.constant(0.1, shape=[LAYER1_NODE]))
輸出層引數初始化
weights2 = tf.Variable(tf.truncated_normal([LAYER1_NODE, OUTPUT_NODE], stddev=0.1)) biases2 = tf.Variable(tf.constant(0.1, shape=[OUTPUT_NODE]))
前向傳播計算
我們用此方程計算從輸入到輸出。對隱藏層使用ReLU啟用函式,以去除線性化
def forward_pass(input_tensor, weights1, biases1, weights2, biases2): ayer1 = tf.nn.relu(tf.matmul(input_tensor, weights1) + biases1) return tf.matmul(layer1, weights2) + biases2
這樣的話y就是我們的計算結果:
y = inference(x, weights1, biases1, weights2, biases2)
滑動平均類
首先我們要再宣告一些變數將在訓練中使用,最好是在檔案的開始處,把所有需要宣告的變數放在一起
LEARNING_RATE_BASE = 0.8 LEARNING_RATE_DECAY = 0.99 REGULARAZTION_RATE = 0.0001 TRAINING_STEPS = 5000 MOVING_AVERAGE_DECAY = 0.99
倘若我們要使用滑動平均模型代替單一點取值,則提供一個滑動平均類用於計算
# trainable=False 表示該變數不需要訓練,global_step代表一共需要訓練的輪數 global_step = tf.Variable(0, trainable=False) # MOVING_AVERAGE_DECAY 為衰減率,用以控制模型更新速度,一般設定為非常接近1的值,容如0.9999 variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step) # 在所有可以訓練的引數變數上使用平均滑動模型 variables_averages_op = variable_averages.apply(tf.trainable_variables())
前向傳播函式:
def forward_pass(input_tensor, avg_class, weights1, biases1, weights2, biases2): layer1 = tf.nn.relu(tf.matmul(input_tensor, avg_class.average(weights1)) + avg_class.average(biases1)) return tf.matmul(layer1, avg_class.average(weights2)) + avg_class.average(biases2)
輸出為
average_y = inference(x, variable_averages, weights1, biases1, weights2, biases2)
損失函式
我們使用交叉熵和正則化共同作為損失函式。交叉熵代表預測值和實際值之間的損失函式,正則化函式則是計算模型的正則化損失,二者之和用來衡量整個模型的損失函式。
# 交叉熵 cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=average_y, labels=tf.argmax(y_, 1)) cross_entropy_mean = tf.reduce_mean(cross_entropy) #正則化 regularizer = tf.contrib.layers.l2_regularizer(REGULARAZTION_RATE) regularaztion = regularizer(weights1) + regularizer(weights2) #最終損失函式 loss = cross_entropy_mean + regularaztion
衰減學習率
如上一章所說,我們希望學習率從一個較大的值開始,然後隨著迭代的進行而衰減,這樣有利於我們剛開始較快速的到達一個較優解,然後慢慢接近最優解。(參考優化演算法-梯度下降,反向傳播,學習率 )
learning_rate = tf.train.exponential_decay( LEARNING_RATE_BASE, global_step, mnist.train.num_examples / BATCH_SIZE, LEARNING_RATE_DECAY, staircase=True)
引數優化
利用梯度下降優化損失函式;使用tf.group同時更新反向傳播過程中的引數,以及買一個引數的滑動平均值
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step) train_op = tf.group(train_step, variables_averages_op)
計算正確率
這裡和之前的一樣,就直接過了。
correct_prediction = tf.equal(tf.argmax(average_y, 1), tf.argmax(y_, 1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
建立Session開始訓練
with tf.Session() as sess: # 初始化引數變數 tf.global_variables_initializer().run() # 定義輸入資料,分為訓練集和測試集 validate_feed = {x: mnist.validation.images, y_: mnist.validation.labels} test_feed = {x: mnist.test.images, y_: mnist.test.labels} for i in range(TRAINING_STEPS): # 每訓練一千次,列印一次在訓練集中的正確率 if i % 1000 == 0: validate_acc = sess.run(accuracy, feed_dict=validate_feed) print("After %d training step(s), validation accuracy using average model is %g " % (i, validate_acc)) # 更新下一個batch,開始訓練 xs,ys=mnist.train.next_batch(BATCH_SIZE) sess.run(train_op, feed_dict={x:xs,y_:ys}) # 訓練完成後,使用測試集進行測試 test_acc=sess.run(accuracy,feed_dict=test_feed) print(("After %d training step(s), test accuracy using average model is %g" %(TRAINING_STEPS, test_acc)))
執行結果
除了jupyter notebook, 我們也可以直接執行python檔案。最終的測試結果會在98.4%左右,遠遠好於我們之前的91%的準確率。而這個模型僅僅是加了一層隱藏層,並且使用的最簡單的全連線神經網路結構。這就是深度學習在這次人工智慧浪潮中大放異彩的原因。大家可以任意改變引數,嘗試新的組合,試一試也許會有更高的準確率。
下一章我們會開始介紹卷積神經網路,並再一次使用MNIST作為案例,看CNN如何輕鬆達到99%以上的準確率。歡迎大家關注我們以便獲得及時的更新,歡迎留言,一起學習~