美文网首页
深度学习调参技巧 调参trick

深度学习调参技巧 调参trick

作者: ad110fe9ec46 | 来源:发表于2021-12-17 18:12 被阅读0次

    |公|众|号|包包算法笔记|

    背景

    事情的起因其实这样,实验室老同学的论文要冲分,问我有没有啥在NN上,基本都有用的刷点方法,最好是就是短小精悍,代码量不大,不需要怎么调参。

    一般通用的trick都被写进论文和代码库里了,

    像优秀的优化器,学习率调度方法,数据增强,dropout,初始化,BN,LN,确实是调参大师的宝贵经验,大家平常用的也很多。

    除了这些,天底下还有这样的好事?

    确实有一些这样的方法的,他们通用,简单。根据我的经验,在大多数的数据上都有效。

    一、对抗训练

    第一个,对抗训练。

    对抗训练就是在输入的层次增加扰动,根据扰动产生的样本,来做一次反向传播。

    以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这个参数要换成你模型中embedding的参数名
            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这个参数要换成你模型中embedding的参数名
            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的实现

    # 初始化
    fgm = FGM(model)
    for batch_input, batch_label in data:
        # 正常训练
        loss = model(batch_input, batch_label)
        loss.backward() # 反向传播,得到正常的grad
        # 对抗训练
        fgm.attack() # 在embedding上添加对抗扰动
        loss_adv = model(batch_input, batch_label)
        loss_adv.backward() # 反向传播,并在正常的grad基础上,累加对抗训练的梯度
        fgm.restore() # 恢复embedding参数
        # 梯度下降,更新参数
        optimizer.step()
        model.zero_grad()
    

    二、EMA

    第二个,EMA(指数滑动平均)

    移动平均,保存历史的一份参数,在一定训练阶段后,拿历史的参数给目前学习的参数做一次平滑。这个东西,我之前在earhian的祖传代码里看到的。他喜欢这东西+衰减学习率。确实每次都有用。

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

    # 初始化
    ema = EMA(model, 0.999)ema.register()# 训练过程中,更新完参数后,同步update shadow weightsdef train():    optimizer.step()    ema.update()# eval前,apply shadow weights;eval之后,恢复原来模型的参数def evaluate():    ema.apply_shadow()    # evaluate    ema.restore()
    

    具体EMA实现,即插即用:

    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()
    
    # 训练过程中,更新完参数后,同步update shadow weights
    def train():
        optimizer.step()
        ema.update()
    
    # eval前,apply shadow weights;eval之后,恢复原来模型的参数
    def evaluate():
        ema.apply_shadow()
        # evaluate
        ema.restore()
    

    三、TTA

    第三个,TTA。

    这个一句话说明白,测试时候构造靠谱的数据增强,简单一点的数据增强方式比较好,然后把预测结果加起来算个平均。

    这个实现实在是比较简单,就不贴代码了。

    四、伪标签

    第四个,伪标签学习。

    这个也一句话说明白,就是用训练的模型,把测试数据,或者没有标签的数据,推断一遍。构成伪标签,然后拿回去训练。注意不要leak。

    下面那个老图,比较形象。

    image.gif

    五、特定样本处理

    第五个,特定样本处理。

    说这个通用勉强一点,但确实在这类数据上基本都有效。

    就是小样本,长尾样本,或者模型不太有把握的样本。把分类过程为根据特征检索的过程。

    用向量表征去查找最近邻样本。

    这块,有个ICLR2020的文章写的比较好,facebook的老哥把几种典型的方法整理了一下,具体可以参考:

    https://arxiv.org/abs/1910.09217

    相关文章

      网友评论

          本文标题:深度学习调参技巧 调参trick

          本文链接:https://www.haomeiwen.com/subject/eqgifrtx.html