@liuhui0803
2017-05-13T08:45:16.000000Z
字数 6262
阅读 2703
机器学习 深度学习 神经网络 MXNet AWS
摘要:
Apache MXNet是一种功能全面、可以灵活编程并且扩展能力超强的深度学习框架,支持包括卷积神经网络(CNN)与长短期记忆网络(LSTM)在内的顶尖深度模型。这一系列文章介绍了MXNet的基本概念和使用方法。本篇主要介绍了MXNet的Module API。
正文:
在第2篇文章中,我们介绍了如何使用Symbols定义计算中使用的Graph,并处理存储在NDArray(在第1篇文章中有介绍)中的数据。
本文将介绍如何使用Symbol和NDArray准备所需数据并构建神经网络。随后将使用Module API训练该网络并预测结果。
我们(设想中的)数据集包含1000个数据样本:
import mxnet as mximport numpy as npimport logginglogging.basicConfig(level=logging.INFO)sample_count = 1000train_count = 800valid_count = sample_count - train_countfeature_count = 100category_count = 10batch=10
我们将通过均匀分布的方式生成这1000个样本,将其存储在一个名为“X”的NDArray中:1000行,100列。
X = mx.nd.uniform(low=0, high=1, shape=(sample_count,feature_count))>>> X.shape(1000L, 100L)>>> X.asnumpy()array([[ 0.70029777, 0.28444085, 0.46263582, ..., 0.73365158,0.99670047, 0.5961988 ],[ 0.34659418, 0.82824177, 0.72929877, ..., 0.56012964,0.32261589, 0.35627609],[ 0.10939316, 0.02995235, 0.97597599, ..., 0.20194994,0.9266268 , 0.25102937],...,[ 0.69691515, 0.52568913, 0.21130568, ..., 0.42498392,0.80869114, 0.23635457],[ 0.3562004 , 0.5794751 , 0.38135922, ..., 0.6336484 ,0.26392782, 0.30010447],[ 0.40369365, 0.89351988, 0.88817406, ..., 0.13799617,0.40905532, 0.05180593]], dtype=float32)
这1000个样本的类别用介于0-9的整数来代表,类别是随机生成的,存储在一个名为“Y”的NDArray中。
Y = mx.nd.empty((sample_count,))for i in range(0,sample_count-1):Y[i] = np.random.randint(0,category_count)>>> Y.shape(1000L,)>>> Y[0:10].asnumpy()array([ 3., 3., 1., 9., 4., 7., 3., 5., 2., 2.], dtype=float32)
随后我们将针对训练和验证两个用途对数据集进行80/20拆分。为此需要使用NDArray.crop函数。在这里,数据集是完全随机的,因此可以使用前80%的数据进行训练,用后20%的数据进行验证。实际运用中,我们可能需要首先搅乱数据集,这样才能避免按顺序生成的数据可能造成的偏差。
X_train = mx.nd.crop(X, begin=(0,0), end=(train_count,feature_count-1))X_valid = mx.nd.crop(X, begin=(train_count,0), end=(sample_count,feature_count-1))Y_train = Y[0:train_count]Y_valid = Y[train_count:sample_count]
至此数据已经准备完毕!
这个网络其实很简单,一起看看其中的每一层:
data = mx.sym.Variable('data')
fc1 = mx.sym.FullyConnected(data, name='fc1', num_hidden=64)
relu1 = mx.sym.Activation(fc1, name='relu1', act_type="relu")
fc2 = mx.sym.FullyConnected(relu1, name='fc2', num_hidden=category_count)
out = mx.sym.SoftmaxOutput(fc2, name='softmax')mod = mx.mod.Module(out)
在第1篇文章中,我们了解到神经网络并不会一次只训练一个样本,因为这样做从性能的角度来看效率太低。因此我们会使用批,即一批固定数量的样本。
为了给神经网络提供这样的“批”,我们需要使用NDArrayIter函数构建一个迭代器。其参数包括训练数据、分类(MXNet将其称之为标签(Label)),以及批大小。
如你所见,我们可以对整个数据集进行迭代,同时对10个样本和10个标签执行该操作。随后即可调用reset()函数将迭代器恢复为初始状态。
train_iter = mx.io.NDArrayIter(data=X_train,label=Y_train,batch_size=batch)>>> for batch in train_iter:... print batch.data... print batch.label...[<NDArray 10x99 @cpu(0)>][<NDArray 10 @cpu(0)>][<NDArray 10x99 @cpu(0)>][<NDArray 10 @cpu(0)>][<NDArray 10x99 @cpu(0)>][<NDArray 10 @cpu(0)>]<edited for brevity>>>> train_iter.reset()
网络已经准备完成,开始训练吧!
首先将输入Symbol**绑定**至实际的数据集(样本和标签),这时候就会用到迭代器。
mod.bind(data_shapes=train_iter.provide_data, label_shapes=train_iter.provide_label)
随后对网络中的神经元权重进行初始化。这个步骤非常重要:使用“恰当”的技术对齐进行初始化可以帮助网络更快速地学习。此时可用的技术很多,Xavier初始化器(名称源自该技术的发明人Xavier Glorot — PDF)就是其中之一。
# Allowed, but not efficientmod.init_params()# Much bettermod.init_params(initializer=mx.init.Xavier(magnitude=2.))
接着需要定义优化参数:
mod.init_optimizer(optimizer='sgd', optimizer_params=(('learning_rate', 0.1), ))
最后,终于可以开始训练网络了!我们会执行50个回合(Epoch)的训练,也就是说,整个数据集需要在这个网络中(以10个样本为一批)运行50次。
mod.fit(train_iter, num_epoch=50)INFO:root:Epoch[0] Train-accuracy=0.097500INFO:root:Epoch[0] Time cost=0.085INFO:root:Epoch[1] Train-accuracy=0.122500INFO:root:Epoch[1] Time cost=0.074INFO:root:Epoch[2] Train-accuracy=0.153750INFO:root:Epoch[2] Time cost=0.087INFO:root:Epoch[3] Train-accuracy=0.162500INFO:root:Epoch[3] Time cost=0.082INFO:root:Epoch[4] Train-accuracy=0.192500INFO:root:Epoch[4] Time cost=0.094INFO:root:Epoch[5] Train-accuracy=0.210000INFO:root:Epoch[5] Time cost=0.108INFO:root:Epoch[6] Train-accuracy=0.222500INFO:root:Epoch[6] Time cost=0.104INFO:root:Epoch[7] Train-accuracy=0.243750INFO:root:Epoch[7] Time cost=0.110INFO:root:Epoch[8] Train-accuracy=0.263750INFO:root:Epoch[8] Time cost=0.101INFO:root:Epoch[9] Train-accuracy=0.286250INFO:root:Epoch[9] Time cost=0.097INFO:root:Epoch[10] Train-accuracy=0.306250INFO:root:Epoch[10] Time cost=0.100...INFO:root:Epoch[20] Train-accuracy=0.507500...INFO:root:Epoch[30] Train-accuracy=0.718750...INFO:root:Epoch[40] Train-accuracy=0.923750...INFO:root:Epoch[50] Train-accuracy=0.998750INFO:root:Epoch[50] Time cost=0.077
如你所见,训练的准确度有了飞速提升,50个回合后已经接近99%以上。似乎我们的网络已经从训练数据集中学成了。非常惊人!
但针对验证数据集执行的效果如何呢?
随后将新的数据样本放入网络,例如剩下的那20%尚未在训练中使用过的数据。
首先构建一个迭代器,这一次将使用验证样本和标签。
pred_iter = mx.io.NDArrayIter(data=X_valid,label=Y_valid, batch_size=batch)
随后要使用Module.iter_predict()函数,借此让样本在网络中运行。这样做的同时,还需要对预测的标签和实际标签进行对比。我们需要追踪比分并显示验证准确度,即,网络针对验证数据集的执行效果到底如何。
pred_count = valid_countcorrect_preds = total_correct_preds = 0for preds, i_batch, batch in mod.iter_predict(pred_iter):label = batch.label[0].asnumpy().astype(int)pred_label = preds[0].asnumpy().argmax(axis=1)correct_preds = np.sum(pred_label==label)total_correct_preds = total_correct_preds + correct_predsprint('Validation accuracy: %2.2f' % (1.0*total_correct_preds/pred_count))
这个过程中发生了不少事 :)
iter_predict()返回了:
随后我们需要使用Numpy.sum()将label和pred_label中相等值的数量进行对比。
最后需要计算并显示验证准确度。
验证准确度:0.09
什么?只有9%?真是太悲催了!如果你希望证明我们的数据集真的是随机的,那么你有证据了!
底线在于,我们确实可以通过训练神经网络学习任何东西,但如果数据本身是无意义的(例如我们本例中使用的数据),那么就什么都预测不出来。种瓜得瓜,种豆得豆!
如果你已经读到这里,我猜你是真心希望看到本例的完整代码 ;) 请花些时间用你自己的数据进行验证,这才是学习的最佳方法。
代码已发布至GitHub:mxnet_example1.py。
后续内容:
作者:Julien Simon,阅读英文原文:An introduction to the MXNet API — part 3
