最近准备学习MXNet,发现官方文档的中文支持还不完整,便打算一边学习一边将文档翻译过来,以方便日后复习和之后的学习者。本文是官方文档的第一步“Get Started”,原文档链接:MXNet:Get Started。本人能力有限,有翻译的不足之处还请在下方留言,我会及时更新。
MXNet:一个可扩展深度学习框架
MXNet是一个开源的深度学习框架。它可以使你能自行定义、训练、配置和部署深度人工神经网络,并且适用于从云端到移动端诸多不同的设备上。可快速模型训练、灵活支持各种编程模型和语言使得MXNet具有高度的可扩展性。同时,它还允许混合使用命令式与符号式编程以最大化程序的效率和性能。MXNet建立了在运行时可以自动并行命令式与符号式操作符的动态依赖调度机制,运行在其上的图优化层使得符号的执行快速且节省存储空间。MXNet库轻量便携,并且可以扩展为多GPU或多机器模式。
灵活的编程模型:支持命令式和符号式编程模型以最大化效率和性能。
从云端到客户端可移植:可运行于多CPU、多GPU、集群、服务器、工作站甚至移动智能手机。
多语言支持:支持七种主流编程语言,包括C++、Python、R、Scala、Julia、Matlab和JavaScript。
本地分布式训练:支持在多CPU/GPU设备上的分布式训练,使其可充分利用云计算的规模优势。
性能优化:使用一个优化的C++后端引擎并行I/O和计算,无论使用哪种语言都能达到最佳性能。
MXNet开源社区
多模型支持:训练部署最新的深度卷积神经网络(CNNs)和长短期记忆(LSTMs)模型。
大量库参考示例:位于示例教程中(包括源代码),如图像分类、语言建模、神经网络艺术以及语音识别等。
开放合作的社区:由诸多顶尖大学和行业伙伴提供贡献和支持。
训练基于MNIST的多层感知机(MLP)
在开始学习MXNet前,让我们先通过训练一个基本的数字识别模型来大致了解MXNet的编程接口。我们将训练一个基于MNIST数据集的多层感知机(MLP)。之后,我们将进一步了解MXNet的张量计算接口。
符号计算
在MNIST中,每个样本由一个28*28大小的手写数字灰度图组成,样本的标签是一个0~9的整型。长为784的向量和标签分别由x和y来表示。
在没有隐层的情况下,MLP 预测的标签可能性如下:
textrm{softmax}(Wx+b)
W是一个784*10的权重矩阵,而b是一个长度为10的偏移向量。softmax操作将向量转换到概率分布。
为了得到一个多隐层的多层感知机,我们可以一个一个的堆叠每一层。令第0层的输出X0=X。第i层输出一个长度为ni的向量:
Xi = σi(WiXi-1+bi)
σi是激活函数,如tanh;Wi大小为ni*ni-1。之后,对最后一层使用softmax操作已得到预测值。
训练的目的是计算得到在训练集上使每一层的预测标签和真实标签差异最小的权重和偏移值。
下面的部分将展现如何使用不同的语言实现一个训练程序。
Python
首先,导入MXNet:
import mxnet as mx
声明训练和校验数据集的数据迭代器:
train = mx.io.MNISTIter(
image ="mnist/train-images-idx3-ubyte",
label ="mnist/train-labels-idx1-ubyte",
batch_size =128,
data_shape = (784, ))
val = mx.io.MNISTIter(...)
声明一个两层的MLP:
data = mx.symbol.Variable('data')
fc1 = mx.symbol.FullyConnected(data= data, num_hidden=128)
act1 = mx.symbol.Activation(data= fc1, act_type="relu")
fc2 = mx.symbol.FullyConnected(data= act1, num_hidden =64)
act2 = mx.symbol.Activation(data= fc2, act_type="relu")
fc3 = mx.symbol.FullyConnected(data= act2, num_hidden=10)
mlp = mx.symbol.SoftmaxOutput(data= fc3, name ='softmax')
用样本数据训练模型:
model = mx.model.FeedForward(
symbol = mlp,
num_epoch =20,
learning_rate =.1)
model.fit(X= train, eval_data = val)
现在,产生预测:
test = mx.io.MNISTIter(...)
model.predict(X= test)
R
使用require命令获取mxnet包:
require(mxnet)
声明训练和校验数据集的数据迭代器:
train <- mx.io.MNISTIter(
image ="train-images-idx3-ubyte",
label ="train-labels-idx1-ubyte",
input_shape =c(28,28,1),
batch_size =100,
shuffle =TRUE,
flat =TRUE
)
val <- mx.io.MNISTIter(
image ="t10k-images-idx3-ubyte",
label ="t10k-labels-idx1-ubyte",
input_shape =c(28,28,1),
batch_size =100,
flat =TRUE
声明一个两层的MLP:
data <- mx.symbol.Variable('data')
fc1 <- mx.symbol.FullyConnected(data = data, name ='fc1', num_hidden =128)
act1 <- mx.symbol.Activation(data = fc1, name ='relu1', act_type ="relu")
fc2 <- mx.symbol.FullyConnected(data = act1, name ='fc2', num_hidden =64)
act2 <- mx.symbol.Activation(data = fc2, name ='relu2', act_type ="relu")
fc3 <- mx.symbol.FullyConnected(data = act2, name ='fc3', num_hidden =10)
mlp <- mx.symbol.SoftmaxOutput(data = fc3, name ='softmax')
训练模型:
model <- mx.model.FeedForward.create(
X = train,
eval.data = val,
ctx = mx.cpu(),
symbol = mlp,
eval.metric = mx.metric.accuracy,
num.round =5,
learning.rate =0.1,
momentum =0.9,
wd =0.0001,
array.batch.size =100,
epoch.end.callback = mx.callback.save.checkpoint("mnist"),
batch.end.callback = mx.callback.log.train.metric(50)
)
读取新的数据集,生成预测:
test <- mx.io.MNISTIter(...)
preds <- predict(model, test)
Scala
导入MXNet:
importml.dmlc.mxnet._
声明训练和校验数据集的数据迭代器:
val trainDataIter =IO.MNISTIter(Map(
"image"->"data/train-images-idx3-ubyte",
"label"->"data/train-labels-idx1-ubyte",
"data_shape"->"(1, 28, 28)",
"label_name"->"sm_label",
"batch_size"-> batchSize.toString,
"shuffle"->"1",
"flat"->"0",
"silent"->"0",
"seed"->"10"))
val valDataIter =IO.MNISTIter(Map(
"image"->"data/t10k-images-idx3-ubyte",
"label"->"data/t10k-labels-idx1-ubyte",
"data_shape"->"(1, 28, 28)",
"label_name"->"sm_label",
"batch_size"-> batchSize.toString,
"shuffle"->"1",
"flat"->"0","silent"->"0"))
声明一个两层的MLP:
val data =Symbol.Variable("data")
val fc1 =Symbol.FullyConnected(name="fc1")(Map("data"-> data,"num_hidden"->128))
val act1 =Symbol.Activation(name="relu1")(Map("data"-> fc1,"act_type"->"relu"))
val fc2 =Symbol.FullyConnected(name="fc2")(Map("data"-> act1,"num_hidden"->64))
val act2 =Symbol.Activation(name="relu2")(Map("data"-> fc2,"act_type"->"relu"))
val fc3 =Symbol.FullyConnected(name="fc3")(Map("data"-> act2,"num_hidden"->10))
val mlp =Symbol.SoftmaxOutput(name="sm")(Map("data"-> fc3))
训练模型:
importml.dmlc.mxnet.optimizer.SGD
// setup model and fit the training set
val model =FeedForward.newBuilder(mlp)
.setContext(Context.cpu())
.setNumEpoch(10)
.setOptimizer(newSGD(learningRate=0.1f, momentum =0.9f, wd =0.0001f))
.setTrainData(trainDataIter)
.setEvalData(valDataIter)
.build()
产生预测:
val probArrays = model.predict(valDataIter)
// in this case, we do not have multiple outputs
require(probArrays.length==1)
val prob = probArrays(0)
// get predicted labels
val py =NDArray.argmaxChannel(prob)
// deal with predicted labels 'py'
Scala
导入MXNet:
using MXNet
载入数据:
batch_size =100
include("mnist-data.jl")
train_provider, eval_provider = get_mnist_providers(batch_size)
定义MLP:
mlp = @mx.chain mx.Variable(:data) =>
mx.FullyConnected(num_hidden=128)=>
mx.Activation(act_type=:relu) =>
mx.FullyConnected(num_hidden=64) =>
mx.Activation(act_type=:relu) =>
mx.FullyConnected(num_hidden=10) =>
mx.SoftmaxOutput(name=:softmax)
训练模型:
model = mx.FeedForward(mlp, context=mx.cpu())
optimizer = mx.SGD(lr=0.1, momentum=0.9, weight_decay=0.00001)
mx.fit(model, optimizer, train_provider, n_epoch=20, eval_data=eval_provider)
生成预测:
probs= mx.predict(model, test_provider)
张量计算
现在,我们可以看看张量计算接口。张量计算接口通常比符号计算接口更为灵活。它通常被用来实现层、定义权重更新规则和调试。
Python
Python的接口和numpy.NDArray接口类似:
>>>importmxnetasmx
>>> a = mx.nd.ones((2,3),
... mx.gpu())
>>>print (a *2).asnumpy()
[[ 2. 2. 2.]
[ 2. 2. 2.]]
R
>require(mxnet)
Loading required package: mxnet
> a <- mx.nd.ones(c(2,3))
> a
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 1
> a +1
[,1] [,2] [,3]
[1,] 2 2 2
[2,] 2 2 2
Scala
你可以在纯Scala中执行张量或矩阵运算:
scala>importml.dmlc.mxnet._
importml.dmlc.mxnet._
scala>val arr =NDArray.ones(2,3)
arr:ml.dmlc.mxnet.NDArray= ml.dmlc.mxnet.NDArray@f5e74790
scala> arr.shape
res0:ml.dmlc.mxnet.Shape=(2,3)
scala>(arr*2).toArray
res2:Array[Float]=Array(2.0,2.0,2.0,2.0,2.0,2.0)
scala>(arr*2).shape
res3:ml.dmlc.mxnet.Shape=(2,3)