MXNet是基础,Gluon是封装,两者犹如TensorFlow和Keras,不过得益于动态图机制,两者交互比TensorFlow和Keras要方便得多,其基础操作和pytorch极为相似,但是方便不少,有pytorch基础入门会很简单。注意和TensorFlow不同,MXNet的图片维度是 batch x channel x height x width 。

MXNet的API主要分为3层,最基础的时mxnet.ndarray(NDArray API),它以近似numpy数组的形式记录了诸多基础的函数式的操作,支持自动求导和GPU加速应该是它针对numpy的最主要改进;然后是mxnet.Symbol(Symbol API)模块,它是MXNet符号式编程的基石,与mxnet.model(Module API)模块相互搭配可以灵活、快速地构建网络,这一层比较类似TensorFlow;最后就是Gloun(Gluon API)模块,它更近似于Keras,高度的封装了代码。

市面上的大部分教程(包含框架作者的"动手学习深度学习")都以ndarray的简要上手为引入,以Gloun为主要学习内容,不过,如果经常浏览MXNet开源项目的话,会发现,实际上Symbol的使用才是主流。我对于Symbol的了解也很肤浅,有希望学习MXNet的新人如果看到这段引文希望能有针对的避开我掉进去的坑。

库导入写法,

from mxnet import ndarray as nd
from mxnet import autograd
from mxnet import gluon
import mxnet as mx

实际上第一个包 from mxnet import nd 也行,简化工作很厉害……

MXNet.ndarray

mxnet.ndarray是整个科学计算系统的基础,整体API和numpy的nparray一致,这一点类似于pytorch,不过不同于pytorch内置变量、张量等不同数据类型,mxnet简化了只有ndarray一种,通过mxnet.autograd可以直接实现求导,十分便捷.

自动求导

x = nd.arange(4).reshape((4, 1))
# 标记需要自动求导的量
x.attach_grad()
# 有自动求导就需要记录计算图
with autograd.record():
y = 2 * nd.dot(x.T, x)
# 反向传播输出
y.backward()
# 获取梯度
print('x.grad: ', x.grad)

设备

array.copyto()  # 传入设备则复制进设备,传入array则覆盖(也会进入传入的设备)

array.as_in_context()  # 修改设备

nd转化为数字

nd.asscalar()

nd与np数组互化

y = nd.array(x) # NumPy转换成NDArray。

z = y.asnumpy() # NDArray转换成NumPy。

节约内存的加法

nd.elemwise_add(x, y, out=z)

持久化

nd.save(file, [arr1, arr2, ……])

nd.load(file)

层实现

拉伸

nd.flatten(array)

relu激活

内置,

nd.nn.relu()

手动实现,

def relu(X):
return nd.maximum(X, 0)

卷积层

# 输入输出数据格式是 batch x channel x height x width,这里batch和channel都是1
# 权重格式是 output_channels x in_channels x height x width,这里input_filter和output_filter都是1。
w = nd.arange(4).reshape((1,1,2,2))
b = nd.array([1])
data = nd.arange(9).reshape((1,1,3,3)) out = nd.Convolution(data, w, b, kernel=w.shape[2:], num_filter=w.shape[1], stride=(2,2), pad=(1,1))

池化层

data = nd.arange(18).reshape((1,2,3,3))

max_pool = nd.Pooling(data=data, pool_type="max", kernel=(2,2))
avg_pool = nd.Pooling(data=data, pool_type="avg", kernel=(2,2))

全连接层

# 变量生成
w = nd.random.normal(scale=1, shape=(num_inputs, 1))
b = nd.zeros(shape=(1,))
params = [w, b] # 变量挂载梯度
for param in params:
param.attach_grad() # 实现全连接
def net(X, w, b):
return nd.dot(X, w) + b

批量归一化层

在测试时我们还是需要继续使用批量归一化的,只是需要做些改动。在测试时,我们需要把原先训练时用到的批量均值和方差替换成整个训练数据的均值和方差。但 是当训练数据极大时,这个计算开销很大。因此,我们用移动平均的方法来近似计算(参见实现中的moving_meanmoving_variance)。

def batch_norm(X, gamma, beta, is_training, moving_mean, moving_variance,
eps = 1e-5, moving_momentum = 0.9):
assert len(X.shape) in (2, 4)
# 全连接: batch_size x feature
if len(X.shape) == 2:
# 每个输入维度在样本上的平均和方差
mean = X.mean(axis=0)
variance = ((X - mean)**2).mean(axis=0)
# 2D卷积: batch_size x channel x height x width
else:
# 对每个通道算均值和方差,需要保持4D形状使得可以正确的广播
mean = X.mean(axis=(0,2,3), keepdims=True)
variance = ((X - mean)**2).mean(axis=(0,2,3), keepdims=True)
# 变形使得可以正确的广播
moving_mean = moving_mean.reshape(mean.shape)
moving_variance = moving_variance.reshape(mean.shape) # 均一化
if is_training:
X_hat = (X - mean) / nd.sqrt(variance + eps)
#!!! 更新全局的均值和方差
moving_mean[:] = moving_momentum * moving_mean + (
1.0 - moving_momentum) * mean
moving_variance[:] = moving_momentum * moving_variance + (
1.0 - moving_momentum) * variance
else:
#!!! 测试阶段使用全局的均值和方差
X_hat = (X - moving_mean) / nd.sqrt(moving_variance + eps) # 拉升和偏移
return gamma.reshape(mean.shape) * X_hat + beta.reshape(mean.shape)

