深度學(xué)習(xí)調(diào)參技巧 調(diào)參trick

|公|眾|號|包包算法筆記|

背景

事情的起因其實這樣,實驗室老同學(xué)的論文要沖分,問我有沒有啥在NN上,基本都有用的刷點方法,最好是就是短小精悍,代碼量不大,不需要怎么調(diào)參。

一般通用的trick都被寫進(jìn)論文和代碼庫里了,

像優(yōu)秀的優(yōu)化器,學(xué)習(xí)率調(diào)度方法,數(shù)據(jù)增強,dropout,初始化,BN,LN,確實是調(diào)參大師的寶貴經(jīng)驗,大家平常用的也很多。

除了這些,天底下還有這樣的好事?

確實有一些這樣的方法的,他們通用,簡單。根據(jù)我的經(jīng)驗,在大多數(shù)的數(shù)據(jù)上都有效。

一、對抗訓(xùn)練

第一個,對抗訓(xùn)練。

對抗訓(xùn)練就是在輸入的層次增加擾動,根據(jù)擾動產(chǎn)生的樣本,來做一次反向傳播。

以FGM為例,在NLP上,擾動作用于embedding層。

給個即插即用代碼片段吧,引用了知乎id:Nicolas的代碼,寫的不錯,帶著看原理很容易就明白了。

import torch
class FGM():
    def __init__(self, model):
        self.model = model
        self.backup = {}

    def attack(self, epsilon=1., emb_name='emb.'):
        # emb_name這個參數(shù)要換成你模型中embedding的參數(shù)名
        for name, param in self.model.named_parameters():
            if param.requires_grad and emb_name in name:
                self.backup[name] = param.data.clone()
                norm = torch.norm(param.grad)
                if norm != 0 and not torch.isnan(norm):
                    r_at = epsilon * param.grad / norm
                    param.data.add_(r_at)

    def restore(self, emb_name='emb.'):
        # emb_name這個參數(shù)要換成你模型中embedding的參數(shù)名
        for name, param in self.model.named_parameters():
            if param.requires_grad and emb_name in name: 
                assert name in self.backup
                param.data = self.backup[name]
        self.backup = {}

具體FGM的實現(xiàn)

# 初始化
fgm = FGM(model)
for batch_input, batch_label in data:
    # 正常訓(xùn)練
    loss = model(batch_input, batch_label)
    loss.backward() # 反向傳播,得到正常的grad
    # 對抗訓(xùn)練
    fgm.attack() # 在embedding上添加對抗擾動
    loss_adv = model(batch_input, batch_label)
    loss_adv.backward() # 反向傳播,并在正常的grad基礎(chǔ)上,累加對抗訓(xùn)練的梯度
    fgm.restore() # 恢復(fù)embedding參數(shù)
    # 梯度下降,更新參數(shù)
    optimizer.step()
    model.zero_grad()

二、EMA

第二個,EMA(指數(shù)滑動平均)

移動平均,保存歷史的一份參數(shù),在一定訓(xùn)練階段后,拿歷史的參數(shù)給目前學(xué)習(xí)的參數(shù)做一次平滑。這個東西,我之前在earhian的祖?zhèn)鞔a里看到的。他喜歡這東西+衰減學(xué)習(xí)率。確實每次都有用。

代碼引用博客:https://fyubang.com/2019/06/01/ema/

# 初始化
ema = EMA(model, 0.999)ema.register()# 訓(xùn)練過程中,更新完參數(shù)后,同步update shadow weightsdef train():    optimizer.step()    ema.update()# eval前,apply shadow weights;eval之后,恢復(fù)原來模型的參數(shù)def evaluate():    ema.apply_shadow()    # evaluate    ema.restore()

具體EMA實現(xiàn),即插即用:

class EMA():
    def __init__(self, model, decay):
        self.model = model
        self.decay = decay
        self.shadow = {}
        self.backup = {}

    def register(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                self.shadow[name] = param.data.clone()

    def update(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                assert name in self.shadow
                new_average = (1.0 - self.decay) * param.data + self.decay * self.shadow[name]
                self.shadow[name] = new_average.clone()

    def apply_shadow(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                assert name in self.shadow
                self.backup[name] = param.data
                param.data = self.shadow[name]

    def restore(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                assert name in self.backup
                param.data = self.backup[name]
        self.backup = {}

# 初始化
ema = EMA(model, 0.999)
ema.register()

# 訓(xùn)練過程中,更新完參數(shù)后,同步update shadow weights
def train():
    optimizer.step()
    ema.update()

# eval前,apply shadow weights;eval之后,恢復(fù)原來模型的參數(shù)
def evaluate():
    ema.apply_shadow()
    # evaluate
    ema.restore()

三、TTA

第三個,TTA。

這個一句話說明白,測試時候構(gòu)造靠譜的數(shù)據(jù)增強,簡單一點的數(shù)據(jù)增強方式比較好,然后把預(yù)測結(jié)果加起來算個平均。

這個實現(xiàn)實在是比較簡單,就不貼代碼了。

四、偽標(biāo)簽

第四個,偽標(biāo)簽學(xué)習(xí)。

這個也一句話說明白,就是用訓(xùn)練的模型,把測試數(shù)據(jù),或者沒有標(biāo)簽的數(shù)據(jù),推斷一遍。構(gòu)成偽標(biāo)簽,然后拿回去訓(xùn)練。注意不要leak。

下面那個老圖,比較形象。

image.gif

五、特定樣本處理

第五個,特定樣本處理。

說這個通用勉強一點,但確實在這類數(shù)據(jù)上基本都有效。

就是小樣本,長尾樣本,或者模型不太有把握的樣本。把分類過程為根據(jù)特征檢索的過程。

用向量表征去查找最近鄰樣本。

這塊,有個ICLR2020的文章寫的比較好,facebook的老哥把幾種典型的方法整理了一下,具體可以參考:

https://arxiv.org/abs/1910.09217

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容