pytorch 实现Gradient Flipping 各种坑

点击上方,选择星标置顶,每天给你送干货

阅读大概需要4分钟

跟随小博主,每天进步一丢丢

来自 | 知乎

地址 | https://zhuanlan.zhihu.com/p/263827804

作者 | 侠肝义胆陈浩天

编辑 | 机器学习算法与自然语言处理公众号

本文仅作学术分享,若侵权,请联系后台删文处理

实现梯度反转非常多坑,我来一一总结。

首先是pytorch版本的问题,一般旧版的这样写,定义一个类,然后用函数的方式去调用:

from torch.autograd import Function
class GradReverse(Function):
    def __init__(self, lambd):
        self.lambd = lambd

    def forward(self, x):
        return x.view_as(x)

    def backward(self, grad_output):
        return (grad_output * -self.lambd)


def grad_reverse(x, lambd=1.0):
    return GradReverse(lambd)(x)

不过现在这种写法已经不行了,我现在的版本是1.6.0。上面报错的解决方案十分简单,而且直接告诉你怎么改:

RuntimeError: Legacy autograd function with non-static forward method is deprecated. 
Please use new-style autograd function with static forward method.
# 直接让你参考:
https://pytorch.org/docs/stable/autograd.html#torch.autograd.Function

我们看看官网给出的例子:

和原来的区别:

  • 无需init了,直接转成静态:  staticmethod;

  • 在调用的时候,直接使用类名.apply使用;

  • 需要传参的时候,是这样写: ctx.lambda = lambda

这里注意,第一个参数必须是ctx. (Context method mixins),估计也是一种重复使用的组件之类的。。。以后补充

它这里的解释我也看得不是很明白。

注意这里还可能会在backward的时候报错:

Runtime Error: returned an incorrect number of gradients

这里的意思就是说程序默认返回所有forward参数个数的loss,i.e. 为每一个输入参数返回loss,现在我们并不需要给所有参数返回loss,只需要给input tensor返回就够了,其他的直接返回None就ok了。

追求完美的人记得在重写的时候把其他参数也带上,不然有warning。

最后改写成:

class GradReverse(Function):

    # 重写父类方法的时候,最好添加默认参数,不然会有warning
    @ staticmethod
    def forward(ctx, x, lambd, **kwargs: None):
        ctx.lambd = lambd
        return x.view_as(x)

    @staticmethod
    def backward(ctx, *grad_output):
        return grad_output * -ctx.lambd, None

补充说明,一定要注意Grad Reverse应用在叶子节点之前!!写了一个简单的程序来说明:

如图所示,不会影响到Linear_3

结合GAN理解

为什么不能直接在loss前面几个负号?事实上它们原理一样的,比如我最近做的SSDA。

https://zhuanlan.zhihu.com/p/264763158

但其实直接对loss加个负号,或者不要负号这样取反,很容易会出现梯度爆炸的情况。加上梯度反转层,程序会在优化过程中不会优化得“太过分”。直接优化loss,没有比优化参数好,这里应该可以是用数学直接推导出来的,希望未来有时间我可以推一下。

比如说,在GAN中我们使用CrossEntropy作为我们的loss function. 显然  , 在更新Generator的时候假如说我们不要负号,就是maximize了。试想一下,pred会越来越小,导致导数  越来越大,最终出现梯度爆炸。事实上这正是为什么在GAN中discriminator为什么是每更新几次,再到generator更新的原因。这里也说明了直接加负号与梯度反转的区别。(李宏毅老师的解释:判别器比生成器训练的步数多是因为希望内层max能够更好的近似生成分布和真实样本分布之间的js散度。事实上就是必须要有一个好的“指导”discriminator,才能很好的“教会”generator)

能不能对Minimax问题有一个新的见识,启发?

下载一:中文版!学习TensorFlow、PyTorch、机器学习、深度学习和数据结构五件套!

后台回复【五件套】
下载二:南大模式识别PPT

后台回复【南大模式识别】




说个正事哈

由于微信平台算法改版,公号内容将不再以时间排序展示,如果大家想第一时间看到我们的推送,强烈建议星标我们和给我们多点点【在看】。星标具体步骤为:(1)点击页面最上方“深度学习自然语言处理”,进入公众号主页。(2)点击右上角的小点点,在弹出页面点击“设为星标”,就可以啦。
感谢支持,比心。投稿或交流学习,备注:昵称-学校(公司)-方向,进入DL&NLP交流群。
方向有很多:机器学习、深度学习,python,情感分析、意见挖掘、句法分析、机器翻译、人机对话、知识图谱、语音识别等。记得备注呦

推荐两个专辑给大家:专辑 | 李宏毅人类语言处理2020笔记专辑 | NLP论文解读专辑 | 情感分析

整理不易,还望给个在看!
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值