TensorFlow筆記-07-神經網路優化-學習率,滑動平均

肖朋偉發表於2018-09-12

TensorFlow筆記-07-神經網路優化-學習率,滑動平均

學習率

  • 學習率 learning_rate: 表示了每次引數更新的幅度大小。學習率過大,會導致待優化的引數在最小值附近波動,不收斂;學習率過小,會導致待優化的引數收斂緩慢
  • 在訓練過程中,引數的更新向著損失函式梯度下降的方向
  • 引數的更新公式為:
    wn+1 = wn - learning_rate▽
  • 假設損失函式 loss = (w + 1)2。梯度是損失函式 loss 的導數為 ▽ = 2w + 2 。如引數初值為5,學習率為 0.2,則引數和損失函式更新如下:

    1次 ·······引數w: 5 ·················5 - 0.2 * (2 * 5 + 2) = 2.6
    2次 ·······引數w: 2.6 ··············2.6 - 0.2 * (2 * 2.6 + 2) = 1.16
    3次 ·······引數w: 1.16 ············1.16 - 0.2 * (2 * 1.16 +2) = 0.296
    4次 ·······引數w: 0.296

損失函式loss = (w + 1) 2 的影象為:
這裡寫圖片描述
由圖可知,損失函式 loss 的最小值會在(-1,0)處得到,此時損失函式的導數為 0,得到最終引數 w = -1。
程式碼 tf08learn 檔案:https://xpwi.github.io/py/TensorFlow/tf08learn.py

# coding: utf-8
# 設損失函式loss = (w + 1)^2 , 令 w 是常數 5。反向傳播就是求最小
# loss 對應的 w 值

import tensorflow as tf
# 定義待優化引數 w 初值賦予5
w = tf.Variable(tf.constant(5, dtype=tf.float32))
# 定義損失函式 loss
loss = tf.square(w + 1)
# 定義反向傳播方法
train_step = tf.train.GradientDescentOptimizer(0.20).minimize(loss)
# 生成會話,訓練40輪
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    for i in range(40):
        sess.run(train_step)
        W_val = sess.run(w)
        loss_val = sess.run(loss)
        print("After %s steps: w: is %f,  loss: is %f." %(i, W_val, loss_val))

執行結果

這裡寫圖片描述
執行結果分析: 由結果可知,隨著損失函式值得減小,w 無線趨近於 -1

學習率的設定

  • 學習率過大,會導致待優化的引數在最小值附近波動,不收斂;學習率過小,會導致待優化的引數收斂緩慢
  • 例如:
  • (1) 對於上例的損失函式loss = (w + 1) 2,則將上述程式碼中學習率改為1,其餘內容不變
    實驗結果如下:
    這裡寫圖片描述
  • (2) 對於上例的損失函式loss = (w + 1) 2,則將上述程式碼中學習率改為0.0001,其餘內容不變
    實驗結果如下:
    這裡寫圖片描述
    由執行結果可知,損失函式 loss 值緩慢下降,w 值也在小幅度變化,收斂緩慢

指數衰減學習率

  • 指數衰減學習率:學習率隨著訓練輪數變化而動態更新
    這裡寫圖片描述
    其中,LEARNING_RATE_BASE 為學習率初始值,LEARNING_RATE_DECAY 為學習率衰減率,global_step 記錄了當前訓練輪數,為了不可訓練型引數。學習率 learning_rate 更新頻率為輸入資料集總樣本數除以每次喂入樣本數。若 staircase 設定為 True 時,表示 global_step / learning rate step 取整數,學習率階梯型衰減;若 staircase 設定為 False 時,學習率會是一條平滑下降的曲線。
  • 例如:
    在本例中,模型訓練過程不設定固定的學習率,使用指數衰減學習率進行訓練。其中,學習率初值設定為0.1,學習率衰減值設定為0.99,BATCH_SIZE 設定為1。
  • 程式碼 tf08learn2 檔案:https://xpwi.github.io/py/TensorFlow/tf08learn2.py
