1. 程式人生 > >深度學習框架TensorFlow學習與應用(四)——擬合問題、優化器

深度學習框架TensorFlow學習與應用(四)——擬合問題、優化器

一、擬合

1)迴歸問題:

這裡寫圖片描述

過擬合儘量去通過每一個樣本點,誤差為零。假如有一個新的樣本點:

這裡寫圖片描述

會發現過擬合的偏差會很大。

2)分類問題:

這裡寫圖片描述

同樣的當得到新的樣本點後,過擬合的錯誤率可能會提高。

3)防止過擬合:

1.增加資料集

2.正則化方法,在代價函式後面加一個正則項

這裡寫圖片描述

3.Dropout:訓練時,在每一次迭代時使得一些神經元工作,一些神經元不工作。測試時再使用所有的神經元。

這裡寫圖片描述

4)使用Dropout避免過擬合:

例如:建立一個神經網路,2000個神經元的隱藏層,後面又是2000個神經元的隱藏層,之後是1000個神經元的隱藏層,最後是10個輸出層。用來進行前部分的MINST資料集分類訓練。

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
#載入資料集
mnist=input_data.read_data_sets("D:\BaiDu\MNIST_data",one_hot=True)

#每個批次的大小
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])#標籤 keep_prob=tf.placeholder(tf.float32) #建立一個的神經網路,2000個神經元的隱藏層,後面又是2000個神經元的隱藏層,只有是1000個神經元的隱藏層,最後是10個輸出層 W1=tf.Variable(tf.truncated_normal([784,2000],stddev=0.1)) b1=tf.Variable(tf.zeros([2000])+0.1) L1=tf.nn.tanh(tf.matmul(x,W1)+b1) L1_drop=tf.nn.dropout(L1,keep_prob) W2=tf.Variable(tf.truncated
_normal([2000,2000],stddev=0.1)) b2=tf.Variable(tf.zeros([2000])+0.1) L2=tf.nn.tanh(tf.matmul(L1_drop,W2)+b2) L2_drop=tf.nn.dropout(L2,keep_prob) W3=tf.Variable(tf.truncated_normal([2000,1000],stddev=0.1)) b3=tf.Variable(tf.zeros([1000])+0.1) L3=tf.nn.tanh(tf.matmul(L2_drop,W3)+b3) L3_drop=tf.nn.dropout(L3,keep_prob) W4=tf.Variable(tf.truncated_normal([1000,10],stddev=0.1)) b4=tf.Variable(tf.zeros([10])+0.1) prediction=tf.nn.softmax(tf.matmul(L3_drop,W4)+b4) #二次代價函式 #loss=tf.reduce_mean(tf.square(y-prediction)) loss=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=prediction)) #使用梯度下降法 train_step=tf.train.GradientDescentOptimizer(0.2).minimize(loss) #初始化變數 init=tf.global_variables_initializer() #結果存放在一個布林型列表中 correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))#比較兩個引數大小,相同為true。argmax返回一維張量中最大的值所在的位置 #求準確率 accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))#將布林型轉化為32位浮點型,再求一個平均值。true變為1.0,false變為0。 with tf.Session() as sess: sess.run(init) for epoch in range(31): for batch in range(n_batch): batch_xs,batch_ys=mnist.train.next_batch(batch_size) sess.run(train_step,feed_dict={x:batch_xs,y:batch_ys,keep_prob:1.0})#keep_prob為1.0表示所有的神經元都是工作的 test_acc=sess.run(accuracy,feed_dict={x:mnist.test.images,y:mnist.test.labels,keep_prob:1.0})#測試資料算出來的準確率 train_acc=sess.run(accuracy,feed_dict={x:mnist.train.images,y:mnist.train.labels,keep_prob:1.0})#訓練集算出的準確率 print("Iter "+str(epoch)+",Testing Accuracy "+str(test_acc)+",Training Accuracy "+str(train_acc))

由於神經元較多,執行會很慢很慢。。。。。
結果是:

