理解滑動平均(exponential moving average)

目錄

1. 用滑動平均估計局部均值
2. TensorFlow中使用滑動平均來更新變量(參數)
3. 滑動平均爲何在測試過程當中被使用?git

1. 用滑動平均估計局部均值

  滑動平均(exponential moving average),或者叫作指數加權平均(exponentially weighted moving average),能夠用來估計變量的局部均值,使得變量的更新與一段時間內的歷史取值有關。github

  變量$v$在$t$時刻記爲 $v_t$,$\theta_t$ 爲變量 $v$ 在 $t$ 時刻的取值,即在不使用滑動平均模型時 $v_t = \theta_t$,在使用滑動平均模型後,$v_t$ 的更新公式以下:算法

\begin{equation} v_t = \beta \cdot v_{t-1} + (1 - \beta) \cdot \theta_t \end{equation}網絡

  上式中,$\beta \in [0,1)$。$\beta = 0$ 至關於沒有使用滑動平均。框架

  假設起始 $v_0= 0$,$\beta = 0.9$,以後每一個時刻,依次對變量 $v$ 進行賦值,不使用滑動平均和使用滑動平均結果以下:學習

表 1  三種變量更新方式
測試

t 不使用滑動平均模型,即給$v$直接賦值$\theta$

使用滑動平均模型,
按照公式(1)更新$v$
網站

使用滑動平均模型,
按照公式(2)更新$v\_biased$
spa

0, 1, 2,  ... ,  35 [0, 10, 20, 10, 0, 10, 20, 30, 5, 0, 10, 20, 10, 0, 10, 20, 30, 5, 0, 10, 20, 10, 0, 10, 20, 30, 5, 0, 10, 20, 10, 0, 10, 20, 30, 5] [0, 1.0, 2.9, 3.61, 3.249, 3.9241, 5.5317, 7.9785, 7.6807, 6.9126, 7.2213, 8.4992, 8.6493, 7.7844, 8.0059, 9.2053, 11.2848, 10.6563, 9.5907, 9.6316, 10.6685, 10.6016, 9.5414, 9.5873, 10.6286, 12.5657, 11.8091, 10.6282, 10.5654, 11.5089, 11.358, 10.2222, 10.2, 11.18, 13.062, 12.2558] [0, 10.0, 15.2632, 13.321, 9.4475, 9.5824, 11.8057, 15.2932, 13.4859, 11.2844, 11.0872, 12.3861, 12.0536, 10.4374, 10.3807, 11.592, 13.8515, 12.7892, 11.2844, 11.1359, 12.145, 11.9041, 10.5837, 10.5197, 11.5499, 13.5376, 12.6248, 11.2844, 11.1489, 12.0777, 11.8608, 10.6276, 10.5627, 11.5365, 13.4357, 12.5704]

圖 1:三種變量更新方式code

  Andrew Ng在Course 2 Improving Deep Neural Networks中講到,$t$ 時刻變量 $v$ 的滑動平均值大體等於過去 $1/(1 - \beta)$ 個時刻 $\theta$ 值的平均。這個結論在滑動平均起始時相差比較大,因此有了Bias correction,將 $v_t$ 除以 $(1 - \beta^t)$ 修正對均值的估計。

  加入了Bias correction後,$v_t$ 和 $v\_biased_{t}$ 的更新公式以下:

\begin{equation} v_t = \beta \cdot v_{t-1} + (1 - \beta) \cdot \theta_t \\ v\_biased_{t} = \frac{v_t}{1 - \beta^t} \end{equation}

$t$ 越大,$1-\beta^t$ 越接近 1,則公式(1)和(2)獲得的結果 ($v_t$ 和 $v\_biased_{t}$)將愈來愈近,如圖 1 所示。

  當 $\beta$ 越大時,滑動平均獲得的值越和 $\theta$ 的歷史值相關。若是 $\beta = 0.9$,則大體等於過去 10 個 $\theta$ 值的平均;若是 $\beta = 0.99$,則大體等於過去 100 個 $\theta$ 值的平均。

  滑動平均的好處:

