The basic
创建矩阵
1 | import mxnet as mx |
或者也可以通过numpy.ndarray
来创建
1 | import numpy as np |
可以通过dtype
来指定元素类型
1 | # float32 is used in deafult |
同时还可以初始化矩阵而不需要给每一个元素指定数值,其中后面两种需要特别注意
1 | a=mx.nd.zeros((2,3)) |
基础操作
算数运算都是元素和元素之间的(elementwise)的,同时一个新的array
会被创建并用来存储这个结果。
1 | a = mx.nd.ones((2,3)) |
矩阵的乘法运算和numpy
一样,是使用dot
来实现的。
1 | a = mx.nd.ones((2,2)) |
+=
和*=
操作会直接修改现有的array
而不是去生成一个新的。
1 | a = mx.nd.ones((2,2)) |
索引和切片
其中将a
的第二行全部设置为了1
。
1 | a = mx.nd.array(np.arange(6).reshape(3,2)) |
也可以沿着特定的维度进行切片。沿着第二个维度进行切片,也就是将第二个维度中满足(begin,end]
的维度切出来。
1 | d = mx.nd.slice_axis(a, axis=1, begin=1, end=2) |
形状操作
将array
修改成另一个大小相同的array
。
1 | a = mx.nd.array(np.arange(24)) |
也可将多个array
进行拼接,可以使用concatenate
方法,在不给额外参数的情况下是沿着第0维拼接的。可以通过增加axis=1
来指定沿其他维度进行拼接,这时候要求这几个array
除了被axis
指定的维度的大小不一样以外,其他维度都要求是相同的。
1 | a = mx.nd.ones((2,3)) |
归约
沿着第一维求和,最后会让第一维消失
1 | a=mx.nd.ones((2,3)) |
Broadcast
这个操作会自动补齐维度,通过复制的方式
1 | a = mx.nd.array(np.arange(6).reshape(6,1)) |
1 | c = a.reshape((2,1,1,3)) |
*
和+
会自动使用boardcast
让两个矩阵的形状相同
数据拷贝
普通的赋值操作并不会产生新的数据,下面的b实际上还是a本身,类似指针。
1 | a = mx.nd.ones((2,2)) |
1 | True |
下面的操作同样也没有产生新的数据
1 | def f(x): |
显示
1 | True |
可以使用copy
操作来进行真正的拷贝
1 | b = a.copy() |
利用GPU进行运算
可以加上mx.gpu(0)
或者mx.gpu()
来切换到GPU
来进行计算
1 | a = mx.nd.ones((100, 100), mx.gpu(0)) |
则显示
1 | <NDArray 100x100 @gpu(0)> |
现在的MXNet
要求两个矩阵要在同一个设备上才能进行计算,可以将一个矩阵拷贝到GPU
上
1 | a = mx.nd.ones((100,100), mx.cpu()) |
将数据写到磁盘以及从磁盘中读取数据
使用pickle
1 | import pickle as pkl |
使用mxnet自带的功能
可以dump一个list
1 | a = mx.nd.ones((2,3)) |
NDArray和Numpy的区别
- NDArray每次只能对一个维度做切片,像
x[:,1]
这样同时对两个维度做切片是做不到的 - 切片只能是连续的,不能使用
x[1:2:3]
这样的 - 布尔索引是不被支持的
- 缺乏像
max
和min
这样的reduce函数
Symbol
创建三个symbol,并将其命名为a
,b
。可以使用mx.sym
和mx.symbol
,两者是一样的东西
1 | import mxnet as mx |
大部分的NDArray
的操作可以直接作用于Symbol
。
1 | # elemental wise times |
可以将网络可视化输出为pdf
只需要调用,但是似乎会报错。尽管会报错,但是输出的也是正常的。
1 | mx.viz.plot_network(symbol=g).view() |
Symbol和NDArray的关系
Symbol
可以提供几乎所有的NDArray
的功能。- 提供大量的神经网络相关操作,比如卷积,激活和
BatchNorm
。 - 提供自动求导的功能
- 便于构建和操作复杂的计算,例如深度神经网络
- 便于存储、加载和可视化
- 便于后端优化计算和内存使用
Symbol Save和Load
1
2
3
4print(c.tojson())
c.save('symbol-c.json')
c2 = mx.symbol.load('symbol-c.json')
c.tojson() == c2.tojson()
建立自己的操作
1 | class Softmax(mx.operator.CustomOp): |
这里用asnumpy
来将NDArray
转变成numpy.ndarray
,最后再用CustomOp.assign
来将结果写回mxnet.NDArray
。
1 | # register this operator into MXNet by name "softmax" |
最后能够使用mx.sym.Custom
和register name
来使用这个operator
1 | net = mx.symbol.Custom(data=prev_input, op_type='softmax') |
但是这个方法定义的operator
不能放在GPU
上运行。
Advanced Usages
MXNet
默认使用32-bit float
。有时候我们想要使用低精度的数据类型来获得更好的accuracy-performance trade-off
。例如Nvidia Tesla Pascal GPUs
已经改进了16-bit float
的性能,并且GTX Pascal GPUs
(e.g.GTX1080)在8-bit intergers
上是很快的。
我们可以使用mx.sym.Cast
操作来转换数据类型
1 | a = mx.sym.Variable('data') |
Variable Sharing
1 | a = mx.sym.Variable('a') |
Training and Inference Module
在这个tutorial中,我们将使用一个简单的多层感知机和一个合成的数据集
1 | import mxnet as mx |
Create Module
最广泛使用的模块是Module
,这个包含了Symbol
和一个或多个Executor
。我们构建一个module
通过
symbol
网络的符号context
执行的设备data_names
数据变量名字的listlabel_names
1
2
3
4mod = mx.mod.Module(symbol=net,
context=mx.cpu(),
data_names=['data'],
label_names=['softmax_label'])
Train, Predict and Evaluate
前面我们获得了一个mod
,然后这个模块提供了一个fit
函数,可以看到其中需要一个数据迭代器来传送训练数据和标准数据。
1 |
|
当整个模型训练好了之后,可以使用predict
来预测新的数据,输入的是一个数据迭代器,虽然每次只是输入一个batch,但是它会收集并返回所有的预测结果。
1 | y = mod.predict(data.get_iter(batch_size)) |
考虑到如果内存是不够的,那么也可以每次只预测一个batch
1 | for preds, i_batch, batch in mod.iter_predict(data.get_iter(batch_size)): |
如果是用来在测试集上做评价的话,可以使用score
函数来得出结果
1 | mod.score(data.get_iter(batch_size), ['mse', 'acc']) |
这里给了MSE
和ACC
两种度量方式,那么返回的也会是两种
1 | [('mse', 27.438781929016113), ('accuracy', 0.115625)] |
Save and Load
Save
我们可以在每一个epoch
结束之后保存模型的参数,这个里的方式就是使用一个回调函数。
1 | # @@@ AUTOTEST_OUTPUT_IGNORED_CELL |
Load
从磁盘中读取上一次的网络状态,然后将它设置到模型中
1 | sym, arg_params, aux_params = mx.model.load_checkpoint(model_prefix, 3) |
也可以直接直接开始训练
1 | # @@@ AUTOTEST_OUTPUT_IGNORED_CELL |
Module as a computation “machine”
一个模块有多个状态
Initial state
内存还未分配,还没有准备好计算Binded
输入、输出和参数的形状都已经知道了,内存也已经分配给它了,已经准备好了计算Parameter initialized
一个模块如果没有对参数初始化就进行计算的话,会出现没定义好的输出Optimizer installed
指定了网络的优化方式,只有这样才能对权值进行更新。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27# @@@ AUTOTEST_OUTPUT_IGNORED_CELL
# initial state
mod = mx.mod.Module(symbol=net)
# bind, tell the module the data and label shapes, so
# that memory could be allocated on the devices for computation
train_iter = data.get_iter(batch_size)
mod.bind(data_shapes=train_iter.provide_data, label_shapes=train_iter.provide_label)
# init parameters
mod.init_params(initializer=mx.init.Xavier(magnitude=2.))
# init optimizer
mod.init_optimizer(optimizer='sgd', optimizer_params=(('learning_rate', 0.1), ))
# use accuracy as the metric
metric = mx.metric.create('acc')
# train one epoch, i.e. going over the data iter one pass
for batch in train_iter:
mod.forward(batch, is_train=True) # compute predictions
mod.update_metric(metric, batch.label) # accumulate prediction accuracy
mod.backward() # compute gradients
mod.update() # update parameters using SGD
# training accuracy
print(metric.get())
Loading Data
Basic Data Iterator
这是一个数据迭代器,类似python中的迭代器。
1 | class SimpleBatch(object): |
一个batch
的形状应该是batch_size x num_chaneel x height x width
Symbol and Data Variables
新建一个数据迭代器
1 | import numpy as np |
mxnet.symbol.SoftmaxOutput
在前向传播中,这个函数会返回softmax
的输出,而在后向传播的时候,这个函数会加上logit loss
。
用numpy为mx.nd.array赋值
1 | a=mx.nd.ones((2,3),ctx=mx.gpu()) |
不能使用
1 | a=np.random.rand(*a.shape) |