加權平均是什么意思(平均和加權平均的區別)
指數加權移動平均法(EWMA)
** 本文內容來自于吳恩達深度學習公開課
1、概述
加權移動平均法,是對觀察值分別給予不同的權數,按不同權數求得移動平均值,并以最后的移動平均值為基礎,確定預測值的方法。采用加權移動平均法,是因為觀察期的近期觀察值對預測值有較大影響,它更能反映近期變化的趨勢。
指數移動加權平均法,是指各數值的加權系數隨時間呈指數式遞減,越靠近當前時刻的數值加權系數就越大。
指數移動加權平均較傳統的平均法來說,一是不需要保存過去所有的數值;二是計算量顯著減小。
2、算法理解
引入一個例子,例子為美國一年內每天的溫度分布情況,具體如下圖所示

EWMA 的表達式如下:
vt=βvt?1+(1?β)θt
上式中 θt
為時刻 t 的實際溫度;系數 β 表示加權下降的速率,其值越小下降的越快;vt 為 t
時刻 EWMA 的值。
在上圖中有兩條不同顏色的線,分別對應著不同的 β
值。
當 β=0.9
時,有 vt=0.9vt?1+0.1θt
,對應著圖中的紅線,此時雖然曲線有些波動,但總體能擬合真實數據
當 β=0.98
時,有vt=0.98vt?1+0.02θt
,對應著圖中的綠線,此時曲線較平,但卻有所偏離真實數據
在 t=0
時刻,一般初始化 v0=0 ,對 EWMA 的表達式進行歸納可以將 t
時刻的表達式寫成:
vt=(1?β)(θt+βθt?1+…+βt?1θ1)
從上面式子中可以看出,數值的加權系數隨著時間呈指數下降。在數學中一般會以 1e
來作為一個臨界值,小于該值的加權系數的值不作考慮,接著來分析上面 β=0.9 和 β=0.98
的情況。
當 β=0.9
時,0.910 約等于1e
,因此認為此時是近10個數值的加權平均。
當 β=0.98
時,0.950 約等于1e
,因此認為此時是近50個數值的加權平均。這種情況也正是移動加權平均的來源。
具體的分析如下圖所示:

3、偏差修正
在初始化 v0=0
時實際上會存在一個問題。具體的如下圖所示:

從上圖中可以看出有一條綠色和紫色的曲線,都是對應于 β=0.98
時的曲線。理想狀況下應該是綠色的曲線,但當初始化 v0=0
時卻會得到紫色的曲線,這是因為初始化的值太小,導致初期的數值都偏小,而隨著時間的增長,初期的值的影響減小,紫色的曲線就慢慢和綠色的曲線重合。我們對公式做一些修改:
vt=βvt?1+(1?β)θt1?βt
當 t很小時,分母可以很好的放大當前的數值;當 t很大時,分母的數值趨于1,對當前數值幾乎沒有影響。
EWMA 主要是被應用在動量優化算法中,比如Adam算法中的一階矩和二階矩都采用了上面修改后的EWMA算法。
深入解析TensorFlow中滑動平均模型與代碼實現
2018年08月09日 21:00:56 無敵的白金之星 閱讀數:2271
因為本人是自學深度學習的,有什么說的不對的地方望大神指出
指數加權平均算法的原理
TensorFlow中的滑動平均模型使用的是滑動平均(Moving Average)算法,又稱為指數加權移動平均算法(exponenentially weighted average),這也是ExponentialMovingAverage()函數的名稱由來。
先來看一個簡單的例子,這個例子來自吳恩達老師的DeepLearning課程,個人強烈推薦初學者都看一下。
開始例子。首先這是一年365天的溫度散點圖,以天數為橫坐標,溫度為縱坐標,你可以看見各個小點分布在圖上,有一定的曲線趨勢,但是并不明顯

接著,如果我們要看出這個溫度的變化趨勢,很明顯需要做一點處理,也即是我們的主題,用滑動平均算法處理。
首先給定一個值v0,然后我們定義每一天的溫度是a1,a2,a3·····
接著,我們計算出v1,v2,v3····來代替每一天的溫度,也就是上面的a1,a2,a3
計算方法是:v1 = v0 * 0.9 + a1 (1-0.9),v2= v1 0.9 + a2 (1-0.9),v3= v2 0.9 + a3 (1-0.9)···,也就是說,每一天的溫度改變為前一天的v值 0.9 + 當天的溫度 * 0.1,vt = v(t-1) * 0.9 + at * 0.1,把所有的v計算完之后畫圖,紅線就是v的曲線:

v值就是指數加權平均數,整個過程就是指數加權平均算法,它很好的把一年的溫度曲線給擬合了出來。把0.9抽象為β,總結為vt = v(t-1) * β + at * (1-β)。
β這個值的意義是什么?實際上vt ≈ 1/(1 – β) 天的平均溫度,例如:假設β等于0.9,1/(1 – β) 就等于10,也就是vt等于前十天的平均溫度,這個說可能不太看得出來;假設把β值調大道接近1,例如,將β等于0.98,1/(1-β)=50,按照剛剛的說法也就是前50天的平均溫度,然后求出v值畫出曲線,如圖所示:

綠線就是β等于0.98時候的曲線,可以明顯看到綠線比紅線的變化更遲,紅線達到某一溫度,綠線要過一陣子才能達到相同溫度。因為綠線是前50天的平均溫度,變化就會更加緩慢,而紅線是最近十天的平均溫度,只要最近十天的溫度都是上升,紅線很快就能跟著變化。所以直觀的理解就是,vt是前1/(1-β)天的平均溫度。
再看看另一個極端情況:β等于0.5,意味著vt≈最近兩天的平均溫度,曲線如下黃線:

和原本的溫度很相似,但曲線的波動幅度也相當大!
然后說一下這個滑動平均模型和深度學習有什么關系:通常來說,我們的數據也會像上面的溫度一樣,具有不同的值,如果使用滑動平均模型,就可以使得整體數據變得更加平滑——這意味著數據的噪音會更少,而且不會出現異常值。但是同時β太大也會使得數據的曲線右移,和數據不擬合。需要不斷嘗試出一個β值,既可以擬合數據集,又可以減少噪音。
滑動平均模型在深度學習中還有另一個優點:它只占用極少的內存
當你在模型中計算最近十天(有些情況下遠大于十天)的平均值的時候,你需要在內存中加載這十天的數據然后進行計算,但是指數加權平均值約等于最近十天的平均值,而且根據vt = v(t-1) * β + at * (1-β),你只需要提供at這一天的數據,再加上v(t-1)的值和β值,相比起十天的數據這是相當小的數據量,同時占用更少的內存。
偏差修正
指數加權平均值通常都需要偏差修正,TensorFlow中提供的ExponentialMovingAverage()函數也帶有偏差修正。
首先看一下為什么會出現偏差,再來說怎么修正。當β等于0.98的時候,還是用回上面的溫度例子,曲線實際上不是像綠線一樣,而是像紫線:

你可以注意到在紫線剛剛開始的時候,曲線的值相當的低,這是因為在一開始的時候并沒有50天(1/(1-β)為50)的數據,而是只有寥寥幾天的數據,相當于少加了幾十天的數據,所以vt的值很小,這和實際情況的差距是很大的,也就是出現的偏差。
而在TensorFlow中的ExponentialMovingAverage()采取的偏差修正方法是:使用num_updates來動態設置β的大小
在數據迭代的前期,數據量比較少的時候,(1+num_updates)/(10+num_updates)的值比較小,使用這個值作為β來進行vt的計算,所以在迭代前期就會像上面的紅線一樣,和原數據更加接近。舉個例子,當天數是第五天,β為0.98,那么(1+num_updates)/(10+num_updates) = 6/15 = 0.4,相當于最近1.6天的平均溫度,而不是β=0.98時候的50天,這樣子就做到了偏差修正。
滑動平均模型的代碼實現
看到這里你應該大概了解了滑動平均模型和偏差修正到底是怎么回事了,接下來把這個想法對應到TensorFlow的代碼中。
首先明確一點,TensorFlow中的ExponentialMovingAverage()是針對權重weight和偏差bias的,而不是針對訓練集的。如果你現在訓練集中實現這個效果,需要自己設計代碼。
為什么要對w和b使用滑動平均模型呢?因為在神經網絡中,
更新的參數時候不能太大也不能太小,更新的參數跟你之前的參數有聯系,不能發生突變。一旦訓練的時候遇到個“瘋狂”的參數,有了滑動平均模型,瘋狂的參數就會被抑制下來,回到正常的隊伍里。這種對于突變參數的抑制作用,用專業術語講叫魯棒性,魯棒性就是對突變的抵抗能力,魯棒性越好,這個模型對惡性參數的提抗能力就越強。
在TensorFlow中,ExponentialMovingAverage()可以傳入兩個參數:衰減率(decay)和數據的迭代次數(step),這里的decay和step分別對應我們的β和num_updates,所以在實現滑動平均模型的時候,步驟如下:
1、定義訓練輪數step
2、然后定義滑動平均的類
3、給這個類指定需要用到滑動平均模型的變量(w和b)
4、執行操作,把變量變為指數加權平均值
# 1、定義訓練的輪數,需要用trainable=False參數指定不訓練這個變量,
# 避免這個變量被計算滑動平均值
global_step = tf.Variable(0, trainable=False)
# 2、給定滑動衰減率和訓練輪數,初始化滑動平均類
# 定訓練輪數的變量可以加快訓練前期的迭代速度
variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,
global_step)
# 3、用tf.trainable_variable()獲取所有可以訓練的變量列表,也就是所有的w和b
# 全部指定為使用滑動平均模型
variables_averages_op = variable_averages.apply(tf.trainable_variables())
# 反向傳播更新參數之后,再更新每一個參數的滑動平均值,用下面的代碼可以一次完成這兩個操作
with tf.control_dependencies([train_step, variables_averages_op]):
train_op = tf.no_op(name="train")
設置完使用滑動平均模型之后,只需要在每次使用反向傳播的時候改為使用run.(train_op)就可以正常執行了。