【深度学习】MXNet自动求解函数梯度

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28869927/article/details/84946899

概述

本节需要先了解MXNet中NDArray的基本用法,可以参考我的前一篇博客:【深度学习】MXNet基本数据结构NDArray常用操作

如下示例包括:

  1. MXNet中使用autograd包自动求解梯度;
  2. MXNet可以python中自定义的函数(一般化的命令式程序)求梯度;
  3. MXNet的运行模式包含训练模式和预测模式,可以通过特定函数进行判断。

示例

示例代码中包含了python中的with用法,先做简单介绍。

with语句

简单来说,with提供了一种资源管理的方式。资源的管理在程序设计中是一个很常见的问题,例如管理开启的文件、网络 socket 和各种锁(locks)等。最主要的问题就在于我们必须确保这些开启的资源在使用完之后,确实被关闭或释放。如果忘记关闭这些资源,可能会造成程序执行上的效能问题,甚至出现错误。而除了关闭之外,有些特殊的资源在使用完毕之后,还必须进行一些后续的清理操作,这些也都是资源管理上需要注意的。

Python 语言提供了 with 这个独特的语法,可让程序设计者更容易管理这些开启的资源,在这样的语法架构之下,Python 程序会自动进行资源的建立、清理与回收动作,让程序设计者在使用各种资源时更为方便。

下面举一个简单的使用文件资源的例子:

当我们需要使用一个文件资源,可能会这样写:

# 开启
f = open(filename)
...
# 关闭
f.close()

这种写法会有一个问题,如果在使用文件的过程中发生了一些意外状况,造成程序提早跳开时,这个开启的文件就没有被关闭。所以比较好的写法是使用 tryfinally

# 开启
f = open(filename)
try:
	...
finally:
	# 关闭
	f.close()

上面这种写法虽然不会有问题,但是缺点就是必须手动加入关闭文件的代码,不是很方便,也很容易忘记。

with则可以解决上述问题,使用 with 开启文件时,会将开启的文件放在 f 变量中。 f 只有在 with 的范围内使用,离开范围时就会自动被关闭,回收相关的资源。

# 开启
with open(filename) as f:
	f.write("hello mxnet!")

求解梯度代码

# coding=utf-8
# author: BebDong
# 2018.12.10
# 梯度相关计算

from mxnet import nd, autograd

print('------- A Simple Example -------')
# 求解函数:y=2(X^T)X关于列向量X的梯度
X = nd.arange(4).reshape(4, 1)              # 创建列向量
X.attach_grad()                             # 调用attach_grad函数申请存储梯度的内存
with autograd.record():
    y = 2 * nd.dot(X.T, X)                  # 定义函数y。record函数要求MXNet记录与求梯度相关的计算,默认条件不计算

y.backward()                                # backward函数用于自动求梯度。y若不是标量,MXNet将对y所有元素求和得到新变量,再求这个变量关于X的梯度

assert (X.grad - 4 * X).norm().asscalar() == 0  # 验证梯度是否为4X
print(X.grad)                                   # 输出结果也是NDArray格式


print('\n------- Different Mode Detection -------')
# 默认autograd会将运行模式从预测模式转换为训练模式,可通过函数is_training查看
print(autograd.is_training())
with autograd.record():
    print(autograd.is_training())


print('\n------- Gradient on Python Block -------')
# 即使函数的计算包含了python的控制流,使用MXNet也可能对变量求梯度


def f(a):                                              # python控制流,示例包含while循环和if条件
    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)                          # 创建一个元素的NDArray
a.attach_grad()                                        # 调用attach_grad函数申请存储梯度的内存
with autograd.record():                                # record函数记录梯度
    c = f(a)
c.backward()                                           # backward函数求解梯度
print(a.grad == c / a)                                 # f(a)实际上是一个c关于a的线性函数,梯度为:c/a

猜你喜欢

转载自blog.csdn.net/qq_28869927/article/details/84946899
今日推荐