mxnet_mxnet 版本 - CSDN
精华内容
参与话题
  • MXNet基本介绍

    千次阅读 2017-02-10 14:31:10
    原文:https://github.com/dmlc/mxnet/issues/797 神经网络本质上是一种语言,我们通过它来表达对应用问题的理解。例如我们用卷积层来表达空间相关性,RNN来表达时间连续性。根据问题的复杂性和信息如何从输入到输出...

    原文:https://github.com/dmlc/mxnet/issues/797


    http://www.cnblogs.com/zhizhan/p/5118185.html


    神经网络本质上是一种语言,我们通过它来表达对应用问题的理解。例如我们用卷积层来表达空间相关性,RNN来表达时间连续性。根据问题的复杂性和信息如何从输入到输出一步步提取,我们将不同大小的层按一定原则连接起来。近年来随着数据的激增和计算能力的大幅提升,神经网络也变得越来越深和大。例如最近几次imagnet竞赛的冠军都使用有数十至百层的网络。对于这一类神经网络我们通常称之为深度学习。从应用的角度而言,对深度学习最重要的是如何方便的表述神经网络,以及如何快速训练得到模型。

    对于一个优秀的深度学习系统,或者更广来说优秀的科学计算系统,最重要的编程接口的设计。他们都采用将一个领域特定语言(domain specific language)嵌入到一个主语言中。例如numpy将矩阵运算嵌入到python中。这类嵌入一般分为两种,其中一种嵌入的较浅,其中每个语句都按原来的意思执行,且通常采用命令式编程(imperative programming),其中numpy和Torch就是属于这种。而另一种则用一种深的嵌入方式,提供一整套针对具体应用的迷你语言。这一种通常使用声明式语言(declarative programing),既用户只需要声明要做什么,而具体执行则由系统完成。这类系统包括Caffe,theano和刚公布的TensorFlow。

    这两种方式各有利弊,总结如下

      浅嵌入,命令式编程 深嵌入,声明式编程
    如何执行a=b+1 需要b已经被赋值。立即执行加法,将结果保存在a中。 返回对应的计算图(computation graph),我们可以之后对b进行赋值,然后再执行加法运算
    优点 语义上容易理解,灵活,可以精确控制行为。通常可以无缝的和主语言交互,方便的利用主语言的各类算法,工具包,bug和性能调试器。 在真正开始计算的时候已经拿到了整个计算图,所以我们可以做一系列优化来提升性能。实现辅助函数也容易,例如对任何计算图都提供forward和backward函数,对计算图进行可视化,将图保存到硬盘和从硬盘读取。
    缺点 实现统一的辅助函数困和提供整体优化都很困难。 很多主语言的特性都用不上。某些在主语言中实现简单,但在这里却经常麻烦,例如if-else语句 。debug也不容易,例如监视一个复杂的计算图中的某个节点的中间结果并不简单。

    目前现有的系统大部分都采用上两种编程模式的一种。与它们不同的是,MXNet尝试将两种模式无缝的结合起来。在命令式编程上MXNet提供张量运算,而声明式编程中MXNet支持符号表达式。用户可以自由的混合它们来快速实现自己的想法。例如我们可以用声明式编程来描述神经网络,并利用系统提供的自动求导来训练模型。另一方便,模型的迭代训练和更新模型法则中可能涉及大量的控制逻辑,因此我们可以用命令式编程来实现。同时我们用它来进行方便的调式和与主语言交互数据。

    下表我们比较MXNet和其他流行的深度学习系统

      主语言 从语言 硬件 分布式 命令式 声明式
    Caffe C++ Python/Matlab CPU/GPU x x v
    Torch Lua - CPU/GPU/FPGA x v x
    Theano Python - CPU/GPU x x v
    TensorFlow C++ Python CPU/GPU/Mobile v x v
    MXNet C++ Python/R/Julia/Go CPU/GPU/Mobile v v v

    (注,TensforFlow暂时没有公开其分布式实现)

    MXNet的系统架构如下图所示:

    从上到下分别为各种主语言的嵌入,编程接口(矩阵运算,符号表达式,分布式通讯),两种编程模式的统一系统实现,以及各硬件的支持。接下一章我们将介绍编程接口,然后下一章介绍系统实现。之后我们给出一些实验对比结果,以及讨论MXNet的未来。

    编程接口

    Symbol: 声明式的符号表达式

    MXNet使用多值输出的符号表达式来声明计算图。符号是由操作子构建而来。一个操作子可以是一个简单的矩阵运算“+”,也可以是一个复杂的神经网络里面的层,例如卷积层。一个操作子可以有多个输入变量和多个输出变量,还可以有内部状态变量。一个变量既可以是自由的,我们可以之后对其赋值;也可以是某个操作子的输出。例如下面的代码中我们使用Julia来定义一个多层感知机,它由一个代表输入数据的自由变量,和多个神经网络层串联而成。

    using MXNet
    mlp = @mx.chain mx.Variable(:data) =>
      mx.FullyConnected(num_hidden=64) =>
      mx.Activation(act_type=:relu)    =>
      mx.FullyConnected(num_hidden=10) =>
      mx.Softmax()

    在执行一个符号表达式前,我们需要对所有的自由变量进行赋值。上例中,我们需要给定数据,和各个层里隐式定义的输入,例如全连接层的权重和偏值。我们同时要申明所需要的输出,例如softmax的输出。

    除了执行获得softmax输出外(通常也叫forward),符号表达式也支持自动求导来获取各权重和偏值对应的梯度(也称之为backward)。此外,我们还可以提前估计计算时需要的内存,符号表达式的可视化,读入和输出等。

    NDArray:命令式的张量计算

    MXNet提供命令式的张量计算来桥接主语言的和符号表达式。下面代码中,我们在GPU上计算矩阵和常量的乘法,并使用numpy来打印结果

    >>> import MXNet as mx
    >>> a = mx.nd.ones((2, 3),
    ... mx.gpu())
    >>> print (a * 2).asnumpy()
    [[ 2.  2.  2.]
     [ 2.  2.  2.]]

    另一方面,NDArray可以无缝和符号表达式进行对接。假设我们使用Symbol定义了一个神经网络,那么我们可以如下实现一个梯度下降算法

    for (int i = 0; i < max_iter; ++i) {
      network.forward();
      network.backward();
      network.weight -= eta * network.gradient
    }

    这里梯度由Symbol计算而得。Symbol的输出结果均表示成NDArray,我们可以通过NDArray提供的张量计算来更新权重。此外,我们还利用了主语言的for循环来进行迭代,学习率eta也是在主语言中进行修改。

    上面的混合实现跟使用纯符号表达式实现的性能相差无二,然后后者在表达控制逻辑时会更加复杂。其原因是NDArray的执行会和Symbol类似的构建一个计算图,并与其他运算一同交由后台引擎执行。对于运算-=由于我们只是将其结果交给另一个Symbol的forward作为输入,因此我们不需要立即得到结果。当上面的for循环结束时,我们只是将数个Symbol和NDarray对应的计算图提交给了后台引擎。当我们最终需要结果的时候,例如将weight复制到主语言中或者保存到磁盘时,程序才会被阻塞直到所有计算完成。

    KVStore:多设备间的数据交互

    MXNet提供一个分布式的key-value存储来进行数据交换。它主要有两个函数,
    1. push: 将key-value对从一个设备push进存储
    2. pull:将某个key上的值从存储中pull出来此外,KVStore还接受自定义的更新函数来控制收到的值如何写入到存储中。最后KVStore提供数种包含最终一致性模型和顺序一致性模型在内的数据一致性模型。

    在下面例子中,我们将前面的梯度下降算法改成分布式梯度下降。

    KVStore kvstore("dist_async");
    kvstore.set_updater([](NDArray weight, NDArray gradient) {
        weight -= eta * gradient;
      });
    for (int i = 0; i < max_iter; ++i) {
       kvstore.pull(network.weight);
       network.forward();
       network.backward();
       kvstore.push(network.gradient);
    }

    在这里我们先使用最终一致性模型创建一个kvstore,然后将更新函数注册进去。在每轮迭代前,每个计算节点先将最新的权重pull回来,之后将计算的得到的梯度push出去。kvstore将会利用更新函数来使用收到的梯度更新其所存储的权重。

    这里push和pull跟NDArray一样使用了延后计算的技术。它们只是将对应的操作提交给后台引擎,而引擎则调度实际的数据交互。所以上述的实现跟我们使用纯符号实现的性能相差无几。

    读入数据模块

    数据读取在整体系统性能上占重要地位。MXNet提供工具能将任意大小的样本压缩打包成单个或者数个文件来加速顺序和随机读取。

    通常数据存在本地磁盘或者远端的分布式文件系统上(例如HDFS或者Amazon S3),每次我们只需要将当前需要的数据读进内存。MXNet提供迭代器可以按块读取不同格式的文件。迭代器使用多线程来解码数据,并使用多线程预读取来隐藏文件读取的开销。

    训练模块

    MXNet实现了常用的优化算法来训练模型。用户只需要提供数据数据迭代器和神经网络的Symbol便可。此外,用户可以提供额外的KVStore来进行分布式的训练。例如下面代码使用分布式异步SGD来训练一个模型,其中每个计算节点使用两快GPU。

    import MXNet as mx
    model = mx.model.FeedForward(
        ctx                = [mx.gpu(0), mx.gpu(1)],
        symbol             = network,
        num_epoch          = 100,
        learning_rate      = 0.01,
        momentum           = 0.9,
        wd                 = 0.00001,
        initializer        = mx.init.Xavier(factor_type="in", magnitude=2.34))
    model.fit(
        X                  = train_iter,
        eval_data          = val_iter,
        kvstore            = mx.kvstore.create('dist_async'),
        epoch_end_callback = mx.callback.do_checkpoint('model_'))

    系统实现

    计算图

    一个已经赋值的符号表达式可以表示成一个计算图。下图是之前定义的多层感知机的部分计算图,包含forward和backward。

    其中圆表示变量,方框表示操作子,箭头表示数据依赖关系。在执行之前,MXNet会对计算图进行优化,以及为所有变量提前申请空间。

    计算图优化

    计算图优化已经在数据库等领域被研究多年,我们目前只探索了数个简单的方法。
    1. 注意到我们提前申明了哪些输出变量是需要的,这样我们只需要计算这些输出需要的操作。例如,在预测时我们不需要计算梯度,所以整个backforward图都可以忽略。而在特征抽取中,我们可能只需要某些中间层的输出,从而可以忽略掉后面的计算。
    2. 我们可以合并某些操作。例如 ab+1*只需要一个blas或者cuda函数即可,而不需要将其表示成两个操作。
    3. 我们实现了一些“大”操作,例如一个卷积层就只需要一个操作子。这样我们可以大大减小计算图的大小,并且方便手动的对这个操作进行优化。

    内存申请

    内存通常是一个重要的瓶颈,尤其是对GPU和智能设备而言。而神经网络计算时通常需要大量的临时空间,例如每个层的输入和输出变量。对每个变量都申请一段独立的空间会带来高额的内存开销。幸运的是,我们可以从计算图推断出所有变量的生存期,就是这个变量从创建到最后被使用的时间段,从而可以对两个不交叉的变量重复使用同一内存空间。这个问题在诸多领域,例如编译器的寄存器分配上,有过研究。然而最优的分配算法需要 O(n2) 时间复杂度,这里n是图中变量的个数。

    MXNet提供了两个启发式的策略,每个策略都是线性的复杂度。
    1. inplace。在这个策略里,我们模拟图的遍历过程,并为每个变量维护一个还有多少其他变量需要它的计数。当我们发现某个变量的计数变成0时,我们便回收其内存空间。
    2. co-share。我们允许两个变量使用同一段内存空间。这么做当然会使得这两个变量不能同时在写这段空间。所以我们只考虑对不能并行的变量进行co-share。每一次我们考虑图中的一条路(path),路上所有变量都有依赖关系所以不能被并行,然后我们对其进行内存分配并将它们从图中删掉。

    引擎

    在MXNet中,所有的任务,包括张量计算,symbol执行,数据通讯,都会交由引擎来执行。首先,所有的资源单元,例如NDArray,随机数生成器,和临时空间,都会在引擎处注册一个唯一的标签。然后每个提交给引擎的任务都会标明它所需要的资源标签。引擎则会跟踪每个资源,如果某个任务所需要的资源到到位了,例如产生这个资源的上一个任务已经完成了,那么引擎会则调度和执行这个任务。

    通常一个MXNet运行实例会使用多个硬件资源,包括CPU,GPU,PCIe通道,网络,和磁盘,所以引擎会使用多线程来调度,既任何两个没有资源依赖冲突的任务都可能会被并行执行,以求最大化资源利用。

    与通常的数据流引擎不同的是,MXNet的引擎允许一个任务修改现有的资源。为了保证调度正确性,提交任务时需要分开标明哪些资源是只读,哪些资源会被修改。这个附加的写依赖可以带来很多便利。例如我们可以方便实现在numpy以及其他张量库中常见的数组修改操作,同时也使得内存分配时更加容易,比如操作子可以修改其内部状态变量而不需要每次都重来内存。再次,假如我们要用同一个种子生成两个随机数,那么我们可以标注这两个操作会同时修改种子来使得引擎不会并行执行,从而使得代码的结果可以很好的被重复。

    数据通讯

    KVStore的实现是基于参数服务器。但它跟前面的工作有两个显著的区别。
    1. 我们通过引擎来管理数据一致性,这使得参数服务器的实现变得相当简单,同时使得KVStore的运算可以无缝的与其他结合在一起。
    2. 我们使用一个两层的通讯结构,原理如下图所示。第一层的服务器管理单机内部的多个设备之间的通讯。第二层服务器则管理机器之间通过网络的通讯。第一层的服务器在与第二层通讯前可能合并设备之间的数据来降低网络带宽消费。同时考虑到机器内和外通讯带宽和延时的不同性,我们可以对其使用不同的一致性模型。例如第一层我们用强的一致性模型,而第二层我们则使用弱的一致性模型来减少同步开销。

    可移植性

    轻量和可移植性是MXNet的一个重要目标。MXNet核心使用C++实现,并提供C风格的头文件。因此方便系统移植,也使得其很容易被其他支持C FFI (forigen language interface )的语言调用。此外,我们也提供一个脚本将MXNet核心功能的代码连同所有依赖打包成一个单一的只有数万行的C++源文件,使得其在一些受限的平台,例如智能设备,方便编译和使用。

    实验结果

    这里我们提供一些早期的实验结果。

    与其他系统相比

    我们首先使用一个流行卷积网络测试方案来对比MXNet与Torch,Caffe和TensorFlow在过去几届imagenet竞赛冠军网络上的性能。每个系统使用同样的CUDA 7.0和CUDNN 3,但TensorFlow使用其只支持的CUDA 6.5 和CUDNN 2。我们使用单块GTX 980并报告单个forward和backward的耗时。

    可以看出MXNet,Torch和Caffe三者在性能上不相上下。这个符合预期,因为在单卡上我们评测的几个网络的绝大部分运算都由CUDA和CUDNN完成。TensorFlow比其他三者都慢2倍以上,这可能由于是低版本的CUDNN和项目刚开源的缘故。

    内存的使用

    接下来我们考察不同的内存分配算法对内存占用的影响。下图分别表示使用batch=128时,在做预测时和做训练时的不同算法在内部变量(除去模型,最初输入和最终输出)上的内存开销。

     

    可以看出,inplace和co-share两者都可以极大的降低内存使用。将两者合起来可以在训练时减少2倍内存使用,在预测时则可以减小4倍内存使用。特别的,即使是最复杂的vggnet,对单张图片进行预测时,MXNet只需要16MB额外内存。

    Scalability

    最后我们报告在分布式训练下的性能。我们使用imagenet 1k数据(120万224x224x3图片,1000类),并用googlenet加上batch normalization来训练。我们使用Amazon EC2 g2.8x,单机和多机均使用同样的参数,下图表示了使用单机和10台g2.8x时的收敛情况。

    从训练精度来看,单机的收敛比多机快,这个符合预期,因为多机时有效的batch大小比单机要大,在处理同样多的数据上收敛通常会慢。但有意思的是两者在测试精度上非常相似。

    单机下每遍历一次数据需要1万4千秒,而在十台机器上,每次只需要1千4百秒。如果考虑运行时间对比测试精度,10台机器带来了10倍的提升。

    过去,现状,和未来

    大半年前我们拉来数个优秀的C++机器学习系统的开发人员成立了DMLC,本意是更方便共享各自项目的代码,并给用户提供一致的体验。当时我们有两个深度学习的项目,一个是CXXNet,其通过配置来定义和训练神经网络。另一个是Minerva,提供类似numpy一样的张量计算接口。前者在图片分类等使用卷积网络上很方便,而后者更灵活。那时候我们想要能不能一个两者功能都具备的系统,于是这样就有了MXNet。其名字来自Minerva的M和CXXNet的XNet。其中Symbol的想法来自CXXNet,而NDArray的想法来自Minerva。我们也常把MXNet叫“mix net”。

    MXNet是DMLC第一个结合了所有的成员努力的项目,也同时吸引了很多核心成员的加入。MXNet目的是做一个有意思的系统,能够让大家用着方便的系统,一个轻量的和可以快速测试系统和算法想法的系统。对于未来,我们主要关注下面四个方向:

    1. 支持更多的硬件,我们目前在积极考虑支持AMD GPU,高通GPU,Intel Phi,FPGA,和更多智能设备。相信MXNet的轻量和内存节省可以在这些上大有作为。
    2. 更加完善的操作子。目前不论是Symbol还是NDArray支持的操作还是有限,我们希望能够尽快的扩充他们。
    3. 更多编程语言。除了C++,目前MXNet对Python,R和Julia的支持比较完善。但我们希望还能有很多的语言,例如javascript。
    4. 更的应用。我们之前花了很多精力在图片分类上,下面我们会考虑很多的应用。例如上周我们试了下如何利用一张图片的风格和一张图片的内容合成一张新图片。下图是利用我办公室窗景和梵高的starry night来合成图片

      接下来我们希望能够在更多应用,例如语音,翻译,问答,上有所产出。

    我们忠心希望MXNet能为大家做深度学习相关研究和应用带来便利。也希望能与更多的开发者一起学习和进步。

    扩展阅读

      1. 此文大部分内容已经发表在NIPS LearningSys 2016上,paper link
      2. 本文只是对MXNet各个部件做了初步的介绍,更多文档参见 MXNet/doc
      3. 本文实验代码均在 MXNet/example
    展开全文
  • mxnet安装和使用

    万次阅读 2018-05-13 18:18:52
    通过Conda安装首先根据操作系统下载并安装Miniconda(Anaconda也可以)。接下来下载所有教程的包(下载tar.gz格式或者下载zip格式均可)。解压后进入文件夹。例如Linux或者Mac OSX 10.11以上可以使用如下命令mkdir ...

    通过Conda安装

    首先根据操作系统下载并安装MinicondaAnaconda也可以)。

    wget (复制的连接地址)  会下载.sh脚本,然后bash (文件名.sh)就可以安装了

    接下来下载所有教程的包(下载tar.gz格式或者下载zip格式均可)。解压后进入文件夹。

    例如Linux或者Mac OSX 10.11以上可以使用如下命令

    mkdir gluon-tutorials && cd gluon-tutorials
    curl https://zh.gluon.ai/gluon_tutorials_zh.tar.gz -o tutorials.tar.gz
    tar -xzvf tutorials.tar.gz && rm tutorials.tar.gz

    Windows用户可以用浏览器下载zip格式并解压,在解压目录文件资源管理器的地址栏输入cmd进入命令行模式。

    【可选项】配置下载源来使用国内镜像加速下载:

    # 优先使用清华conda镜像
    conda config --prepend channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
    
    # 也可选用科大conda镜像
    conda config --prepend channels http://mirrors.ustc.edu.cn/anaconda/pkgs/free/

    然后安装所需的依赖包并激活环境:

    conda env create -f environment.yml
    source activate gluon # 注意Windows下不需要 source
    之后运行下面命令,然后浏览器打开http://localhost:8888(通常会自动打开)就可以查看和运行各个教程了。
    jupyter notebook

    【可选项】国内用户可使用国内Gluon镜像加速数据集和预训练模型的下载

    • Linux/OSX用户:
    bash   MXNET_GLUON_REPO=https://apache-mxnet.s3.cn-north-1.amazonaws.com.cn/ jupyter notebook
    • Windows用户:
    bash   set MXNET_GLUON_REPO=https://apache-mxnet.s3.cn-north-1.amazonaws.com.cn/ jupyter notebook

    通过docker安装

    首先你需要下载并安装docker。例如Linux下可以

    wget -qO- https://get.docker.com/ | sh
    sudo usermod -aG docker
    # 然后logout一次
    然后运行下面命令即可
    docker run -p 8888:8888 muli/gluon-tutorials-zh

    然后浏览器打开http://localhost:8888 ,这时通常需要填docker运行时产生的token。 ## 更新教程

    目前我们仍然一直在快速更新教程,通常每周都会加入新的章节。同时MXNet的Gluon前端也在快速发展,因此我们推荐大家也做及时的更新。更新包括下载最新的教程,和更新对应的依赖(通常是升级MXNet)。

    用Conda更新

    先重新下载新的zip或者tar.gz教程包。解压后,使用下面命令更新环境
    conda env update -f environment.yml

    用Docker更新

    直接下载新的docker image就行。

    docker pull muli/gluon-tutorials-zh

    高级选项

    使用GPU

    默认安装的MXNet只支持CPU。有一些教程需要GPU来运行。假设电脑有N卡而且CUDA7.5或者8.0已经安装了,那么先卸载CPU版本

    sudo apt-get install build-essential git  装编译器和git

    下载cuda后,chmod +x cuda...文件名  变成可执行文件,然后sudo 文件名   就行了

    nvidia-smi查看显卡信息,windows用户需要设置一下PATH :set PATH=c:\Program Files\NVIDIA Corporation\NVSMI;%PATH%)

    pip uninstall mxnet

    然后选择安装下面版本之一:

    pip install --pre mxnet-cu75 # CUDA 7.5
    pip install --pre mxnet-cu80 # CUDA 8.0
    【可选项】国内用户可使用豆瓣pypi镜像加速下载:
    pip install --pre mxnet-cu75 -i https://pypi.douban.com/simple # CUDA 7.5
    pip install --pre mxnet-cu80 -i https://pypi.douban.com/simple # CUDA 8.0

    使用notedown插件来读写github源文件

    注意:这个只推荐给想上github提交改动的小伙伴。 我们源代码是用markdown格式来存储,而不是jupyter默认的ipynb格式。我们可以用notedown插件来读写markdown格式。下面命令下载源代码并且安装环境:

    要先sudo apt-get update,然后  sudo apt-get git

    git clone https://github.com/mli/gluon-tutorials-zh
    cd gluon-tutorials-zh
    conda env create -f environment.yml
    source activate gluon # Windows下不需要 source
    然后安装notedown,运行Jupyter并加载notedown插件:
    pip install https://github.com/mli/notedown/tarball/master
    jupyter notebook --NotebookApp.contents_manager_class='notedown.NotedownContentsManager'

    【可选项】默认开启notedown插件

    首先生成jupyter配置文件(如果已经生成过可以跳过)

    jupyter notebook --generate-config
    将下面这一行加入到生成的配置文件的末尾(Linux/macOS一般在~/.jupyter/jupyter_notebook_config.py)

    c.NotebookApp.contents_manager_class = 'notedown.NotedownContentsManager'
    之后就只需要运行jupyter notebook即可。

    在远端服务器上运行Jupyter

    Jupyter的一个常用做法是在远端服务器上运行,然后通过 http://myserver:8888来访问。 有时候防火墙阻挡了直接访问对应的端口,但ssh是可以的。如果本地机器是linux或者mac(windows通过第三方软件例如putty应该也能支持),那么可以使用端口映射
    ssh myserver -L 8888:localhost:8888
    然后我们可以使用http://localhost:8888打开远端的Jupyter。

    运行计时

    我们可以通过ExecutionTime插件来对每个cell的运行计时。
    pip install jupyter_contrib_nbextensions
    jupyter contrib nbextension install --user
    jupyter nbextension enable execute_time/ExecuteTime

    老中医自检程序

    用途

    本教程提供了一系列自检程序供没有成功安装或者运行报错的难民进行自救,如果全篇都没找到药方,希望可以自己搜索问题,欢迎前往 https://discuss.gluon.ai 提问并且帮他人解答。

    通过Conda安装

    确保conda已经安装完成,并且可以在命令行识别到 “conda –version”

    症状

    -bash: conda: command not found /’conda‘不是内部或外部命令,也不是可运行的程序
    病情分析

    conda不在系统搜索目录下,无法找到conda可执行文件

    药方
    # linux或者mac系统
    export PATH=/path/to/miniconda3/bin:$PATH
    # windows用set或者setx
    set PATH=C:\path\to\miniconda3\bin;%PATH%
    完成后命令行测试 "conda --version"
    如果显示类似于 “conda 4.3.21”,则症状痊愈

    症状

    Conda安装正常,conda env -f environment.yml失败
    病情分析

    如果在国内的网络环境下,最大的可能是连接太慢,用国内镜像加速不失为一良方

    药方
    病情分析

    失败后重新尝试 conda env -f environment.yml会报错 ##### 药方

    conda info -e查看失败信息,建议删除失败的env: conda env remove –name gluon –all ### 手动pip安装

    症状:pip install mxnet失败

    病情分析

    pip本身不存在, pip –version不能正确显示pip版本号和安装目录

    药方

    参考http://pip-cn.readthedocs.io/en/latest/installing.html 安装pip

    病情分析

    pip版本太低

    药方
    pip install --upgrade pip
    病情分析

    无法找到匹配的wheel, No matching distribution found for mxnet>=0.11.1b20170902

    药方

    确保系统被支持,比如Ubuntu 14.04/16.04, Mac10.11/10.12(10.10即将支持), Windows 10(win7 未测试), 如果都符合,可以试试命令

    python -c "import pip; print(pip.pep425tags.get_supported())"

    然后上论坛讨论:https://discuss.gluon.ai

    症状: pip install mxnet 成功,但是import mxnet失败

    病情分析

    如果看到这样的错误

    ImportError: No module named mxnet

    python无法找到mxnet,有可能系统上有多个python版本, 导致pip和python版本不一致

    药方

    找到pip的安装目录

    pip --version
    找到python安装目录
    which python
    # or
    whereis python
    # or
    python -c "import os, sys; print(os.path.dirname(sys.executable))"
    如果pip目录和python目录不一致,可以改变默认加载的python,比如
    python3 -c "import mxnet as mx; print(mx.__version__)"
    或者用和python对应的pip重新安装mxnet
    pip3 install mxnet --pre
    pip2 install mxnet --pre

    如果不是简单的python2/3的问题,推荐修复默认调用的python。

    病情分析

    假设你看到这个错误:

    ImportError: libgfortran.so.3: cannot open shared object file: No such file or
    directory

    药方

    这个一般发生在Linux下。安装libgfortran就好,例如Ubuntu下可以sudo apt-get install libgfortran

    症状:可以import mxnet,但是版本不正常(< 0.11.1b20170908)

    病情分析

    安装时没有指定最新的版本 ##### 药方 可以使用pip install mxnet –upgrade –pre安装最新的mxnet ##### 病情分析 由于系统的问题,无法正确安装最新版本,参考 No matching distribution found for mxnet>=0.11.1b20170902 ### Jupyter Notebook #### 症状: 打开notebook乱码 ##### 病情分析 Windows下不支持编码? ##### 未测试药方 把md文件用文本编辑器保存为GBK编码 ### 其他 #### 症状: Windows下curl, tar失败 ##### 病情分析 Windows默认不支持curl,tar ##### 药方 下载和解压推荐用浏览器和解压软件,手动拷贝 ### 最后 如果你尝试了很多依然一头雾水,可以试试docker安装:https://zh.gluon.ai/install.html#docker







    展开全文
  • MXNet 中文文档

    千次阅读 2016-01-07 17:22:19
    MXNet设计和实现简介对于一个优秀的深度学习系统,或者更广来说优秀的科学计算系统,最重要的是编程接口的设计。他们都采用将一个领域特定语言(domain specific language)嵌入到一个主语言中。例如numpy将矩阵运算...

    MXNet设计和实现简介

    对于一个优秀的深度学习系统,或者更广来说优秀的科学计算系统,最重要的是编程接口的设计。他们都采用将一个领域特定语言(domain specific language)嵌入到一个主语言中。例如numpy将矩阵运算嵌入到python中。这类嵌入一般分为两种,其中一种嵌入的较浅,其中每个语句都按原来的意思执行,且通常采用命令式编程(imperative programming),其中numpy和Torch就是属于这种。而另一种则用一种深的嵌入方式,提供一整套针对具体应用的迷你语言。这一种通常使用声明式语言(declarative programing),既用户只需要声明要做什么,而具体执行则由系统完成。这类系统包括Caffe,theano和刚公布的TensorFlow。

    浅嵌入,命令式编程 深嵌入,声明式编程
    如何执行 a=b+1 需要b已经被赋值。立即执行加法,将结果保存在a中。 返回对应的计算图(computation graph),我们可以之后对b进行赋值,然后再执行加法运算
    优点 语义上容易理解,灵活,可以精确控制行为。通常可以无缝地和主语言交互,方便地利用主语言的各类算法,工具包,debug和性能调试器。 在真正开始计算的时候已经拿到了整个计算图,所以我们可以做一系列优化来提升性能。实现辅助函数也容易,例如对任何计算图都提供forward和backward函数,对计算图进行可视化,将图保存到硬盘和从硬盘读取。
    缺点 实现统一的辅助函数和提供整体优化都很困难。 很多主语言的特性都用不上。某些在主语言中实现简单,但在这里却经常麻烦,例如if-else语句 。debug也不容易,例如监视一个复杂的计算图中的某个节点的中间结果并不简单。

    目前现有的系统大部分都采用上两种编程模式的一种。与它们不同的是,MXNet尝试将两种模式无缝的结合起来。在命令式编程上MXNet提供张量运算,而声明式编程中MXNet支持符号表达式。用户可以自由的混合它们来快速实现自己的想法。例如可以用声明式编程来描述神经网络,并利用系统提供的自动求导来训练模型。另一方便,模型的迭代训练和更新模型法则中可能涉及大量的控制逻辑,因此我们可以用命令式编程来实现。同时用它来进行方便地调式和与主语言交互数据。

    下表比较MXNet和其他流行的深度学习系统

    主语言 从语言 硬件 分布式 命令式 声明式
    Caffe C++ Python/Matlab CPU/GPU x x v
    Torch Lua - CPU/GPU/FPGA x v x
    Theano Python - CPU/GPU x v x
    TensorFlow C++ Python CPU/GPU/Mobile v x v
    MXNet C++ Python/R/Julia/Go CPU/GPU/Mobile v v v

    MXNet的系统框架如下:
    此处输入图片的描述

    从上到下分别为各种主语言的嵌入,编程接口(矩阵运算,符号表达式,分布式通讯),两种编程模式的统一系统实现,以及各硬件的支持。

    编程接口

    Symbol: 声明式的符号表达式

    MXNet使用多值输出的符号表达式来声明计算图。符号是由操作子(也就是TensorFlow 中的ops概念)构建而来。一个操作子可以是一个简单的矩阵运算“+”,也可以是一个复杂的神经网络里面的层,例如卷积层。一个操作子可以有多个输入变量和多个输出变量,还可以有内部状态变量。一个变量既可以是自由的,我们可以之后对其赋值;也可以是某个操作子的输出。

    NDArray:命令式的张量计算

    MXNet提供命令式的张量计算来桥接主语言的和符号表达式。下面代码中,我们在GPU上计算矩阵和常量的乘法,并使用numpy来打印结果

    >>> import MXNet as mx
    >>> a = mx.nd.ones((2, 3), mx.gpu())
    >>> print (a * 2).asnumpy()
    [[ 2.  2.  2.]
     [ 2.  2.  2.]]

    另一方面,NDArray可以无缝和符号表达式进行对接。假设我们使用Symbol定义了一个神经网络,那么我们可以如下实现一个梯度下降算法

    for (int i = 0; i < n; ++i) {
      net.forward();
      net.backward();
      net.weight -= eta * net.grad
    }

    这里梯度由Symbol计算而得。Symbol的输出结果均表示成NDArray,我们可以通过NDArray提供的张量计算来更新权重。此外,还利用了主语言的for循环来进行迭代,学习率eta也是在主语言中进行修改。

    KVStore: 多设备间的数据交互

    MXNet提供一个分布式的key-value存储来进行数据交换。它主要有两个函数,

    push: 将key-value对从一个设备push进存储
    pull:将某个key上的值从存储中pull出来此外,KVStore还接受自定义的更新函数来控制收到的值如何写入到存储中。最后KVStore提供数种包含最终一致性模型和顺序一致性模型在内的数据一致性模型。

    分布式梯度下降算法:

    KVStore kvstore("dist_async");
    kvstore.set_updater([](NDArray weight, NDArray gradient) {
        weight -= eta * gradient;
      });
    for (int i = 0; i < max_iter; ++i) {
       kvstore.pull(network.weight);
       network.forward();
       network.backward();
       kvstore.push(network.gradient);
    }
    

    在这里先使用最终一致性模型创建一个kvstore,然后将更新函数注册进去。在每轮迭代前,每个计算节点先将最新的权重pull回来,之后将计算的得到的梯度push出去。kvstore将会利用更新函数来使用收到的梯度更新其所存储的权重。

    这里push和pull跟NDArray一样使用了延后计算的技术。它们只是将对应的操作提交给后台引擎,而引擎则调度实际的数据交互。所以上述的实现跟我们使用纯符号实现的性能相差无几。

    读入数据模块

    数据读取在整体系统性能上占重要地位。MXNet提供工具能将任意大小的样本压缩打包成单个或者数个文件来加速顺序和随机读取。

    通常数据存在本地磁盘或者远端的分布式文件系统上(例如HDFS或者Amazon S3),每次我们只需要将当前需要的数据读进内存。MXNet提供迭代器可以按块读取不同格式的文件。迭代器使用多线程来解码数据,并使用多线程预读取来隐藏文件读取的开销。

    训练模块

    MXNet实现了常用的优化算法来训练模型。用户只需要提供数据数据迭代器和神经网络的Symbol便可。此外,用户可以提供额外的KVStore来进行分布式的训练。例如下面代码使用分布式异步SGD来训练一个模型,其中每个计算节点使用两快GPU。

    import MXNet as mx
    model = mx.model.FeedForward(
        ctx                = [mx.gpu(0), mx.gpu(1)],
        symbol             = network,
        num_epoch          = 100,
        learning_rate      = 0.01,
        momentum           = 0.9,
        wd                 = 0.00001,
        initializer        = mx.init.Xavier(factor_type="in", magnitude=2.34))
    model.fit(
        X                  = train_iter,
        eval_data          = val_iter,
        kvstore            = mx.kvstore.create('dist_async'),
        epoch_end_callback = mx.callback.do_checkpoint('model_'))

    系统实现

    计算图

    一个已经赋值的符号表达式可以表示成一个计算图。下图是之前定义的多层感知机的部分计算图,包含forward和backward。
    此处输入图片的描述

    其中圆表示变量,方框表示操作子,箭头表示数据依赖关系。在执行之前,MXNet会对计算图进行优化,以及为所有变量提前申请空间。

    计算图优化

    计算图优化已经在数据库等领域被研究多年,我们目前只探索了数个简单的方法。

    1. 注意到我们提前申明了哪些输出变量是需要的,这样我们只需要计算这些输出需要的操作。例如,在预测时不需要计算梯度,所以整个backforward图都可以忽略。而在特征抽取中,可能只需要某些中间层的输出,从而可以忽略掉后面的计算。
    2. 可以合并某些操作。例如 ab+1*只需要一个blas或者cuda函数即可,而不需要将其表示成两个操作。
    3. 实现了一些“大”操作,例如一个卷积层就只需要一个操作子。这样我们可以大大减小计算图的大小,并且方便手动的对这个操作进行优化。

    内存申请

    内存通常是一个重要的瓶颈,尤其是对GPU和智能设备而言。而神经网络计算时通常需要大量的临时空间,例如每个层的输入和输出变量。对每个变量都申请一段独立的空间会带来高额的内存开销。幸运的是,可以从计算图推断出所有变量的生存期,就是这个变量从创建到最后被使用的时间段,从而可以对两个不交叉的变量重复使用同一内存空间。这个问题在诸多领域,例如编译器的寄存器分配上,有过研究。然而最优的分配算法需要 O(n2) 时间复杂度,这里n是图中变量的个数。

    MXNet提供了两个启发式的策略,每个策略都是线性的复杂度。

    1. inplace。在这个策略里,我们模拟图的遍历过程,并为每个变量维护一个还有多少其他变量需要它的计数。当我们发现某个变量的计数变成0时,我们便回收其内存空间。
    2. co-share。我们允许两个变量使用同一段内存空间。这么做当然会使得这两个变量不能同时在写这段空间。所以我们只考虑对不能并行的变量进行co-share。每一次我们考虑图中的一条路(path),路上所有变量都有依赖关系所以不能被并行,然后我们对其进行内存分配并将它们从图中删掉。

    引擎

    在MXNet中,所有的任务,包括张量计算,symbol执行,数据通讯,都会交由引擎来执行。首先,所有的资源单元,例如NDArray,随机数生成器,和临时空间,都会在引擎处注册一个唯一的标签。然后每个提交给引擎的任务都会标明它所需要的资源标签。引擎则会跟踪每个资源,如果某个任务所需要的资源到到位了,例如产生这个资源的上一个任务已经完成了,那么引擎会则调度和执行这个任务。

    通常一个MXNet运行实例会使用多个硬件资源,包括CPU,GPU,PCIe通道,网络,和磁盘,所以引擎会使用多线程来调度,既任何两个没有资源依赖冲突的任务都可能会被并行执行,以求最大化资源利用。

    与通常的数据流引擎不同的是,MXNet的引擎允许一个任务修改现有的资源。为了保证调度正确性,提交任务时需要分开标明哪些资源是只读,哪些资源会被修改。这个附加的写依赖可以带来很多便利。例如我们可以方便实现在numpy以及其他张量库中常见的数组修改操作,同时也使得内存分配时更加容易,比如操作子可以修改其内部状态变量而不需要每次都重来内存。再次,假如我们要用同一个种子生成两个随机数,那么我们可以标注这两个操作会同时修改种子来使得引擎不会并行执行,从而使得代码的结果可以很好的被重复。

    数据通讯

    KVStore的实现是基于参数服务器。但它跟前面的工作有两个显著的区别。

    1. 我们通过引擎来管理数据一致性,这使得参数服务器的实现变得相当简单,同时使得KVStore的运算可以无缝的与其他结合在一起。
    2. 我们使用一个两层的通讯结构,原理如下图所示。第一层的服务器管理单机内部的多个设备之间的通讯。第二层服务器则管理机器之间通过网络的通讯。第一层的服务器在与第二层通讯前可能合并设备之间的数据来降低网络带宽消费。同时考虑到机器内和外通讯带宽和延时的不同性,我们可以对其使用不同的一致性模型。例如第一层我们用强的一致性模型,而第二层我们则使用弱的一致性模型来减少同步开销。

    可移植性

    轻量和可移植性是MXNet的一个重要目标。MXNet核心使用C++实现,并提供C风格的头文件。因此方便系统移植,也使得其很容易被其他支持C FFI (forigen language interface )的语言调用。此外,我们也提供一个脚本将MXNet核心功能的代码连同所有依赖打包成一个单一的只有数万行的C++源文件,使得其在一些受限的平台,例如智能设备,方便编译和使用。

    MXNet Python库操作简介

    MXNet的Python库有三个基本的概念:

    • NDArray:提供矩阵和张量计算,可在CPU和GPU上进行,并自动化的平行。
    • Symbol:使定义神经网络变得非常简单,并提供自动化的微分。
    • KVStore:使数据在多GPU和多机器之间的同步变得简单。

    NDArray:在CPU和GPU上Numpy类型的张量计算

    创建和初始化

    可以在GPU或者是CPU上创建NDArray

    >>> import mxnet as mx
    >>> a = mx.nd.empty((2, 3)) # 在cpu上创建一个2×3的矩阵
    >>> b = mx.nd.empty((2, 3), mx.gpu()) # 在gpu 0上创建一个2×3的矩阵
    >>> c = mx.nd.empty((2, 3), mx.gpu(2)) # 在gpu 2上创建一个2×3的矩阵
    >>> c.shape # 获取矩阵的大小
    (2L, 3L)
    >>> c.context # 获取设备信息
    gpu(2)

    可以通过多种方式进行初始化

    >>> a = mx.nd.zeros((2, 3)) # 创建一个2×3的0矩阵
    >>> b = mx.nd.ones((2, 3))  # 创建一个2×3的1矩阵
    >>> b[:] = 2 # 把b中所有的元素都变成2

    可以将一个数组的值复制给另一个数组,即使是不同是设备

    >>> a = mx.nd.ones((2, 3))
    >>> b = mx.nd.zeros((2, 3), mx.gpu())
    >>> a.copyto(b) # 将cpu中的值复制到gpu中

    可以将NDArray转换成numpy.ndarray

    >>> a = mx.nd.ones((2, 3))
    >>> b = a.asnumpy()
    >>> type(b)
    <type 'numpy.ndarray'>
    >>> print b
    [[ 1.  1.  1.]
     [ 1.  1.  1.]]

    反过来也是一样

    >>> import numpy as np
    >>> a = mx.nd.empty((2, 3))
    >>> a[:] = np.random.uniform(-0.1, 0.1, a.shape)
    >>> print a.asnumpy()
    [[-0.06821112 -0.03704893  0.06688045]
     [ 0.09947646 -0.07700162  0.07681718]]

    基本操作

    元素级别的操作

    在默认情况下,NDArray使用元素级别运算

    >>> a = mx.nd.ones((2, 3)) * 2
    >>> b = mx.nd.ones((2, 3)) * 4
    >>> print b.asnumpy()
    [[ 4.  4.  4.]
     [ 4.  4.  4.]]
    >>> c = a + b
    >>> print c.asnumpy()
    [[ 6.  6.  6.]
     [ 6.  6.  6.]]
    >>> d = a * b
    >>> print d.asnumpy()
    [[ 8.  8.  8.]
     [ 8.  8.  8.]]

    如果两个NDArray位于两个不同的设备,需要将它们移动到一个设备上

    >>> a = mx.nd.ones((2, 3)) * 2
    >>> b = mx.nd.ones((2, 3), mx.gpu()) * 3
    >>> c = a.copyto(mx.gpu()) * b
    >>> print c.asnumpy()
    [[ 6.  6.  6.]
     [ 6.  6.  6.]]

    加载和保存

    有两种方法使加载和保存数据变得简单。第一种是使用pickleNDArray兼容pickle

    >>> import mxnet as mx
    >>> import pickle as pkl
    
    >>> a = mx.nd.ones((2, 3)) * 2
    >>> data = pkl.dumps(a)
    >>> b = pkl.loads(data)
    >>> print b.asnumpy()
    [[ 2.  2.  2.]
     [ 2.  2.  2.]]

    另一种直接将NDArray以二进制的形式倒入到磁盘中

    >>> a = mx.nd.ones((2,3))*2
    >>> b = mx.nd.ones((2,3))*3
    >>> mx.nd.save('mydata.bin', [a, b])
    >>> c = mx.nd.load('mydata.bin')
    >>> print c[0].asnumpy()
    [[ 2.  2.  2.]
     [ 2.  2.  2.]]
    >>> print c[1].asnumpy()
    [[ 3.  3.  3.]
     [ 3.  3.  3.]]

    可以导入字典

    >>> mx.nd.save('mydata.bin', {'a':a, 'b':b})
    >>> c = mx.nd.load('mydata.bin')
    >>> print c['a'].asnumpy()
    [[ 2.  2.  2.]
     [ 2.  2.  2.]]
    >>> print c['b'].asnumpy()
    [[ 3.  3.  3.]
     [ 3.  3.  3.]]

    自动并行化

    NDArray能够自动地进行并行化操作。当我们需要用多个资源进行计算时,这个功能就显得非常友好。

    例如,a+=1后面接着b+=1,其中a在CPU上运行,b在GPU上运行,我们希望将他们同时进行运算以提高效率。此外,CPU与GPU之间的数据复制的开销是非常昂贵的,因此我们希望能让运行他们与其他的计算同样能进行运算。

    然而通过人眼去判断哪些应该并行处理,哪些不应该并行处理是一件非常难的事情。在下面的例子里,a+=1c*=3能够进行并行话计算,但是a+=1b*=3只能按顺序进行计算

    a = mx.nd.ones((2,3))
    b = a
    c = a.copyto(mx.cpu())
    a += 1
    b *= 3
    c *= 3

    幸运的是MXNet能自动地解析这些依赖关系,并且能保证并行化操作能正确地运行。如果我们写一个程序,只使用一个单线程,MXNet会自动地将它分配到多个设备上:多个GPU或者是多个机器上。

    他这是通过延迟计算实现的。每个我们写的操作都发布到了internal引擎,然后返回来。例如,我们运行a+=1,他在我们将加运算推送到引擎后立即返回结果。这种异步性允许我们push更多的运算到引擎上,因此他能够决定读写的依赖关系,并且选择一个最佳的方式进行并行运算。

    当我们相要把计算结果复制到其他地方时,如: print a.asnumpy() or mx.nd.save([a]), 他的运算实际上已经结束了。因此,当我想要写一个高度并行化的代码时,我们只需要延迟访问结果就可以了。

    Symbolic and Automatic Differentiation

    NDArray是MXNet中最基本的计算单元。除此之外,MXNet提供一个符号化接口,成为Symbol,用来简明地构造神经网络。这个接口很灵活和高效。

    Symbols的基本组成

    下面的代码创建了两层感知网络:

    >>> import mxnet as mx
    >>> net = mx.symbol.Variable('data')
    >>> net = mx.symbol.FullyConnected(data=net, name='fc1', num_hidden=128)
    >>> net = mx.symbol.Activation(data=net, name='relu1', act_type="relu")
    >>> net = mx.symbol.FullyConnected(data=net, name='fc2', num_hidden=64)
    >>> net = mx.symbol.SoftmaxOutput(data=net, name='out')
    >>> type(net)
    <class 'mxnet.symbol.Symbol'>

    每个Symbol都有一个唯一的字符串名字。变量通常用来定义输入或者自由变量。其他的symbols用一个symbol作为他们的输入,或者接受其他的超参数如隐藏神经元的数量或者激活函数。

    这个symbol能够以一个函数的形式被查看,他的参数的名字可以自动生成并且通过下面的方式进行查看。

    >>> net.list_arguments()
    ['data', 'fc1_weight', 'fc1_bias', 'fc2_weight', 'fc2_bias', 'out_label']

    可以看到,上面的这些参数是每个symbol所需要的输入参数

    • data:variable data所需要的输入数据
    • fc1_weight和fc1_bias:是第一全连层fc1所需要的权值和偏执
    • fc2_weight和fc2_bias:是第二全连层fc2所需要的权值和偏执
    • out_lable:损失函数的计算出来的标签

    可以明确地制定生成的名字:

    >>> net = mx.symbol.Variable('data')
    >>> w = mx.symbol.Variable('myweight')
    >>> net = mx.symbol.FullyConnected(data=net, weight=w, name='fc1', num_hidden=128)
    >>> net.list_arguments()
    ['data', 'myweight', 'fc1_bias']

    更多复杂的组成

    MXNet为深度学习提供了优化的symbols,我们能很容易地定义操作子。下面的例子先在两个symbol之间执行了元素级别的加法,然后将加的结果反馈到了fully connected operator。

    >>> lhs = mx.symbol.Variable('data1')
    >>> rhs = mx.symbol.Variable('data2')
    >>> net = mx.symbol.FullyConnected(data=lhs + rhs, name='fc1', num_hidden=128)
    >>> net.list_arguments()
    ['data1', 'data2', 'fc1_weight', 'fc1_bias']

    我们能更加灵活地去构造一个symbol

    >>> net = mx.symbol.Variable('data')
    >>> net = mx.symbol.FullyConnected(data=net, name='fc1', num_hidden=128)
    >>> net2 = mx.symbol.Variable('data2')
    >>> net2 = mx.symbol.FullyConnected(data=net2, name='net2', num_hidden=128)
    >>> composed_net = net(data=net2, name='compose')
    >>> composed_net.list_arguments()
    ['data2', 'net2_weight', 'net2_bias', 'compose_fc1_weight', 'compose_fc1_bias']

    在上面的例子中,net作为一个函数应用于一个已经存在的symbol net,他们的结果composed_net将会替换原始的参数data net2.

    参数shape接口

    接下来了解如何调用所有参数的大小维数

    >>> net = mx.symbol.Variable('data')
    >>> net = mx.symbol.FullyConnected(data=net, name='fc1', num_hidden=10)
    >>> arg_shape, out_shape, aux_shape = net.infer_shape(data=(100, 100))
    >>> dict(zip(net.list_arguments(), arg_shape))
    {'data': (100, 100), 'fc1_weight': (10, 100), 'fc1_bias': (10,)}
    >>> out_shape
    [(100, 10)]

    这个shape接口可以用来检测参数shape不一致。

    绑定symbol和运行

    我们可以绑定symbol的自由变量,执行前馈和反馈的操作。bind函数可以创建一个Excutor用来计算出真正的结果。

    >>> # 定义一个计算流图
    >>> A = mx.symbol.Variable('A')
    >>> B = mx.symbol.Variable('B')
    >>> C = A * B
    >>> a = mx.nd.ones(3) * 4
    >>> b = mx.nd.ones(3) * 2
    >>> # 绑定符号和真实数据
    >>> c_exec = C.bind(ctx=mx.cpu(), args={'A' : a, 'B': b})
    >>> # 执行一个向前传播的运算.
    >>> c_exec.forward()
    >>> c_exec.outputs[0].asnumpy()
    [ 8.  8.  8.]

    对于神经网络而言,一个更加常用的形式是simple_bind,将会为你创建所有的参数数组。然后你调用forwardbackward来获取梯度。

    >>> # 定义计算流图
    >>> net = some symbol
    >>> texec = net.simple_bind(data=input_shape)
    >>> texec.forward()
    >>> texec.backward()

    分布式Key-Value存储

    KVStore是一个数据共享的地方,我们可以将它认为是一个单一对象被不同的设备所共享,在这里每个设备都能将数据推送和拉取。

    Initialization

    考虑一个简单的例子,在store里面初始化一个(int, NDArray)对,然后将这个值拉出去。

    >>> kv = mx.kv.create('local') # 创建一个本地的kv store.
    >>> shape = (2,3)
    >>> kv.init(3, mx.nd.ones(shape)*2)
    >>> a = mx.nd.zeros(shape)
    >>> kv.pull(3, out = a)
    >>> print a.asnumpy()
    [[ 2.  2.  2.]
     [ 2.  2.  2.]]

    Push, Aggregation, 和 Updater

    对于任何已经被初始化的key值,我们可以push一个新的相同大小的值。

    >>> kv.push(3, mx.nd.ones(shape)*8)
    >>> kv.pull(3, out = a) # pull 这个值
    >>> print a.asnumpy()
    [[ 8.  8.  8.]
     [ 8.  8.  8.]]

    用来push的值可以在任意的设备上。除此之外,我们可以push多个值到相同的key,首先KVStore会将所有的值进行求和,然后push这个聚合的值。

    >>> gpus = [mx.gpu(i) for i in range(4)]
    >>> b = [mx.nd.ones(shape, gpu) for gpu in gpus]
    >>> kv.push(3, b)
    >>> kv.pull(3, out = a)
    >>> print a.asnumpy()
    [[ 4.  4.  4.]
     [ 4.  4.  4.]]

    对每次push,KVStore使用updater将push的值和存储的值加起来。默认的updater是ASSIGN,我们可以替换默认的来控制怎样融合数据

    >>> def update(key, input, stored):
    >>>     print "update on key: %d" % key
    >>>     stored += input * 2
    >>> kv._set_updater(update)
    >>> kv.pull(3, out=a)
    >>> print a.asnumpy()
    [[ 4.  4.  4.]
     [ 4.  4.  4.]]
    >>> kv.push(3, mx.nd.ones(shape))
    update on key: 3
    >>> kv.pull(3, out=a)
    >>> print a.asnumpy()
    [[ 6.  6.  6.]
     [ 6.  6.  6.]]

    Pull

    通过一个单独的调用将值pull到几个设备上。

    >>> b = [mx.nd.ones(shape, gpu) for gpu in gpus]
    >>> kv.pull(3, out = b)
    >>> print b[1].asnumpy()
    [[ 6.  6.  6.]
     [ 6.  6.  6.]]

    处理一个键值对的链表

    KVStore提供处理一系列键值对的接口,对于单个设备:

    >>> keys = [5, 7, 9]
    >>> kv.init(keys, [mx.nd.ones(shape)]*len(keys))
    >>> kv.push(keys, [mx.nd.ones(shape)]*len(keys))
    update on key: 5
    update on key: 7
    update on key: 9
    >>> b = [mx.nd.zeros(shape)]*len(keys)
    >>> kv.pull(keys, out = b)
    >>> print b[1].asnumpy()
    [[ 3.  3.  3.]
     [ 3.  3.  3.]]

    对多个设备:

    >>> b = [[mx.nd.ones(shape, gpu) for gpu in gpus]] * len(keys)
    >>> kv.push(keys, b)
    update on key: 5
    update on key: 7
    update on key: 9
    >>> kv.pull(keys, out = b)
    >>> print b[1][1].asnumpy()
    [[ 11.  11.  11.]
     [ 11.  11.  11.]]

    多机器

    基于参数服务器,updater将运行在服务器节点上,

    分布式训练

    如何在MXNet上写一个分布式程序

    MXNet提供了一个分布式key-value store名为kvstore减少了数据同步操作的复杂性。它提供了以下的功能:

    • push:将本地数据push到分布式存储,如梯度等
    • pull:将数据从分布式存储中pull过来,如新的权值
    • set_updater:为分布式存储设置一个updater,明确store是如何将接收到的数据进行融合的,例如:怎样使用接收到的梯度来更新权值。

    如果你的程序按照下面的结构写的,事情会更加简单:

    data  = mx.io.ImageRecordIter(...)
    net   = mx.symbol.SoftmaxOutput(...)
    model = mx.model.FeedForward.create(symbol = net, X = data, ...)

    上面的数据是取自于一个image record iterator,并使用一个符号化网络进行模型训练。为了将它扩展成一个分布式的程序,首先要建立一个kvstore,然后将它传入到create函数中。下面的程序将上面的SGD修改成了分布式异步的SGD:

    kv    = mx.kvstore.create('dist_sync')
    model = mx.model.FeedForward.create(symbol = net, X = data, kvstore = kv, ...)

    使用下面的命令,用本地机器来模拟一个分布式的环境(两个工作节点,两个服务器节点):

    mxnet/tracker/dmlc_local.py -n 2 -s 2 python train.py

    数据并行

    在上面的例子中每个工作节点处理整个训练数据。对于收敛这不是所期望的,因为它们可能在一次迭代中对相同的数据计算同一个梯度,因此这并没有提高计算速度。

    这个问题可以通过数据并行来解决,也就是每个工作节点处理数据的一部分。kvstore提供两个函数用来查询工作节点的信息:

    • kvstore.num_workers:返回工作节点的数目。
    • kvstore.rank:返回当前worker的唯一的rank值,是一个[0,kvstore.num_workers-1]的整数。

    此外,mxnet提供的数据迭代器支持对数据的虚拟分区,它会将数据分成几个parts,并且只会读取其中的一个part。因此,我们可以将上面的程序改为,将数据分成和num_workers一样数目的parts,并要求每个worker只读其中的一个part:

    data = mx.io.ImageRecordIter(num_parts = kv.num_workers, part_index = kv.rank, ...)

    同步和异步

    kvstore提供两种方式将minibatch SGD转变成一个分布式版本。第一种方式是使用Bulk Synchronous Parallel (BSP) protocol,在MXNet上被称为dist_sync。在更新权值之前,它会将每次迭代中(或者minibatch中)所有工作节点上产生的梯度值聚合起来。假设每个工作节点使用mini-batch 的大小为 b,并且总共有 n 个workers。然后dist_sync将会产生与单个worker处理batch大小为 bn 相似的结果。

    需要注意的是,由于数据分区的不完善,每个worker可能会得到有些不同大小的数据。为了确保每个worker在每次数据传递时计算相同数目的batches,我们需要在create函数中为dist_sync明确的设置epoch_size的大小(对于dist_async不需要)。其中一种可选方式是:

    epoch_size = num_examples_in_data / batch_size / kv.num_workers

    第二种方式是使用异步来更新,被称为dist_async。在这个协议中,每个worker独立地更新权值。仍假设有n个workers,每个worker使用batch 大小为b的数据。然后dist_async可以被视为单个机器SGD使用batch大小为b,但是在每次迭代过程中,它会使用几次迭代之前的权值(平均为n)来计算梯度。

    哪个方式更好往往取决于几个因素。通常来说,dist_async要比dist_sync快,因为没有workers之间的数据同步。但是dist_sync可以保证收敛,也就是说,它相当于单个机器使用相当大小的batch大小。关于dist_async的收敛速率仍然是一个有趣的研究课题。

    如果使用dist_sync,一个sever首先会将所有的workers产生的梯度值聚合在一起,然后再执行更新。当使用dist_async时,server会在接收到任意worker传来的梯度值后立即更新。

    在一个集群上载入任务

    MXNet提供几种方式在一个集群上载入任务,包括了资源管理器如:Yarn或者简单的ssh

    机器使用多网卡情况

    对于机器集群上安装了多网卡的用户,MXNet提供了方法让你选择你想选的网卡。例如:你的机器装备了两个网卡,一张卡叫做“eth0(ethernet device)”,另一张卡叫做“ib0(infiniband device)”。你能按下面的方式选择NIC

    export DMLC_INTERFACE="ib0"

    export DMLC_INTERFACE="eth0"

    深度学习编程模型

    MXNet有多个机器学习的库,每一个都有它自己的特点。

    展开全文
  • MXNet简介

    千次阅读 2018-11-13 19:19:32
    MXNet简介 MXNet是一个十分优秀的深度学习框架。目前包含了许多语言接口,如Python、C++、Scala、R等。目前,MXNet版本已经更新到1.3.0。本系列文章主要使用Python接口。 在MXNet官网[1]上,官方建议新手使用Python...

    MXNet是一个十分优秀的深度学习框架。目前包含了许多语言接口,如Python、C++、Scala、R等。目前,MXNet版本已经更新到1.3.0。本系列文章主要使用Python接口。

    在MXNet官网[1]上,官方建议新手使用Python接口,进一步使用下面的Gluon APIs。因为这种方式可以很灵活且容易进行调试。Gluon接口有许多丰富的资源,包括官网上面的例子以及李沐老师的课程[2]。但是,在许多开源的论文程序中,Module接口被大量地使用,并且由于Module接口下的程序本身有许多优秀的特点。所以,本系列文章的主要目标是尽可能地梳理Module接口下涉及到的知识点,尽量用更加丰富的例子来展现。

    训练神经网络通常包括以下几个步骤:输入训练数据、初始化模型参数、前向传播、反向传播、更新参数、保存模型等。MXNet将这些步骤都整合到了一个module包中。Module对训练、测试一个定义好的网络提供了高层和中层接口。用户可以同时使用这两种接口。

    关于MXNet的安装,请参考李沐老师的课程[2]。里面有十分详尽的关于MXNet安装的方法。

    第一课:
    MXNet实战之多层感知机
    第二课:
    利用MXNet的Module接口构建一个CNN模型

    参考

    [1] http://mxnet.incubator.apache.org/

    [2] https://discuss.gluon.ai/

    展开全文
  • 深度框架 MXNet/Gluon 初体验

    万次阅读 2018-05-24 15:33:04
    MXNet: A flexible and efficient library for deep learning. 这是MXNet的官网介绍,“MXNet是灵活且高效的深度学习库”。 MXNet是主流的三大深度学习框架之一: TensorFlow:Google支持,其简化版是Keras; ...
  • MXNet之网络结构搭建

    千次阅读 2019-06-26 19:33:57
    网络结构搭建1.卷积层(Convolution)2.BN层(Batch Normalization)3.激活层(Activation)4.池化层(Pooling)5.全连接层(FullyConnected)6. 损失函数层7.通道合并层(concat)8....import mxnet as mx input_dat...
  • Windows10下安装MXNet-走过的那些坑

    万次阅读 2018-11-05 23:45:01
    一、一开始看到各种安装方法,简单的,用pip安装mxnet的python CPU版本和GPU版本。 windows还是linux,python2还是python3,安装命令都一样 用pip安装mxnet的python CPU版本:pip install mxnet 用pip安装mxnet的...
  • MxNet学习笔记(1)

    2019-01-06 15:09:29
    mxnet.ndarray.concat import mxnet.ndarray as nd x=[[1,1],[2,2]] y=[[3,3],[4,4],[5,5]] z=[[6,6],[7,7],[8,8]] nd.concat(x,y,z,dim=0)##按行拼接 nd.concat(y,z,dim=1)##按列拼接 2 Python中*和**的区别...
  • MXNet

    千次阅读 2019-07-27 11:21:41
    MXNet 是亚马逊(Amazon)选择的深度学习库,并且也许是最优秀的库之一。 TensorFlow、MXNet、Keras如何取舍? 常用深度学习框架对比深度学习 http://www.pinggu.org/index.php?m=content&c=index&a=show&...
  • MXNet安装教程

    万次阅读 2015-12-07 17:38:11
    最近一直在学习深度学习,折腾了几个比较著名的深度学习的框架。...所以,我最终看好的是我大mxnet,使用方便,灵活性和效率并重,而且使用C++写的哦,大可以研究源码,而且相对于caffe而言,安装so ea
  • ubantu下mxnet版本更新

    千次阅读 2017-11-08 15:36:33
    由于mxnet更新迭代还算频繁,所以在学习mxnet的小伙伴,要及时更新自己的mxnet版本。1.如何查看mxnet版本: 在cmd输入python,然后import mxnet,然后打印mxnet.version 2.更新mxnet版本: 先卸载 pip ...
  • linux 安装GPU版本的mxnet

    万次阅读 2019-12-10 09:31:45
    1.先查看自己cuda的版本: ...2.建议先卸载之前安装的mxnet pip uninstall mxnet pip uninstall mxnet-cu90 3.例如cuda的版本是9.0的 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple mxnet-cu...
  • Anaconda+Mxnet安装

    千次阅读 2018-10-22 20:04:47
    在网上找了很多anaconda安装mxnet的方法都是很麻烦或者报各种各样的错误,最后查询anaconda的官方文档成功安装。 conda install mxnet-gpu
  • 在python中超简单安装mxnet

    万次阅读 2020-04-22 15:07:48
    1) 用pip安装mxnet的python版本(CPU版本) 2) 用pip安装mxnet的python版本(GPU版本) 3) 编译安装到操作系统上 这里只说前两种,且不管是windows还是linux,python2还是python3,安装命令都一样 以下分别介绍...
  • ubuntu 16.04 安装MXNet GPU版本

    万次阅读 2017-04-05 10:57:35
    ubuntu 16.04安装MXNet GPU版本
  • 成功解决mxnet.base.MXNetError: C:\Jenkins\workspace\mxnet-tag\mxnet\3rdparty\dmlc-core\src\io\local_file 目录 解决问题 解决思路 解决方法 解决问题 mxnet.base.MXNetError: [22:36:52] C:\...
  • 最近开始尝试MXNet框架,官方文档已经更新,网上中文文档的翻译已经是之前版本。因此打算在学习过程中将最新版的官方文档翻译出来,以便今后自己和相关学习者作为学习参考。不足之处,尽请留言! 官方文档链接:...
  • ubuntu从零开始安装mxnet--安装mxnet

    千次阅读 2017-10-13 01:37:14
    mxnet的安装有多种方式,最简单的自然是pip直接安装。这里只说明gpu版本。pip安装python准备安装python, python-pip这些都不在赘述安装mxnetpip install mxnet-cu80==0.11.0测试mxnetpython import mxnet as mx a = ...
  • mxnet 安装在了conda的虚拟环境下,但是jupyter 起的kernel 是原生的python的环境导致的. 这时需要在conda virtual environment 中创建kernel ,然后使用该kernel即可正常使用mxnet 可参考: jupyter中添加conda虚拟...
  • ubuntu anaconda安装mxnet

    千次阅读 2018-07-15 15:07:45
    mxnet官网上的mxnet安装指令好像有点多,而且没有anaconda下mxnet的安装步骤(virtualenv和anaconda应该差不多,但是我从来没用过)。这里稍微记录一下自己的安装过程,比较简单。 2. 安装环境 我的安装环境是...
1 2 3 4 5 ... 20
收藏数 12,882
精华内容 5,152
关键字:

mxnet