简单例子
首先我们要导入所需要的模块:
from mxnet import nd, autograd
对函数y = 2xTx求关于列向量x的梯度(注:这里我们可以视作给函数y=2x2求导),我们先创建变量x,并赋初始值。
x = nd.arange(4).reshape((4, 1))
为了求有关变量x的梯度,我们需要先调⽤attach_grad函数来申请存储梯度所需要的内存。
x.attach_grad()
下面定义有关变量x的函数。为了减少计算和内存开销,默认条件下MXNet不会记录⽤于求梯度的计算。我们需要调用record函数来要求MXNet记录与求梯度有关的计算。
with autograd.record():
y = 2 * nd.dot(x.T, x)
注:with
语句是一个上下文管理器,可以很好的处理上下文环境产生的异常,这里我们可以简单理解为开辟一个"容器"来"盛放"定义的函数。
autograd.record()
是一个记录需要求梯度的函数的程序。
由于x的形状为(4, 1),y是一个标量。接下来我们可以通过调⽤backward函数⾃动求梯度。需要注意的是,如果y不是一个标量,MXNet将默认先对y中元素求和得到新的变量,再求该变量有关x的梯度。
y.backward()
函数 y = 2x T x 关于x 的梯度应为4x。现在我们来验证一下求出来的梯度是正确的。
assert (x.grad - 4 * x).norm().asscalar()==0 # 判断梯度是否是4x
print(x.grad)
注:assert
是python中很重要的一个功能,可以在条件不满足程序运行的情况下直接返回错误,而不必等待程序运行后出现崩溃的情况,没有实际输出。
输出:
[[ 0.]
[ 4.]
[ 8.]
[12.]]
<NDArray 4x1 @cpu(0)>
这里的输出结果是我们最开始对x初始值设定下每点的梯度值(也可以理解为函数f(x)在各点的导数值)。下面是完整代码:
from mxnet import nd, autograd
# 设定初始值
x = nd.arange(4).reshape((4, 1))
x.attach_grad()
# 定义函数并求导
with autograd.record():
y = 2 * nd.dot(x.T, x)
y.backward()
# 判定准确性并输出结果
assert (x.grad - 4 * x).norm().asscalar() == 0
print(x.grad)
*训练模式和预测模式
这里不多作介绍,后面再详细说明。
对Python控制流求梯度
在MXNet中,即使函数的计算图包含了Python的控制流(如条件和循环控制),我们也有可能对变量求梯度。如下:
from mxnet import nd, autograd
def f(x): # 定义函数
b = x * 2
while b.norm().asscalar() < 1000: # 这里x相当于输入的未知数,由于只有一个元素,我们可以把这一步理解为取b的绝对值
b = b * 2
if b.sum().asscalar() > 0:
c = b
else:
c = 100 * b
return c # 在上述整个过程中,对未知数的转换仅限于对其系数的变换,所以最后的输出结果可以理解为c=k*x
x = nd.random.normal(shape=1) # 创建一个随机数作为未知数x的值
x.attach_grad()
with autograd.record():
c = f(x)
c.backward()
assert (x.grad - c / x).norm().asnumpy() == 0 # 验证函数
print(x.grad == c / x) # 输出判定结果
分析函数可知f (x)= c = kx,求导结果为k,所以最终结果x.grad = k = c / x
输出:
[1.]
<NDArray 1 @cpu(0)>
共有 0 条评论