Tensorflow的應用(三)

         主要是兩部分內容:代價函數和優化器

一、代價函數

1、二次代價函數

      二次代價函數計算公式如下:

                         

       其中,其中, C表示代價 函數 ,x表示樣本, y表示實際值, 表示實際值, 表示實際值, a表示輸出值, 表示輸出值, n表示樣本的總數。爲簡單起見 表示樣本的總數。爲簡單起見 表示樣本的總數。爲簡單起見 表示樣本的總數。爲簡單起見 表示樣本的總數。爲簡單起見 ,同樣一個本爲例進行說明,此時二次代價函數:


其中,a=σ(z), z=∑W a=σ(z), σ()是激活函數

       假如我們使用梯度下降法 (Gradient descent) (Gradient descent) (Gradient descent) (Gradient descent) (Gradient descent) 來調整權值 參數的大小,w和偏置 和偏置 b的梯度推導 的梯度推導 的梯度推導如下:

                                        

       其中, z表示神經元的輸入, σ表示激活函數。 w和b的梯度跟激活函數成正比,梯度越大, w和b的大小調整得越快。

       假設我們的激活函數是sigmoid函數,假設目標值是求最小損失,離目標較遠的時候,梯度下降速度較慢,離目標較近時,梯度下降較快,這是不合理的,所以在使用激活函數爲sigmoid函數的情況下,二次代價函數不適合。

2、交叉熵代價函數

其公式如下所示:

                     

其中, C表示代價 函數 ,x表示樣本, y表示實際值, a表示輸出值, n表示樣本的總數。





       權值和偏置值的調整與無關,另外,梯度公式中的表示輸出值與實際值的誤差。所以當誤差越大時,梯度就越大,參數w和b的調整越快。如果輸出神經元是線性的,那麼二次代價函數就是一種合適的選擇。如果輸出神經元是S型函數,那麼比較適合用交叉熵代價函數。

3、對數似然函數

        對數釋然函常用來作爲 softmax 迴歸的代價函數,如果輸出層神經元是sigmoid函數,可以採用交叉熵代價函數,而深度學習中更普遍的做法是將softmax作爲最後一層,此時常用的代價函數是對數似然代價函數。

       對數似然代價函數與softmax的組合和交叉熵與sigmoid函數的組合非常相似。對數似然代價函數在二分類時可以簡化爲交叉熵代價函數的形式。

        tf.sigmoid_cross_entropy_with_logits表示跟sigmoid搭配使用的交叉熵, tf.softmax_cross_entropy_with_logits表示跟softmax搭配使用的交叉熵

4、解決過擬合問題

(1)增加數據集

(2)正則化方法,有L1正則化和L2正則化,就是在代價函數中加入L1正則項和L2正則項,L1正則化是全部權重的絕對值平均,L2正則化是全部權重的均方,某些神經元的權重會被設置得特別小,甚至接近0,以減小過擬合情況。

(3)dropout方法,就是每次訓練時,每層隱藏層只允許部分神經元工作。

二、優化器

1、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

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

3、常用的幾種優化器介紹

(1)SGD

W =W−η⋅∇WJ(W;x(i);y(i))

(2) Momentun

γ:動力,通常設置爲0.9
vt = γvt−1 + η∇WJ(W)
W = W−vt
當前權值的改變會受到上一次權值改變的影響,類似於小球向下滾動的時候帶上了慣性。這樣可以加快小球的向下的速度。

(3)NAG

vt = γvt−1 + η∇WJ(W−γvt−1)
W = W−vt

       NAG在TF中跟Momentum合併在同一個函數tf.train.MomentumOptimizer中,可以通過參數配置啓用。
在Momentun中小球會盲目地跟從下坡的梯度,容易發生錯誤,所以我們需要一個更聰明的小球,這個小球提前知道它要去哪裏,它還要知道走到坡底的時候速度慢下來而不是又衝上另一個坡。γvt−1會用來修改W的值,計算W−γvt−1可以表示小球下一個位置大概在哪裏。從而我們可以提前計算下一個位置的梯度,然後使用到當前位置。

(4)Adagrad

i:代表第i個分類
t:代表出現次數
ϵ:的作用是避免分母爲0,取值一般爲1e-8
η:取值一般爲0.01
gt,i = ∇WJ(Wi)

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

(5)RMSprop

RMS(Root Mean Square)是均方根的縮寫。
γ:動力,通常設置爲0.9
η:取值一般爲0.001
E[g2]t:表示前t次的梯度平方的平均值
gt= ∇WJ(W)
E[g2]t= γE[g2]t-1+ (1-γ)g
2t


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

(6)Adadelta


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

(7) Adam:


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

三、代碼實例

      依然是tensorflow應用(二)中的手寫識別字體的例子,但增加了dropout,改變了優化器。

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data


#載入數據集
mnist = input_data.read_data_sets("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)


#創建一個簡單的神經網絡
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) #使用dropout解決過擬合


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)
train_step = tf.train.AdamOptimizer(1e-2).minimize(loss)#使用adam優化器


#初始化變量
init = tf.global_variables_initializer()


#結果存放在一個布爾型列表中
correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(prediction,1))#argmax返回一維張量中最大的值所在的位置
#求準確率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))


with tf.Session() as sess:
    sess.run(init)
    for epoch in range(31):

            sess.run(tf.assign(lr, 0.001 * (0.95 ** epoch)))#一開始賦予比較高的學習率,當其越來越接近最低點的時候,降低其學習率,防止其在最低點震盪。
        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:0.7})
        learning_rate = sess.run(lr)
        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)+",Learning Rate= " + str(learning_rate))


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章