佔內存少,不須要保存過去10個或者100個歷史 $\theta$ 值,就可以估計其均值。(固然,滑動平均不如將歷史值全保存下來計算均值準確,但後者佔用更多內存和計算成本更高)

 

2. TensorFlow中使用滑動平均來更新變量(參數)

  滑動平都可以看做是變量的過去一段時間取值的均值,相比對變量直接賦值而言,滑動平均獲得的值在圖像上更加平緩光滑,抖動性更小,不會由於某次的異常取值而使得滑動平均值波動很大,如圖 1所示。

  TensorFlow 提供了 tf.train.ExponentialMovingAverage 來實現滑動平均。在初始化 ExponentialMovingAverage 時,須要提供一個衰減率(decay),即公式(1)(2)中的 $\beta$。這個衰減率將用於控制模型的更新速度。ExponentialMovingAverage 對每個變量(variable)會維護一個影子變量(shadow_variable),這個影子變量的初始值就是相應變量的初始值,而每次運行變量更新時,影子變量的值會更新爲:

\begin{equation} \mbox{shadow_variable} = \mbox{decay} \cdot \mbox{shadow_variable} + (1 - \mbox{decay}) \cdot \mbox{variable} \end{equation}

公式(3)中的 shadow_variable 就是公式(1)中的 $v_t$,公式(3)中的 variable 就是公式(1)中的 $\theta_t$,公式(3)中的 decay 就是公式(1)中的 $\beta$。

  公式(3)中,decay 決定了影子變量的更新速度,decay 越大影子變量越趨於穩定。在實際運用中,decay通常會設成很是接近 1 的數(好比0.999或0.9999)。爲了使得影子變量在訓練前期能夠更新更快,ExponentialMovingAverage 還提供了 num_updates 參數動態設置 decay 的大小。若是在初始化 ExponentialMovingAverage 時提供了 num_updates 參數,那麼每次使用的衰減率將是:

\begin{equation} min\{\mbox{decay}, \frac{1 + \mbox{num_updates}}{10 + \mbox{num_updates}}\} \end{equation}

這一點其實和 Bias correction 很像。

  TensorFlow 中使用 ExponentialMovingAverage 的例子:code (若是 GitHub 沒法加載 .ipynb 文件,則將 .ipynb 文件的 URL 複製到網站 https://nbviewer.jupyter.org/

 

3. 滑動平均爲何在測試過程當中被使用?

  滑動平都可以使模型在測試數據上更健壯(robust)。「採用隨機梯度降低算法訓練神經網絡時,使用滑動平均在不少應用中均可以在必定程度上提升最終模型在測試數據上的表現。」 

  對神經網絡邊的權重 weights 使用滑動平均,獲得對應的影子變量 shadow_weights。在訓練過程仍然使用原來不帶滑動平均的權重 weights,否則沒法獲得 weights 下一步更新的值,又怎麼求下一步 weights 的影子變量 shadow_weights。以後在測試過程當中使用 shadow_weights 來代替 weights 做爲神經網絡邊的權重,這樣在測試數據上效果更好。由於 shadow_weights 的更新更加平滑,對於隨機梯度降低而言,更平滑的更新說明不會偏離最優勢很遠;對於梯度降低 batch gradient decent,我感受影子變量做用不大,由於梯度降低的方向已是最優的了,loss 必定減少;對於 mini-batch gradient decent,能夠嘗試滑動平均,畢竟 mini-batch gradient decent 對參數的更新也存在抖動。

  設 $\mbox{decay} = 0.999$,一個更直觀的理解,在最後的 1000 次訓練過程當中,模型早已經訓練完成,正處於抖動階段,而滑動平均至關於將最後的 1000 次抖動進行了平均,這樣獲得的權重會更加 robust。

  

References

Course 2 Improving Deep Neural Networks by Andrew Ng

《TensorFlow實戰Google深度學習框架》 4.4.3

相關文章
相關標籤/搜索