Droupout

def dropout(X, drop_probability):
keep_probability = 1 - drop_probability
assert 0 <= keep_probability <= 1
# 这种情况下把全部元素都丢弃。
if keep_probability == 0:
return X.zeros_like() # 随机选择一部分该层的输出作为丢弃元素。
mask = nd.random.uniform(
0, 1.0, X.shape, ctx=X.context) < keep_probability
# 保证 E[dropout(X)] == X
scale = 1 / keep_probability
return mask * X * scale

SGD实现

def sgd(params, lr, batch_size):
for param in params:
param[:] = param - lr * param.grad / batch_size

Gluon

内存数据集加载

import mxnet as mx
from mxnet import autograd, nd
import numpy as np num_inputs = 2
num_examples = 1000
true_w = [2, -3.4]
true_b = 4.2
features = nd.random.normal(scale=1, shape=(num_examples, num_inputs))
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
labels += nd.random.normal(scale=0.01, shape=labels.shape) from mxnet.gluon import data as gdata batch_size = 10
dataset = gdata.ArrayDataset(features, labels)
data_iter = gdata.DataLoader(dataset, batch_size, shuffle=True) for X, y in data_iter:
print(X, y)
break
[[-1.74047375  0.26071024]
[ 0.65584248 -0.50490594]
[-0.97745866 -0.01658815]
[-0.55589193 0.30666101]
[-0.61393601 -2.62473822]
[ 0.82654613 -0.00791582]
[ 0.29560572 -1.21692061]
[-0.35985938 -1.37184834]
[-1.69631028 -1.74014604]
[ 1.31199837 -1.96280086]]
<NDArray 10x2 @cpu(0)>
[ -0.14842382 7.22247267 2.30917668 2.0601418 11.89551163
5.87866735 8.94194221 8.15139961 6.72600317 13.50252151]
<NDArray 10 @cpu(0)>

模型定义

  • 序列模型生成
  • 层填充
  • 初始化模型参数
net = gluon.nn.Sequential()
with net.name_scope():
net.add(gluon.nn.Dense(1))
net.collect_params().initialize(mx.init.Normal(sigma=1)) # 模型参数初始化选择normal分布

优化器:gluon.Trainer

wd参数为模型添加了L2正则化,机制为:w = w - lr*grad - wd*w

trainer = gluon.Trainer(net.collect_params(), 'sgd', {
'learning_rate': learning_rate, 'wd': weight_decay})

trainer.step(batch_size)需要运行在每一次反向传播之后,会更新参数,一次模拟的训练过程如下,

for e in range(epochs):
for data, label in data_iter_train:
with autograd.record():
output = net(data)
loss = square_loss(output, label)
loss.backward()
trainer.step(batch_size)
train_loss.append(test(net, X_train, y_train))
test_loss.append(test(net, X_test, y_test))

设备

net.collect_params().reset_ctx()可以重置model设备

持久化

net.save_params(file)

net.load_params(file, ctx)  # 可以指定加载设备

层函数API:gluon.nn

拉伸

nn.Flatten()

卷积层

nn.Conv2D(1, kernel_size=(1, 2)) # 输出通道1,卷积核横2纵

nn.Conv2D(channels=6, kernel_size=5, activation='sigmoid')

池化层

最大池化层

nn.MaxPool2D(pool_size=2, strides=2)

全连接层

nn.Dense(256, activation="relu")  # 参数表示输出节点数

激活函数

nn.Activation("relu")

批量归一化层

nn.BatchNorm(axis=1)  # 卷积层后的BN层对每个通道求一个平均

损失函数class API:gluon.loss

交叉熵

loss = gluon.loss.SoftmaxCrossEntropyLoss()

