在mxnet中,NDArray是所有运算的核心数据结构,mxnet中的所有数据均使用NDArray进行表示,NDarray有点类似于numpy中的ndarray,操作上面也与numpy很相似,但是NDArray提供了numpy.ndarray所不具备的操作,比如:GPU,CPU的切换,自动求梯度的运算等等,这也是为什么mxnet要重新封装一个NDArray的原因。
NDArray就好比盖房子的砖,砖有了自然可以盖房子了,所以利用NDArray你便可以实现所有的深度学习模型了,只是深度学习日新月异,如果每个模型都从NDArray开始写,那当然是比较麻烦的,所以MXnet或者gluon帮我们封装了一些函数可以直接使用,接下来我们都会逐一的了解,那么这一节我们先来仔细学习一下mxnet的NDArray:
特别说明:下面的操作只是NDArray的一些基本操作,
获取更多的操作还请查找MXNet文档:https://mxnet.incubator.apache.org/api/python/ndarray/ndarray.html
当然,我希望你可以跟我一起来敲如下的代码而不是看一遍就过去了,事实证明,敲一遍的效果会好很多
在mxnet中,使用NDArray需要引用nd包(nd是ndarray的缩写),如下:
from mxnet import nd
在引入nd包之后就可以愉快的使用NDArry了。
特别说明,下面代码中 ‘->’ 代表的是输出结果
1. 定义x为一个序列,这里与numpy一致,不同的是,这里返回的每个元素类型都是ndarray
x = nd.arange(12) -> [0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.]
2. 当然我们可以打印出ndarray的shape以及size,这里的shape和size不要混淆了
x.shape -> (12 ,)
x.size -> 12
x.context -> x在CPU还是在GPU上
x.dtype -> data type,即每个元素的类型
## 当然,我们也可以改变元素的类型
x = x.astype(‘float32’) ## 利用astype便可以改变元素的类型了。
3. 那么如果我们想要构建一个二维矩阵怎么办呢?可以考虑reshape函数
x = nd.arange(12)
x.reshape(shape=(3,4))
# 当然你同样可以省略shape参数,直接这样写:
x.reshape((3,4)) ## 不过不要忘记(3,4)这个括号
4. 如果我们想初始化一个值为0或者值为1的多维矩阵该怎么做呢?
zero = nd.zeros((2,3,4)) # 别忘记了是负数
one = nd.ones((2,3,4))
5. 那如何建立一个随机初始化的矩阵呢?
S = nd.random.normal(0,1,shape=(3,4)) # normal是高斯分布
6. 当然我们也可以直接利用list直接建立ndarray,如下:
Y = nd.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])
7. 在计算机视觉中,图像一般是3维的,但是在进行模型训练的时候,往往需要将多张图像组成一个batch,构成4维数组,ndarray当然支持,使用concat:
x=nd.random.normal(shape=(2,3,4)) -> x.shape (2,3,4)
y=nd.random.normal(shape=(2,3,4)) -> y.shape (2,3,4)
z=nd.concat(x,y,dim=0) -> z.shape (4,3,4)
# 因为concat是不改变维度的,那么如果构建一个batch呢?利用expand_dims函数
x = nd.expand_dims(x, axis=0) -> x.shape (1,2,3,4)
y = nd.expand_dims(y, axis=0) -> y.shape (1,2,3,4)
z=nd.concat(x,y,dim=0) -> z.shape (2,2,3,4)
8. ndarray天然支持常用的数学计算,这里方法较多,可以查阅文档,里面有例子,使用会比较方便
S*Y
S/Y
S.exp()
S == Y
nd.dot(S,Y.T) ## 点乘比较常用,深度学习中矩阵计算就是使用的点乘,如果你从头编写神经网络,一定离不开点乘
nd.floor(S) ## 向下取整
nd.ceil(S) ## 向上取整
nd.argmax() ## 返回最大值的index
nd.topk() ## 返回topk
9. ndarray与numpy的相互转换:
# ndarray -> numpy
C = S.asnumpy()
# numpy -> ndarray
p = np.ones((2,3))
d = nd.array(p)
# 同样的,我们也可以直接返回一个标量
x = nd.ones((1,), dtype='int32')
y = x.asscalar() ## 这里注意,必须是1维的才可以使用,二维会报错。
10. 前面我们说了,NDArray可以自动计算梯度,那么如何使用呢?
1. 引用包 :from mxnet import autograd
2. 定义变量 : x = nd.arange(4).reshape((4,1))
3. 关联梯度,默认变量是不为梯度在内存开空间的,如果想要计算梯度,需要进行梯度关联,这样程序才会在内存上为变量开梯度的空间,如下:
x.attach_grad()
4. 计算的时候,使用autograd.record()记录梯度,如下是点乘的计算。
with autograd.record():
y = 2 * nd.dot(x.T,x)
5. 使用backward()计算梯度: y.backward()
总结到一起就是如下:
from mxnet import autograd
x = nd.arange(4).reshape((4,1))
x.attach_grad()
with autograd.record():
y = 2 * nd.dot(x.T,x)
y.backward()
11. 关于CPU与GPU的切换
x = nd.random.normal(shape=(3,4)) ## 默认在CPU内存中
y = nd.random.normal(shape=(3,4), ctx=mx.gpu(0)) ## 利用ctx指定对应的GPU
x = x.as_in_context(mx.gpu(0)) ## 利用as_in_context进行CPU到GPU的切换
12. 复制也是常用的操作,利用copy()可以避免浅拷贝的尴尬
x = nd.array([1,2,3])
y = x.copy()
## 为什么要使用copy()呢?因为在python中,默认的copy是浅拷贝,如果直接y=x,当x改变的时候,y会跟着改变,这就会出现错误。
特别说明:之上只是NDArray的一些基本操作,
获取更多的操作还请查找MXNet文档https://mxnet.incubator.apache.org/