第零章第2节——工欲善其事必先利其器

0.2 MXNet框架

0.2.1 数据操作

            在MXNet中,NDArray是一个类,也是存储和变换数据的主要工具,下面介绍其常用方法。

0.2.1.1 创建NDArray

先介绍下NDArray的基本功能。首先从MXNet导入ndarray模块              

然后我们用arrange函数创建一个行向量。

这时返回一个NDArray实例,其中包含了从0开始的12个连续整数。从打印x时显示的属性<NDArray 12 @cpu(0)>可以看出,它是长度为12的一维数组,且被创建在CPU使用的内存上。

可以用shape属性来获取NDArray实例的形状。

也可以用size属性来获取NDArray实例中元素的总数。

下面使用reshape函数把向量x的形状改为(3,4),即一个3行4列的矩阵,并记作X。

注意X属性中的形状发生了变化。上面x.reshape((3,4))也可以写成x.reshape((-1,4))或x.reshape((3,-1))。由于x的元素个数是已知的,这里的-1是能通过元素个数和其他唯独的大小推断出来的。

接着,我们创建一个各元素为0,形状为(2,3,4)的张量。

类似,可以创建各元素为1的张量。

也可以通过列表指定需要创建的NDArray中的每个元素的值。

下面创建一个形状为(3,4)的NDArray。它的每个元素都随机采样于均值0,、标准差为1的正态分布。

0.2.2 运算

NDArray支持大量的运算符(operator)。例如,我们可以对之前创建的两个形状为(3,4)的NDArray做按元素的加法,所得结果形状不变。

按元素乘法:

按元素除法:

按元素做指数运算:

使用dot函数做X和Y的转置的矩阵乘法:

可以将多个NDArray连接(concatenate)。下面分别在行上(维度0,即形状中的最左边元素)和列上(维度1,即形状中坐起第二个元素)连接两个矩阵。

输出的第一个NDArray在维度0的长度(6)为两个输入矩阵在维度0的长度之和(3+3),而输出的第二个NDArray在维度1的长度(8)为两个输入矩阵在维度1的长度之和(4+4)。

使用条件判断式可以得到元素为0或1的新的NDArray。以X==Y为例,如果X和Y在相同位置的条件判断为真(值相等),那么新的NDArray在相同位置的值为1;反之为0。

 

对NDArray中的所有元素求和得到只有一个元素的NDArray。

可以通过asscalar函数将结果变换为Python中的标量。下面例子中X的L_{2}范数结果同上例一样是氮元素NDArray,但最后结果变换成了Python中的标量。

我们也可以把Y.exp()、X.sum()、X.norm()等分别改写为nd.exp(Y)、nd.sum(X)、nd.norm(X)等。

0.2.3 广播(broadcasting)机制

        前面所述的都是形状相同的NDArray做按元素运算。当两个形状不同的NDArray按元素运算时,可能会触发广播机制:先适当复制元素使这两个NDArray形状相同后再按元素运算。

定义两个NDArray:

由于A和B分别是3行1列和1行2列的矩阵,如果要计算A+B,那么A中第一列的3个元素被广播(复制)到了第二列,而B中第一行的2个元素被广播(复制)到了第二行和第三行。如此,就可以对2个3行2列的矩阵按元素相加。

0.2.4 索引

在NDArray中,索引(index)代表了元素的位置。NDArray的索引从0开始逐一递增。例如,一个3行2列的矩阵的行索引分别为0、1和2,列索引分别为0和1。

在下面的例子中,我们制定了NDArray的行索引截取范围[1:3]。依据左闭右开指定范围的惯例,它截取了矩阵X中行索引为1和2的两行。

我们可以指定NDArray中需要访问的单个元素的位置,如矩阵中行和列的索引,并为该元素重新赋值。

当然,我们也可以截取一部分元素,并为他们重新赋值。在下面的例子中,我们为行索引为1的每一列元素重新赋值。

0.2.5 运算的内存开销

在前面的例子中我们对每个操作新开内存来存储运算结果。举个例子,即使像Y = X + Y这样的运算,我们也会新开内存,然后将Y指向新内存。为了演示这一点,我们可以使用Python自带的id函数:如果两个实例的ID一致,那么他们所对应的的内存地址相同;反之则不同。

若果想指定结果到特定内存,我们可以使用前面介绍的索引来进行替换操作。在下面的例子中,我们先通过zeros_like创建和Y形状相同且元素为0的NDArray,记为Z。接下来,我们把X + Y的结果通过[:]写进Z对应的内存中。

实际上,上例中我们还是为X + Y开了临时内存来存储计算结果,再复制到Z对应的内存。如果想避免这个临时内存开销,我们可以使用运算符全名函数中的out函数。

如果X的值在之后的程序中不会复用,我们也可以用X[:] = X + Y 或者 X += Y来减少运算的内存开销。

0.2.6 NDArray和NumPy相互变换

我们可以通过array函数和asnumpy函数令数据在NDArray和NumPy格式之间相互变换。下面将NumPy实例变换成NDArray实例。

再将NDArray实例变换成NumPy实例。

0.2.7 自动求梯度

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

0.2.7.1 一个简单例子

对函数y=2x^{\top }x求关于列向量x的梯度。我们先创建变量x,并赋初值。

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

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

由于x的形状为(4,1),y不是一个标量。接下来我们可以通过调用backward函数自动求梯度。需要注意的是,如果y不是一个标量,MXMNet将默认先对y中元素求和得到新的变量,再求该变量有关x的梯度。

函数y=2x^{\top }x关于x的梯度应为4x。现在我们来验证下求出的梯度是正确的。

0.2.7.2 训练模式和预测模式

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值