Iter 0,Testing Accuracy 0.9469,Training Accuracy 0.956455
Iter 1,Testing Accuracy 0.9567,Training Accuracy 0.974745
Iter 2,Testing Accuracy 0.9617,Training Accuracy 0.982473
Iter 3,Testing Accuracy 0.9632,Training Accuracy 0.986273
Iter 4,Testing Accuracy 0.9654,Training Accuracy 0.988509
Iter 5,Testing Accuracy 0.9679,Training Accuracy 0.989818
Iter 6,Testing Accuracy 0.9676,Training Accuracy 0.991
Iter 7,Testing Accuracy 0.9675,Training Accuracy 0.991655
Iter 8,Testing Accuracy 0.9681,Training Accuracy 0.992164
Iter 9,Testing Accuracy 0.9688,Training Accuracy 0.992509
Iter 10,Testing Accuracy 0.968,Training Accuracy 0.993018
Iter 11,Testing Accuracy 0.9692,Training Accuracy 0.993255
Iter 12,Testing Accuracy 0.968,Training Accuracy 0.993527
Iter 13,Testing Accuracy 0.9688,Training Accuracy 0.993745
Iter 14,Testing Accuracy 0.9699,Training Accuracy 0.994018
Iter 15,Testing Accuracy 0.9697,Training Accuracy 0.994109
Iter 16,Testing Accuracy 0.9693,Training Accuracy 0.9942
Iter 17,Testing Accuracy 0.9695,Training Accuracy 0.994345
Iter 18,Testing Accuracy 0.9692,Training Accuracy 0.9944
Iter 19,Testing Accuracy 0.9696,Training Accuracy 0.994436
Iter 20,Testing Accuracy 0.9704,Training Accuracy 0.994527
Iter 21,Testing Accuracy 0.9704,Training Accuracy 0.994582
Iter 22,Testing Accuracy 0.97,Training Accuracy 0.994727
Iter 23,Testing Accuracy 0.9698,Training Accuracy 0.994764
Iter 24,Testing Accuracy 0.97,Training Accuracy 0.994855
Iter 25,Testing Accuracy 0.9701,Training Accuracy 0.994891
Iter 26,Testing Accuracy 0.9705,Training Accuracy 0.995036
Iter 27,Testing Accuracy 0.9707,Training Accuracy 0.995145
Iter 28,Testing Accuracy 0.9707,Training Accuracy 0.995273
Iter 29,Testing Accuracy 0.9705,Training Accuracy 0.995364
Iter 30,Testing Accuracy 0.9705,Training Accuracy 0.9954

之後使用Dropout:

sess.run(train_step,feed_dict={x:batch_xs,y:batch_ys,keep_prob:0.7})

得到:

Iter 0,Testing Accuracy 0.9179,Training Accuracy 0.912891
Iter 1,Testing Accuracy 0.9328,Training Accuracy 0.9284
Iter 2,Testing Accuracy 0.9344,Training Accuracy 0.935255
Iter 3,Testing Accuracy 0.9409,Training Accuracy 0.940891
Iter 4,Testing Accuracy 0.9439,Training Accuracy 0.944909
Iter 5,Testing Accuracy 0.9471,Training Accuracy 0.949964
Iter 6,Testing Accuracy 0.9499,Training Accuracy 0.952018
Iter 7,Testing Accuracy 0.9502,Training Accuracy 0.953527
Iter 8,Testing Accuracy 0.9548,Training Accuracy 0.957055
Iter 9,Testing Accuracy 0.9563,Training Accuracy 0.958418
Iter 10,Testing Accuracy 0.9566,Training Accuracy 0.959309
Iter 11,Testing Accuracy 0.958,Training Accuracy 0.961364
Iter 12,Testing Accuracy 0.9593,Training Accuracy 0.962527
Iter 13,Testing Accuracy 0.96,Training Accuracy 0.964055
Iter 14,Testing Accuracy 0.9607,Training Accuracy 0.965745
Iter 15,Testing Accuracy 0.9622,Training Accuracy 0.966818
Iter 16,Testing Accuracy 0.9624,Training Accuracy 0.967655
Iter 17,Testing Accuracy 0.9641,Training Accuracy 0.968564
Iter 18,Testing Accuracy 0.964,Training Accuracy 0.969564
Iter 19,Testing Accuracy 0.9633,Training Accuracy 0.969945
Iter 20,Testing Accuracy 0.9661,Training Accuracy 0.971182
Iter 21,Testing Accuracy 0.9664,Training Accuracy 0.972127
Iter 22,Testing Accuracy 0.9682,Training Accuracy 0.972709
Iter 23,Testing Accuracy 0.968,Training Accuracy 0.973145
Iter 24,Testing Accuracy 0.9662,Training Accuracy 0.974345
Iter 25,Testing Accuracy 0.9695,Training Accuracy 0.974436
Iter 26,Testing Accuracy 0.9689,Training Accuracy 0.975164
Iter 27,Testing Accuracy 0.9689,Training Accuracy 0.9756
Iter 28,Testing Accuracy 0.9699,Training Accuracy 0.976091
Iter 29,Testing Accuracy 0.9696,Training Accuracy 0.976545
Iter 30,Testing Accuracy 0.9719,Training Accuracy 0.977236

