动手深度学习--自动求梯度--3

2.3. 自动求梯度

在深度学习中,我们经常需要对函数求梯度(gradient)。本节将介绍如何使用MXNet提供的autograd模块来自动求梯度。

通过下面的代码导入autograd模块

from mxnet import autograd

2.3.1. 一个简单的例子

我们先来看一个简单的例子,如何使用MXNet来求解 y = 2 x T x y=2x^T x y=2xTx这个函数关于 x x x的梯度的方法。

print('简单例子')
x=nd.arange(4).reshape((4,1))#创建一个4*1的向量,元素值为从0到3
print(x)

# 1. 为了求有关变量x的梯度,我们需要先调用attach_grad函数来申请存储梯度所需要的内存。
x.attach_grad()

# 2. 我们需要调用record函数来要求MXNet记录与求梯度有关的计算。
with autograd.record():
    y=2*nd.dot(x.T,x)#定义有关变量x的函数。

# 3. 通过调用backward函数自动求梯度。当y不是一个标量,MXNet将默认先对y中元素求和得到新变量,再求该变量有关x的梯度。
y.backward()

assert (x.grad-4*x).norm().asscalar()==0 #判断函数y关于x的梯度是否正确
# 4. 输出梯度
print(x.grad)

输出:

简单例子

[[0.]
 [1.]
 [2.]
 [3.]]


[[ 0.]
 [ 4.]
 [ 8.]
 [12.]]

在上面的例子中,仅定义y=2*nd.dot(x.T,x)这个表达式不会记录用于求梯度的计算,这是为了减少计算和内存开销。通过调用record函数来要求MXNet记录与求梯度有关的计算。

2.4.2. 训练模式和预测模式

从上面可以看出,在调用record函数后,MXNet会记录并计算梯度。此外,默认情况下autograd还会将运行模式从预测模式转为训练模式。这可以通过调用is_training函数来查看。

print('训练模式和预测模式')
print(autograd.is_training())
with autograd.record():
    print(autograd.is_training())

在有些情况下,同一个模型在训练模式和预测模式下的行为并不相同。

2.4.3. 对python控制流求梯度

使用MXNet的一个便利之处是,即使函数的计算图包含了Python的控制流(如条件和循环控制),我们也有可能对变量求梯度。
本节将提供一个包含python条件和循环控制的函数,输入值为a,输出为c。我们将对a求解梯度。

print('对Python控制流求梯度')
# 定义一个函数,待会将对这个函数求关于a的梯度
def f(a):
    b=a*2
    while b.norm().asscalar()<1000:
        b=b*2
    if b.sum().asscalar()>0:
        c=b
    else:
        c=100*b
    return c

a=nd.random.normal(shape=1)
# 1. 为了求有关变量a的梯度,我们需要先调用attach_grad函数来申请存储梯度所需要的内存。
a.attach_grad()
# 2. 我们需要调用record函数来要求MXNet记录与求梯度有关的计算。
with autograd.record():
    c=f(a)
# 3. 通过调用backward函数自动求梯度。
c.backward()

# 4. 验证梯度求解的是否正确
print(a.grad==c/a)

输出:

对Python控制流求梯度

[1.]

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

练习

  • 在本节对控制流求梯度的例子中,把变量a改成一个随机向量或矩阵。此时计算结果c不再是标量,运行结果将有何变化?该如何分析该结果?

    print('练习1')
    a=nd.random.normal(shape=2)
    print(a)
    a.attach_grad()
    with autograd.record():
    	c=f(a)
    c.backward()
    print(a.grad)
    print(c)
    

    输出:

    练习1
    
    [0.4838046  0.29956347]
    
    
    [2048. 2048.]
    
    
    [990.83185 613.506  ]
    
    

    从上面可以发现,将变量a改为一个随机的包含两个元素的向量。此时计算结果c也为包含两个元素的向量,得到a的梯度也为包含两个元素的向量。运算的结果的判断方式还是a.grad==c/a,这里的c/a为对应元素相除。

  • 重新设计一个对控制流求梯度的例子。运行并分析结果。

你可能感兴趣的:(深度学习,mxnet,机器学习,动手深度学习笔记)