『MXNet』第一弹_基础架构及API的更多相关文章

  1. 『MXNet』第九弹_分类器以及迁移学习DEMO

    解压文件命令: with zipfile.ZipFile('../data/kaggle_cifar10/' + fin, 'r') as zin: zin.extractall('../data/k ...

  2. 『PyTorch』第一弹_静动态图构建if逻辑对比

    对比TensorFlow和Pytorch的动静态图构建上的差异 静态图框架设计好了不能够修改,且定义静态图时需要使用新的特殊语法,这也意味着图设定时无法使用if.while.for-loop等结构,而 ...

  3. 关于『Markdown』:第一弹

    关于『Markdown』:第一弹 建议缩放90%食用 声明: 在我之前已有数位大佬发布 "Markdown" 的语法知识点, 在此, 仅整理归类以及补缺, 方便阅读. 感谢 C20 ...

  4. 关于『HTML5』第一弹

    关于『HTML5』:第一弹 建议缩放90%食用 祝各位国庆节快乐!!1 经过了「过时的 HTML」.「正当时的 Markdown」的双重洗礼后,我下定决心,好好学习HTML5  这回不过时了吧(其实和 ...

  5. 关于『HTML』:第一弹

    关于『HTML』:第一弹 建议缩放90%食用 根据C2024XSC212童鞋的提问, 我准备写一稿关于『HTML』基础的帖 But! 当我看到了C2024XSC130的 "关于『HTML5』 ...

  6. 『PyTorch』第九弹_前馈网络简化写法

    『PyTorch』第四弹_通过LeNet初识pytorch神经网络_上 『PyTorch』第四弹_通过LeNet初识pytorch神经网络_下 在前面的例子中,基本上都是将每一层的输出直接作为下一层的 ...

  7. 『TensorFlow』第九弹_图像预处理_不爱红妆爱武装

    部分代码单独测试: 这里实践了图像大小调整的代码,值得注意的是格式问题: 输入输出图像时一定要使用uint8编码, 但是数据处理过程中TF会自动把编码方式调整为float32,所以输入时没问题,输出时 ...

  8. 『MXNet』第二弹_Gluon构建模型

    上节用了Sequential类来构造模型.这里我们另外一种基于Block类的模型构造方法,它让构造模型更加灵活,也将让你能更好的理解Sequential的运行机制. 回顾: 序列模型生成 层填充 初始 ...

  9. 『PyTorch』第二弹_张量

    参考:http://www.jianshu.com/p/5ae644748f21# 几个数学概念: 标量(Scalar)是只有大小,没有方向的量,如1,2,3等 向量(Vector)是有大小和方向的量 ...

随机推荐

  1. oracle 之 包,包体创建和使用案例

    先创建包,再创建包体---------------创建包体--------------------- create or replace package body pkg_yygl_service I ...

  2. P3239 [HNOI2015]亚瑟王

    思路 神仙概率dp 由于期望的线性性质,能够想到最后要求的期望价值就是把每个卡牌发动的概率\(g_i\)乘上伤害\(val_i\)之后加到一起 然后怎么求\(g_i\)呢,肯定是要dp的 我想了例如d ...

  3. P4609 [FJOI2016]建筑师

    思路 裸的第一类斯特林数,思路和CF960G相同 预处理组合数和第一类斯特林数回答即可 代码 #include <cstdio> #include <cstring> #inc ...

  4. p1654 OSU!

    期望DP 设\(g[i]\)表示前i个的连续1的期望长度,\(h[i]\)表示前i个连续1的长度的平方的期望,\(f[i]\)表示前i个的期望得分 由期望的线性性质,我们可以考虑统计新增一个对答案的贡 ...

  5. ZJOI 2015 幻想乡战略游戏(动态点分治)

    题意 https://loj.ac/problem/2135 思路 首先要明确一点,答案分布是有单调性的.什么意思呢?假设我们的答案在 \(u\) 节点,\((u,v)\) 之间有一条边且 \(u\) ...

  6. WijmoJS 使用Web Workers技术,让前端 PDF 导出效率更高效

    概述 Web Workers是一种Web标准技术,允许在后台线程中执行脚本处理. WijmoJS 的2018v3版本引入了Web Workers技术,以便在生成PDF时提高应用程序的运行速度. 一般来 ...

  7. PHP 内置函数fgets读取文件

    php fgets()函数从文件指针中读取一行 语法: fgets(file,length) 参数 描述 file  必需.规定尧要读取的文件 length 可选 .规定尧都区的字节数.默认是102字 ...

  8. 1st,Python基础——01

    1 Python介绍 2 Python发展史 3 Python2 or 3? 4 Python安装 就不写了,各路大牛的博客都很详细. 5 Hello World程序 #!/usr/bin/env p ...

  9. HttpUrlConnection底层实现和关于java host绑定ip即时生效的设置及分析

    最近有个需求需要对于获取URL页面进行host绑定并且立即生效,在java里面实现可以用代理服务器来实现:因为在测试环境下可能需要通过绑定来访问测试环境的应用实现代码如下: public static ...

  10. ZJOI-2017 R1游记

    无实力非既得利益的$xrdog$作为一名外卡选手去参加ZJOI2017啦... Day 0: 颓?(细节待填坑..) Day 1: 上午我来到讲课现场发现讲课内容是:搜索专题  QwQ不太清醒的我一下 ...