tensorflow中学习率、过拟合、滑动平均的学习
1. 學(xué)習(xí)率的設(shè)置
我們知道在參數(shù)的學(xué)習(xí)主要是通過(guò)反向傳播和梯度下降,而其中梯度下降的學(xué)習(xí)率設(shè)置方法是指數(shù)衰減。
通過(guò)指數(shù)衰減的學(xué)習(xí)率既可以讓模型在訓(xùn)練的前期快速接近較優(yōu)解,又可以保證模型在訓(xùn)練后期不會(huì)有太大的波動(dòng),從而更加接近局部的最優(yōu)解。
在tensorflow中提供了一個(gè)靈活的學(xué)習(xí)率設(shè)置方法,tf.train.exponential_decay函數(shù)實(shí)現(xiàn)了指數(shù)衰減,其實(shí)現(xiàn)的原理如下:
其中:
decayed_learning_rate:每一輪優(yōu)化時(shí)使用的學(xué)習(xí)率
learning_rate:事先設(shè)定的初始學(xué)習(xí)率
decay_rate:衰減系數(shù)
decay_steps:衰減速度
tf.train.exponential_decay函數(shù)還可以通過(guò)設(shè)置參數(shù)staircase 選擇不同的衰減方式。
- staircase默認(rèn)值是false,這時(shí)的學(xué)習(xí)率會(huì)隨迭代的輪數(shù)成平滑的衰減下降,這里的不同訓(xùn)練數(shù)據(jù)有不同的學(xué)習(xí)率。
- staircase默認(rèn)值是true,(global_step/decay_steps)會(huì)被轉(zhuǎn)化為整數(shù),這時(shí)的學(xué)習(xí)率會(huì)隨著輪數(shù)成階梯狀的下降,在這種設(shè)置下,decay_steps指完整的使用一遍訓(xùn)練數(shù)據(jù)所需要的迭代輪數(shù)(總的訓(xùn)練樣本數(shù)處以每一個(gè)batch中的訓(xùn)練樣本數(shù)),這里的意思就是每完整的過(guò)完一遍訓(xùn)練數(shù)據(jù),學(xué)習(xí)率就減少一次,這可以使得訓(xùn)練集中的所有數(shù)據(jù)對(duì)模型訓(xùn)練有相等的作用。如下圖:
tensorflow使用如下:
示例:
import tensorflow as tf from numpy.random import RandomState# 假設(shè)我們要最小化函數(shù) y=x^2 , 選擇初始點(diǎn) 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))運(yùn)行結(jié)果:
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. 過(guò)擬合
通常解決過(guò)擬合的方法是正則化,正則化就是在損失函數(shù)中加入刻畫(huà)模型復(fù)雜程度的指標(biāo)。
具體就是:如果損失函數(shù)是J(θ)J(θ),那么在優(yōu)化時(shí)不直接優(yōu)化J(θ)J(θ),而是優(yōu)化J(θ)+λR(w)J(θ)+λR(w),其中R(w)R(w)就是刻畫(huà)模型的復(fù)雜度,而λλ就是表示模型復(fù)雜損失在總損失中的比例。常用來(lái)刻畫(huà)模型復(fù)雜度的函數(shù)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|
這兩種正則化的區(qū)別在于L1正則化會(huì)讓參數(shù)變得稀疏(指更多的參數(shù)變?yōu)?,有點(diǎn)特征提取的意思),而L2正則化則不會(huì),因?yàn)樗鼤?huì)讓系數(shù)變得非常小,但不至于變?yōu)?。但是在優(yōu)化時(shí)需要對(duì)損失函數(shù)求偏導(dǎo),所以常用的是L2正則化。
這里還可以同時(shí)用兩種正則化:R(w)=∑ia|wi|+(1?a)w2iR(w)=∑ia|wi|+(1?a)wi2
tensorflow中提供了tf.contrib.layers.l2_regularizer(lambda1)(var)函數(shù),它可以返回一個(gè)函數(shù),這個(gè)函數(shù)可以計(jì)算一個(gè)給定參數(shù)的L2正則化項(xiàng)的值。
例如:
當(dāng)網(wǎng)絡(luò)復(fù)雜時(shí),這種方法就不行了,這時(shí)可以通過(guò)使用tensorflow中提供的集合(在一個(gè)計(jì)算圖中保存一組實(shí)體)來(lái)解決。
示例:
import tensorflow as tf import matplotlib.pyplot as plt import numpy as np# 生成模擬數(shù)據(jù)集 data = [] label = [] np.random.seed(0)# 以原點(diǎn)為圓心,半徑為1的圓把散點(diǎn)劃分成紅藍(lán)兩部分,并加入隨機(jī)噪音。 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()# 定義一個(gè)獲取權(quán)重,并自動(dòng)加入正則項(xiàng)到損失的函數(shù) def get_weight(shape, lambda1):var = tf.Variable(tf.random_normal(shape), dtype=tf.float32)# 下面的函數(shù)把新生成變量的L2正則化損失加入集合:第一個(gè)參數(shù)是集合的名字,第二個(gè)參數(shù)是要加入的集合tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(lambda1)(var))print('var:',var)return var####### 定義神經(jīng)網(wǎng)絡(luò)############## 輸入數(shù)據(jù)是二維特征 x = tf.placeholder(tf.float32, shape=(None, 2)) y_ = tf.placeholder(tf.float32, shape=(None, 1)) sample_size = len(data)# 每層節(jié)點(diǎn)的個(gè)數(shù),這里是5層的神經(jīng)網(wǎng)絡(luò) layer_dimension = [2,10,5,3,1] n_layers = len(layer_dimension) # 該變量維護(hù)前向傳播時(shí)最深層的節(jié)點(diǎn),開(kāi)始的時(shí)候就是輸入層 cur_layer = x in_dimension = layer_dimension[0]# 循環(huán)生成5層的網(wǎng)絡(luò)結(jié)構(gòu),這里主要是為了構(gòu)造前向傳播的過(guò)程 for i in range(1, n_layers):out_dimension = layer_dimension[i]# 生成當(dāng)前層的權(quán)重,并同時(shí)把權(quán)重的L2正則化損失加入計(jì)算圖的集合weight = get_weight([in_dimension, out_dimension], 0.003)bias = tf.Variable(tf.constant(0.1, shape=[out_dimension]))# 這里使用relu激活函數(shù)cur_layer = tf.nn.relu(tf.matmul(cur_layer, weight) + bias)# 更新需要運(yùn)算的層in_dimension = layer_dimension[i]# 最后輸出的樣本預(yù)測(cè)值 y= cur_layer # 損失函數(shù)的定義,這里只是模型在訓(xùn)練數(shù)據(jù)上變現(xiàn)的損失函數(shù),因?yàn)長(zhǎng)2的正則化已經(jīng)加入了損失集合 mse_loss = tf.reduce_sum(tf.pow(y_ - y, 2)) / sample_size # 將均方誤差損失函數(shù)加入損失集合 tf.add_to_collection('losses', mse_loss) # tf.get_collection('losses')返回集合losses中的元素, # 得到的是一個(gè)列表,在這里就是損失函數(shù)的不同部分,加起來(lái)就是總的損失 loss = tf.add_n(tf.get_collection('losses')) # 定義訓(xùn)練的目標(biāo)函數(shù)loss,訓(xùn)練次數(shù)及訓(xùn)練模型 train_op = tf.train.AdamOptimizer(0.001).minimize(loss) TRAINING_STEPS = 40000# 開(kāi)啟會(huì)話,進(jìn)行計(jì)算 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})))# 畫(huà)出訓(xùn)練后的分割曲線 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()運(yùn)行結(jié)果:
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這里會(huì)有一個(gè)報(bào)錯(cuò):
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)。
這里還有一個(gè)沒(méi)太搞得太明白,就是神經(jīng)網(wǎng)絡(luò)是怎么畫(huà)出分界線的,以后有時(shí)間再搞吧。。。
3. 滑動(dòng)平均m模型
滑動(dòng)平均模型可以使模型在測(cè)試集上更加健壯。
tensorflow中提供了 tf.train.ExponentialMovingAverage()來(lái)實(shí)現(xiàn)滑動(dòng)平均模型,初始化時(shí)需要提供一個(gè)衰減率,以用于模型更新的速度。ExponentialMovingAverage對(duì)每個(gè)變量會(huì)維護(hù)一個(gè)影子變量,這個(gè)影子變量的初始值就是相應(yīng)變量的初始值,而每次運(yùn)行時(shí)變量的值會(huì)更新為:
shadow_variable=decay×shadow_variable+(1?decay)×variableshadow_variable=decay×shadow_variable+(1?decay)×variable
其中:
shadow_variable:影子變量
variable:待更新變量
decay:衰減率(決定模型更新的速度)
ExponentialMovingAverage還提供了num_updates參數(shù)來(lái)動(dòng)態(tài)設(shè)置decay:
下面簡(jiǎn)單一個(gè)例子說(shuō)明更新過(guò)程: import tensorflow as tf# 定義一個(gè)變量用于計(jì)算滑動(dòng)平均,初始值設(shè)為0,并且類型必須為實(shí)數(shù)型 v1 = tf.Variable(0, dtype=tf.float32) # 這里的step變量模擬神經(jīng)網(wǎng)絡(luò)中迭代的輪數(shù),用于動(dòng)態(tài)控制衰減率 step = tf.Variable(0, trainable=False) # 定義一個(gè)滑動(dòng)平均類,初始衰減率為0.99 ema = tf.train.ExponentialMovingAverage(0.99, step) # 定義一個(gè)更新變量滑動(dòng)平均的操作,這里給定一個(gè)列表 maintain_averages_op = ema.apply([v1]) with tf.Session() as sess:# 初始化所有的變量init_op = tf.global_variables_initializer()sess.run(init_op)# ema.average(v1)獲得滑動(dòng)平均之后變量的取值。初始化之后變量v1的值和v1的滑動(dòng)平均都為0print(sess.run([v1, ema.average(v1)]))# 更新變量v1的取值sess.run(tf.assign(v1, 5))# 更新v1的滑動(dòng)平均值,這時(shí)的衰減率為min{0.99,(1+step)/(10+step)=0.1}=0.1# 所以此時(shí)v1的滑動(dòng)平均值更新為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的滑動(dòng)平均值,這時(shí)的衰減率為min{0.99,(1+step)/(10+step)=0.999}=0.99# 所以此時(shí)v1的滑動(dòng)平均值更新為0.99x4.5+0.01x10=4.555sess.run(maintain_averages_op)print(sess.run([v1, ema.average(v1)])) # 更新一次v1的滑動(dòng)平均值sess.run(maintain_averages_op)print (sess.run([v1, ema.average(v1)]))
結(jié)果:
[0.0, 0.0] [5.0, 4.5] [10.0, 4.555] [10.0, 4.60945]參考:《Tensorflow實(shí)戰(zhàn)Google深度學(xué)習(xí)框架》
總結(jié)
以上是生活随笔為你收集整理的tensorflow中学习率、过拟合、滑动平均的学习的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: tensorflow入门之损失函数
- 下一篇: 通俗讲解自底向上构建知识图谱全过程