可以看出:

使用Dropout後,模型的收斂速度變慢,準確率上升的速度慢。那麼為什麼還要使用Dropout呢?通過對比兩次的測試準確率和訓練準確率,可以看到,沒有使用Dropout的方法測試準確率和訓練準確率相差比較大,這就是過擬合的問題,使用了Dropout就可以進行優化。另外,本部分提供的例子並沒有很好的體現出Dropout的優勢,兩者的準確率的對比不明顯,如果使用大型卷積神經網路進行樣本訓練,結果會更明顯。

二、優化器

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

各種優化器對比:
標準梯度下降法:標準梯度下降先計算所有樣本彙總誤差,然後根據總誤差來更新權值。
隨機梯度下降法:隨機梯度下降隨機抽取一個樣本來計算誤差,然後更新權值。
批量梯度下降法:批量梯度下降算是一種折中的方案,從總樣本中選取一個批次(比如一共有10000個樣本,隨機選取100個樣本作為一個batch),然後計算這個batch的總誤差,根據總誤差來更新權值。

梯度下降法執行的方式

接下來具體講一下幾個優化器:

W:要訓練的引數

J(W):代價函式

這裡寫圖片描述:代價函式的梯度

這裡寫圖片描述:學習率

1)SGD(隨機梯度下降法):

這裡寫圖片描述

2)Momentum:

這裡寫圖片描述

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

3)NAG(Nesterov accelerated gradient):

這裡寫圖片描述

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

4)Adagrad:

這裡寫圖片描述

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

5)RMSprop:
RMS(Root Mean Square)是均方根的縮寫。

這裡寫圖片描述

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

6)Adadelta:

這裡寫圖片描述

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

7)Adam:

這裡寫圖片描述

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

8)舉例:

更改學習率、優化器種類、迭代次數、神經元等對比一下。

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
#載入資料集
mnist=input_data.read_data_sets("D:\BaiDu\MNIST_data",one_hot=True)

#每個批次的大小
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.nn.softmax_cross_entropy_with_logits(labels=y,logits=prediction))
#使用優化器
#train_step=tf.train.GradientDescentOptimizer(0.2).minimize(loss)
train_step=tf.train.AdamOptimizer(0.001).minimize(loss)
#初始化變數
init=tf.global_variables_initializer()

#結果存放在一個布林型列表中
correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))#比較兩個引數大小,相同為true。argmax返回一維張量中最大的值所在的位置
#求準確率
accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))#將布林型轉化為32位浮點型,再求一個平均值。true變為1.0,false變為0。

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(train_step,feed_dict={x:batch_xs,y:batch_ys})

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

結果:

Iter 0,Testing Accuracy 0.8988
Iter 1,Testing Accuracy 0.9125
Iter 2,Testing Accuracy 0.916
Iter 3,Testing Accuracy 0.919
Iter 4,Testing Accuracy 0.9221
Iter 5,Testing Accuracy 0.9227
Iter 6,Testing Accuracy 0.9271
Iter 7,Testing Accuracy 0.9269
Iter 8,Testing Accuracy 0.9274
Iter 9,Testing Accuracy 0.9282
Iter 10,Testing Accuracy 0.929
Iter 11,Testing Accuracy 0.9291
Iter 12,Testing Accuracy 0.9304
Iter 13,Testing Accuracy 0.9288
Iter 14,Testing Accuracy 0.9302
Iter 15,Testing Accuracy 0.9304
Iter 16,Testing Accuracy 0.93
Iter 17,Testing Accuracy 0.9315
Iter 18,Testing Accuracy 0.9311
Iter 19,Testing Accuracy 0.9321
Iter 20,Testing Accuracy 0.9311

可以看出,同之前使用梯度下降法相比,使用Adam的收斂性和準確率更好。