tensorflow中学习率、过拟合、滑动平均的学习
1. 學習率的設置
我們知道在參數的學習主要是通過反向傳播和梯度下降,而其中梯度下降的學習率設置方法是指數衰減。 
 通過指數衰減的學習率既可以讓模型在訓練的前期快速接近較優解,又可以保證模型在訓練后期不會有太大的波動,從而更加接近局部的最優解。 
 在tensorflow中提供了一個靈活的學習率設置方法,tf.train.exponential_decay函數實現了指數衰減,其實現的原理如下:
其中: 
 decayed_learning_rate:每一輪優化時使用的學習率 
 learning_rate:事先設定的初始學習率 
 decay_rate:衰減系數 
 decay_steps:衰減速度
tf.train.exponential_decay函數還可以通過設置參數staircase 選擇不同的衰減方式。
- staircase默認值是false,這時的學習率會隨迭代的輪數成平滑的衰減下降,這里的不同訓練數據有不同的學習率。
 - staircase默認值是true,(global_step/decay_steps)會被轉化為整數,這時的學習率會隨著輪數成階梯狀的下降,在這種設置下,decay_steps指完整的使用一遍訓練數據所需要的迭代輪數(總的訓練樣本數處以每一個batch中的訓練樣本數),這里的意思就是每完整的過完一遍訓練數據,學習率就減少一次,這可以使得訓練集中的所有數據對模型訓練有相等的作用。如下圖: 
tensorflow使用如下: 
示例:
import tensorflow as tf from numpy.random import RandomState# 假設我們要最小化函數 y=x^2 , 選擇初始點 x0=5 TRAINING_STEPS = 100 LEARNING_RATE = 1 x = tf.Variable(tf.constant(5, dtype=tf.float32), name="x") y = tf.square(x)train_op = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(y)global_step = tf.Variable(0) LEARNING_RATE = tf.train.exponential_decay(0.1, global_step, 1, 0.96, staircase=True)x = tf.Variable(tf.constant(5, dtype=tf.float32), name="x") y = tf.square(x) train_op = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(y, global_step=global_step)with tf.Session() as sess:sess.run(tf.global_variables_initializer())for i in range(TRAINING_STEPS):sess.run(train_op)if i % 10 == 0:LEARNING_RATE_value = sess.run(LEARNING_RATE)x_value = sess.run(x)print ("After %s iteration(s): x%s is %f, learning rate is %f." \% (i+1, i+1, x_value, LEARNING_RATE_value))運行結果:
After 1 iteration(s): x1 is 4.000000, learning rate is 0.096000. After 11 iteration(s): x11 is 0.690561, learning rate is 0.063824. After 21 iteration(s): x21 is 0.222583, learning rate is 0.042432. After 31 iteration(s): x31 is 0.106405, learning rate is 0.028210. After 41 iteration(s): x41 is 0.065548, learning rate is 0.018755. After 51 iteration(s): x51 is 0.047625, learning rate is 0.012469. After 61 iteration(s): x61 is 0.038558, learning rate is 0.008290. After 71 iteration(s): x71 is 0.033523, learning rate is 0.005511. After 81 iteration(s): x81 is 0.030553, learning rate is 0.003664. After 91 iteration(s): x91 is 0.028727, learning rate is 0.002436.2. 過擬合
通常解決過擬合的方法是正則化,正則化就是在損失函數中加入刻畫模型復雜程度的指標。 
 具體就是:如果損失函數是J(θ)J(θ),那么在優化時不直接優化J(θ)J(θ),而是優化J(θ)+λR(w)J(θ)+λR(w),其中R(w)R(w)就是刻畫模型的復雜度,而λλ就是表示模型復雜損失在總損失中的比例。常用來刻畫模型復雜度的函數R(w)R(w)有2種: 
 L1正則化:R(w)=||w||1=∑i|wi|R(w)=||w||1=∑i|wi| 
 L2正則化:R(w)=||wi||22=∑i|w2i|R(w)=||wi||22=∑i|wi2| 
 這兩種正則化的區別在于L1正則化會讓參數變得稀疏(指更多的參數變為0,有點特征提取的意思),而L2正則化則不會,因為它會讓系數變得非常小,但不至于變為0。但是在優化時需要對損失函數求偏導,所以常用的是L2正則化。 
 這里還可以同時用兩種正則化:R(w)=∑ia|wi|+(1?a)w2iR(w)=∑ia|wi|+(1?a)wi2 
 tensorflow中提供了tf.contrib.layers.l2_regularizer(lambda1)(var)函數,它可以返回一個函數,這個函數可以計算一個給定參數的L2正則化項的值。 
 例如:
當網絡復雜時,這種方法就不行了,這時可以通過使用tensorflow中提供的集合(在一個計算圖中保存一組實體)來解決。
示例:
import tensorflow as tf import matplotlib.pyplot as plt import numpy as np# 生成模擬數據集 data = [] label = [] np.random.seed(0)# 以原點為圓心,半徑為1的圓把散點劃分成紅藍兩部分,并加入隨機噪音。 for i in range(150):x1 = np.random.uniform(-1,1)x2 = np.random.uniform(0,2)if x1**2 + x2**2 <= 1:data.append([np.random.normal(x1, 0.1),np.random.normal(x2,0.1)])label.append(0)else:data.append([np.random.normal(x1, 0.1), np.random.normal(x2, 0.1)])label.append(1)data = np.hstack(data).reshape(-1,2) label = np.hstack(label).reshape(-1, 1) plt.scatter(data[:,0], data[:,1], c=np.squeeze(label),cmap="RdBu", vmin=-.2, vmax=1.2, edgecolor="white") plt.show()# 定義一個獲取權重,并自動加入正則項到損失的函數 def get_weight(shape, lambda1):var = tf.Variable(tf.random_normal(shape), dtype=tf.float32)# 下面的函數把新生成變量的L2正則化損失加入集合:第一個參數是集合的名字,第二個參數是要加入的集合tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(lambda1)(var))print('var:',var)return var####### 定義神經網絡############## 輸入數據是二維特征 x = tf.placeholder(tf.float32, shape=(None, 2)) y_ = tf.placeholder(tf.float32, shape=(None, 1)) sample_size = len(data)# 每層節點的個數,這里是5層的神經網絡 layer_dimension = [2,10,5,3,1] n_layers = len(layer_dimension) # 該變量維護前向傳播時最深層的節點,開始的時候就是輸入層 cur_layer = x in_dimension = layer_dimension[0]# 循環生成5層的網絡結構,這里主要是為了構造前向傳播的過程 for i in range(1, n_layers):out_dimension = layer_dimension[i]# 生成當前層的權重,并同時把權重的L2正則化損失加入計算圖的集合weight = get_weight([in_dimension, out_dimension], 0.003)bias = tf.Variable(tf.constant(0.1, shape=[out_dimension]))# 這里使用relu激活函數cur_layer = tf.nn.relu(tf.matmul(cur_layer, weight) + bias)# 更新需要運算的層in_dimension = layer_dimension[i]# 最后輸出的樣本預測值 y= cur_layer # 損失函數的定義,這里只是模型在訓練數據上變現的損失函數,因為L2的正則化已經加入了損失集合 mse_loss = tf.reduce_sum(tf.pow(y_ - y, 2)) / sample_size # 將均方誤差損失函數加入損失集合 tf.add_to_collection('losses', mse_loss) # tf.get_collection('losses')返回集合losses中的元素, # 得到的是一個列表,在這里就是損失函數的不同部分,加起來就是總的損失 loss = tf.add_n(tf.get_collection('losses')) # 定義訓練的目標函數loss,訓練次數及訓練模型 train_op = tf.train.AdamOptimizer(0.001).minimize(loss) TRAINING_STEPS = 40000# 開啟會話,進行計算 with tf.Session() as sess:tf.global_variables_initializer().run()for i in range(TRAINING_STEPS):sess.run(train_op, feed_dict={x: data, y_: label})if i % 2000 == 0:print("After %d steps, loss: %f" % (i, sess.run(loss, feed_dict={x: data, y_: label})))# 畫出訓練后的分割曲線 xx, yy = np.mgrid[-1:1:.01, 0:2:.01]grid = np.c_[xx.ravel(), yy.ravel()]probs = sess.run(y, feed_dict={x:grid})probs = probs.reshape(xx.shape)plt.scatter(data[:,0], data[:,1], c=np.squeeze(label),cmap="RdBu", vmin=-.2, vmax=1.2, edgecolor="white") plt.contour(xx, yy, probs, levels=[.5], cmap="Greys", vmin=0, vmax=.1) plt.show()運行結果:
After 0 steps, loss: 1.503084 After 2000 steps, loss: 0.136486 After 4000 steps, loss: 0.077162 After 6000 steps, loss: 0.060446 After 8000 steps, loss: 0.057898 After 10000 steps, loss: 0.057211 After 12000 steps, loss: 0.057091 After 14000 steps, loss: 0.057002 After 16000 steps, loss: 0.056941 After 18000 steps, loss: 0.056830 After 20000 steps, loss: 0.056788 After 22000 steps, loss: 0.056766 After 24000 steps, loss: 0.056751 After 26000 steps, loss: 0.056741 After 28000 steps, loss: 0.056727 After 30000 steps, loss: 0.056714 After 32000 steps, loss: 0.056713 After 34000 steps, loss: 0.056713 After 36000 steps, loss: 0.056713 After 38000 steps, loss: 0.056714這里會有一個報錯: 
 ValueError: c of shape (150, 1) not acceptable as a color sequence for x with size 150, y with size 150 
 這里需要把:plt.scatter(data[:,0], data[:,1], c=label, 
 cmap="RdBu", vmin=-.2, vmax=1.2, edgecolor="white")中的c=label改成c=np.squeeze(label)。
