本次對mnist資料集采用單隐層的BP神經網絡,在對參數初始化,激活函數,學習率,正則系數選擇,隐層神經元數量選擇,随機采樣樣本數量進行調優後,模型在測試集上的正确率可以達到98%。
1、 參數初始化方式
首先調優w和b的初始化,對比了0矩陣指派tf.zero,均值和方差為0的正太分布指派tf.random_normal,發現随機指派可以收斂速度更快更好,故而選擇了随機指派。
2、 激活函數
在選擇0.3作為學習率時,sigmoid最慢,50k時僅0.97,到200k步時準确率才達到0.9722;而relu較快但正确率在50k時時0.978左右,selu在50k就可以達到0.9804
三種常用激活函數的特點
使用不同模型在minist測試集上,學習率取0.3時,正确率随步數變化 | |||
步數(k步) | sigmoid | relu | selu |
5 | 0.9426 | 0.9491 | 0.954 |
10 | 0.9641 | 0.9687 | 0.9715 |
15 | 0.9668 | 0.9796 | 0.9748 |
20 | 0.9618 | 0.9827 | 0.971 |
25 | 0.9647 | 0.9833 | 0.977 |
30 | 0.9657 | 0.9834 | 0.979 |
40 | 0.9689 | 0.984 | 0.9814 |
50 | 0.969 | 0.9827 | 0.9814 |
60 | 0.9701 | 0.9827 | 0.981 |
80 | 0.9703 | 0.9827 | 0.9813 |
100 | 0.9705 | 0.9828 | 0.981 |
200 | 0.9722 | 0.984 | 0.9804 |
本次對三種不同的模型,其中relu的性能最好0.984,selu其次,sigmoid最差也最慢,而本文選擇暫選擇了selu作為進一步的資料探索。
3、 學習率
3.1采用固定學習率
首先對比了0.1、0.2、0.25、0.3、0.35、0.4、0.45、0.5、0.7、0.9在計算收斂,此處計算50k步,結果顯示learn_rate=0.3-0.4時效果不錯。
3.2采用可衰減學習率
考察了學習率衰減的效果,對比了學習率在不同衰減速率下的效果,結果顯示當學習率取0.4時,模型的收斂速度與準确率較好,其在200k步左右可以達到最高進度。故而選擇帶衰減率的學習率,使得學習率在20k步時前保持0.4,随後開始衰減。
4、 正則參數
通過對比不同正則參數對訓練集和測試集上準确率造成的影響,後發現需要将模型訓練收斂後才能判斷參數是否适合,本次調優訓練5k步,進行觀測。
判斷的标準時,正則對應訓練集的正确率需要達到100%,在此間選擇測試集上正确率最高的,本次調優選擇的正則參數是0.0004.
5、 隐層神經元數量
曆遍100~2000區域,訓練100k步後,選擇了神經元數量=1200
6、 對min_batch進行調優
在曆遍100~1000的區域,訓練100k步後選擇了神經元數量=550
defTrain(batch_size=550,n1=1000,learn_rate_0=0.4,learn_rate_reduce=0.00001,regular_rate=0.0004,steps=10000,plot=False):
#此為第一層資料輸入層
w1=tf.Variable(tf.random_normal([784,n1]))
b1=tf.Variable(tf.random_normal([n1]))
logits_1=tf.matmul(x,w1)+b1
keep_prob = tf.placeholder(tf.float32)
logits_1_drop = tf.nn.dropout(logits_1, keep_prob)
h1=tf.nn.selu(logits_1)
#單層神經網絡,相當于一個資料784維,其分10個神經元輸出故而每個神經元的權重w都有784個
w2 = tf.Variable(tf.random_normal([n1,10]))
b2 = tf.Variable(tf.random_normal([10]))
y= tf.matmul(h1, w2) + b2
#Define loss and optimizer
#定義我們的ground truth 占位符
y_ = tf.placeholder(tf.float32, [None, 10])
#使用正則函數
# L2_loss=regular_rate*(tf.nn.l2_loss(w1)+tf.nn.l2_loss(b1)+tf.nn.l2_loss(w2)+tf.nn.l2_loss(b2))
tv = tf.trainable_variables()
regularization_cost = regular_rate* tf.reduce_sum([ tf.nn.l2_loss(v) forv in tv ])
#接下來我們計算交叉熵,注意這裡不要使用注釋中的手動計算方式,而是使用系統函數。
#另一個注意點就是,softmax_cross_entropy_with_logits的logits參數是**未經激活的wx+b**
#此處定義損失函數
cross_entropy =tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_,logits=y)+regularization_cost)
learn_rate=learn_rate_0*math.exp(-1*learn_rate_reduce*1)
#生成一個訓練step
train_step =tf.train.GradientDescentOptimizer(learn_rate).minimize(cross_entropy)
sess = tf.Session()
init_op = tf.global_variables_initializer()
sess.run(init_op)
#在這裡我們仍然調用系統提供的讀取資料,為我們取得一個batch。
#然後我們運作3k個step(5 epochs),對權重進行優化。
acc_dict_train={}
acc_dict={} #用于存儲一次運作中acc vs step
for step in range(steps):
#生成可衰減的學習率
learn_rate=learn_rate_0*math.exp(-1*learn_rate_reduce*step)
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
sess.run(train_step, feed_dict={x: batch_xs, y_:batch_ys,keep_prob:0.5})
if step%500==0:
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
#擷取測試集上的accuracy
acc=sess.run(accuracy, feed_dict={x: mnist.test.images,
y_: mnist.test.labels,keep_prob:1})
acc_dict[step]=acc
#擷取訓練集上的accuracy
acc_train=sess.run(accuracy, feed_dict={x: mnist.train.images,
y_:mnist.train.labels,keep_prob:1})
acc_dict_train[step]=acc_train
if plot==True:
print(step,round(step/steps*100,1),'%',acc,learn_rate)
#将accuracy随step變化繪制出來
if plot==True:
plt.figure(figsize=(8,4))
plt.plot(acc_dict.keys(),acc_dict.values())
plt.plot(acc_dict_train.keys(),acc_dict_train.values())
plt.xlabel('step')
plt.ylabel('accuracy')
plt.show()
best_value=max(acc_dict.values())
best_key=list(acc_dict.keys())[list(acc_dict.values()).index(best_value)]
print('Test_best_accuracy',best_key,best_value)
best_value_train=max(acc_dict_train.values())
best_key_train=list(acc_dict_train.keys())[list(acc_dict_train.values()).index(best_value_train)]
print('Train_best_accuracy',best_value_train,best_key_train)
# Test trained model
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
acc=sess.run(accuracy, feed_dict={x: mnist.test.images,
y_:mnist.test.labels,keep_prob:1})
return(acc,acc_train)