MXNet中的autograd 自动求导/梯度

MXNet中的autograd 自动求导/梯度

  想要跑程序可以参考这里


  从例子出发,对于一个函数z = 2 * x * x,求z对x的导数
  为了求有关变量x的梯度(即是对x求导),我们需要先调用attach_grad()函数申请存储梯度所需要的内存

import mxnet.ndarray as nd
import mxnet.autograd as ag  #这两句也可以等价于from mxnet import autograd, nd
x = nd.array([[1,2],[3,4]]) #定义一个2*2的矩阵
x.attach_grad() #当我们求导时,需要一个地方来存x的导数

  接下来要定义有关变量x的函数。为了减少计算和内存开销,默认条件下MXNet不会记录用于求梯度的计算。我们需要调用record()函数来要求MXNet记录与求梯度有关的计算,即用record()函数来记录需要求导的程序。

with ag.record(): #record()函数用来记录我们需要求导的程序
    y = x*2
    z = y*x   # z = 2*x*x
z

[[ 2.  8.]
 [18. 32.]]
<NDArray 2x2 @cpu(0)>

  接下来我们可以通过调用backward()函数自动求梯度。需要注意的是,如果z不是一个标量,MXNet将默认先对z中元素求和得到新的变量,再求该变量有关x的梯度,即等价于nd.sum(z).backward()。(这里是对z求导,但z本身也是个矩阵,难道矩阵算作标量吗?这点不是很清楚。这里的结果好像是对z中每个元素进行求导。)

z.backward() #进行求导
x.grad #z对x的导数

[[ 4.  8.]
 [12. 16.]]
<NDArray 2x2 @cpu(0)>

  验证一波:

x.grad == 4*x #验证

[[1. 1.]
 [1. 1.]]
<NDArray 2x2 @cpu(0)>

  使用MXNet的一个便利之处是,即使函数的计算图包含了Python的控制流(如条件和循环控制),我们也有可能对变量求梯度。考虑下面程序,其中包含Python的条件和循环控制。需要强调的是,这里循环(while循环)迭代的次数和条件判断(if语句)的执行都取决于输入a的值。

def f(a):
    b = a * 2
    while b.norm().asscalar() < 1000: #norm()将b中的元素平方后求和,用asscalar()转换成标量
        b = b * 2
    if b.sum().asscalar() > 0:
        c = b
    else:
        c = 100 * b
    return c #可以看出,f(a) =  x * a,x的值取决于输入a

我们像之前一样使用record()函数记录计算,并调用backward()函数求梯度。

a = nd.random.normal(0,1,shape=3) #a的每个元素都随机采样于均值为0、标准差为1的正态分布  
a.attach_grad()
with ag.record():
    c = f(a)
c.backward()

对于上面定义的f函数,不难看出,给定任意输入a,其输出必然是 f(a) = x * a的形式,其中标量系数x的值取决于输入a。由于c = f(a)有关a的导数为x,且值为c / a,我们可以像下面这样验证对本例中控制流求梯度的结果的正确性:

a.grad == c/a

[1. 1. 1.]
<NDArray 3 @cpu(0)>

总结:对谁求导,对谁用attach_grad()函数;with ag.record():后面跟需要求导的程序;backward()计算导数;grad查看结果。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值