這里還有一個沒太搞得太明白,就是神經網絡是怎么畫出分界線的,以后有時間再搞吧。。。
3. 滑動平均m模型
滑動平均模型可以使模型在測試集上更加健壯。 
 tensorflow中提供了 tf.train.ExponentialMovingAverage()來實現滑動平均模型,初始化時需要提供一個衰減率,以用于模型更新的速度。ExponentialMovingAverage對每個變量會維護一個影子變量,這個影子變量的初始值就是相應變量的初始值,而每次運行時變量的值會更新為: 
 shadow_variable=decay×shadow_variable+(1?decay)×variableshadow_variable=decay×shadow_variable+(1?decay)×variable 
 其中: 
 shadow_variable:影子變量 
 variable:待更新變量 
 decay:衰減率(決定模型更新的速度) 
 ExponentialMovingAverage還提供了num_updates參數來動態設置decay: 
 
下面簡單一個例子說明更新過程: import tensorflow as tf# 定義一個變量用于計算滑動平均,初始值設為0,并且類型必須為實數型 v1 = tf.Variable(0, dtype=tf.float32) # 這里的step變量模擬神經網絡中迭代的輪數,用于動態控制衰減率 step = tf.Variable(0, trainable=False) # 定義一個滑動平均類,初始衰減率為0.99 ema = tf.train.ExponentialMovingAverage(0.99, step) # 定義一個更新變量滑動平均的操作,這里給定一個列表 maintain_averages_op = ema.apply([v1]) with tf.Session() as sess:# 初始化所有的變量init_op = tf.global_variables_initializer()sess.run(init_op)# ema.average(v1)獲得滑動平均之后變量的取值。初始化之后變量v1的值和v1的滑動平均都為0print(sess.run([v1, ema.average(v1)]))# 更新變量v1的取值sess.run(tf.assign(v1, 5))# 更新v1的滑動平均值,這時的衰減率為min{0.99,(1+step)/(10+step)=0.1}=0.1# 所以此時v1的滑動平均值更新為0.1x0+0.9x5=4.5sess.run(maintain_averages_op)print(sess.run([v1, ema.average(v1)]))# 更新step和v1的取值sess.run(tf.assign(step, 10000)) sess.run(tf.assign(v1, 10))# 更新v1的滑動平均值,這時的衰減率為min{0.99,(1+step)/(10+step)=0.999}=0.99# 所以此時v1的滑動平均值更新為0.99x4.5+0.01x10=4.555sess.run(maintain_averages_op)print(sess.run([v1, ema.average(v1)])) # 更新一次v1的滑動平均值sess.run(maintain_averages_op)print (sess.run([v1, ema.average(v1)]))
結果:
[0.0, 0.0] [5.0, 4.5] [10.0, 4.555] [10.0, 4.60945]參考:《Tensorflow實戰Google深度學習框架》
總結
以上是生活随笔為你收集整理的tensorflow中学习率、过拟合、滑动平均的学习的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: tensorflow入门之损失函数
 - 下一篇: 通俗讲解自底向上构建知识图谱全过程