# coding: utf-8
'''
 設損失函式loss = (w + 1)^2 , 令 w 初值是常數5,
反向傳播就是求最優 w,即求最小 loss 對應的w值。
 使用指數衰減的學習率,在迭代初期得到較高的下降速度,
可以在較小的訓練輪數下取得更有收斂度
'''

import tensorflow as tf

LEARNING_RATE_BASE = 0.1 # 最初學習率
LEARNING_RATE_DECAY = 0.99 # 學習率衰減率
# 喂入多少輪 BATCH_SIZE 後,更新一次學習率,一般設定為:樣本數/BATCH_SIZE
LEARNING_RATE_STEP = 1

# 執行了幾輪 BATCH_SIZE 的計算器,初始值是0,設為不被訓練
global_step = tf.Variable(0, trainable=False)

# 定義指數下降學習率
learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE, global_step,
LEARNING_RATE_STEP, LEARNING_RATE_DECAY, staircase=True)

# 定義待優化引數 w 初值賦予5
w = tf.Variable(tf.constant(5, dtype=tf.float32))
# 定義損失函式 loss
loss = tf.square(w+1)
# 定義反向傳播方法
# 學習率為:0.2
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)
# 生成會話,訓練40輪
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    for i in range(40):
        sess.run(train_step)
        learning_rate_val = sess.run(learning_rate)
        global_step_val = sess.run(global_step)
        w_val = sess.run(w)
        loss_val = sess.run(loss)
        print("After %s steps: global_step is %f; : w: is %f;learn rate is %f; loss: is %f."
              %(i,global_step_val, w_val, learning_rate_val, loss_val))

執行結果

這裡寫圖片描述
由結果可以看出,隨著訓練輪數增加學習率在不斷減小

滑動平均

  • **滑動平均:記錄了一段時間內模型中所有引數 w 和 b 各自的平均值,利用滑動平均值可以增強模型的泛化能力
  • **滑動平均值(影子)計算公式:影子 = 衰減率 * 引數
  • 其中衰減率 = min{AVERAGEDECAY(1+輪數/10+輪數)},影子初值 = 引數初值
  • 用 Tensorflow 函式表示:

    **ema = tf.train.ExpoentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)

  • 其中 MOVING_AVERAGE_DECAY 表示滑動平均衰減率,一般會賦予接近1的值,global_step 表示當前訓練了多少輪

    **ema_op = ema.apply(tf.trainable_varables())

  • 其中 ema.apply() 函式實現對括號內引數的求滑動平均,tf.trainable_variables() 函式實現把所有待訓練引數彙總為列表

    with tf.control_dependencies([train_step, ema_op]):
    train_op = tf.no_op(name='train')

  • 其中,該函式實現滑動平均和訓練步驟同步執行
  • 檢視模型中引數的平均值,可以用 ema.average() 函式
  • 例如:
    在神經網路中將 MOVING_AVERAGE_DECAY 設定為 0.9,引數 w1 設定為 0,w1 滑動平均值設定為 0
  • (1)開始時,輪數 global_step 設定為 0,引數 w1 更新為 1,則滑動平均值為:

    w1 滑動平均值 = min(0.99, 1/10)0+(1-min(0.99,1/10))1 = 0.9

  • (2)當輪數 global_step 設定為 0,引數 w1 更新為 10,以下程式碼 global_step 保持 100,每次執行滑動平均操作影子更新,則滑動平均值變為:

    w1 滑動平均值 = min(0.99, 101/110)0.9+(1-min(0.99,101/110))10 = 0.826+0.818 = 1.644

  • (3)再次執行,引數 w1 更新為 1.644,則滑動平均值變為:

    **w1

更多文章連結:Tensorflow 筆記


  • 本筆記不允許任何個人和組織轉載

相關文章