做網(wǎng)站銷售一個(gè)星期的計(jì)劃市場(chǎng)營(yíng)銷案例
文章目錄
- 前言
- EMA的定義
- 在深度學(xué)習(xí)中的應(yīng)用
- PyTorch代碼實(shí)現(xiàn)
- yolov5中模型的EMA實(shí)現(xiàn)
- 參考
前言
在深度學(xué)習(xí)中,經(jīng)常會(huì)使用EMA(指數(shù)移動(dòng)平均)這個(gè)方法對(duì)模型的參數(shù)做平均,以求提高測(cè)試指標(biāo)并增加模型魯棒。
實(shí)際上,_EMA可以看作是Temporal Ensembling,在模型學(xué)習(xí)過(guò)程中融合更多的歷史狀態(tài),從而達(dá)到更好的優(yōu)化效果。
EMA的定義
指數(shù)移動(dòng)平均(Exponential Moving Average)也叫權(quán)重移動(dòng)平均(Weighted Moving Average),是一種給予近期數(shù)據(jù)更高權(quán)重的平均方法。
假設(shè)有n個(gè)權(quán)重?cái)?shù)據(jù):
- 普通的平均數(shù):
- EMA:
其中, vt表示前 t條的平均值 ( v0=0 ),β是加權(quán)權(quán)重值 (一般設(shè)為0.9-0.999)。
Andrew Ng在Course 2 Improving Deep Neural Networks中講到,EMA可以近似看成過(guò)去 1/(1?β) 個(gè)時(shí)刻 v 值的平均。
普通的過(guò)去n時(shí)刻的平均是這樣的:
類比EMA,可以發(fā)現(xiàn)當(dāng) 時(shí),兩式形式上相等。需要注意的是,兩個(gè)平均并不是嚴(yán)格相等的,這里只是為了幫助理解。
實(shí)際上,EMA計(jì)算時(shí),過(guò)去 1/(1?β) 個(gè)時(shí)刻之前的數(shù)值平均會(huì)decay到 1/e 的加權(quán)比例,證明如下。
如果將這里的 vt展開(kāi),可以得到:
其中, ,代入可以得到
。
在深度學(xué)習(xí)中的應(yīng)用
上面講的是廣義的ema定義和計(jì)算方法,特別的,在深度學(xué)習(xí)的優(yōu)化過(guò)程中, 是t時(shí)刻的模型權(quán)重weights, vt是t時(shí)刻的影子權(quán)重(shadow weights)。在梯度下降的過(guò)程中,會(huì)一直維護(hù)著這個(gè)影子權(quán)重,但是這個(gè)影子權(quán)重并不會(huì)參與訓(xùn)練。
基本的假設(shè)是,模型權(quán)重在最后的n步內(nèi),會(huì)在實(shí)際的最優(yōu)點(diǎn)處抖動(dòng),所以我們?nèi)∽詈髇步的平均,能使得模型更加的魯棒。
PyTorch代碼實(shí)現(xiàn)
下面是一個(gè)簡(jiǎn)單的指數(shù)移動(dòng)平均(EMA)的PyTorch實(shí)現(xiàn):
import torchclass EMA():def __init__(self, alpha):self.alpha = alpha # 初始化平滑因子alphaself.average = None # 初始化平均值為空self.count = 0 # 初始化計(jì)數(shù)器為0def update(self, x):if self.average is None: # 如果平均值為空,則將其初始化為與x相同大小的全零張量self.average = torch.zeros_like(x)self.average = self.alpha * x + (1 - self.alpha) * self.average # 更新平均值self.count += 1 # 更新計(jì)數(shù)器def get(self):return self.average / (1 - self.alpha ** self.count) # 根據(jù)計(jì)數(shù)器和平滑因子計(jì)算EMA值,并返回平均值除以衰減系數(shù)的結(jié)果
在這個(gè)類中,我們定義了三個(gè)方法,分別是__init__、update和get。
- __init__方法用于初始化平滑因子alpha、平均值average和計(jì)數(shù)器count
- update方法用于更新EMA值
- get方法用于獲取最終的EMA值。
使用這個(gè)類時(shí),我們可以先實(shí)例化一個(gè)EMA對(duì)象,然后在每個(gè)時(shí)間步中調(diào)用update方法來(lái)更新EMA值,最后調(diào)用get方法來(lái)獲取最終的EMA值。
例如:
ema = EMA(alpha=0.5)
for value in data:ema.update(torch.tensor(value))
smoothed_data = ema.get()
在這個(gè)例子中,我們使用alpha=0.5來(lái)初始化EMA對(duì)象,然后遍歷數(shù)據(jù)集data中的每個(gè)數(shù)據(jù)點(diǎn),調(diào)用update方法更新EMA值。最后我們調(diào)用get方法來(lái)獲取平滑后的數(shù)據(jù)。
yolov5中模型的EMA實(shí)現(xiàn)
如下:
class ModelEMA:""" Updated Exponential Moving Average (EMA) from https://github.com/rwightman/pytorch-image-modelsKeeps a moving average of everything in the model state_dict (parameters and buffers)For EMA details see https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage"""def __init__(self, model, decay=0.9999, tau=2000, updates=0):# Create EMAself.ema = deepcopy(de_parallel(model)).eval() # FP32 EMAself.updates = updates # number of EMA updatesself.decay = lambda x: decay * (1 - math.exp(-x / tau)) # decay exponential ramp (to help early epochs)for p in self.ema.parameters():p.requires_grad_(False)def update(self, model):# Update EMA parametersself.updates += 1d = self.decay(self.updates)msd = de_parallel(model).state_dict() # model state_dictfor k, v in self.ema.state_dict().items():if v.dtype.is_floating_point: # true for FP16 and FP32v *= dv += (1 - d) * msd[k].detach()# assert v.dtype == msd[k].dtype == torch.float32, f'{k}: EMA {v.dtype} and model {msd[k].dtype} must be FP32'def update_attr(self, model, include=(), exclude=('process_group', 'reducer')):# Update EMA attributescopy_attr(self.ema, model, include, exclude)
參考
https://zhuanlan.zhihu.com/p/68748778
如果有用,請(qǐng)點(diǎn)個(gè)三連唄 點(diǎn)贊、關(guān)注、收藏
。
你的鼓勵(lì)是我最大的動(dòng)力