编译:(AI公园)

导读

使用SAM(锐度感知最小化),优化到损失的最平坦的最小值的地方,增强泛化能力。

论文:

代码:

【过拟合】再也不用担心过拟合的问题了

动机来自先前的工作,在此基础上,我们提出了一种新的、有效的方法来同时减小损失值和损失的锐度。具体来说,在我们的处理过程中,进行锐度感知最小化(SAM),在领域内寻找具有均匀的低损失值的参数。这个公式产生了一个最小-最大优化问题,在这个问题上梯度下降可以有效地执行。我们提出的实证结果表明,SAM在各种基准数据集上都改善了的模型泛化。

在深度学习中,我们使用SGD/Adam等优化算法在我们的模型中实现收敛,从而找到全局最小值,即训练数据集中损失较低的点。但等几种研究表明,许多网络可以很容易地记住训练数据并有能力随时,为了防止这个问题,增强泛化能力,谷歌研究人员发表了一篇新论文叫做 ,在上以及其他的数据集上达到了最先进的结果。

在本文中,我们将看看为什么SAM可以实现更好的泛化,以及我们如何在中实现SAM。

SAM的原理是什么?

在梯度下降或任何其他优化算法中,我们的目标是找到一个具有低损失值的参数。但是,与其他常规的优化方法相比,SAM实现了更好的泛化,它将重点放在领域内寻找具有均匀的低损失值的参数(而不是只有参数本身具有低损失值)上。

由于计算邻域参数而不是计算单个参数,损失超平面比其他优化方法更平坦,这反过来增强了模型的泛化。

【过拟合】再也不用担心过拟合的问题了

(左))用SGD训练的收敛到的一个尖锐的最小值。(右)用SAM训练的相同的收敛到的一个平坦的最小值。

注意:SAM不是一个新的优化器,它与其他常见的优化器一起使用,比如SGD/Adam。

在中实现SAM

在中实现SAM非常简单和直接

import torch

class SAM(torch.optim.Optimizer):
    def __init__(self, params, base_optimizer, rho=0.05, **kwargs):
        assert rho >= 0.0f"Invalid rho, should be non-negative: {rho}"

        defaults = dict(rho=rho, **kwargs)
        super(SAM, self).__init__(params, defaults)

        self.base_optimizer = base_optimizer(self.param_groups, **kwargs)
        self.param_groups = self.base_optimizer.param_groups

    @torch.no_grad()
    def first_step(self, zero_grad=False):
        grad_norm = self._grad_norm()
        for group in self.param_groups:
            scale = group["rho"] / (grad_norm + 1e-12)

            for p in group["params"]:
                if p.grad is Nonecontinue
                e_w = p.grad * scale.to(p)
                p.add_(e_w)  # climb to the local maximum "w + e(w)"
                self.state[p]["e_w"] = e_w

        if zero_grad: self.zero_grad()

    @torch.no_grad()
    def second_step(self, zero_grad=False):
        for group in self.param_groups:
            for p in group["params"]:
                if p.grad is Nonecontinue
                p.sub_(self.state[p]["e_w"])  # get back to "w" from "w + e(w)"

        self.base_optimizer.step()  # do the actual "sharpness-aware" update

        if zero_grad: self.zero_grad()


    def _grad_norm(self):
        shared_device = self.param_groups[0]["params"][0].device  # put everything on the same device, in case of model parallelism
        norm = torch.norm(
                    torch.stack([
                        p.grad.norm(p=2).to(shared_device)
                        for group in self.param_groups for p in group["params"]
                        if p.grad is not None
                    ]),
                    p=2
               )
        return norm

代码取自非官方的实现。

代码解释:

【过拟合】再也不用担心过拟合的问题了

from sam import SAM
...

model = YourModel()
base_optimizer = torch.optim.SGD  # define an optimizer for the "sharpness-aware" update
optimizer = SAM(model.parameters(), base_optimizer, lr=0.1, momentum=0.9)
...

for input, output in data:

  # first forward-backward pass
  loss = loss_function(output, model(input))  # use this loss for any training statistics
  loss.backward()
  optimizer.first_step(zero_grad=True)
  
  # second forward-backward pass
  loss_function(output, model(input)).backward()  # make sure to do a full forward pass
  optimizer.second_step(zero_grad=True)
...

总结

虽然SAM的泛化效果较好,但是这种方法的主要缺点是,由于前后两次计算锐度感知梯度,需要花费两倍的训练时间。除此之外,SAM还在最近发布的上证明了它的效果,这是目前的最高水平,在未来,我们可以期待越来越多的论文利用这一技术来实现更好的泛化。

英文原文:

说个正事哈

由于微信平台算法改版,公号内容将不再以时间排序展示,如果大家想第一时间看到我们的推送,强烈建议星标我们和给我们多点点【在看】。星标具体步骤为:

(1)点击页面最上方“深度学习自然语言处理”,进入公众号主页。

(2)点击右上角的小点点,在弹出页面点击“设为星标”,就可以啦。

感谢支持,比心

投稿或交流学习,备注:昵称-学校(公司)-方向,进入DL&NLP交流群。

方向有很多:机器学习、深度学习,,情感分析、意见挖掘、句法分析、机器翻译、人机对话、知识图谱、语音识别等。

记得备注呦

整理不易,还望给个在看!

发表回复

后才能评论