Apache Mxnet 简明教程
Apache MXNet - Introduction
本章重点介绍了 Apache MXNet 的功能,并讨论了该深度学习软件框架的最新版本。
What is MXNet?
Apache MXNet 是一款功能强大的开源深度学习软件框架工具,旨在帮助开发人员构建、训练和部署深度学习模型。在过去的几年里,从医疗保健到交通再到制造业,事实上,在我们的日常生活各个方面,深度学习的影响都已得到广泛普及。如今,深度学习被公司用于解决一些难题,如人脸识别、物体检测、光学字符识别 (OCR)、语音识别和机器翻译。
这就是 Apache MXNet 受支持的原因:
-
英特尔、百度、微软、Wolfram Research 等一些大公司。
-
包括亚马逊网络服务 (AWS) 和 Microsoft Azure 在内的公共云提供商
-
卡内基梅隆大学、麻省理工学院、华盛顿大学和香港科技大学等一些大型研究机构。
Why Apache MXNet?
当时,已经存在各种深度学习平台,如 Torch7、Caffe、Theano、TensorFlow、Keras、Microsoft Cognitive Toolkit 等,您可能想知道为什么选择 Apache MXNet?我们来了解一下背后的原因:
-
Apache MXNet 解决了一个现有的深度学习平台中最大的问题。问题在于,为了使用深度学习平台,人们必须学习另一个系统以采用不同的编程风格。
-
借助 Apache MXNet,开发人员可以充分利用 GPU 和云计算的能力。
-
Apache MXNet 可以加速任何数值计算,并特别注重加快大规模 DNN(深度神经网络)的开发和部署。
-
它为用户提供了命令式和符号式编程的功能。
Various Features
如果您正在寻找一个灵活的深度学习库来快速开发前沿的深度学习研究,或者一个强大的平台来推动生产工作负载,那么 Apache MXNet 就是您搜索之旅的终点。这是因为它具有以下特点:
Distributed Training
无论是在具有近似线性缩放效率的多 GPU 或多主机训练中,Apache MXNet 都允许开发人员最大程度地利用其硬件。MXNet 也支持与 Horovod 集成,Horovod 是优步创建的一个开源分布式深度学习框架。
针对此次集成,以下是一些 Horovod 中定义的常见分布式 API:
-
horovod.broadcast()
-
horovod.allgather()
-
horovod.allgather()
在这方面,MXNet 为我们提供了以下功能:
-
Device Placement −借助 MXNet,我们可以轻松指定每个数据结构 (DS)。
-
Automatic Differentiation −Apache MXNet 自动完成微分,即衍生计算。
-
Multi-GPU training − MXNet 允许我们通过可用 GPU 数量来实现扩展效率。
-
Optimized Predefined Layers − 我们还可以在 MXNet 中对我们自己的层进行编码,以及针对速度对预定义层进行优化。
Latest version MXNet 1.6.0
Apache Software Foundation (ASF) 已于 2020 年 2 月 21 日根据 Apache License 2.0 发布了 Apache MXNet 的稳定版本 1.6.0。这是支持 Python 2 的最后一个 MXNet 版本,因为 MXNet 社区投票决定在以后的版本中不再支持 Python 2。让我们了解一下此版本为其用户带来的一些新特性。
Apache MXNet - Installing MXNet
为了开始使用 MXNet,我们需要做的第一件事,就是将其安装在我们的计算机上。Apache MXNet 几乎适用于所有可用平台,包括 Windows、Mac 和 Linux。
Linux OS
我们可以在 Linux 系统上按照以下方式安装 MXNet -
By using Pip method
您可以使用以下命令在您的 Linus 系统上安装 MXNet -
pip install mxnet
Apache MXNet 还提供 MKL pip 包,在英特尔硬件上运行时速度更快。这里例如 mxnet-cu101mkl 表示 -
-
该软件包使用 CUDA/cuDNN 构建
-
该软件包已启用 MKL-DNN
-
CUDA 版本是 10.1
对于其他选项,您还可以参考 https://pypi.org/project/mxnet/ 。
By using Docker
您可以在 DockerHub 上找到包含 MXNet 的 docker 镜像,它位于 https://hub.docker.com/u/mxnet 。让我们检出以下步骤,以使用带有 GPU 的 Docker 安装 MXNet -
Step 1 − 首先,按照可在 https://docs.docker.com/engine/install/ubuntu/ 获得的 docker 安装说明。我们需要在我们的计算机上安装 Docker。
Step 2 − 为了从 docker 容器中启用 GPU 的使用,接下来我们需要安装 nvidia-docker-plugin。您可以按照 https://github.com/NVIDIA/nvidia-docker/wiki 中提供的安装说明进行操作。
Step 3 − 使用以下命令,您可以拉取 MXNet docker 镜像 -
$ sudo docker pull mxnet/python:gpu
现在为了查看 mxnet/python docker 镜像拉取是否成功,我们可以按如下列出 docker 镜像 -
$ sudo docker images
为了获得最快的 MXNet 推断速度,建议使用带有 Intel MKL-DNN 的最新 MXNet。查看以下命令 -
$ sudo docker pull mxnet/python:1.3.0_cpu_mkl
$ sudo docker images
From source
要通过 GPU 构建 MXNet 共享库,首先需要为 CUDA 和 cuDNN 设置环境,如下所述−
-
下载并安装 CUDA 工具包,建议此处使用 CUDA 9.2。
-
Next download cuDNN 7.1.4.
-
现在需要解压该文件。还需要更改为 cuDNN 根目录。还要将头文件和库移动到本地 CUDA Toolkit 文件夹中,如下所示:
tar xvzf cudnn-9.2-linux-x64-v7.1
sudo cp -P cuda/include/cudnn.h /usr/local/cuda/include
sudo cp -P cuda/lib64/libcudnn* /usr/local/cuda/lib64
sudo chmod a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn*
sudo ldconfig
设置 CUDA 和 cuDNN 的环境后,按照以下步骤从源代码构建 MXNet 共享库:
Step 1 − 首先,我们需要安装必备软件包。Ubuntu 16.04 或更高版本需要这些依赖项。
sudo apt-get update
sudo apt-get install -y build-essential git ninja-build ccache libopenblas-dev
libopencv-dev cmake
Step 2 − 在此步骤中,我们将下载 MXNet 源代码并进行配置。首先,让我们使用以下命令克隆存储库:
git clone –recursive https://github.com/apache/incubator-mxnet.git mxnet
cd mxnet
cp config/linux_gpu.cmake #for build with CUDA
Step 3 − 使用以下命令可以构建 MXNet 核心共享库:
rm -rf build
mkdir -p build && cd build
cmake -GNinja ..
cmake --build .
Two important points regarding the above step is as follows−
如果要构建调试版本,请按以下方式指定:
cmake -DCMAKE_BUILD_TYPE=Debug -GNinja ..
为了设置并行编译作业的数量,请指定以下内容:
cmake --build . --parallel N
一旦成功构建 MXNet 核心共享库,您将在 build 中 MXNet project root, 找到 libmxnet.so ,这是安装语言绑定(可选)所必需的。
Central Processing Unit (CPU)
在此,当使用 CPU 进行处理时,我们将使用各种方法(即 Pip、Docker 和 Source)来安装 MXNet:
By using Pip method
可以使用以下命令在 Linus OS 上安装 MXNet:
pip install mxnet
当在英特尔硬件上运行时,Apache MXNet 还提供了支持 MKL-DNN 的 pip 包,而这些包要快得多。
pip install mxnet-mkl
By using Docker
在 DockerHub 上可以找到带 MXNet 的 Docker 镜像,网址为 https://hub.docker.com/u/mxnet 。让我们查看以下步骤,以使用 Docker 和 CPU 安装 MXNet:
Step 1 − 首先,按照可在 https://docs.docker.com/engine/install/ubuntu/ 获得的 docker 安装说明。我们需要在我们的计算机上安装 Docker。
Step 2 − 使用以下命令可以提取 MXNet docker 镜像:
$ sudo docker pull mxnet/python
现在,为了查看 mxnet/python docker 镜像提取是否成功,我们可以按如下方式列出 docker 镜像:
$ sudo docker images
为了获得 MXNet 的最快推理速度,建议使用带有英特尔 MKL-DNN 的最新 MXNet。
检查以下命令:
$ sudo docker pull mxnet/python:1.3.0_cpu_mkl
$ sudo docker images
From source
若要从源代码使用 CPU 编译 MXNet 共享库,请执行以下步骤 −
Step 1 − 首先,我们需要安装必备软件包。Ubuntu 16.04 或更高版本需要这些依赖项。
sudo apt-get update
sudo apt-get install -y build-essential git ninja-build ccache libopenblas-dev libopencv-dev cmake
Step 2 − 在此步骤中,我们将下载 MXNet 源代码并进行配置。首先,让我们使用以下命令克隆存储库:
git clone –recursive https://github.com/apache/incubator-mxnet.git mxnet
cd mxnet
cp config/linux.cmake config.cmake
Step 3 − 您可以使用以下命令编译 MXNet 核心共享库:
rm -rf build
mkdir -p build && cd build
cmake -GNinja ..
cmake --build .
Two important points regarding the above step is as follows−
如果您想编译调试版本,请按如下指定:
cmake -DCMAKE_BUILD_TYPE=Debug -GNinja ..
要设置并行编译作业的数量,请指定以下内容 −
cmake --build . --parallel N
一旦成功编译 MXNet 核心共享库,您将在 MXNet 项目根目录的 build 文件夹中找到 libmxnet.so,该库是安装语言绑定(可选)所需的。
MacOS
我们可以在 MacOS 上通过以下方式安装 MXNet −
Graphical Processing Unit (GPU)
如果您打算在带有 GPU 的 MacOS 上编译 MXNet,那么 NO Pip 和 Docker 方法可用。在这种情况下,唯一的方法是从源代码编译它。
From source
要从源代码使用 GPU 编译 MXNet 共享库,首先需要为 CUDA 和 cuDNN 设置环境。您需要按照 NVIDIA CUDA Installation Guide 中提供的说明操作,该说明可在 https://docs.nvidia.com 中找到以及 cuDNN Installation Guide, 中提供的说明,该说明可在 https://docs.nvidia.com/deeplearning 中找到以适用于 Mac OS。
请注意,在 2019 年中,CUDA 停止了对 macOS 的支持。事实上,未来版本的 CUDA 可能也不支持 macOS。
一旦您为 CUDA 和 cuDNN 设置了环境,按照下面给出的步骤在 OS X(Mac)上从源代码安装 MXNet−
Step 1 − 由于我们在 OS x 上有一些依赖项,因此首先需要安装必备包。
xcode-select –-install #Install OS X Developer Tools
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" #Install Homebrew
brew install cmake ninja ccache opencv # Install dependencies
我们还可以不用 OpenCV 编译 MXNet,因为 opencv 是可选的依赖项。
Step 2 − 在此步骤中,我们下载 MXNet 源代码并进行配置。首先,让我们使用以下命令克隆存储库−
git clone –-recursive https://github.com/apache/incubator-mxnet.git mxnet
cd mxnet
cp config/linux.cmake config.cmake
对于支持 GPU,首先有必要安装 CUDA 依赖项,因为当人们尝试在没有 GPU 的机器上编译支持 GPU 的编译时,MXNet 编译不能自动检测到您的 GPU 架构。在这样的情况下,MXNet 将针对所有可用的 GPU 架构。
Step 3 − 使用以下命令可以构建 MXNet 核心共享库:
rm -rf build
mkdir -p build && cd build
cmake -GNinja ..
cmake --build .
有关上述步骤的两个重要说明如下−
如果要构建调试版本,请按以下方式指定:
cmake -DCMAKE_BUILD_TYPE=Debug -GNinja ..
要设置并行编译作业的数量,请指定以下内容:
cmake --build . --parallel N
一旦成功编译 MXNet 核心共享库,您将在 build 文件夹中的 MXNet project root, 中找到 libmxnet.dylib, ,它是安装语言绑定(可选)所需的。
Central Processing Unit (CPU)
在这里,当我们使用 CPU 进行处理时,我们将使用 Pip、Docker 和源这几种方法来安装 MXNet−
By using Docker
您可以在 DockerHub 上找到带有 MXNet 的 docker 映像,它可在 https://hub.docker.com/u/mxnet 上获得。让我们看看以下步骤以使用具有 CPU 的 Docker 安装 MXNet−
Step 1 − 首先,按照可在 https://docs.docker.com/docker-for-mac 上获得的 docker installation instructions 安装 Docker 到我们的机器上。
Step 2 − 通过使用以下命令,您可以拉取 MXNet docker 映像−
$ docker pull mxnet/python
现在为了查看 mxnet/python docker 映像拉取是否成功,我们可以按以下方式列出 docker 映像−
$ docker images
为了获得 MXNet 最快的推理速度,推荐使用带有 Intel MKL-DNN 的最新 MXNet。查看以下命令−
$ docker pull mxnet/python:1.3.0_cpu_mkl
$ docker images
From source
按照以下提供的步骤在 OS X(Mac)上从源代码安装 MXNet−
Step 1 − 因为我们需要一些在 OS x 上的依赖项,所以首先,我们需要安装先决条件包。
xcode-select –-install #Install OS X Developer Tools
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" #Install Homebrew
brew install cmake ninja ccache opencv # Install dependencies
我们还可以不用 OpenCV 编译 MXNet,因为 opencv 是可选的依赖项。
Step 2 − 在此步骤中,我们将下载 MXNet 源代码并配置。首先,让我们通过使用以下命令克隆仓库−
git clone –-recursive https://github.com/apache/incubator-mxnet.git mxnet
cd mxnet
cp config/linux.cmake config.cmake
Step 3 − 您可以使用以下命令编译 MXNet 核心共享库:
rm -rf build
mkdir -p build && cd build
cmake -GNinja ..
cmake --build .
Two important points regarding the above step is as follows−
如果要构建调试版本,请按以下方式指定:
cmake -DCMAKE_BUILD_TYPE=Debug -GNinja ..
要设置并行编译作业的数量,请指定以下内容 −
cmake --build . --parallel N
一旦成功编译 MXNet 核心共享库,您将在 build 文件夹中的 MXNet project root, 中找到 libmxnet.dylib, ,它是安装语言绑定(可选)所需的。
Windows OS
为在 Windows 上安装 MXNet,以下为先决条件−
Minimum System Requirements
-
Windows 7、10、Server 2012 R2 或 Server 2016
-
Visual Studio 2015 或 2017(任何类型)
-
Python 2.7 or 3.6
-
pip
Recommended System Requirements
-
Windows 10、Server 2012 R2 或 Server 2016
-
Visual Studio 2017
-
至少一个 NVIDIA CUDA 支持的 GPU
-
启用了 MKL 的 CPU:英特尔® 至强® 处理器、英特尔® 酷睿™ 处理器家族、英特尔凌动® 处理器或英特尔® 至强融核™ 处理器
-
Python 2.7 or 3.6
-
pip
By using Pip method−
如果您计划在带有 NVIDIA GPU 的 Windows 上构建 MXNet,则有两个选择,可以使用 Python 包使用 CUDA 支持安装 MXNet−
Install with CUDA Support
以下是我们借助其设置带有 CUDA 的 MXNet 的步骤。
Step 1 − 首先安装 Microsoft Visual Studio 2017 或 Microsoft Visual Studio 2015。
Step 2 − 接下来,下载并安装 NVIDIA CUDA。推荐使用 CUDA 版本 9.2 或 9.0,因为在过去已经发现了 CUDA 9.1 中的一些问题。
Step 3 − 现在,下载并安装 NVIDIA_CUDA_DNN。
Step 4 − 最后,使用以下 pip 命令,安装带 CUDA 的 MXNet。
pip install mxnet-cu92
Install with CUDA and MKL Support
以下是可供参考的步骤,我们可以利用这些步骤,使用 CUDA 和 MKL 设置 MXNet。
Step 1 − 首先安装 Microsoft Visual Studio 2017 或 Microsoft Visual Studio 2015。
Step 2 − 接下来,下载并安装英特尔 MKL。
Step 3 − 现在,下载并安装 NVIDIA CUDA。
Step 4 − 现在,下载并安装 NVIDIA_CUDA_DNN。
Step 5 − 最后,使用以下 pip 命令,安装带 MKL 的 MXNet。
pip install mxnet-cu92mkl
From source
要通过源代码使用 GPU 构建 MXNet 核心库,我们有以下两个选项:
Option 1− Build with Microsoft Visual Studio 2017
为了使用 Microsoft Visual Studio 2017 自己构建和安装 MXNet,您需要以下依赖项。
Install/update Microsoft Visual Studio.
-
如果您的计算机上尚未安装 Microsoft Visual Studio,请先下载并安装它。
-
它会提示您安装 Git。同样,安装它。
-
如果您的计算机上已经安装了 Microsoft Visual Studio,但您想要更新它,则继续执行下一步以修改您的安装。在这里,您也有机会更新 Microsoft Visual Studio。
按照 https://docs.microsoft.com/en-us 中提供的打开 Visual Studio 安装程序的说明来修改各个组件。
在 Visual Studio 安装程序应用程序中,根据需要更新。之后,查找并选中 VC++ 2017 version 15.4 v14.11 toolset ,然后单击 Modify 。
现在,使用以下命令,将 Microsoft VS2017 的版本更改为 v14.11−
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" -vcvars_ver=14.11
接下来,您需要下载并安装 CMake ,它可在 https://cmake.org/download/ 获得。建议您使用 CMake v3.12.2 ,它可在 https://cmake.org/download/ 获得,因为它经过 MXNet 测试。
现在,下载并运行 OpenCV 程序包,它可在 https://sourceforge.net/projects/opencvlibrary/ 获得。该程序包将解压缩几个文件。由您决定是否将它们放入另一个目录。在这里,我们将 C:\utils(mkdir C:\utils) 路径用作我们的默认路径。
接下来,我们需要设置环境变量 OpenCV_DIR,以便指向我们刚刚解压的 OpenCV 构建目录。为此,打开命令提示符并键入 set OpenCV_DIR=C:\utils\opencv\build 。
一个重要的问题是,如果您没有安装英特尔 MKL(Math Kernel Library),您可以安装它。
您可以使用的另一个开源包是 OpenBLAS 。在此,为了进一步说明,我们假设您正在使用 OpenBLAS 。
因此,下载 OpenBlas 包,该包可在 https://sourceforge.net 中获取,然后解压该文件,将其重命名为 OpenBLAS 并将其放在 C:\utils 下。
接下来,我们需要设置环境变量 OpenBLAS_HOME 以指向包含 include 和 lib 目录的 OpenBLAS 目录。为此,打开命令提示符并键入 set OpenBLAS_HOME=C:\utils\OpenBLAS 。
现在,下载并安装可在 https://developer.nvidia.com 中获取的 CUDA。请注意,如果您已经安装了 CUDA,然后安装了 Microsoft VS2017,那么您现在需要重新安装 CUDA,以便您可以获取 Microsoft VS2017 集成的 CUDA 工具包组件。
接下来,您需要下载并安装 cuDNN。
接下来,您需要下载并安装也在 https://gitforwindows.org/ 的 git。
一旦安装了所有必需的依赖项,请按照以下步骤来构建 MXNet 源代码 -
Step 1 - 在 Windows 中打开命令提示符。
Step 2 - 现在,使用以下命令,从 GitHub 下载 MXNet 源代码:
cd C:\
git clone https://github.com/apache/incubator-mxnet.git --recursive
Step 3 - 接下来,验证以下内容 -
DCUDNN_INCLUDE and DCUDNN_LIBRARY 环境变量指向安装了 CUDA 的位置的 include 文件夹和 cudnn.lib 文件
C:\incubator-mxnet 是您在上一步中克隆的源代码的位置。
Step 4 - 接下来,使用以下命令,创建一个构建 directory 并转到该目录,例如 -
mkdir C:\incubator-mxnet\build
cd C:\incubator-mxnet\build
Step 5 - 现在,使用 cmake,编译 MXNet 源代码,如下所示 -
cmake -G "Visual Studio 15 2017 Win64" -T cuda=9.2,host=x64 -DUSE_CUDA=1 -DUSE_CUDNN=1 -DUSE_NVRTC=1 -DUSE_OPENCV=1 -DUSE_OPENMP=1 -DUSE_BLAS=open -DUSE_LAPACK=1 -DUSE_DIST_KVSTORE=0 -DCUDA_ARCH_LIST=Common -DCUDA_TOOLSET=9.2 -DCUDNN_INCLUDE=C:\cuda\include -DCUDNN_LIBRARY=C:\cuda\lib\x64\cudnn.lib "C:\incubator-mxnet"
Step 6 - CMake 成功完成后,使用以下命令编译 MXNet 源代码 -
msbuild mxnet.sln /p:Configuration=Release;Platform=x64 /maxcpucount
Option 2: Build with Microsoft Visual Studio 2015
为了使用 Microsoft Visual Studio 2015 自己构建并安装 MXNet,您需要以下依赖项。
安装/更新 Microsoft Visual Studio 2015。从源代码构建 MXnet 的最低要求是,Microsoft Visual Studio 2015 的更新 3。你可以使用 Tools → Extensions and Updates… | Product Updates 菜单对其进行升级。
接下来,你需要下载并安装 CMake ,可从 https://cmake.org/download/ 获得。建议使用 CMake v3.12.2 ,该软件位于 https://cmake.org/download/ ,因为它已通过 MXNet 的测试。
现在,下载并运行 OpenCV 包,该包可从 https://excellmedia.dl.sourceforge.net 获得,它将解压多个文件。至于是否将它们放入另一个目录由你决定。
接下来,我们需要将环境变量 OpenCV_DIR 设置为指向我们刚刚解压的 OpenCV 构建目录。为此,打开命令提示符并键入 set OpenCV_DIR=C:\opencv\build\x64\vc14\bin 。
一个重要的问题是,如果您没有安装英特尔 MKL(Math Kernel Library),您可以安装它。
您可以使用的另一个开源包是 OpenBLAS 。在此,为了进一步说明,我们假设您正在使用 OpenBLAS 。
因此,下载可从 https://excellmedia.dl.sourceforge.net 获得的 OpenBLAS 包,并解压该文件,将其重命名为 OpenBLAS 并将其放入 C:\utils。
接下来,我们需要将环境变量 OpenBLAS_HOME 设置为指向包含 include 和 lib 目录的 OpenBLAS 目录。你可以在 C:\Program files (x86)\OpenBLAS\ 中找到该目录。
请注意,如果你已经安装了 CUDA,然后安装了 Microsoft VS2015,那么你需要重新安装 CUDA,这样你才能获得适用于 Microsoft VS2017 集成的 CUDA 工具包组件。
接下来,您需要下载并安装 cuDNN。
现在,我们需要将环境变量 CUDACXX 设置为指向 CUDA Compiler(C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.1\bin\nvcc.exe (例如)。
类似地,我们还需要将环境变量 CUDNN_ROOT 设置为指向包含 include, lib 和 bin 目录的 cuDNN 目录(例如 C:\Downloads\cudnn-9.1-windows7-x64-v7\cuda )。
一旦安装了所有必需的依赖项,请按照以下步骤来构建 MXNet 源代码 -
Step 1 − 首先,从 GitHub 下载 MXNet 源代码−
cd C:\
git clone https://github.com/apache/incubator-mxnet.git --recursive
Step 2 − 接下来,使用 CMake 在 ./build 中创建一个 Visual Studio。
Step 3 − 现在,在 Visual Studio 中,我们需要打开解决方案文件 .sln 并对其进行编译。这些命令将在 ./build/Release/ or ./build/Debug 文件夹中生成一个名为 mxnet.dll 的库
Step 4 − 一旦 CMake 成功完成,使用以下命令编译 MXNet 源代码
msbuild mxnet.sln /p:Configuration=Release;Platform=x64 /maxcpucount
Central Processing Unit (CPU)
在这里,当我们使用 CPU 进行处理时,我们将使用 Pip、Docker 和源这几种方法来安装 MXNet−
By using Pip method
如果你计划在配备 CPU 的 Windows 上构建 MXNet,则可以使用 Python 包安装 MXNet,方法有两种:
Install with CPUs
使用以下命令使用 Python 安装带有 CPU 的 MXNet−
pip install mxnet
Install with Intel CPUs
如上所述,MXNet 实验性地支持 Intel MKL,还支持 MKL-DNN。使用以下命令使用 Python 安装带有 Intel CPU 的 MXNet−
pip install mxnet-mkl
By using Docker
你可以在 DockerHub 中找到具有 MXNet 的 docker 镜像,可以在 https://hub.docker.com/u/mxnet 上获得。我们通过 Docker 使用 CPU 安装 MXNet 的步骤如下:
Step 1 − 首先,通过按照可从 https://docs.docker.com/docker-for-mac/install 阅读的 Docker 安装说明进行操作。我们需要在我们的机器上安装 Docker。
Step 2 − 通过使用以下命令,您可以拉取 MXNet docker 映像−
$ docker pull mxnet/python
现在为了查看 mxnet/python docker 映像拉取是否成功,我们可以按以下方式列出 docker 映像−
$ docker images
为了获得 MXNet 的最快推理速度,建议使用带有英特尔 MKL-DNN 的最新 MXNet。
检查下面的命令−
$ docker pull mxnet/python:1.3.0_cpu_mkl
$ docker images
Installing MXNet On Cloud
您还可以通过对 Graphical Processing Unit (GPU) 提供支持的几个云提供商来获取 Apache MXNet。可以找到的另外两种支持如下−
-
用于可扩展推理之类的用例的 GPU/CPU 混合支持。
-
支持使用 AWS Elastic Inference 的 Factorial GPU。
以下是提供支持 Apache MXNet 的不同虚拟机的 GPU 支持的云提供商−
The Alibaba Console
您可以使用阿里巴巴控制台创建 NVIDIA GPU Cloud Virtual Machine (VM) (可在 https://docs.nvidia.com/ngc 获得),并使用 Apache MXNet。
AWS Deep Learning AMI
它为 Python 2 和 Python 3 提供了预安装的 Conda 环境,其中包括 Apache MXNet、CUDA、cuDNN、MKL-DNN 和 AWS Elastic Inference。
Dynamic Training on AWS
它对实验手动 EC2 设置以及半自动化 CloudFormation 设置提供培训。
您可以使用 Amazon Web Services 中提供的 NVIDIA VM (可在 https://aws.amazon.com 获得)。
Google Cloud Platform
Google 还提供 NVIDIA GPU cloud image ,可在 https://console.cloud.google.com 获得,可用于处理 Apache MXNet。
Microsoft Azure
Microsoft Azure Marketplace 还提供 NVIDIA GPU cloud image ,可在 https://azuremarketplace.microsoft.com 获得,可用于处理 Apache MXNet。
Oracle Cloud
Oracle 还提供 NVIDIA GPU cloud image ,可在 https://docs.cloud.oracle.com 获得,可用于处理 Apache MXNet。
Installing MXNet on Devices
让我们了解如何在设备上安装 MXNet。
Raspberry Pi
您也可以在 Raspberry Pi 3B 设备上运行 Apache MXNet,因为 MXNet 也支持基于 Respbian ARM 的操作系统。为了在 Raspberry Pi3 上平稳运行 MXNet,建议使用具有 1 GB 以上内存和至少 4GB 可用空间的 SD 卡的设备。
以下是利用这些方法为 Raspberry Pi 构建 MXNet 并安装该库的 Python 绑定:
Quick installation
预先构建的 Python wheel 可用于安装在带有 Stretch 的 Raspberry Pi 3B 上以便快速安装。此方法的一个重要问题是我们可能需要安装若干个依赖项才能让 Apache MXNet 运行。
Docker installation
您可以按照 https://docs.docker.com/engine/install/ubuntu/ 中提供的 docker 安装说明在您的机器上安装 Docker。为此,我们也可以安装和使用社区版 (CE)。
Native Build (from source)
为了从源安装 MXNet,我们需要按照以下两个步骤操作:
Step 1
Build the shared library from the Apache MXNet C++ source code
为了在 Raspberry 版本 Wheezy 及更高版本上构建共享库,我们需要以下依赖项:
-
Git - 必需从 GitHub 拉取代码。
-
Libblas - 必需用于线性代数运算。
-
Libopencv - 必需用于计算机视觉相关运算。但是如果您想保存您的内存和磁盘空间,它则是可选的。
-
C Compiler - 必需编译和构建 MXNet 源代码。以下是支持 C 11 的受支持编译器:G++(4.8 或更高版本)Clang(3.9-6)
使用以下命令安装上述依赖项:
sudo apt-get update
sudo apt-get -y install git cmake ninja-build build-essential g++-4.9 c++-4.9 liblapack*
libblas* libopencv*
libopenblas* python3-dev python-dev virtualenv
接下来,我们需要克隆 MXNet 源代码存储库。为此,请在您的主目录中使用以下 git 命令:
git clone https://github.com/apache/incubator-mxnet.git --recursive
cd incubator-mxnet
现在,利用以下命令构建共享库:
mkdir -p build && cd build
cmake \
-DUSE_SSE=OFF \
-DUSE_CUDA=OFF \
-DUSE_OPENCV=ON \
-DUSE_OPENMP=ON \
-DUSE_MKL_IF_AVAILABLE=OFF \
-DUSE_SIGNAL_HANDLER=ON \
-DCMAKE_BUILD_TYPE=Release \
-GNinja ..
ninja -j$(nproc)
一旦您执行了上述命令,它将启动构建过程,该过程将需要几个小时才能完成。您将在构建目录中得到一个名为 libmxnet.so 的文件。
NVIDIA Jetson Devices
您也可以在 NVIDIA Jetson 设备上(如 TX2 或 Nano )运行 Apache MXNet,因为 MXNet 也支持基于 Ubuntu Arch64 的操作系统。为了在 NVIDIA Jetson 设备上平稳运行 MXNet,在您的 Jetson 设备上安装 CUDA 是必要的。
以下是借助其可以为 NVIDIA Jetson 设备构建 MXNet 的方式:
-
通过使用 Jetson MXNet pip 轮子进行 Python 开发
-
From source
但是,在通过上述任何一种方式构建 MXNet 之前,您需要在 Jetson 设备上安装以下依赖项−
Python Dependencies
为了使用 Python API,我们需要以下依赖项−
sudo apt update
sudo apt -y install \
build-essential \
git \
graphviz \
libatlas-base-dev \
libopencv-dev \
python-pip
sudo pip install --upgrade \
pip \
setuptools
sudo pip install \
graphviz==0.8.4 \
jupyter \
numpy==1.15.2
Clone the MXNet source code repository
通过在主目录中使用以下 git 命令克隆 MXNet 源代码存储库−
git clone --recursive https://github.com/apache/incubator-mxnet.git mxnet
Setup environment variables
在主目录中的 .profile 文件中添加以下内容−
export PATH=/usr/local/cuda/bin:$PATH
export MXNET_HOME=$HOME/mxnet/
export PYTHONPATH=$MXNET_HOME/python:$PYTHONPATH
现在,使用以下命令立即应用更改−
source .profile
Configure CUDA
在使用 nvcc 配置 CUDA 之前,您需要检查正在运行哪个版本的 CUDA −
nvcc --version
假设您的设备或计算机上安装了多个 CUDA 版本,并且您希望切换 CUDA 版本,那么请使用以下并将其替换为您想要的版本的符号链接−
sudo rm /usr/local/cuda
sudo ln -s /usr/local/cuda-10.0 /usr/local/cuda
上述命令将切换到 CUDA 10.0,该版本预装在 NVIDIA Jetson 设备 Nano 上。
完成上述先决条件后,您现在可以在 NVIDIA Jetson 设备上安装 MXNet。因此,让我们了解借助其可以安装 MXNet 的方式−
By using a Jetson MXNet pip wheel for Python development −如果您想使用已准备好的 Python 轮子,那么请将以下内容下载到 Jetson 并运行−
-
MXNet 1.4.0(适用于 Python 3)可从 https://docs.docker.com 获得
-
MXNet 1.4.0(适用于 Python 2)可从 https://docs.docker.com 获得
Native Build (from source)
为了从源安装 MXNet,我们需要按照以下两个步骤操作:
Step 1
Build the shared library from the Apache MXNet C++ source code
若要从 Apache MXNet C++ 源代码构建共享库,您可以使用 Docker 方法或手动构建−
Docker method
此方法中,您首先需要安装 Docker 并能够在不使用 sudo 的情况下运行它(在前面的步骤中也有说明)。完成后,运行以下内容以通过 Docker 执行交叉编译−
$MXNET_HOME/ci/build.py -p jetson
Manual
此方法中,您需要编辑 Makefile (使用以下命令)以使用 CUDA 绑定安装 MXNet,以利用 NVIDIA Jetson 设备上的图形处理单元 (GPU):
cp $MXNET_HOME/make/crosscompile.jetson.mk config.mk
编辑 Makefile 之后,您需要编辑 config.mk 文件,以便对 NVIDIA Jetson 设备进行一些额外更改。
为此,请更新以下设置−
-
更新 CUDA 路径:USE_CUDA_PATH = /usr/local/cuda
-
向 CUDA_ARCH 设置中添加 -gencode arch=compute-63, code=sm_62
-
更新 NVCC 设置:NVCCFLAGS := -m64
-
启用 OpenCV:USE_OPENCV = 1
现在为了确保 MXNet 以 Pascal 的硬件级别低精度加速构建,我们需要编辑 Mshadow Makefile,如下所示:
MSHADOW_CFLAGS += -DMSHADOW_USE_PASCAL=1
最后,在以下命令的帮助下,您可以构建完整的 Apache MXNet 库:
cd $MXNET_HOME
make -j $(nproc)
一旦你执行完上述命令,它就会开始构建过程,这将需要几个小时才能完成。您将在 mxnet/lib directory 中获得一个名为 libmxnet.so 的文件。
Apache MXNet - Toolkits and Ecosystem
为了支持跨多个领域的深度学习应用程序的研发,Apache MXNet 为我们提供了一个丰富的工具包、库等生态系统。让我们探索它们--
ToolKits
以下是 MXNet 提供的部分最常用且最重要的工具包--
GluonCV
顾名思义,GluonCV 是一个由 MXNet 驱动的 Gluon 工具包,用于计算机视觉。它提供了计算机视觉 (CV) 中最先进的 DL(深度学习)算法的实现。在 GluonCV 工具包的帮助下,工程师、研究人员和学生们可以验证新想法并轻松学习 CV。
下面给出了一些 features of GluonCV —
-
它训练脚本以复制最新研究中报告的最先进的结果。
-
170 多个高质量预训练模型。
-
Embrace flexible development pattern.
-
GluonCV 易于优化。我们可以部署它而无需保留重量级 DL 框架。
-
它提供了精心设计的 API,极大地降低了实现的复杂性。
-
Community support.
-
Easy to understand implementations.
以下 supported applications 基于 GluonCV 工具包:
-
Image Classification
-
Object Detection
-
Semantic Segmentation
-
Instance Segmentation
-
Pose Estimation
-
Video Action Recognition
我们可以使用 pip 安装 GluonCV,如下所示 -
pip install --upgrade mxnet gluoncv
GluonNLP
顾名思义,GluonNLP 是由 MXNet 驱动的用于自然语言处理 (NLP) 的 Gluon 工具包。它提供了 NLP 领域中先进的 DL(深度学习)模型实现。
借助 GluonNLP 工具包,工程师、研究人员和学生可以构建文本数据管道和模型。基于这些模型,他们可以快速构建研究理念和产品原型。
以下是 GluonNLP 的一些特性:
-
它训练脚本以复制最新研究中报告的最先进的结果。
-
为常见 NLP 任务设置预训练的模型。
-
它提供了精心设计的 API,极大地降低了实现的复杂性。
-
Community support.
-
它还提供了教程,帮助你轻松入门新的 NLP 任务。
以下是我们使用 GluonNLP 工具包可以实现的 NLP 任务 -
-
Word Embedding
-
Language Model
-
Machine Translation
-
Text Classification
-
Sentiment Analysis
-
Natural Language Inference
-
Text Generation
-
Dependency Parsing
-
Named Entity Recognition
-
意图分类和时隙标注
我们可以使用 pip 安装 GluonNLP,如下所示 -
pip install --upgrade mxnet gluonnlp
GluonTS
顾名思义,GluonTS 是由 MXNet 驱动的用于概率时间序列建模的 Gluon 工具包。
它提供以下特性 -
-
已准备就绪的先进深度学习模型。
-
加载和迭代时间序列数据集的实用工具。
-
定义你自己的模型的构建模块。
借助 GluonTS 工具包,工程师、研究人员和学生可以在自己的数据上训练和评估任何内置模型,快速尝试不同的解决方案,并针对其时间序列任务提出解决方案。
他们还可以使用所提供的抽象和构建模块创建自定义时间序列模型,并针对基线算法快速对其进行基准测试。
我们可以使用 pip 安装 GluonTS,如下所示 -
pip install gluonts
GluonFR
顾名思义,它是一个用于 FR(人脸识别)的 Apache MXNet Gluon 工具包。它提供了以下特性 -
-
人脸识别的最新深度学习模型。
-
在 MXNet 框架中使用 PyTorch/Gluon,实现了 SoftmaxCrossEntropyLoss、ArcLoss、TripletLoss、RingLoss、CosLoss/AMsoftmax、L2-Softmax、A-Softmax、CenterLoss、ContrastiveLoss 和 LGM Loss 等损失函数。
要安装 gluon face,则需要 Python 3.5 或更高版本。我们还需要先安装 GluonCV 和 MXNet,如下所示:
pip install gluoncv --pre
pip install mxnet-mkl --pre --upgrade
pip install mxnet-cuXXmkl --pre –upgrade # if cuda XX is installed
安装依赖项后,可以使用以下命令安装 GluonFR:
From Source
pip install git+https://github.com/THUFutureLab/gluon-face.git@master
Pip
pip install gluonfr
Ecosystem
现在,让我们探索 MXNet 丰富的库、包和框架:
Coach RL
Intel AI 实验室创建的 Python 强化学习 (RL) 框架 Coach。它支持轻松试验 State-of-the-art RL 算法。Coach RL 支持 Apache MXNet 作为后端,并允许轻松集成新的环境进行求解。
为了轻松扩展和重复利用现有组件,Coach RL 很好的解耦了基本的强化学习组件,如算法、环境、神经网络架构、探索策略。
以下面向 Coach RL 框架的智能体和支持算法:
Value Optimization Agents
-
Deep Q Network (DQN)
-
Double Deep Q Network (DDQN)
-
Dueling Q Network
-
Mixed Monte Carlo (MMC)
-
Persistent Advantage Learning (PAL)
-
Categorical Deep Q Network (C51)
-
Quantile Regression Deep Q Network (QR-DQN)
-
N-Step Q Learning
-
Neural Episodic Control (NEC)
-
Normalized Advantage Functions (NAF)
-
Rainbow
Policy Optimization Agents
-
Policy Gradients (PG)
-
Asynchronous Advantage Actor-Critic (A3C)
-
Deep Deterministic Policy Gradients (DDPG)
-
Proximal Policy Optimization (PPO)
-
Clipped Proximal Policy Optimization (CPPO)
-
Generalized Advantage Estimation (GAE)
-
Sample Efficient Actor-Critic with Experience Replay (ACER)
-
Soft Actor-Critic (SAC)
-
Twin Delayed Deep Deterministic Policy Gradient (TD3)
Deep Graph Library
Deep Graph Library (DGL) 由纽约大学和亚马逊网络服务团队(上海)开发,这是一个可在 MXNet 之上提供图神经网络 (GNN) 轻松实现的 Python 包。它还可在 PyTorch、Gluon 等其他现有主流深度学习库之上提供 GNN 的轻松实现。
Deep Graph Library 是一款免费软件。它在 Ubuntu 16.04、macOS X 以及 Windows 7 或更高版本的系统上均可用。它还需要 Python 3.5 或更高版本。
以下是 DGL 的功能 −
No Migration cost − DGL 建立在流行的现有 DL 框架之上,因此使用它没有迁移成本。
Message Passing − DGL 提供消息传递并对其具有多功能控制。消息传递的范围从低级操作(例如沿着选定的边发送)到高级控制(例如图级特征更新)。
Smooth Learning Curve − 由于强大的用户自定义函数既灵活又易于使用,因此学习和使用 DGL 非常容易。
Transparent Speed Optimization − DGL 通过自动批处理计算和稀疏矩阵乘法提供透明的速度优化。
High performance − 为了达到最大的效率,DGL 自动将 DNN(深度神经网络)训练批处理在一起或多个图。
Easy & friendly interface − DGL 为我们提供了用于边缘特征访问以及图结构操作的简单友好的界面。
InsightFace
InsightFace,一个用于面部分析的深度学习工具包,它提供了由 MXNet 提供支持的计算机视觉中 SOTA(最先进)面部分析算法的实现。它提供 −
-
高质量的大型预训练模型。
-
State-of-the-art (SOTA) training scripts.
-
InsightFace 易于优化。我们可以在不保留重量级 DL 框架的情况下部署它。
-
它提供了精心设计的 API,极大地降低了实现的复杂性。
-
定义你自己的模型的构建模块。
我们可以使用 pip 安装 InsightFace 如下 −
pip install --upgrade insightface
请注意,在安装 InsightFace 之前,请根据您的系统配置安装正确的 MXNet 软件包。
Keras-MXNet
众所周知,Keras 是用 Python 编写的用于神经网络(NN)的高级 API,Keras-MXNet 为 Keras 提供后端支持。它可以在高性能和可扩展的 Apache MXNet DL 框架之上运行。
Keras-MXNet 的功能如下所述 −
-
允许用户轻松、平稳、快速地进行原型设计。这一切都是通过用户友好性、模块化和可扩展性实现的。
-
支持 CNN(卷积神经网络)和 RNN(循环神经网络)以及两者的组合。
-
在中央处理器(CPU)和图形处理器(GPU)上均能完美运行。
-
可以在一个或多个 GPU 上运行。
为了使用此后端,您首先需要按如下方式安装 keras-mxnet −
pip install keras-mxnet
现在,如果您使用 GPU,则按以下方式安装并支持 CUDA 9 的 MXNet。
pip install mxnet-cu90
但如果您只使用 CPU,则按以下方式安装基本 MXNet。
pip install mxnet
MXBoard
MXBoard 是一个用 Python 编写的记录工具,用于记录 MXNet 数据帧并在 TensorBoard 中显示。换句话说,MXBoard 意在遵循 tensorboard-pytorch API。它支持 TensorBoard 中的大多数数据类型。
下面提到了一些数据类型:
-
Graph
-
Scalar
-
Histogram
-
Embedding
-
Image
-
Text
-
Audio
-
Precision-Recall Curve
MXFusion
MXFusion 是一个模块化概率编程库,具有深度学习功能。MXFusion 允许我们充分利用模块化,这是概率编程库的一个关键特性。它易于使用,并为用户提供了一个便捷的界面,用于设计概率模型并将其应用于实际问题。
MXFusion 已在 Python 版本 3.4 及更高版本、MacOS 和 Linux 操作系统上验证。为了安装 MXFusion,我们首先需要安装以下依赖项:
-
MXNet >= 1.3
-
Networkx >= 2.1
借助以下 pip 命令,您可以安装 MXFusion:
pip install mxfusion
TVM
Apache TVM,一个面向 CPU、GPU 和专用加速器等硬件后端的开源端到端深度学习编译堆栈,旨在填补以生产力为中心的深度学习框架与以性能为导向的硬件后端之间的差距。随着最新的 MXNet 1.6.0 版本,用户可以利用 Apache(孵化中)TVM 用 Python 编程语言实现高性能算子内核。
Apache TVM 最初实际上是华盛顿大学 Paul G. Allen 计算机科学与工程学院 SAMPL 小组的一个研究项目,现在它正在 Apache 软件基金会(ASF)孵化,由一个 OSC(开源社区)推动,该社区涉及多个行业以及 Apache 方式下的学术机构。
以下是 Apache(孵化中)TVM 的主要特性:
-
简化了以往基于 C++ 的开发流程。
-
允许跨多个硬件后端(如 CPU、GPU 等)共享相同实现。
-
TVM 提供了各种框架(如 Kears、MXNet、PyTorch、Tensorflow、CoreML、DarkNet)中的 DL 模型编译,使其在不同的硬件后端上成为最小的可部署模块。
-
它还为我们提供了基础架构,用于自动生成和优化具有更好性能的张量算子。
XFer
Xfer,一个迁移学习框架,是用 Python 编写的。它基本上采用 MXNet 模型,并且也训练元模型或修改模型以适应新的目标数据集。
简单来说,Xfer 是一个 Python 库,允许用户快速轻松地传输存储在 DNN(深度神经网络)中的知识。
Xfer 可用于:
-
对任意数字格式的数据进行分类。
-
对图像或文本数据的常见情况进行分类。
-
作为一条管道,从提取特征扩展到训练转换器(在目标任务中执行分类的对象)。
下面是 Xfer 的功能:
-
Resource efficiency
-
Data efficiency
-
轻松访问神经网络
-
Uncertainty modeling
-
Rapid prototyping
-
从 NN 提取特征的实用工具
Apache MXNet - System Architecture
本章节将帮助您了解 MXNet 系统架构。让我们从学习 MXNet 模块开始。
MXNet Modules
下图是 MXNet 系统架构图,它显示了 MXNet modules and their interaction 的主要模块和组件。
在上图中 −
-
蓝色盒子中的模块是 User Facing Modules 。
-
绿色盒子中的模块是 System Modules 。
-
实线箭头表示高度依赖性,即极大地依赖接口。
-
虚线箭头表示弱依赖性,即为方便和接口一致性而使用的数据结构。事实上,它可以被备选项替换。
让我们进一步讨论面向用户和系统模块。
Apache MXNet - System Components
此处详细介绍了 Apache MXNet 中的系统组件。首先,我们将研究 MXNet 中的执行引擎。
Execution Engine
Apache MXNet 的执行引擎非常通用。它可以用深度学习或任何特定领域问题:执行一些函数,同时遵循这些函数的依赖关系。它的设计方式使依赖函数序列化,而没有依赖关系的函数可以并行执行。
Core Interface
下面给出的 API 是 Apache MXNet 执行引擎的核心接口:
virtual void PushSync(Fn exec_fun, Context exec_ctx,
std::vector<VarHandle> const& const_vars,
std::vector<VarHandle> const& mutate_vars) = 0;
以上 API 具有以下内容:
-
exec_fun −MXNet 的核心接口 API 允许我们会同其上下文信息和依赖关系将名为 exec_fun 的函数推送到执行引擎。
-
exec_ctx −所述函数 exec_fun 应在其中执行的上下文信息。
-
const_vars −这些是函数读取的变量。
-
mutate_vars −这些是将修改的变量。
执行引擎向其用户保证以按顺序推入的方式对修改通用变量的两个函数的执行进行序列化。
Function
以下为 Apache MXNet 执行引擎的函数类型:
using Fn = std::function<void(RunContext)>;
在上述函数中, RunContext 包含运行时信息。运行时信息应由执行引擎来确定。 RunContext 的句法如下:
struct RunContext {
// stream pointer which could be safely cast to
// cudaStream_t* type
void *stream;
};
以下列出有关执行引擎函数的一些重要提示:
-
所有函数均由 MXNet 执行引擎的内部线程执行。
-
最好不要将阻塞函数推送到执行引擎,因为那样函数将占据执行线程,并且还会降低总吞吐率。
为此,MXNet 提供了另一个异步函数,如下所示:
using Callback = std::function<void()>;
using AsyncFn = std::function<void(RunContext, Callback)>;
-
在这个 AsyncFn 函数中,我们可以传递线程的繁重部分,但是直到调用 callback 函数,执行引擎才认为该函数已完成。
Context
在 Context 中,我们可以指定在其中执行函数的上下文。这通常包括以下内容:
-
函数应在 CPU 还是 GPU 上运行。
-
如果我们在上下文中指定 GPU,则指定使用哪个 GPU。
-
Context 和 RunContext 之间有很大区别。Context 具有设备类型和设备 ID,而 RunContext 具有只能在运行时确定的信息。
VarHandle
用于指定函数依赖关系的 VarHandle 就像一个标记(特别是由执行引擎提供的),它可用于表示函数可以修改或使用的外部资源。
但出现了问题,为什么我们需要使用 VarHandle?这是因为,Apache MXNet 引擎被设计为与其他 MXNet 模块分离。
以下是有关 VarHandle 的一些重要要点:
-
它很轻量,因此创建、删除或复制变量几乎不需要操作成本。
-
我们需要指定不可变变量,即将在 const_vars 中使用的变量。
-
我们需要指定可变变量,即将在 mutate_vars 中修改的变量。
-
执行引擎用来解析函数之间依赖关系的规则是,当其中一个函数修改至少一个公共变量时,对这两个函数的执行按其推送顺序进行序列化。
-
对于创建新变量,我们可以使用 NewVar() API。
-
对于删除变量,我们可以使用 PushDelete API。
让我们通过一个简单的示例了解它的工作原理:
假设我们有两个函数,分别称为 F1 和 F2,并且它们都更改了变量 V2。在这种情况下,如果 F2 在 F1 之后被推送,则保证 F2 在 F1 之后执行。另一方面,如果 F1 和 F2 都使用 V2,则它们实际的执行顺序可能是随机的。
Push and Wait
Push 和 wait 是执行引擎中另外两个有用的 API。
以下是 Push API 的两个重要特性:
-
所有推送 API 都是异步的,这意味着无论所推送的函数是否已完成,API 调用都会立即返回。
-
推送 API 不是线程安全的,这意味着一次只能有一个线程进行引擎 API 调用。
现在如果我们讨论 Wait API,以下几点代表它 −
-
如果用户想等待一个特定的函数完成,他/她应该在闭包中包含一个回调函数。包含之后,在函数的末尾调用函数。
-
另一方面,如果用户想等待涉及某个变量的所有函数完成,他/她应该使用 WaitForVar(var) API。
-
如果某人想等待所有推入的函数完成,那么使用 WaitForAll () API。
-
用于指定函数的依赖项,就像一个令牌。
Operator Interface
Forward 是核心运算符接口,其语法如下:
virtual void Forward(const OpContext &ctx,
const std::vector<TBlob> &in_data,
const std::vector<OpReqType> &req,
const std::vector<TBlob> &out_data,
const std::vector<TBlob> &aux_states) = 0;
定义在 Forward() 中的 OpContext 的结构如下:
struct OpContext {
int is_train;
RunContext run_ctx;
std::vector<Resource> requested;
}
OpContext 描述了运算符的状态(是否在训练或测试阶段),运算符应该在哪个设备上运行,以及请求的资源。执行引擎的两个更有用的 API。
从上述 Forward 的核心接口,我们可以理解请求的资源如下 −
-
in_data 和 out_data 代表输入和输出张量。
-
req 表示如何将计算的结果写入到 out_data 中。
OpReqType 可以定义为 −
enum OpReqType {
kNullOp,
kWriteTo,
kWriteInplace,
kAddTo
};
就像 Forward 运算符一样,我们可以选择实现 Backward 接口,如下所示:
virtual void Backward(const OpContext &ctx,
const std::vector<TBlob> &out_grad,
const std::vector<TBlob> &in_data,
const std::vector<TBlob> &out_data,
const std::vector<OpReqType> &req,
const std::vector<TBlob> &in_grad,
const std::vector<TBlob> &aux_states);
Various tasks
Operator 接口允许用户执行以下任务 −
-
用户可以指定就地更新并可以减少内存分配成本
-
为了使其更简洁,用户可以从 Python 中隐藏一些内部参数。
-
用户可以定义张量和输出张量之间的关系。
-
为了执行计算,用户可以从系统获取额外的临时空间。
Operator Property
我们知道在卷积神经网络 (CNN) 中,一个卷积有多种实现。为了从中获得最佳性能,我们可能希望在这些卷积之中进行切换。
这就是 Apache MXNet 将算子语义接口从实现接口中分离出来的原因。此分离以以下形式完成: OperatorProperty 类,它包含以下内容:−
InferShape - InferShape 接口有两个目的,如下所示:
-
第一个目的是告诉系统每个输入和输出张量的尺寸,以便可以在 Forward 和 Backward 调用之前分配空间。
-
第二个目的是执行大小检查,以确保在运行之前不存在错误。
语法如下所示:−
virtual bool InferShape(mxnet::ShapeVector *in_shape,
mxnet::ShapeVector *out_shape,
mxnet::ShapeVector *aux_shape) const = 0;
Request Resource - 如果您的系统可以管理像 cudnnConvolutionForward 这样的操作的计算工作空间会怎么样?您的系统可以执行优化,例如重用空间和更多内容。在这里,MXNet 在以下两个接口的帮助下轻松实现了这一点−
virtual std::vector<ResourceRequest> ForwardResource(
const mxnet::ShapeVector &in_shape) const;
virtual std::vector<ResourceRequest> BackwardResource(
const mxnet::ShapeVector &in_shape) const;
但是,如果 ForwardResource 和 BackwardResource 返回非空数组会怎么样?在这种情况下,系统通过 Forward 和 Backward 接口的 ctx 参数提供相应的资源 Operator 。
Backward dependency - Apache MXNet 具有以下两个不同的运算符签名来处理向后依赖:
void FullyConnectedForward(TBlob weight, TBlob in_data, TBlob out_data);
void FullyConnectedBackward(TBlob weight, TBlob in_data, TBlob out_grad, TBlob in_grad);
void PoolingForward(TBlob in_data, TBlob out_data);
void PoolingBackward(TBlob in_data, TBlob out_data, TBlob out_grad, TBlob in_grad);
在这里,需要注意的两个重要点:
-
FullyConnectedForward 中的 out_data 不被 FullyConnectedBackward 使用,
-
PoolingBackward 需要 PoolingForward 的所有参数。
这就是为什么对于 FullyConnectedForward 来说,一旦消耗了 out_data 张量,就可以安全地释放它,因为后向函数不需要它。在此系统的帮助下,可以尽早收集一些张量作为垃圾。
In place Option - Apache MXNet 为用户提供了另一个接口来节省内存分配的成本。此接口适用于输入和输出张量具有相同形状的逐元素运算。
以下是指定就地更新的语法:
Example for Creating an Operator
借助 OperatorProperty,我们可以创建一个运算符。为此,请执行以下步骤:
virtual std::vector<std::pair<int, void*>> ElewiseOpProperty::ForwardInplaceOption(
const std::vector<int> &in_data,
const std::vector<void*> &out_data)
const {
return { {in_data[0], out_data[0]} };
}
virtual std::vector<std::pair<int, void*>> ElewiseOpProperty::BackwardInplaceOption(
const std::vector<int> &out_grad,
const std::vector<int> &in_data,
const std::vector<int> &out_data,
const std::vector<void*> &in_grad)
const {
return { {out_grad[0], in_grad[0]} }
}
Step 1
Create Operator
首先在 OperatorProperty 中实现以下接口:
virtual Operator* CreateOperator(Context ctx) const = 0;
示例如下:
class ConvolutionOp {
public:
void Forward( ... ) { ... }
void Backward( ... ) { ... }
};
class ConvolutionOpProperty : public OperatorProperty {
public:
Operator* CreateOperator(Context ctx) const {
return new ConvolutionOp;
}
};
Step 2
Parameterize Operator
如果你要实施一个卷积运算符,必须知道核大小、步幅大小、填充大小等。因为在调用任何 Forward 或 backward 接口之前,应将这些参数传递给运算符。
为此,我们需要定义一个 ConvolutionParam 结构,如下所示 −
#include <dmlc/parameter.h>
struct ConvolutionParam : public dmlc::Parameter<ConvolutionParam> {
mxnet::TShape kernel, stride, pad;
uint32_t num_filter, num_group, workspace;
bool no_bias;
};
现在,我们需要将其放入 ConvolutionOpProperty 中,并按照以下方式将其传递给运算符 −
class ConvolutionOp {
public:
ConvolutionOp(ConvolutionParam p): param_(p) {}
void Forward( ... ) { ... }
void Backward( ... ) { ... }
private:
ConvolutionParam param_;
};
class ConvolutionOpProperty : public OperatorProperty {
public:
void Init(const vector<pair<string, string>& kwargs) {
// initialize param_ using kwargs
}
Operator* CreateOperator(Context ctx) const {
return new ConvolutionOp(param_);
}
private:
ConvolutionParam param_;
};
Apache MXNet - Unified Operator API
本章提供有关 Apache MXNet 中统一运算符应用程序编程界面 (API) 的信息。
SimpleOp
SimpleOp 是一种新的统一运算符 API,可统一不同的调用进程。调用后,它返回到运算符的基本元素。统一运算符专门设计用于一元以及二元运算。这是因为大多数数学运算符都应用于一个或两个操作数,并且更多操作数使与依赖项相关的优化变得有用。
我们将使用一个示例了解其 SimpleOp 统一运算符的工作原理。在此示例中,我们将创建一个充当混合损失的 l1 和 l2 损失 smooth l1 loss 的运算符。我们可以按如下所示定义和编写损失 −
loss = outside_weight .* f(inside_weight .* (data - label))
grad = outside_weight .* inside_weight .* f'(inside_weight .* (data - label))
在此,在上述示例中,
-
.* stands for element-wise multiplication
-
f, f’ 是我们假设在 mshadow 中的光滑 l1 损失函数。
将此特定损失实现为一元或二元运算符似乎是不可能的,但 MXNet 为其用户提供符号执行中的自动微分,这将损失直接简化为 f 和 f’。因此,我们当然可以将此特定损失实现为一元运算符。
Defining Shapes
众所周知,MXNet 的 mshadow library 要求显式内存分配,因此我们需要在进行任何计算之前提供所有数据形状。在定义函数和梯度之前,我们需要提供输入形状一致性并输出形状,如下所示:
typedef mxnet::TShape (*UnaryShapeFunction)(const mxnet::TShape& src,
const EnvArguments& env);
typedef mxnet::TShape (*BinaryShapeFunction)(const mxnet::TShape& lhs,
const mxnet::TShape& rhs,
const EnvArguments& env);
函数 mxnet::Tshape 用于检查输入数据形状并指定输出数据形状。如果没有定义此函数,则默认输出形状将与输入形状相同。例如,对于二元运算符,lhs 和 rhs 的形状默认情况下被检查为相同。
现在转向 smooth l1 loss example. 为此,我们需要在头实现 smooth_l1_unary-inl.h. 中为 XPU 定义一个 XPU 到 cpu 或 gpu。原因是在 smooth_l1_unary.cc 和 smooth_l1_unary.cu. 中重复使用相同的代码。
#include <mxnet/operator_util.h>
#if defined(__CUDACC__)
#define XPU gpu
#else
#define XPU cpu
#endif
由于在我们的 smooth l1 loss example, 中输出与源形状相同,因此我们可以使用默认行为。可以写成如下形式 −
inline mxnet::TShape SmoothL1Shape_(const mxnet::TShape& src,const EnvArguments& env) {
return mxnet::TShape(src);
}
Defining Functions
我们可以使用一个输入创建一元或二元函数,如下所示 −
typedef void (*UnaryFunction)(const TBlob& src,
const EnvArguments& env,
TBlob* ret,
OpReqType req,
RunContext ctx);
typedef void (*BinaryFunction)(const TBlob& lhs,
const TBlob& rhs,
const EnvArguments& env,
TBlob* ret,
OpReqType req,
RunContext ctx);
以下是包含运行时执行所需信息的 RunContext ctx struct −
struct RunContext {
void *stream; // the stream of the device, can be NULL or Stream<gpu>* in GPU mode
template<typename xpu> inline mshadow::Stream<xpu>* get_stream() // get mshadow stream from Context
} // namespace mxnet
现在,让我们看看如何在 ret 中编写计算结果。
enum OpReqType {
kNullOp, // no operation, do not write anything
kWriteTo, // write gradient to provided space
kWriteInplace, // perform an in-place write
kAddTo // add to the provided space
};
现在,让我们继续我们的 smooth l1 loss example 。为此,我们将使用 UnaryFunction 来定义此运算符的功能,如下所示:
template<typename xpu>
void SmoothL1Forward_(const TBlob& src,
const EnvArguments& env,
TBlob *ret,
OpReqType req,
RunContext ctx) {
using namespace mshadow;
using namespace mshadow::expr;
mshadow::Stream<xpu> *s = ctx.get_stream<xpu>();
real_t sigma2 = env.scalar * env.scalar;
MSHADOW_TYPE_SWITCH(ret->type_flag_, DType, {
mshadow::Tensor<xpu, 2, DType> out = ret->get<xpu, 2, DType>(s);
mshadow::Tensor<xpu, 2, DType> in = src.get<xpu, 2, DType>(s);
ASSIGN_DISPATCH(out, req,
F<mshadow_op::smooth_l1_loss>(in, ScalarExp<DType>(sigma2)));
});
}
Defining Gradients
除了 Input, TBlob, 和 OpReqType 加倍,二元运算符的梯度函数具有相似的结构。让我们在下面查看,我们在其中创建了具有各种类型输入的梯度函数:
// depending only on out_grad
typedef void (*UnaryGradFunctionT0)(const OutputGrad& out_grad,
const EnvArguments& env,
TBlob* in_grad,
OpReqType req,
RunContext ctx);
// depending only on out_value
typedef void (*UnaryGradFunctionT1)(const OutputGrad& out_grad,
const OutputValue& out_value,
const EnvArguments& env,
TBlob* in_grad,
OpReqType req,
RunContext ctx);
// depending only on in_data
typedef void (*UnaryGradFunctionT2)(const OutputGrad& out_grad,
const Input0& in_data0,
const EnvArguments& env,
TBlob* in_grad,
OpReqType req,
RunContext ctx);
如上所述 Input0, Input, OutputValue, 和 OutputGrad *all share the structure of *GradientFunctionArgument. 定义如下 −
struct GradFunctionArgument {
TBlob data;
}
现在让我们继续我们的 smooth l1 loss example 。为了启用梯度的链式法则,我们需要将 out_grad 从上乘到 in_grad 的结果。
template<typename xpu>
void SmoothL1BackwardUseIn_(const OutputGrad& out_grad, const Input0& in_data0,
const EnvArguments& env,
TBlob *in_grad,
OpReqType req,
RunContext ctx) {
using namespace mshadow;
using namespace mshadow::expr;
mshadow::Stream<xpu> *s = ctx.get_stream<xpu>();
real_t sigma2 = env.scalar * env.scalar;
MSHADOW_TYPE_SWITCH(in_grad->type_flag_, DType, {
mshadow::Tensor<xpu, 2, DType> src = in_data0.data.get<xpu, 2, DType>(s);
mshadow::Tensor<xpu, 2, DType> ograd = out_grad.data.get<xpu, 2, DType>(s);
mshadow::Tensor<xpu, 2, DType> igrad = in_grad->get<xpu, 2, DType>(s);
ASSIGN_DISPATCH(igrad, req,
ograd * F<mshadow_op::smooth_l1_gradient>(src, ScalarExp<DType>(sigma2)));
});
}
Register SimpleOp to MXNet
一旦我们创建了形状、函数和梯度,我们就需要将它们还原为 NDArray 运算符和符号运算符。为此,我们可以使用如下所示的注册宏:
MXNET_REGISTER_SIMPLE_OP(Name, DEV)
.set_shape_function(Shape)
.set_function(DEV::kDevMask, Function<XPU>, SimpleOpInplaceOption)
.set_gradient(DEV::kDevMask, Gradient<XPU>, SimpleOpInplaceOption)
.describe("description");
SimpleOpInplaceOption 可以定义如下 −
enum SimpleOpInplaceOption {
kNoInplace, // do not allow inplace in arguments
kInplaceInOut, // allow inplace in with out (unary)
kInplaceOutIn, // allow inplace out_grad with in_grad (unary)
kInplaceLhsOut, // allow inplace left operand with out (binary)
kInplaceOutLhs // allow inplace out_grad with lhs_grad (binary)
};
现在让我们继续我们的 smooth l1 loss example 。为此,我们有一个依赖于输入数据的梯度函数,因此无法在原地编写该函数。
MXNET_REGISTER_SIMPLE_OP(smooth_l1, XPU)
.set_function(XPU::kDevMask, SmoothL1Forward_<XPU>, kNoInplace)
.set_gradient(XPU::kDevMask, SmoothL1BackwardUseIn_<XPU>, kInplaceOutIn)
.set_enable_scalar(true)
.describe("Calculate Smooth L1 Loss(lhs, scalar)");
SimpleOp on EnvArguments
正如我们所知,某些操作可能需要以下功能 −
-
标量作为输入,例如梯度尺度
-
控制行为的一组关键词参数
-
一个临时空间以加快计算速度。
使用 EnvArguments 的好处是它提供了额外的参数和资源,使计算更具可扩展性和效率。
Example
首先让我们定义以下结构:
struct EnvArguments {
real_t scalar; // scalar argument, if enabled
std::vector<std::pair<std::string, std::string> > kwargs; // keyword arguments
std::vector<Resource> resource; // pointer to the resources requested
};
接下来,我们需要从 EnvArguments.resource. 中请求额外的资源(如 mshadow::Random<xpu> )和临时内存空间。可以如下所示完成:
struct ResourceRequest {
enum Type { // Resource type, indicating what the pointer type is
kRandom, // mshadow::Random<xpu> object
kTempSpace // A dynamic temp space that can be arbitrary size
};
Type type; // type of resources
};
现在,注册将从 mxnet::ResourceManager. 请求已声明的资源请求。之后,它将把资源放在 std::vector<Resource> resource in EnvAgruments. 中
我们可以借助以下代码访问资源 −
auto tmp_space_res = env.resources[0].get_space(some_shape, some_stream);
auto rand_res = env.resources[0].get_random(some_stream);
如果您在我们的平滑 l1 损失示例中看到,需要一个标量输入来标记损失函数的转折点。这就是为什么在注册过程中,我们在函数和梯度声明中使用 set_enable_scalar(true) 和 env.scalar 。
Building Tensor Operation
在这里提出了一个问题,为什么我们需要构建张量运算?原因如下−
-
计算利用 mshadow 库,并且我们有时没有现成可用的函数。
-
如果运算不是以逐元素的方式完成,例如 softmax 损失和梯度。
Example
在这里,我们使用上述的平滑 l1 损失示例。我们将创建两个映射器,即平滑 l1 损失和梯度的标量案例:
namespace mshadow_op {
struct smooth_l1_loss {
// a is x, b is sigma2
MSHADOW_XINLINE static real_t Map(real_t a, real_t b) {
if (a > 1.0f / b) {
return a - 0.5f / b;
} else if (a < -1.0f / b) {
return -a - 0.5f / b;
} else {
return 0.5f * a * a * b;
}
}
};
}
Apache MXNet - Distributed Training
本章是关于 Apache MXNet 中的分布式训练。让我们首先了解 MXNet 中的计算模式。
Modes of Computation
MXNet,一个多语言 ML 库,为其用户提供了以下两种计算模式−
Imperative mode
这种计算模式公开了像 NumPy API 这样的接口。例如,在 MXNet 中,使用以下命令式代码在 CPU 和 GPU 上构建一个零张量 −
import mxnet as mx
tensor_cpu = mx.nd.zeros((100,), ctx=mx.cpu())
tensor_gpu= mx.nd.zeros((100,), ctx=mx.gpu(0))
正如我们在上面的代码中看到的,MXNets 指定了保存张量的位置,可以在 CPU 或 GPU 设备中。在上面的示例中,它位于位置 0。MXNet 可以令人难以置信地利用设备,因为所有计算都是延迟发生的,而不是瞬间发生的。
Kinds of Parallelism
Apache MXNet 支持分布式训练。它使我们能够利用多台机器进行更快速、更有效率的训练。
以下是我们可以在多个设备(CPU 或 GPU 设备)上分配神经网络训练工作负载的两种方式−
Working of distributed training
以下给出的概念是理解 Apache MXNet 中分布式训练工作原理的关键−
Scheduler
调度程序的作用是设置集群,其中包括等待每台节点启动的消息以及该节点正在监听的端口。在设置集群后,调度程序让所有进程了解集群中的其他所有节点。这是因为进程可以相互通信。只有一个调度程序。
KV Store
KV 存储代表 Key-Value 存储。它是用于多设备训练的关键组件。它很重要,因为单一计算机和多台计算机跨设备的参数通信可以通过具有 KVStore 的一个或多个服务器传输参数。让我们借助以下要点了解 KVStore 的工作原理 −
-
KVStore 中的每个值都由 key 和 value 表示。
-
网络中的每个参数数组都被分配一个 key ,并且该参数数组的权重由 value 引用。
-
然后,工作节点在处理一个批次后 push 梯度。在处理一个新批次之前,它们还 pull 更新权重。
KVStore 服务器的概念仅在分布式训练期间存在,其分布式模式可以通过使用包含字符串 dist 的字符串参数 mxnet.kvstore.create 函数来启用
kv = mxnet.kvstore.create(‘dist_sync’)
Distribution of Keys
并非所有服务器都存储所有参数数组或键是必要的,但它们分布在不同的服务器上。键在不同服务器上的这种分布由 KVStore 透明处理,并且哪个服务器存储特定键的决定是随机做出的。
如上所述,KVStore 确保每当拉取密钥时,都会将请求发送到具有相应值的服务器。如果某个键的值很大怎么办?在这种情况下,它可以在不同的服务器之间共享。
Split training data
作为用户,我们希望每台机器都能处理数据集的不同部分,特别是当在数据并行模式下运行分布式训练时。我们知道,为了将数据迭代器提供的样本块拆分为用于在单个工作器上进行数据并行训练,我们可以使用 mxnet.gluon.utils.split_and_load ,然后将块的各个部分加载到将进一步处理它的设备上。
另一方面,在分布式训练的情况下,在开始时我们需要将数据集分为 n 不同的部分,以便每个工作器得到一个不同的部分。一旦得到,每个工作器都可以使用 split_and_load 再次将数据集的部分在单个计算机上的不同设备上进行划分。所有这些都通过数据迭代器发生。 mxnet.io.MNISTIterator 和 mxnet.io.ImageRecordIter 是 MXNet 中支持此功能的两个此类迭代器。
Weights updating
对于更新权重,KVStore 支持以下两种模式 −
-
第一种方法聚合梯度并使用这些梯度更新权重。
-
在第二种方法中,服务器仅聚合梯度。
如果你正在使用 Gluon,可以通过传递 update_on_kvstore 变量在上述方法之间进行选择。我们通过如下创建 trainer 对象来理解它 −
trainer = gluon.Trainer(net.collect_params(), optimizer='sgd',
optimizer_params={'learning_rate': opt.lr,
'wd': opt.wd,
'momentum': opt.momentum,
'multi_precision': True},
kvstore=kv,
update_on_kvstore=True)
Modes of Distributed Training
如果 KVStore 创建字符串包含单词 dist,则表示已启用分布式训练。以下是可以通过使用不同类型的 KVStore 启用的不同分布式训练模式 −
dist_sync
顾名思义,它表示同步分布式训练。在此当中,所有工作器在每一批次的开始时使用相同的同步模型参数集。
此模式的缺点是,在每个批次之后,服务器必须等待接收来自每个工作器的梯度,然后再更新模型参数。这意味着如果一个工作器崩溃,它将停止所有工作器的进度。
dist_async
顾名思义,它表示同步分布式训练。在此当中,服务器接收来自一个工作器的梯度并立即更新其存储。服务器使用更新的存储来响应任何进一步的拉取。
与 dist_sync mode 相比,它的优点在于完成一批次处理的工作器可以从服务器拉取当前参数并开始下一批次。即使其他工作器尚未完成对前一批次的处理,工作器也可以这样做。它也比 dist_sync 模式快,因为它可以花费更多的时间进行收敛而无需任何同步成本。
Apache MXNet - Python Packages
在本章中,我们将了解 Apache MXNet 中可用的 Python 包。
Important MXNet Python packages
MXNet 具有以下重要的 Python 包,我们将会逐个讨论 −
-
Autograd (Automatic Differentiation)
-
NDArray
-
KVStore
-
Gluon
-
Visualization
首先我们从 Apache MXNet 的 Autograd Python 包开始。
Autograd
Autograd 表示 automatic differentiation 用于将梯度从损失指标反向传播到每个参数。它在反向传播时使用动态规划方法来有效计算梯度。它也被称为反向模式自动微分化。这种技术在很多参数影响单个损失指标的「扇入」情况下非常有效。
What are gradients?
梯度是神经网络训练过程中的基础。它们基本上告诉我们如何改变网络参数以提高其性能。
众所周知,神经网络 (NN) 由加法、乘积、卷积等运算符组成。这些运算符在计算中会使用参数,例如卷积核中的权重。我们必须为这些参数找到最佳值,而梯度则向我们展示了方法并引导我们找到解决方案。
我们关注的是改变参数对网络性能的影响,梯度会告诉我们,在某个变量依赖于某个变量时,当我们改变该变量时,该变量会增加或减少多少。性能通常使用我们尝试最小化的损失指标来定义。例如,对于回归,我们可能尝试最小化我们的预测与精确值之间的 L2 损失,而对于分类,我们可能最小化 cross-entropy loss 。
一旦我们按照损失计算了每个参数的梯度,就可以使用优化器,例如随机梯度下降。
How to calculate gradients?
我们有以下选项来计算梯度 −
-
Symbolic Differentiation − 第一个选项是符号微分化,它为每个梯度计算公式。这种方法的缺点是,随着网络的加深和运算符变得更加复杂,它将迅速导致难以置信的冗长公式。
-
Finite Differencing − 另一个选项是使用有限差分法,它对每个参数尝试微小差值,并观察损失指标如何响应。这种方法的缺点是,它在计算上会很昂贵,并且可能具有较差的数值精度。
-
Automatic differentiation − 解决上述方法缺点的方案是使用自动微分化将梯度从损失指标反向传播到每个参数。传播允许我们使用动态规划方法来有效计算梯度。这种方法也被称为反向模式自动微分化。
Automatic Differentiation (autograd)
在这里,我们将详细了解 autograd 的工作原理。它基本上在以下两个阶段进行工作 −
Stage 1 − 该阶段称为训练的 ‘Forward Pass’ 。顾名思义,在此阶段它创建了网络用于预测和计算损失指标所使用运算符的记录。
Stage 2 − 该阶段称为训练的 ‘Backward Pass’ 。顾名思义,在此阶段它通过该记录向后进行工作。向后进行时,它会评估每个运算符的偏导数,一直到网络参数。
Advantages of autograd
以下是使用自动微分化 (autograd) 的优势 −
-
Flexible − 灵活是我们使用 autograd 时的一大好处,它给予我们在定义我们的网络时更大的灵活度。我们可以在每次迭代中更改运算。这些被称为动态图,在需要静态图的框架中实现它们要复杂得多。即使在这种情况 autograd 仍能够正确反向传播梯度。
-
Automatic − autograd 是自动的,即反向传播过程的复杂性由它为您处理。我们只需要指定我们有兴趣计算哪些梯度。
-
Efficient − Autogard 非常有效地计算梯度。
-
Can use native Python control flow operators − 我们可以使用原生 Python 控制流运算符,例如 if 条件和 while 循环。autograd 仍然可以有效且正确地反向传播梯度。
Using autograd in MXNet Gluon
这里,借助示例,我们将了解如何在 MXNet Gluon 中使用 autograd 。
Implementation Example
在以下示例中,我们将实现一个有两个层回归模型。实现后,我们将使用自动梯度计算损失函数关于各个权重参数的梯度 −
首先,如下导入自动梯度和其他必需的包 −
from mxnet import autograd
import mxnet as mx
from mxnet.gluon.nn import HybridSequential, Dense
from mxnet.gluon.loss import L2Loss
现在,我们需要如下定义网络 −
N_net = HybridSequential()
N_net.add(Dense(units=3))
N_net.add(Dense(units=1))
N_net.initialize()
现在我们需要如下定义损失 −
loss_function = L2Loss()
接下来,我们需要如下创建虚拟数据 −
x = mx.nd.array([[0.5, 0.9]])
y = mx.nd.array([[1.5]])
现在,我们已准备好进行首次前向网络遍历。我们希望自动梯度记录计算图,以便我们可以计算梯度。为此,我们需要在 autograd.record 上下文的范围内运行网络代码,如下所示 −
with autograd.record():
y_hat = N_net(x)
loss = loss_function(y_hat, y)
现在,我们准备进行反向遍历,首先对目标量调用反向方法。在我们示例中,目标量是损失,因为我们正尝试计算损失关于参数的梯度 −
loss.backward()
现在,对于网络的每个参数,我们都有梯度,优化器将使用这些梯度来更新参数值,以提升性能。让我们检查第一层的梯度,如下所示 −
N_net[0].weight.grad()
Output
输出如下 −
[[-0.00470527 -0.00846948]
[-0.03640365 -0.06552657]
[ 0.00800354 0.01440637]]
<NDArray 3x2 @cpu(0)>
Complete implementation example
完整实现示例如下:
from mxnet import autograd
import mxnet as mx
from mxnet.gluon.nn import HybridSequential, Dense
from mxnet.gluon.loss import L2Loss
N_net = HybridSequential()
N_net.add(Dense(units=3))
N_net.add(Dense(units=1))
N_net.initialize()
loss_function = L2Loss()
x = mx.nd.array([[0.5, 0.9]])
y = mx.nd.array([[1.5]])
with autograd.record():
y_hat = N_net(x)
loss = loss_function(y_hat, y)
loss.backward()
N_net[0].weight.grad()
Apache MXNet - NDArray
在本章中,我们将讨论 MXNet 名为 ndarray
的多维数组格式。
Handling data with NDArray
首先,我们将了解如何使用 NDArray 处理数据。以下是其先决条件 −
Implementation Example
我们借助以下示例了解基本功能 −
首先需要如下从 MXNet 导入 MXNet 和 ndrray −
import mxnet as mx
from mxnet import nd
导入必要的库后,我们将继续以下基本功能:
A simple 1-D array with a python list
Example
x = nd.array([1,2,3,4,5,6,7,8,9,10])
print(x)
Output
输出如下所述 −
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
<NDArray 10 @cpu(0)>
A 2-D array with a python list
Example
y = nd.array([[1,2,3,4,5,6,7,8,9,10], [1,2,3,4,5,6,7,8,9,10], [1,2,3,4,5,6,7,8,9,10]])
print(y)
Output
输出如下所示 −
[[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]]
<NDArray 3x10 @cpu(0)>
Creating an NDArray without any initialisation
这里,我们将使用 .empty
函数创建包含 3 行和 4 列的矩阵。我们还将使用 .full
函数,它会将其他运算符用作想要填充到数组中的值。
Example
x = nd.empty((3, 4))
print(x)
x = nd.full((3,4), 8)
print(x)
Output
输出如下 −
[[0.000e+00 0.000e+00 0.000e+00 0.000e+00]
[0.000e+00 0.000e+00 2.887e-42 0.000e+00]
[0.000e+00 0.000e+00 0.000e+00 0.000e+00]]
<NDArray 3x4 @cpu(0)>
[[8. 8. 8. 8.]
[8. 8. 8. 8.]
[8. 8. 8. 8.]]
<NDArray 3x4 @cpu(0)>
Matrix of all zeros with the .zeros function
Example
x = nd.zeros((3, 8))
print(x)
Output
输出如下 −
[[0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0.]]
<NDArray 3x8 @cpu(0)>
Matrix of all ones with the .ones function
Example
x = nd.ones((3, 8))
print(x)
Output
输出如下:
[[1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1.]]
<NDArray 3x8 @cpu(0)>
Standard Mathematical Operations
以下是 NDArray 支持的标准数学运算 −
Element-wise addition
首先需要如下从 MXNet 导入 MXNet 和 ndrray:
import mxnet as mx
from mxnet import nd
x = nd.ones((3, 5))
y = nd.random_normal(0, 1, shape=(3, 5))
print('x=', x)
print('y=', y)
x = x + y
print('x = x + y, x=', x)
Output
输出与此一同给出 −
x=
[[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]]
<NDArray 3x5 @cpu(0)>
y=
[[-1.0554522 -1.3118273 -0.14674698 0.641493 -0.73820823]
[ 2.031364 0.5932667 0.10228804 1.179526 -0.5444829 ]
[-0.34249446 1.1086396 1.2756858 -1.8332436 -0.5289873 ]]
<NDArray 3x5 @cpu(0)>
x = x + y, x=
[[-0.05545223 -0.3118273 0.853253 1.6414931 0.26179177]
[ 3.031364 1.5932667 1.102288 2.1795259 0.4555171 ]
[ 0.6575055 2.1086397 2.2756858 -0.8332436 0.4710127 ]]
<NDArray 3x5 @cpu(0)>
Element-wise multiplication
Example
x = nd.array([1, 2, 3, 4])
y = nd.array([2, 2, 2, 1])
x * y
Output
您将看到以下输出−
[2. 4. 6. 4.]
<NDArray 4 @cpu(0)>
In-place Operations
在上述示例中,每次我们运行一项操作时,我们都会分配一个新内存来承载其结果。
例如,如果我们编写 A = A+B,我们将解除引用 A 用于指向的矩阵,而将其指向新分配的内存。让我们借助 Python 的 id() 函数使用下面给出的示例来理解它−
print('y=', y)
print('id(y):', id(y))
y = y + x
print('after y=y+x, y=', y)
print('id(y):', id(y))
Output
执行后,您将收到以下输出:
y=
[2. 2. 2. 1.]
<NDArray 4 @cpu(0)>
id(y): 2438905634376
after y=y+x, y=
[3. 4. 5. 5.]
<NDArray 4 @cpu(0)>
id(y): 2438905685664
事实上,我们还可以将结果分配给以前分配的数组,如下所示−
print('x=', x)
z = nd.zeros_like(x)
print('z is zeros_like x, z=', z)
print('id(z):', id(z))
print('y=', y)
z[:] = x + y
print('z[:] = x + y, z=', z)
print('id(z) is the same as before:', id(z))
Output
输出如下所示−
x=
[1. 2. 3. 4.]
<NDArray 4 @cpu(0)>
z is zeros_like x, z=
[0. 0. 0. 0.]
<NDArray 4 @cpu(0)>
id(z): 2438905790760
y=
[3. 4. 5. 5.]
<NDArray 4 @cpu(0)>
z[:] = x + y, z=
[4. 6. 8. 9.]
<NDArray 4 @cpu(0)>
id(z) is the same as before: 2438905790760
从上述输出中,我们可以看到 x+y 仍会分配一个临时缓冲区来存储结果,然后再将其复制到 z。所以现在,我们可以就地执行操作,从而更好地利用内存并避免临时缓冲区。为此,我们将按如下方式指定所有运算符支持的 out 关键字参数−
print('x=', x, 'is in id(x):', id(x))
print('y=', y, 'is in id(y):', id(y))
print('z=', z, 'is in id(z):', id(z))
nd.elemwise_add(x, y, out=z)
print('after nd.elemwise_add(x, y, out=z), x=', x, 'is in id(x):', id(x))
print('after nd.elemwise_add(x, y, out=z), y=', y, 'is in id(y):', id(y))
print('after nd.elemwise_add(x, y, out=z), z=', z, 'is in id(z):', id(z))
Output
在执行上述程序后,您将获得以下结果−
x=
[1. 2. 3. 4.]
<NDArray 4 @cpu(0)> is in id(x): 2438905791152
y=
[3. 4. 5. 5.]
<NDArray 4 @cpu(0)> is in id(y): 2438905685664
z=
[4. 6. 8. 9.]
<NDArray 4 @cpu(0)> is in id(z): 2438905790760
after nd.elemwise_add(x, y, out=z), x=
[1. 2. 3. 4.]
<NDArray 4 @cpu(0)> is in id(x): 2438905791152
after nd.elemwise_add(x, y, out=z), y=
[3. 4. 5. 5.]
<NDArray 4 @cpu(0)> is in id(y): 2438905685664
after nd.elemwise_add(x, y, out=z), z=
[4. 6. 8. 9.]
<NDArray 4 @cpu(0)> is in id(z): 2438905790760
NDArray Contexts
在 Apache MXNet 中,每个数组都有一个上下文,一个上下文可能是 CPU,而其他上下文可能是多个 GPU。当我们在多台服务器上部署工作时,情况甚至会变得更糟。这就是我们为什么需要智能地将数组分配给上下文的。它将最大程度地减少在设备间传输数据所花费的时间。
例如,尝试按如下方式初始化一个数组−
from mxnet import nd
z = nd.ones(shape=(3,3), ctx=mx.cpu(0))
print(z)
Output
执行以上代码时,应该看到以下输出 −
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]]
<NDArray 3x3 @cpu(0)>
我们可以使用 copyto() 方法将给定的 NDArray 从一个上下文复制到另一个上下文,如下所示−
x_gpu = x.copyto(gpu(0))
print(x_gpu)
NumPy array vs. NDArray
我们都熟悉 NumPy 数组,但 Apache MXNet 提供了自己的名为 NDArray 的数组实现。实际上,它最初被设计为类似于 NumPy,但有一个关键区别−
关键区别在于在 NumPy 和 NDArray 中执行计算的方式。在 MXNet 中执行的每个 NDArray 操作都是异步且非阻塞的,这意味着当我们编写 c = a * b 这样的代码时,该函数将被推送到 Execution Engine ,它将启动计算。
这里,a 和 b 都是 NDArrays。使用它的好处是,该函数立即返回,并且用户线程可以继续执行,尽管前面提到的计算可能尚未完成。
Converting NDArray to NumPy Array
让我们了解如何在 MXNet 中将 NDArray 转换为 NumPy 数组。
Combining higher-level operator with the help of few lower-level operators
有时,我们可以通过使用现有运算符来组装高级别的运算符。 np.full_like() 运算符就是其中的一个最佳示例,该运算符在 NDArray API 中不存在。它可以轻松地替换为现有运算符的组合,如下所示:
from mxnet import nd
import numpy as np
np_x = np.full_like(a=np.arange(7, dtype=int), fill_value=15)
nd_x = nd.ones(shape=(7,)) * 15
np.array_equal(np_x, nd_x.asnumpy())
Output
我们将获得如下所示的输出:
True
Finding similar operator with different name and/or signature
在所有运算符中,有些运算符的名称略有不同,但在功能方面它们是相似的。 nd.ravel_index() 带 np.ravel() 函数就是一个示例。同样,某些运算符的名称可能相似,但它们的签名不同。 np.split() 和 nd.split() 是一个示例,它们是相似的。
让我们通过以下编程示例来理解它:
def pad_array123(data, max_length):
data_expanded = data.reshape(1, 1, 1, data.shape[0])
data_padded = nd.pad(data_expanded,
mode='constant',
pad_width=[0, 0, 0, 0, 0, 0, 0, max_length - data.shape[0]],
constant_value=0)
data_reshaped_back = data_padded.reshape(max_length)
return data_reshaped_back
pad_array123(nd.array([1, 2, 3]), max_length=10)
Output
输出如下 −
[1. 2. 3. 0. 0. 0. 0. 0. 0. 0.]
<NDArray 10 @cpu(0)>
Minimising impact of blocking calls
在某些情况下,我们必须使用 .asnumpy() 或 .asscalar() 方法,但这将强制 MXNet 阻塞执行,直到可以检索结果。我们可以通过在某些时刻调用 .asnumpy() 或 .asscalar() 方法来最大程度地减少阻塞调用的影响,我们认为此时已经完成了该值的计算。
Implementation Example
Example
from __future__ import print_function
import mxnet as mx
from mxnet import gluon, nd, autograd
from mxnet.ndarray import NDArray
from mxnet.gluon import HybridBlock
import numpy as np
class LossBuffer(object):
"""
Simple buffer for storing loss value
"""
def __init__(self):
self._loss = None
def new_loss(self, loss):
ret = self._loss
self._loss = loss
return ret
@property
def loss(self):
return self._loss
net = gluon.nn.Dense(10)
ce = gluon.loss.SoftmaxCELoss()
net.initialize()
data = nd.random.uniform(shape=(1024, 100))
label = nd.array(np.random.randint(0, 10, (1024,)), dtype='int32')
train_dataset = gluon.data.ArrayDataset(data, label)
train_data = gluon.data.DataLoader(train_dataset, batch_size=128, shuffle=True, num_workers=2)
trainer = gluon.Trainer(net.collect_params(), optimizer='sgd')
loss_buffer = LossBuffer()
for data, label in train_data:
with autograd.record():
out = net(data)
# This call saves new loss and returns previous loss
prev_loss = loss_buffer.new_loss(ce(out, label))
loss_buffer.loss.backward()
trainer.step(data.shape[0])
if prev_loss is not None:
print("Loss: {}".format(np.mean(prev_loss.asnumpy())))
Output
输出如下所示:
Loss: 2.3373236656188965
Loss: 2.3656985759735107
Loss: 2.3613128662109375
Loss: 2.3197104930877686
Loss: 2.3054862022399902
Loss: 2.329197406768799
Loss: 2.318927526473999
Apache MXNet - Gluon
另一个最重要的 MXNet Python 包是 Gluon。在本章中,我们将讨论此包。Gluon 为深度学习项目提供了一个清晰、简洁、简单的 API。它使 Apache MXNet 能够构建原型、构建和训练深度学习模型,同时不会牺牲训练速度。
Blocks
Blocks 构成了更复杂网络设计的基础。在神经网络中,随着神经网络的复杂性增加,我们需要从设计单个神经元转向整个层。例如,诸如 ResNet-152 等神经网络设计通过包含 blocks 重复层具有非常公平的规律性。
Example
在下面给出的示例中,我们将编写一个简单的块,即多层感知器的块。
from mxnet import nd
from mxnet.gluon import nn
x = nd.random.uniform(shape=(2, 20))
N_net = nn.Sequential()
N_net.add(nn.Dense(256, activation='relu'))
N_net.add(nn.Dense(10))
N_net.initialize()
N_net(x)
Output
这会生成以下输出:
[[ 0.09543004 0.04614332 -0.00286655 -0.07790346 -0.05130241 0.02942038
0.08696645 -0.0190793 -0.04122177 0.05088576]
[ 0.0769287 0.03099706 0.00856576 -0.044672 -0.06926838 0.09132431
0.06786592 -0.06187843 -0.03436674 0.04234696]]
<NDArray 2x10 @cpu(0)>
从定义层到定义一个或多个层的块所需的步骤 −
Step 1 − 块将数据作为输入。
Step 2 − 现在,块将以参数的形式存储状态。例如,在上述编码示例中,块包含两个隐藏层,我们需要一个地方来存储其参数。
Step 3 − 下一个块将调用前向函数来执行前向传播。它也被称为前向计算。作为第一次前向调用的一个部分,块将以惰性方式初始化参数。
Step 4 − 最后,块将调用反向函数并计算相对于其输入的梯度。通常,此步骤会自动执行。
Sequential Block
顺序块是数据通过一系列块流过其中的特殊类型的块。其中,每个块应用于前一个块的输出,第一块应用于输入数据本身。
让我们看看 sequential 类如何工作 −
from mxnet import nd
from mxnet.gluon import nn
class MySequential(nn.Block):
def __init__(self, **kwargs):
super(MySequential, self).__init__(**kwargs)
def add(self, block):
self._children[block.name] = block
def forward(self, x):
for block in self._children.values():
x = block(x)
return x
x = nd.random.uniform(shape=(2, 20))
N_net = MySequential()
N_net.add(nn.Dense(256, activation
='relu'))
N_net.add(nn.Dense(10))
N_net.initialize()
N_net(x)
Output
输出与此一同给出 −
[[ 0.09543004 0.04614332 -0.00286655 -0.07790346 -0.05130241 0.02942038
0.08696645 -0.0190793 -0.04122177 0.05088576]
[ 0.0769287 0.03099706 0.00856576 -0.044672 -0.06926838 0.09132431
0.06786592 -0.06187843 -0.03436674 0.04234696]]
<NDArray 2x10 @cpu(0)>
Custom Block
我们可以轻松地通过如上定义的顺序块超越级联。但是,如果我们想要进行自定义,则 Block 类也为我们提供了所需的功能。块类具有由 nn 模块提供的模型构造函数。我们可以继承该模型构造函数来定义我们想要的模型。
在以下示例中, MLP class 覆盖了块类的 init 和正向函数。
让我们看看它的工作原理。
class MLP(nn.Block):
def __init__(self, **kwargs):
super(MLP, self).__init__(**kwargs)
self.hidden = nn.Dense(256, activation='relu') # Hidden layer
self.output = nn.Dense(10) # Output layer
def forward(self, x):
hidden_out = self.hidden(x)
return self.output(hidden_out)
x = nd.random.uniform(shape=(2, 20))
N_net = MLP()
N_net.initialize()
N_net(x)
Output
当运行代码时,您将看到以下输出:
[[ 0.07787763 0.00216403 0.01682201 0.03059879 -0.00702019 0.01668715
0.04822846 0.0039432 -0.09300035 -0.04494302]
[ 0.08891078 -0.00625484 -0.01619131 0.0380718 -0.01451489 0.02006172
0.0303478 0.02463485 -0.07605448 -0.04389168]]
<NDArray 2x10 @cpu(0)>
Custom Layers
Apache MXNet 的 Gluon API 带有少量预定义层。但有时候,我们可能会发现需要一个新层。我们可以在 Gluon API 中轻松添加一个新层。在本节中,我们将看到我们如何从头开始创建一个新层。
The Simplest Custom Layer
要在 Gluon API 中创建新层,我们必须创建一个从 Block 类继承的类,它提供了最基本的功能。我们可以直接或通过其他子类从它继承所有预定义的层。
要创建新层,只需要实现唯一的实例方法 forward (self, x) 。此方法定义了我们的层将在正向传播期间确切执行什么操作。如前所述,块的反向传播传递将由 Apache MXNet 本身自动完成。
Example
在下面的示例中,我们将定义一个新层。我们还将实现 forward() 方法,通过将输入数据拟合到 [0, 1] 的范围内来标准化输入数据。
from __future__ import print_function
import mxnet as mx
from mxnet import nd, gluon, autograd
from mxnet.gluon.nn import Dense
mx.random.seed(1)
class NormalizationLayer(gluon.Block):
def __init__(self):
super(NormalizationLayer, self).__init__()
def forward(self, x):
return (x - nd.min(x)) / (nd.max(x) - nd.min(x))
x = nd.random.uniform(shape=(2, 20))
N_net = NormalizationLayer()
N_net.initialize()
N_net(x)
Output
在执行上述程序后,您将获得以下结果−
[[0.5216355 0.03835821 0.02284337 0.5945146 0.17334817 0.69329053
0.7782702 1. 0.5508242 0. 0.07058554 0.3677264
0.4366546 0.44362497 0.7192635 0.37616986 0.6728799 0.7032008
0.46907538 0.63514024]
[0.9157533 0.7667402 0.08980197 0.03593295 0.16176797 0.27679572
0.07331014 0.3905285 0.6513384 0.02713427 0.05523694 0.12147208
0.45582628 0.8139887 0.91629887 0.36665893 0.07873632 0.78268915
0.63404864 0.46638715]]
<NDArray 2x20 @cpu(0)>
Hybridisation
它可以定义为 Apache MXNet 用于创建正向计算的符号图的过程。混合允许 MXNet 通过优化计算符号图来提高计算性能。实际上,我们可能会发现,在实现现有层时,块从 HybridBlock 继承,而不是直接继承自 Block 。
原因如下 −
-
Allows us to write custom layers: HybridBlock 允许我们编写自定义层,这些层可以在命令式和符号编程中进一步使用。
-
Increase computation performance − HybridBlock 优化计算符号图,允许 MXNet 提高计算性能。
Example
在此示例中,我们将通过使用 HybridBlock 重写我们上面创建的示例层:
class NormalizationHybridLayer(gluon.HybridBlock):
def __init__(self):
super(NormalizationHybridLayer, self).__init__()
def hybrid_forward(self, F, x):
return F.broadcast_div(F.broadcast_sub(x, F.min(x)), (F.broadcast_sub(F.max(x), F.min(x))))
layer_hybd = NormalizationHybridLayer()
layer_hybd(nd.array([1, 2, 3, 4, 5, 6], ctx=mx.cpu()))
Output
输出如下所示:
[0. 0.2 0.4 0.6 0.8 1. ]
<NDArray 6 @cpu(0)>
混合与 GPU 上的计算无关,人们可以在 CPU 和 GPU 上训练混合网络和非混合网络。
Difference between Block and HybridBlock
如果我们将 Block 类与 HybridBlock 类进行比较,我们会看到 HybridBlock 已经实现了它的 forward() 方法。 HybridBlock 定义了在创建层时需要实现的 hybrid_forward() 方法。F 参数创建了 forward() 和 hybrid_forward() 之间的主要区别。在 MXNet 社区中,F 参数被称为后端。F 可以引用 mxnet.ndarray API (用于命令式编程)或 mxnet.symbol API (用于符号编程)。
How to add custom layer to a network?
除了单独使用自定义层之外,这些层还与预定义的层一起使用。我们可以使用 Sequential 或 HybridSequential 容器来从顺序神经网络。如上所述, Sequential 容器分别继承自 Block 和 HybridSequential 继承自 HybridBlock 。
Example
在下面的示例中,我们将创建一个具有自定义层并且简单的神经网络。 Dense (5) 层的输出将成为 NormalizationHybridLayer 的输入。 NormalizationHybridLayer 的输出将成为 Dense (1) 层的输入。
net = gluon.nn.HybridSequential()
with net.name_scope():
net.add(Dense(5))
net.add(NormalizationHybridLayer())
net.add(Dense(1))
net.initialize(mx.init.Xavier(magnitude=2.24))
net.hybridize()
input = nd.random_uniform(low=-10, high=10, shape=(10, 2))
net(input)
Output
您将看到以下输出 −
[[-1.1272651]
[-1.2299833]
[-1.0662932]
[-1.1805027]
[-1.3382034]
[-1.2081106]
[-1.1263978]
[-1.2524893]
[-1.1044774]
[-1.316593 ]]
<NDArray 10x1 @cpu(0)>
Custom layer parameters
在神经网络中,一层具有一组与其关联的参数。有时我们称之为权重,它是一层的内部状态。这些参数起着不同的作用 −
-
有时这些是我们在反向传播步骤中希望了解的内容。
-
有时这些只是我们在向前传递中想要使用的常量。
如果我们讨论编程概念,则这些参数(权重)通过 ParameterDict 类存储并访问,该类有助于其初始化、更新、保存和加载。
Example
在下面的示例中,我们将定义以下两组参数 −
-
Parameter weights − 这是可训练的,在构建阶段其形状未知。它将在第一次向前传播运行时被推断出来。
-
Parameter scale − 这是一个常量,其值不会更改。与参数权重相反,其形状是在构建期间定义的。
class NormalizationHybridLayer(gluon.HybridBlock):
def __init__(self, hidden_units, scales):
super(NormalizationHybridLayer, self).__init__()
with self.name_scope():
self.weights = self.params.get('weights',
shape=(hidden_units, 0),
allow_deferred_init=True)
self.scales = self.params.get('scales',
shape=scales.shape,
init=mx.init.Constant(scales.asnumpy()),
differentiable=False)
def hybrid_forward(self, F, x, weights, scales):
normalized_data = F.broadcast_div(F.broadcast_sub(x, F.min(x)),
(F.broadcast_sub(F.max(x), F.min(x))))
weighted_data = F.FullyConnected(normalized_data, weights, num_hidden=self.weights.shape[0], no_bias=True)
scaled_data = F.broadcast_mul(scales, weighted_data)
return scaled_data
Apache MXNet - KVStore and Visualization
本章涉及 Python 软件包 KVStore 和可视化。
KVStore package
KV 存储表示键值存储。这是用于多设备训练的关键组件。它很重要,因为通过一个或多个具有参数的 KVStore 服务器在单个计算机或多个计算机上的设备之间传输参数通信。
让我们借助以下几点了解 KVStore 的工作原理:
-
KVStore 中的每个值都由 key 和 value 表示。
-
网络中的每个参数数组都被分配一个 key ,并且该参数数组的权重由 value 引用。
-
然后,工作节点在处理一个批次后 push 梯度。在处理一个新批次之前,它们还 pull 更新权重。
简而言之,我们可以说 KVStore 是一个数据共享的地方,每个设备都可以将数据推入和拉出。
Data Push-In and Pull-Out
KVStore 可以被认为是在不同设备(如 GPU 和计算机)之间共享的单个对象,其中每个设备都能够将数据推入和拉出。
以下是由设备遵循以将数据推入和拉出的实施步骤:
Implementation steps
Initialisation − 第一步是初始化值。这里,对于我们的示例,我们将在 KVStrore 中初始化一个元组(int、NDArray),然后将值提取出来 −
import mxnet as mx
kv = mx.kv.create('local') # create a local KVStore.
shape = (3,3)
kv.init(3, mx.nd.ones(shape)*2)
a = mx.nd.zeros(shape)
kv.pull(3, out = a)
print(a.asnumpy())
Output
生成以下输出:
[[2. 2. 2.]
[2. 2. 2.]
[2. 2. 2.]]
Push, Aggregate, and Update − 初始化后,我们可以使用相同的形状将新值推入 KVStore 至键 −
kv.push(3, mx.nd.ones(shape)*8)
kv.pull(3, out = a)
print(a.asnumpy())
Output
输出如下 −
[[8. 8. 8.]
[8. 8. 8.]
[8. 8. 8.]]
用于推送的数据可以存储在任何设备(如 GPU 或计算机)上。我们还可以将多个值推入同一键。在这种情况下,KVStore 将首先对所有这些值求和,然后推入聚合值,如下所示: −
contexts = [mx.cpu(i) for i in range(4)]
b = [mx.nd.ones(shape, ctx) for ctx in contexts]
kv.push(3, b)
kv.pull(3, out = a)
print(a.asnumpy())
Output
您将看到以下输出 −
[[4. 4. 4.]
[4. 4. 4.]
[4. 4. 4.]]
对于您应用的每个推送,KVStore 都会将已推送的值与已存储的值合并。它将借助于更新器完成。这里,默认更新器为 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())
Output
执行以上代码时,应该看到以下输出 −
[[4. 4. 4.]
[4. 4. 4.]
[4. 4. 4.]]
Example
kv.push(3, mx.nd.ones(shape))
kv.pull(3, out=a)
print(a.asnumpy())
Output
以下是代码的输出 −
update on key: 3
[[6. 6. 6.]
[6. 6. 6.]
[6. 6. 6.]]
Pull − 与推送一样,我们还可以通过一次调用在多个设备上拉取值,如下所示 −
b = [mx.nd.ones(shape, ctx) for ctx in contexts]
kv.pull(3, out = b)
print(b[1].asnumpy())
Output
输出如下 −
[[6. 6. 6.]
[6. 6. 6.]
[6. 6. 6.]]
Complete Implementation Example
下面给出完整的实施示例 −
import mxnet as mx
kv = mx.kv.create('local')
shape = (3,3)
kv.init(3, mx.nd.ones(shape)*2)
a = mx.nd.zeros(shape)
kv.pull(3, out = a)
print(a.asnumpy())
kv.push(3, mx.nd.ones(shape)*8)
kv.pull(3, out = a) # pull out the value
print(a.asnumpy())
contexts = [mx.cpu(i) for i in range(4)]
b = [mx.nd.ones(shape, ctx) for ctx in contexts]
kv.push(3, b)
kv.pull(3, out = a)
print(a.asnumpy())
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())
kv.push(3, mx.nd.ones(shape))
kv.pull(3, out=a)
print(a.asnumpy())
b = [mx.nd.ones(shape, ctx) for ctx in contexts]
kv.pull(3, out = b)
print(b[1].asnumpy())
Handling Key-Value Pairs
我们在上面实现的所有操作都涉及单个键,但 KVStore 还提供了一个 a list of key-value pairs 的接口 −
For a single device
以下是一个示例,展示了 KVStore 接口,用于单个设备的一系列键值对 −
keys = [5, 7, 9]
kv.init(keys, [mx.nd.ones(shape)]*len(keys))
kv.push(keys, [mx.nd.ones(shape)]*len(keys))
b = [mx.nd.zeros(shape)]*len(keys)
kv.pull(keys, out = b)
print(b[1].asnumpy())
Output
您将收到以下输出 −
update on key: 5
update on key: 7
update on key: 9
[[3. 3. 3.]
[3. 3. 3.]
[3. 3. 3.]]
Visualization package
可视化包是 Apache MXNet 包,用于将神经网络 (NN) 表示为包含节点和边的计算图。
Visualize neural network
在下面的示例中,我们将使用 mx.viz.plot_network
可视化神经网络。以下是其先决条件 −
Prerequisites
-
Jupyter notebook
-
Graphviz library
Implementation Example
在下面的示例中,我们将可视化用于线性矩阵分解的样本 NN −
import mxnet as mx
user = mx.symbol.Variable('user')
item = mx.symbol.Variable('item')
score = mx.symbol.Variable('score')
# Set the dummy dimensions
k = 64
max_user = 100
max_item = 50
# The user feature lookup
user = mx.symbol.Embedding(data = user, input_dim = max_user, output_dim = k)
# The item feature lookup
item = mx.symbol.Embedding(data = item, input_dim = max_item, output_dim = k)
# predict by the inner product and then do sum
N_net = user * item
N_net = mx.symbol.sum_axis(data = N_net, axis = 1)
N_net = mx.symbol.Flatten(data = N_net)
# Defining the loss layer
N_net = mx.symbol.LinearRegressionOutput(data = N_net, label = score)
# Visualize the network
mx.viz.plot_network(N_net)
Apache MXNet - Python API ndarray
本章介绍了 Apache MXNet 中提供的 ndarray 库。
Mxnet.ndarray
Apache MXNet 的 NDArray 库为所有数学计算定义了核心 DS(数据结构)。NDArray 的两个基本工作如下 −
-
它支持在各种硬件配置上快速执行。
-
它自动将多个操作并行化到可用硬件上。
下面给出的示例展示了如何使用常规 Python 列表通过 1-D 和 2-D“数组”创建 NDArray −
import mxnet as mx
from mxnet import nd
x = nd.array([1,2,3,4,5,6,7,8,9,10])
print(x)
Output
输出如下:
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
<NDArray 10 @cpu(0)>
Example
y = nd.array([[1,2,3,4,5,6,7,8,9,10], [1,2,3,4,5,6,7,8,9,10], [1,2,3,4,5,6,7,8,9,10]])
print(y)
Output
生成以下输出:
[[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]]
<NDArray 3x10 @cpu(0)>
现在,让我们详细讨论 MXNet 的 ndarray API 的类、函数和参数。
Classes
下表包括 MXNet 的 ndarray API 的类 −
Class |
Definition |
CachedOp(sym[, flags]) |
用于缓存的运算符句柄。 |
NDArray(handle[, writable]) |
用作表示固定大小项的多维、同质数组的数组对象。 |
Functions and their parameters
以下是一些由 mxnet.ndarray API 涵盖的重要函数及其参数 −
Function & its Parameters |
Definition |
Activation([data, act_type, out, name]) |
它将激活函数逐元素应用于输入中。支持 relu、sigmoid、tanh、softrelu、softsign 激活函数。 |
BatchNorm ([data, gamma, beta, moving_mean, …]) |
用于批归一化。此函数通过均值和方差对数据批执行归一化。它应用缩放 gamma 和偏移 beta。 |
BilinearSampler([data, grid, cudnn_off, …]) |
此函数对输入特征映射应用双线性采样。实际上它是“空间转换网络”的关键。如果您熟悉 OpenCV 中的重映射函数,此函数的使用与此非常相似。唯一不同之处在于它有反向通过。 |
BlockGrad([data, out, name]) |
根据名称指定,此函数停止渐变计算。它基本上阻止输入的累积梯度通过反向流过该运算符。 |
cast([data, dtype, out, name]) |
此函数将把输入的所有元素转换为新类型。 |
Implementation Examples
在下面的示例中,我们将使用函数 BilinierSampler() 将数据缩小两倍,并将数据水平偏移 -1 像素−
import mxnet as mx
from mxnet import nd
data = nd.array([[[[2, 5, 3, 6],
[1, 8, 7, 9],
[0, 4, 1, 8],
[2, 0, 3, 4]]]])
affine_matrix = nd.array([[2, 0, 0],
[0, 2, 0]])
affine_matrix = nd.reshape(affine_matrix, shape=(1, 6))
grid = nd.GridGenerator(data=affine_matrix, transform_type='affine', target_shape=(4, 4))
output = nd.BilinearSampler(data, grid)
Output
执行以上代码后,您应该看到以下输出:
[[[[0. 0. 0. 0. ]
[0. 4.0000005 6.25 0. ]
[0. 1.5 4. 0. ]
[0. 0. 0. 0. ]]]]
<NDArray 1x1x4x4 @cpu(0)>
以上输出显示将数据缩小两倍。
将数据偏移 -1 像素的示例如下 −
import mxnet as mx
from mxnet import nd
data = nd.array([[[[2, 5, 3, 6],
[1, 8, 7, 9],
[0, 4, 1, 8],
[2, 0, 3, 4]]]])
warp_matrix = nd.array([[[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]],
[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]]])
grid = nd.GridGenerator(data=warp_matrix, transform_type='warp')
output = nd.BilinearSampler(data, grid)
Output
输出如下 −
[[[[5. 3. 6. 0.]
[8. 7. 9. 0.]
[4. 1. 8. 0.]
[0. 3. 4. 0.]]]]
<NDArray 1x1x4x4 @cpu(0)>
同样,以下示例显示了 cast() 函数的使用 −
nd.cast(nd.array([300, 10.1, 15.4, -1, -2]), dtype='uint8')
Output
执行后,您将收到以下输出:
[ 44 10 15 255 254]
<NDArray 5 @cpu(0)>
ndarray.contrib
Contrib NDArray API 在 ndarray.contrib 包中定义。它通常为新特性提供许多有用的实验性 API。此 API 作为社区尝试新特性的场所。此功能的贡献者也将获得反馈。
Functions and their parameters
以下是 mxnet.ndarray.contrib API 涉及的一些重要函数及其参数 -
Function & its Parameters |
Definition |
rand_zipfian(true_classes, num_sampled, …) |
此函数从近似的 Zipfian 分布中提取随机样本。此函数的基本分布是 Zipfian 分布。此函数随机抽取 num_sampled 候选者,并且 sampled_candidates 的元素从上面给出的基本分布中提取。 |
foreach(body, data, init_states) |
顾名思义,此函数在维度 0 中通过用户定义的 NDArrays 计算来运行一个 for 循环。此函数模拟一个 for 循环,循环体包含该 for 循环迭代的计算。 |
while_loop(cond, func, loop_vars[, …]) |
顾名思义,此函数通过用户定义的计算和循环条件来运行一个 while 循环。此函数模拟一个 while 循环,如果条件得到满足,它会从容地执行自定义计算。 |
cond(pred, then_func, else_func) |
顾名思义,此函数使用用户定义的条件和计算运行一个 if-then-else。此函数模拟一个类似 if 的分支,根据指定条件选择执行两个自定义计算之一。 |
isinf(data) |
此函数执行逐元素检查,以确定 NDArray 是否包含无穷大的元素。 |
getnnz([data, axis, out, name]) |
此函数为我们提供稀疏张量的存储值数量。它还包括显式零。它仅支持 CPU 上的 CSR 矩阵。 |
requantize([data, min_range, max_range, …]) |
此函数对给定的数据进行重新量化,此数据以 int32 和相应的阈值量化,然后使用在运行时计算出的或从校准中获得的最小值和最大值阈值将其量化为 int8。 |
Implementation Examples
在下面的示例中,我们将使用 rand_zipfian 函数从近似 Zipfian 分布中抽取随机样本 -
import mxnet as mx
from mxnet import nd
trueclass = mx.nd.array([2])
samples, exp_count_true, exp_count_sample = mx.nd.contrib.rand_zipfian(trueclass, 3, 4)
samples
Output
您将看到以下输出 −
[0 0 1]
<NDArray 3 @cpu(0)>
Example
exp_count_true
Output
输出如下:
[0.53624076]
<NDArray 1 @cpu(0)>
Example
exp_count_sample
Output
这会生成以下输出:
[1.29202967 1.29202967 0.75578891]
<NDArray 3 @cpu(0)>
在下面的示例中,我们将使用 while_loop 函数运行一个 while 循环,用于用户定义的计算和循环条件:
cond = lambda i, s: i <= 7
func = lambda i, s: ([i + s], [i + 1, s + i])
loop_var = (mx.nd.array([0], dtype="int64"), mx.nd.array([1], dtype="int64"))
outputs, states = mx.nd.contrib.while_loop(cond, func, loop_vars, max_iterations=10)
outputs
Output
输出如下所示−
[
[[ 1]
[ 2]
[ 4]
[ 7]
[ 11]
[ 16]
[ 22]
[ 29]
[3152434450384]
[ 257]]
<NDArray 10x1 @cpu(0)>]
Example
States
Output
生成以下输出:
[
[8]
<NDArray 1 @cpu(0)>,
[29]
<NDArray 1 @cpu(0)>]
ndarray.image
Image NDArray API 在 ndarray.image 包中进行定义。正如名称所示,它通常用于图像及其特征。
Functions and their parameters
以下是一些 mxnet.ndarray.image API 涵盖的重要函数及其参数 -
Function & its Parameters |
Definition |
adjust_lighting([data, alpha, out, name]) |
正如名称所示,此函数调节输入的照明级别。它遵循 AlexNet 风格。 |
crop ([data, x, y, width, height, out, name]) |
在此函数的帮助下,我们可以将形状为 (H x W x C) 或 (N x H x W x C) 的图像 NDArray 裁剪到用户给定的尺寸。 |
normalize ([data, mean, std, out, name]) |
它将使用 mean 和 standard deviation(SD) 标准化形状为 (C x H x W) 或 (N x C x H x W) 的张量。 |
random_crop([data, xrange, yrange, width, …]) |
类似于 crop(),它会随机裁剪形状为 (H x W x C) 或 (N x H x W x C) 的图像 NDArray 到用户给定的尺寸。如果 src 小于尺寸,它会对结果进行上采样。 |
random_lighting([data, alpha_std, out, name]) |
正如名称所示,此函数随机添加 PCA 噪声。它也遵循 AlexNet 风格。 |
random_resized_crop([data, xrange, yrange, …]) |
它还随机裁剪形状为 (H x W x C) 或 (N x H x W x C) 的图像 NDArray 到给定的尺寸。如果 src 小于尺寸,它会对结果进行上采样。它同时会随机化区域和纵横比。 |
resize ([data, size, keep_ratio, interp, …]) |
正如名称所示,此函数将形状为 (H x W x C) 或 (N x H x W x C) 的图像 NDArray 调整到用户给定的尺寸。 |
to_tensor([data, out, name]) |
它将值在 [0, 255] 范围内的形状为 (H x W x C) 或 (N x H x W x C) 的图像 NDArray 转换为值在 [0, 1] 范围内的形状为 (C x H x W) 或 (N x C x H x W) 的张量 NDArray。 |
Implementation Examples
在下面的示例中,我们将使用 to_tensor 函数将值在 [0, 255] 范围内的形状为 (H x W x C) 或 (N x H x W x C) 的图像 NDArray 转换为值在 [0, 1] 范围内的形状为 (C x H x W) 或 (N x C x H x W) 的张量 NDArray。
import numpy as np
img = mx.nd.random.uniform(0, 255, (4, 2, 3)).astype(dtype=np.uint8)
mx.nd.image.to_tensor(img)
Output
您将看到以下输出 −
[[[0.972549 0.5058824 ]
[0.6039216 0.01960784]
[0.28235295 0.35686275]
[0.11764706 0.8784314 ]]
[[0.8745098 0.9764706 ]
[0.4509804 0.03529412]
[0.9764706 0.29411766]
[0.6862745 0.4117647 ]]
[[0.46666667 0.05490196]
[0.7372549 0.4392157 ]
[0.11764706 0.47843137]
[0.31764707 0.91764706]]]
<NDArray 3x4x2 @cpu(0)>
Example
img = mx.nd.random.uniform(0, 255, (2, 4, 2, 3)).astype(dtype=np.uint8)
mx.nd.image.to_tensor(img)
Output
运行代码后,你将看到以下输出 −
[[[[0.0627451 0.5647059 ]
[0.2627451 0.9137255 ]
[0.57254905 0.27450982]
[0.6666667 0.64705884]]
[[0.21568628 0.5647059 ]
[0.5058824 0.09019608]
[0.08235294 0.31764707]
[0.8392157 0.7137255 ]]
[[0.6901961 0.8627451 ]
[0.52156866 0.91764706]
[0.9254902 0.00784314]
[0.12941177 0.8392157 ]]]
[[[0.28627452 0.39607844]
[0.01960784 0.36862746]
[0.6745098 0.7019608 ]
[0.9607843 0.7529412 ]]
[[0.2627451 0.58431375]
[0.16470589 0.00392157]
[0.5686275 0.73333335]
[0.43137255 0.57254905]]
[[0.18039216 0.54901963]
[0.827451 0.14509805]
[0.26666668 0.28627452]
[0.24705882 0.39607844]]]]
<NDArgt;ray 2x3x4x2 @cpu(0)>
在下面的示例中,我们将使用函数 normalize 使用 mean 和 standard deviation(SD) 标准化形状为 (C x H x W) 或 (N x C x H x W) 的张量。
img = mx.nd.random.uniform(0, 1, (3, 4, 2))
mx.nd.image.normalize(img, mean=(0, 1, 2), std=(3, 2, 1))
Output
生成以下输出:
[[[ 0.29391178 0.3218054 ]
[ 0.23084386 0.19615503]
[ 0.24175143 0.21988946]
[ 0.16710812 0.1777354 ]]
[[-0.02195817 -0.3847335 ]
[-0.17800489 -0.30256534]
[-0.28807247 -0.19059572]
[-0.19680339 -0.26256624]]
[[-1.9808068 -1.5298678 ]
[-1.6984252 -1.2839255 ]
[-1.3398265 -1.712009 ]
[-1.7099224 -1.6165378 ]]]
<NDArray 3x4x2 @cpu(0)>
Example
img = mx.nd.random.uniform(0, 1, (2, 3, 4, 2))
mx.nd.image.normalize(img, mean=(0, 1, 2), std=(3, 2, 1))
Output
执行以上代码时,应该看到以下输出 −
[[[[ 2.0600514e-01 2.4972327e-01]
[ 1.4292289e-01 2.9281738e-01]
[ 4.5158025e-02 3.4287784e-02]
[ 9.9427439e-02 3.0791296e-02]]
[[-2.1501756e-01 -3.2297665e-01]
[-2.0456362e-01 -2.2409186e-01]
[-2.1283737e-01 -4.8318747e-01]
[-1.7339960e-01 -1.5519112e-02]]
[[-1.3478968e+00 -1.6790028e+00]
[-1.5685816e+00 -1.7787373e+00]
[-1.1034534e+00 -1.8587360e+00]
[-1.6324382e+00 -1.9027401e+00]]]
[[[ 1.4528830e-01 3.2801408e-01]
[ 2.9730779e-01 8.6780310e-02]
[ 2.6873133e-01 1.7900752e-01]
[ 2.3462953e-01 1.4930873e-01]]
[[-4.4988656e-01 -4.5021546e-01]
[-4.0258706e-02 -3.2384416e-01]
[-1.4287934e-01 -2.6537544e-01]
[-5.7649612e-04 -7.9429924e-02]]
[[-1.8505517e+00 -1.0953522e+00]
[-1.1318740e+00 -1.9624406e+00]
[-1.8375070e+00 -1.4916846e+00]
[-1.3844404e+00 -1.8331525e+00]]]]
<NDArray 2x3x4x2 @cpu(0)>
ndarray.random
Random NDArray API 在 ndarray.random 包中定义。顾名思义,它是 MXNet 的随机分布生成器 NDArray API。
Functions and their parameters
以下是 mxnet.ndarray.random API 涵盖的一些重要函数及其参数 −
Function and its Parameters |
Definition |
uniform([low, high, shape, dtype, ctx, out]) |
它从均匀分布中生成随机样本。 |
normal([loc, scale, shape, dtype, ctx, out]) |
它从正态(高斯)分布中生成随机样本。 |
randn(*shape, **kwargs) |
它从正态(高斯)分布中生成随机样本。 |
exponential([scale, shape, dtype, ctx, out]) |
它从指数分布中生成样本。 |
gamma([alpha, beta, shape, dtype, ctx, out]) |
它从伽马分布中生成随机样本。 |
multinomial(data[, shape, get_prob, out, dtype]) |
它从多个多项分布中生成并发采样。 |
negative_binomial([k, p, shape, dtype, ctx, out]) |
它从负二项分布中生成随机样本。 |
generalized_negative_binomial([mu, alpha, …]) |
它从广义负二项分布中生成随机样本。 |
shuffle(data, **kwargs) |
它随机洗牌元素。 |
randint(low, high[, shape, dtype, ctx, out]) |
它从离散均匀分布中生成随机样本。 |
exponential_like([data, lam, out, name]) |
它根据输入数组形状从指数分布中生成随机样本。 |
gamma_like([数据,阿尔法,贝塔,输出,名称]) |
根据输入数组形状从伽马分布生成随机样本。 |
generalized_negative_binomial_like([data, …]) |
根据输入数组形状从广义负二项分布生成随机样本。 |
negative_binomial_like([数据,k,p,输出,名称]) |
根据输入数组形状从负二项分布生成随机样本。 |
normal_like([数据,位置,比例,输出,名称]) |
根据输入数组形状从正态(高斯)分布生成随机样本。 |
poisson_like([data, lam, out, name]) |
根据输入数组形状从泊松分布生成随机样本。 |
uniform_like([数据,最低,最高,输出,名称]) |
根据输入数组形状从均匀分布生成随机样本。 |
Implementation Examples
在以下示例中,我们将从均匀分布中绘制随机样本。这将使用函数 uniform() 。
mx.nd.random.uniform(0, 1)
Output
输出如下:
[0.12381998]
<NDArray 1 @cpu(0)>
Example
mx.nd.random.uniform(-1, 1, shape=(2,))
Output
输出如下 −
[0.558102 0.69601643]
<NDArray 2 @cpu(0)>
Example
low = mx.nd.array([1,2,3])
high = mx.nd.array([2,3,4])
mx.nd.random.uniform(low, high, shape=2)
Output
您将看到以下输出 −
[[1.8649333 1.8073189]
[2.4113967 2.5691009]
[3.1399727 3.4071832]]
<NDArray 3x2 @cpu(0)>
在以下示例中,我们将从广义负二项分布中绘制随机样本。为此,我们将使用函数 generalized_negative_binomial() 。
mx.nd.random.generalized_negative_binomial(10, 0.5)
Output
执行以上代码时,应该看到以下输出 −
[1.]
<NDArray 1 @cpu(0)>
Example
mx.nd.random.generalized_negative_binomial(10, 0.5, shape=(2,))
Output
输出与此一同给出 −
[16. 23.]
<NDArray 2 @cpu(0)>
Example
mu = mx.nd.array([1,2,3])
alpha = mx.nd.array([0.2,0.4,0.6])
mx.nd.random.generalized_negative_binomial(mu, alpha, shape=2)
Output
以下是代码的输出 −
[[0. 0.]
[4. 1.]
[9. 3.]]
<NDArray 3x2 @cpu(0)>
ndarray.utils
实用 NDArray API 在 ndarray.utils 包中定义。顾名思义,它为 NDArray 和 BaseSparseNDArray 提供实用函数。
Functions and their parameters
以下是由 mxnet.ndarray.utils API 涵盖的部分重要函数及其参数 -
Function and its Parameters |
Definition |
zeros(shape[, ctx, dtype, stype]) |
此函数将返回一个给定形状和类型的、填充为零的新数组。 |
empty(shape[, ctx, dtype, stype]) |
它将返回一个给定形状和类型的新数组,而不初始化条目。 |
array(source_array[, ctx, dtype]) |
顾名思义,此函数将从公开数组界面的任意对象创建数组。 |
load(fname) |
它将从文件加载数组。 |
load_frombuffer(buf) |
顾名思义,此函数将从缓冲区加载数组字典或列表 |
save(fname, data) |
将数组或字符串词典列表保存到文件中的这个函数。 |
Implementation Examples
在下面的例子中,我们将返回一个以零填充的新数组,该数组具有给定的形状和类型。为此,我们将使用函数 [s0]。
mx.nd.zeros((1,2), mx.cpu(), stype='csr')
Output
生成以下输出:
<CSRNDArray 1x2 @cpu(0)>
Example
mx.nd.zeros((1,2), mx.cpu(), 'float16', stype='row_sparse').asnumpy()
Output
您将收到以下输出 −
array([[0., 0.]], dtype=float16)
在下面的例子中,我们将保存一个数组列表和一个字符串词典。为此,我们将使用函数 [s1]。
Example
x = mx.nd.zeros((2,3))
y = mx.nd.ones((1,4))
mx.nd.save('list', [x,y])
mx.nd.save('dict', {'x':x, 'y':y})
mx.nd.load('list')
Output
执行后,您将收到以下输出:
[
[[0. 0. 0.]
[0. 0. 0.]]
<NDArray 2x3 @cpu(0)>,
[[1. 1. 1. 1.]]
<NDArray 1x4 @cpu(0)>]
Example
mx.nd.load('my_dict')
Output
输出如下所示−
{'x':
[[0. 0. 0.]
[0. 0. 0.]]
<NDArray 2x3 @cpu(0)>, 'y':
[[1. 1. 1. 1.]]
<NDArray 1x4 @cpu(0)>}
Apache MXNet - Python API gluon
正如我们在前几章中已经讨论的那样,MXNet Gluon 为 DL 项目提供了一个清晰、简洁且简单的 API。它使 Apache MXNet 能够对 DL 模型进行原型制作、构建和训练,而不会影响训练速度。
gluon.nn
Gluon 在 gluon.nn 模块中提供了大量的内置 NN 层。这就是称其为核心模块的原因。
Methods and their parameters
以下是一些 mxnet.gluon.nn 核心模块涵盖的重要方法及其参数——
Methods and its Parameters |
Definition |
Activation(activation, **kwargs) |
顾名思义,此方法将激活函数应用于输入。 |
AvgPool1D([pool_size, strides, padding, …]) |
这是时间数据的平均池化操作。 |
AvgPool2D([pool_size, strides, padding, …]) |
这是空间数据的平均池化操作。 |
AvgPool3D([pool_size, strides, padding, …]) |
这是 3D 数据的平均池化操作。数据可以是空间或时空数据。 |
BatchNorm([axis, momentum, epsilon, center, …]) |
它表示批归一化层。 |
BatchNormReLU([axis, momentum, epsilon, …]) |
它还表示批归一化层,但带有 Relu 激活函数。 |
Block([prefix, params]) |
它给出了所有神经网络层和模型的基础类。 |
Conv1D(channels, kernel_size[, strides, …]) |
该方法用于 1-D 卷积层。例如,时间卷积。 |
Conv1DTranspose(channels, kernel_size[, …]) |
该方法用于转置 1D 卷积层。 |
Conv2D(channels, kernel_size[, strides, …]) |
该方法用于 2D 卷积层。例如,图像上的空间卷积)。 |
Conv2DTranspose(channels, kernel_size[, …]) |
该方法用于转置 2D 卷积层。 |
Conv3D(channels, kernel_size[, strides, …]) |
该方法用于 3D 卷积层。例如,体积上的空间卷积。 |
Conv3DTranspose(channels, kernel_size[, …]) |
该方法用于转置 3D 卷积层。 |
Dense(units[, activation, use_bias, …]) |
该方法表示常规密集连接 NN 层。 |
Dropout(rate[, axes]) |
顾名思义,该方法对输入应用 Dropout。 |
ELU([alpha]) |
该方法用于指数线性单元 (ELU)。 |
Embedding(input_dim, output_dim[, dtype, …]) |
它将非负整数转换为固定大小的稠密向量。 |
Flatten(**kwargs) |
该方法将输入压平为 2 维。 |
GELU(**kwargs) |
该方法用于高斯指数线性单元 (GELU)。 |
GlobalAvgPool1D([layout]) |
借助此方法,我们可以对时间数据执行全局平均池操作。 |
GlobalAvgPool2D([layout]) |
借助此方法,我们可以对空间数据执行全局平均池操作。 |
GlobalAvgPool3D([layout]) |
借助此方法,我们可以对 3-D 数据执行全局平均池操作。 |
GlobalMaxPool1D([layout]) |
借助此方法,我们可以对 1-D 数据执行全局最大池操作。 |
GlobalMaxPool2D([layout]) |
借助此方法,我们可以对 2-D 数据执行全局最大池操作。 |
GlobalMaxPool3D([layout]) |
借助此方法,我们可以对 3-D 数据执行全局最大池操作。 |
GroupNorm([num_groups, epsilon, center, …]) |
该方法对 n-D 输入数组应用组归一化。 |
HybridBlock([prefix, params]) |
该方法支持使用 Symbol 和 NDArray 进行转发。 |
HybridLambda(function[, prefix]) |
借助这种方法,我们可以将运算符或表达式包装为 HybridBlock 对象。 |
HybridSequential([prefix, params]) |
It stacks HybridBlocks sequentially. |
InstanceNorm([axis, epsilon, center, scale, …]) |
这种方法对 n 维输入数组应用实例归一化。 |
Implementation Examples
在下面的示例中,我们将使用 Block(),它为所有神经网络层和模型提供基本类。
from mxnet.gluon import Block, nn
class Model(Block):
def __init__(self, **kwargs):
super(Model, self).__init__(**kwargs)
# use name_scope to give child Blocks appropriate names.
with self.name_scope():
self.dense0 = nn.Dense(20)
self.dense1 = nn.Dense(20)
def forward(self, x):
x = mx.nd.relu(self.dense0(x))
return mx.nd.relu(self.dense1(x))
model = Model()
model.initialize(ctx=mx.cpu(0))
model(mx.nd.zeros((5, 5), ctx=mx.cpu(0)))
Output
您将看到以下输出 −
[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
<NDArray 5x20 @cpu(0)*gt;
在下面的示例中,我们将使用 HybridBlock(),它支持 Symbol 和 NDArray 进行正向传播。
import mxnet as mx
from mxnet.gluon import HybridBlock, nn
class Model(HybridBlock):
def __init__(self, **kwargs):
super(Model, self).__init__(**kwargs)
# use name_scope to give child Blocks appropriate names.
with self.name_scope():
self.dense0 = nn.Dense(20)
self.dense1 = nn.Dense(20)
def forward(self, x):
x = nd.relu(self.dense0(x))
return nd.relu(self.dense1(x))
model = Model()
model.initialize(ctx=mx.cpu(0))
model.hybridize()
model(mx.nd.zeros((5, 5), ctx=mx.cpu(0)))
Output
输出如下:
[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
<NDArray 5x20 @cpu(0)>
gluon.rnn
Gluon 在 gluon.rnn 模块中提供了大量内置 recurrent neural network (RNN)层。那是它被称作核心模块的原因。
Methods and their parameters
以下是 mxnet.gluon.nn 核心模块涵盖的一些重要方法及其参数:
Methods and its Parameters |
Definition |
BidirectionalCell(l_cell, r_cell[, …]) |
用于双向循环神经网络(RNN)单元。 |
DropoutCell(rate[, axes, prefix, params]) |
此方法将在给定的输入上应用 dropout。 |
GRU(hidden_size[, num_layers, layout, …]) |
它将多层门控循环单元(GRU)RNN 应用于给定的输入序列。 |
GRUCell(hidden_size[, …]) |
用于门控整流单元(GRU)网络单元。 |
HybridRecurrentCell([prefix, params]) |
This method supports hybridize. |
HybridSequentialRNNCell([prefix, params]) |
借助这种方法,我们可以顺序堆叠多个 HybridRNN 单元。 |
LSTM(hidden_size[, num_layers, layout, …])0 |
它将多层长短期记忆(LSTM)RNN 应用于给定的输入序列。 |
LSTMCell(hidden_size[, …]) |
用于长短期记忆(LSTM)网络单元。 |
ModifierCell(base_cell) |
它是修饰器单元的基本类。 |
RNN(hidden_size[, num_layers, activation, …]) |
它通过 tanh 或 ReLU 非线性将多层 Elman RNN 应用于给定的输入序列。 |
RNNCell(hidden_size[, activation, …]) |
用于 Elman RNN 循环神经网络单元。 |
RecurrentCell([prefix, params]) |
它表示 RNN 单元的抽象基类。 |
SequentialRNNCell([prefix, params]) |
借助这种方法,我们可以顺序堆叠多个 RNN 单元。 |
ZoneoutCell(base_cell[, zoneout_outputs, …]) |
此方法在基本单元上应用 Zoneout。 |
Implementation Examples
在下例中,我们将使用 GRU(),它对给定的输入序列应用多层门控循环单元 (GRU) RNN。
layer = mx.gluon.rnn.GRU(100, 3)
layer.initialize()
input_seq = mx.nd.random.uniform(shape=(5, 3, 10))
out_seq = layer(input_seq)
h0 = mx.nd.random.uniform(shape=(3, 3, 100))
out_seq, hn = layer(input_seq, h0)
out_seq
Output
生成以下输出:
[[[ 1.50152072e-01 5.19012511e-01 1.02390535e-01 ... 4.35803324e-01
1.30406499e-01 3.30152437e-02]
[ 2.91542172e-01 1.02243155e-01 1.73325196e-01 ... 5.65296151e-02
1.76546033e-02 1.66693389e-01]
[ 2.22257316e-01 3.76294643e-01 2.11277917e-01 ... 2.28903517e-01
3.43954474e-01 1.52770668e-01]]
[[ 1.40634328e-01 2.93247789e-01 5.50393537e-02 ... 2.30207980e-01
6.61415309e-02 2.70989928e-02]
[ 1.11081995e-01 7.20834285e-02 1.08342394e-01 ... 2.28330195e-02
6.79589901e-03 1.25501186e-01]
[ 1.15944080e-01 2.41565228e-01 1.18612610e-01 ... 1.14908054e-01
1.61080107e-01 1.15969211e-01]]
………………………….
Example
hn
Output
生成以下输出:
[[[-6.08105101e-02 3.86217088e-02 6.64453954e-03 8.18805695e-02
3.85607071e-02 -1.36945639e-02 7.45836645e-03 -5.46515081e-03
9.49622393e-02 6.39371723e-02 -6.37890724e-03 3.82240303e-02
9.11015049e-02 -2.01375950e-02 -7.29381144e-02 6.93765879e-02
2.71829776e-02 -6.64435029e-02 -8.45306814e-02 -1.03075653e-01
6.72040805e-02 -7.06537142e-02 -3.93818803e-02 5.16211614e-03
-4.79770005e-02 1.10734522e-01 1.56721435e-02 -6.93409378e-03
1.16915874e-01 -7.95962065e-02 -3.06530762e-02 8.42394680e-02
7.60370195e-02 2.17055440e-01 9.85361822e-03 1.16660878e-01
4.08297703e-02 1.24978097e-02 8.25245082e-02 2.28673983e-02
-7.88266212e-02 -8.04114193e-02 9.28791538e-02 -5.70827350e-03
-4.46166918e-02 -6.41122833e-02 1.80885363e-02 -2.37745279e-03
4.37298454e-02 1.28888980e-01 -3.07202265e-02 2.50503756e-02
4.00907174e-02 3.37077095e-03 -1.78839862e-02 8.90695080e-02
6.30150884e-02 1.11416787e-01 2.12221760e-02 -1.13236710e-01
5.39616570e-02 7.80710578e-02 -2.28817668e-02 1.92073174e-02
………………………….
在下例中,我们将使用 LSTM(),它对给定的输入序列应用长短期记忆 (LSTM) RNN。
layer = mx.gluon.rnn.LSTM(100, 3)
layer.initialize()
input_seq = mx.nd.random.uniform(shape=(5, 3, 10))
out_seq = layer(input_seq)
h0 = mx.nd.random.uniform(shape=(3, 3, 100))
c0 = mx.nd.random.uniform(shape=(3, 3, 100))
out_seq, hn = layer(input_seq,[h0,c0])
out_seq
Output
输出如下:
[[[ 9.00025964e-02 3.96071747e-02 1.83841765e-01 ... 3.95872220e-02
1.25569820e-01 2.15555862e-01]
[ 1.55962542e-01 -3.10300849e-02 1.76772922e-01 ... 1.92474753e-01
2.30574399e-01 2.81707942e-02]
[ 7.83204585e-02 6.53361529e-03 1.27262697e-01 ... 9.97719541e-02
1.28254429e-01 7.55299702e-02]]
[[ 4.41036932e-02 1.35250352e-02 9.87644792e-02 ... 5.89378644e-03
5.23949116e-02 1.00922674e-01]
[ 8.59075040e-02 -1.67027581e-02 9.69351009e-02 ... 1.17763653e-01
9.71239135e-02 2.25218050e-02]
[ 4.34580036e-02 7.62207608e-04 6.37005866e-02 ... 6.14888743e-02
5.96345589e-02 4.72368896e-02]]
……………
Example
hn
Output
运行代码后,你将看到以下输出 −
[
[[[ 2.21408084e-02 1.42750628e-02 9.53067932e-03 -1.22849066e-02
1.78788435e-02 5.99269159e-02 5.65306023e-02 6.42553642e-02
6.56616641e-03 9.80876666e-03 -1.15729487e-02 5.98640442e-02
-7.21173314e-03 -2.78371759e-02 -1.90690923e-02 2.21447181e-02
8.38765781e-03 -1.38521893e-02 -9.06938594e-03 1.21346042e-02
6.06449470e-02 -3.77471633e-02 5.65885007e-02 6.63008019e-02
-7.34188128e-03 6.46054149e-02 3.19911093e-02 4.11194898e-02
4.43960279e-02 4.92892228e-02 1.74766723e-02 3.40303481e-02
-5.23341820e-03 2.68163737e-02 -9.43402853e-03 -4.11836170e-02
1.55221792e-02 -5.05655073e-02 4.24557598e-03 -3.40388380e-02
……………………
gluon.loss
在 mxnet.gluon.loss 模块中,Gluon 提供了预定义的损失函数。基本上,它具有用于训练神经网络的损失。这就是它称为训练模块的原因。
Methods and their parameters
以下是 mxnet.gluon.loss 训练模块中涵盖的一些重要方法及其参数:
Methods and its Parameters |
Definition |
Loss(weight, batch_axis, **kwargs) |
这充当损失的基础类。 |
L2Loss([weight, batch_axis]) |
它计算 label 和 prediction(pred) 之间的均方误差 (MSE)。 |
L1Loss([weight, batch_axis]) |
它计算 label 和 pred 之间的平均绝对误差 (MAE)。 |
SigmoidBinaryCrossEntropyLoss([…]) |
该方法用于二元分类的交叉熵损失。 |
SigmoidBCELoss |
该方法用于二元分类的交叉熵损失。 |
SoftmaxCrossEntropyLoss([axis, …]) |
它计算 softmax 交叉熵损失 (CEL)。 |
SoftmaxCELoss |
它还计算 softmax 交叉熵损失。 |
KLDivLoss([from_logits, axis, weight, …]) |
它用于 Kullback-Leibler 散度损失。 |
CTCLoss([layout, label_layout, weight]) |
它用于连接主义时间分类损失 (TCL)。 |
HuberLoss([rho, weight, batch_axis]) |
它计算平滑的 L1 损失。如果绝对误差超过 rho,平滑的 L1 损失将等于 L1 损失,否则等于 L2 损失。 |
HingeLoss([margin, weight, batch_axis]) |
此方法计算通常在 SVM 中使用的铰链损失函数: |
SquaredHingeLoss([margin, weight, batch_axis]) |
此方法计算 SVM 中使用的软边距损失函数: |
LogisticLoss([weight, batch_axis, label_format]) |
此方法计算对数损失。 |
TripletLoss([margin, weight, batch_axis]) |
此方法计算给定三个输入张量和正面边距的三元组损失。 |
PoissonNLLLoss([weight, from_logits, …]) |
此函数计算负对数似然损失。 |
CosineEmbeddingLoss([weight, batch_axis, margin]) |
此函数计算向量间的余弦距离。 |
SDMLLoss([smoothing_parameter, weight, …]) |
此方法计算批次平滑深度度量学习 (SDML) 损失,给定两个输入张量和一个平滑权重 SDM 损失。通过将最小批次中不成对的样本用作潜在的反例,它学习成对样本之间的相似性。 |
gluon.parameter
mxnet.gluon.parameter 是一个包含参数的容器,即块的权重。
Methods and their parameters
mxnet.gluon.parameter 训练模块涵盖的一些重要方法及其参数如下 −
Methods and its Parameters |
Definition |
cast(dtype) |
此方法将把数据和此参数的梯度转换成一个新的数据类型。 |
data([ctx]) |
此方法将返回一个在一个上下文中此参数的副本。 |
grad([ctx]) |
此方法将返回一个在一个上下文中此参数的梯度缓冲区。 |
initialize([init, ctx, default_init, …]) |
此方法将初始化参数和梯度数组。 |
list_ctx() |
此方法将返回一个已在此参数上初始化的上下文列表。 |
list_data() |
此方法将返回一个在所有上下文中此参数的副本。将按照创建顺序执行。 |
list_grad() |
此方法将返回所有上下文的梯度缓冲区。这将按照 values() 的顺序执行。 |
list_row_sparse_data(row_id) |
此方法将返回所有上下文中“行稀疏”参数的副本。将按照创建顺序执行。 |
reset_ctx(ctx) |
此方法将重新分配其他上下文的参数。 |
row_sparse_data(row_id) |
此方法将返回与 'row_id' 相同上下文中“行稀疏”参数的副本。 |
set_data(data) |
此方法将在此参数上的所有上下文中设置值。 |
var() |
此方法将返回一个表示此参数的符号。 |
zero_grad() |
此方法将所有上下文的梯度缓冲区设置为 0。 |
Implementation Example
在以下示例中,我们将使用 initialize() 方法初始化参数和梯度数组,如下所示:-
weight = mx.gluon.Parameter('weight', shape=(2, 2))
weight.initialize(ctx=mx.cpu(0))
weight.data()
Output
输出如下:
[[-0.0256899 0.06511251]
[-0.00243821 -0.00123186]]
<NDArray 2x2 @cpu(0)>
Example
weight.grad()
Output
输出如下 −
[[0. 0.]
[0. 0.]]
<NDArray 2x2 @cpu(0)>
Example
weight.initialize(ctx=[mx.gpu(0), mx.gpu(1)])
weight.data(mx.gpu(0))
Output
您将看到以下输出 −
[[-0.00873779 -0.02834515]
[ 0.05484822 -0.06206018]]
<NDArray 2x2 @gpu(0)>
Example
weight.data(mx.gpu(1))
Output
执行以上代码时,应该看到以下输出 −
[[-0.00873779 -0.02834515]
[ 0.05484822 -0.06206018]]
<NDArray 2x2 @gpu(1)>
gluon.trainer
mxnet.gluon.trainer 对一组参数应用了一个优化器。它应该和 autograd 一起使用。
Methods and their parameters
以下是 mxnet.gluon.trainer 训练模块涵盖的一些重要的方法及参数:-
Methods and its Parameters |
Definition |
allreduce_grads() |
此方法将减少各个参数(权重)上的不同内容的梯度。 |
load_states(fname) |
顾名思义,此方法将加载训练器状态。 |
save_states(fname) |
顾名思义,此方法将保存训练器状态。 |
set_learning_rate(lr) |
此方法将设置优化器的新学习率。 |
step(batch_size[, ignore_stale_grad]) |
此方法将执行一次参数更新。它应该在 autograd.backward() 和 record() 范围外调用。 |
update(batch_size[, ignore_stale_grad]) |
此方法还会执行一次参数更新。它应该在 autograd.backward() 和 record() 范围外且在 trainer.update() 之后调用。 |
gluon.data
Gluon 在 gluon.data 模块中提供大量内置的数据集实用程序。这就是它被称为数据模块的原因。
Classes and their parameters
以下是 mxnet.gluon.data 核心模块涵盖的一些重要的方法及参数。这些方法通常与数据集、采样和 DataLoader 相关。
Methods and its Parameters |
Definition |
ArrayDataset(*args) |
此方法表示结合了两个或两个以上类似数据集的对象(如数据集、列表、数组等)的数据集。 |
BatchSampler(sampler, batch_size[, last_batch]) |
此方法封装到另一个 Sampler 上。封装之后,它将返回样本的小批量。 |
DataLoader(dataset[, batch_size, shuffle, …]) |
类似于 BatchSampler,但此方法从数据集加载数据。加载之后,它将返回数据的小批量。 |
这表示抽象数据集类。 |
FilterSampler(fn, dataset) |
此方法表示函数 fn 返回 True 的数据集中的样本元素。 |
RandomSampler(length) |
此方法表示从 [0, length) 中无放回地随机选择样本元素。 |
RecordFileDataset(filename) |
它表示封装 RecordIO 文件上的数据集。该文件扩展名为 .rec 。 |
Sampler |
这是采样器的基类。 |
SequentialSampler(length[, start]) |
它按顺序表示集合 [start, start + length) 中的采样元素。 |
它按顺序表示集合 [start, start + length) 中的采样元素。 |
Implementation Examples
在以下示例中,我们将使用 gluon.data.BatchSampler() API,它包装另一个采样器。它返回批量迷你采样。
import mxnet as mx
from mxnet.gluon import data
sampler = mx.gluon.data.SequentialSampler(15)
batch_sampler = mx.gluon.data.BatchSampler(sampler, 4, 'keep')
list(batch_sampler)
Output
输出如下:
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14]]
gluon.data.vision.datasets
Gluon 在 gluon.data.vision.datasets 模块中提供了大量的预定义视觉数据集函数。
Classes and their parameters
MXNet 为我们提供了有用且重要的数据集,其类和参数如下所示——
Classes and its Parameters |
Definition |
MNIST([root, train, transform]) |
这是一个有用的数据集,为我们提供了手写数字。MNIST 数据集的 URL 为 [role="bare"] [role="bare"]http://yann.lecun.com/exdb/mnist |
FashionMNIST([root, train, transform]) |
该数据集包含 Zalando 的包含时尚产品的商品图片。它是原始 MNIST 数据集的直接替代品。您可以从 [role="bare"] [role="bare"]https://github.com/zalandoresearch/fashion-mnist 获取此数据集 |
CIFAR10([root, train, transform]) |
这是一个来自 [role="bare"] [role="bare"]https://www.cs.toronto.edu/~kriz/cifar.html 的图像分类数据集。在该数据集中,每个样本都是一个形状为 (32, 32, 3) 的图像。 |
CIFAR100([root, fine_label, train, transform]) |
这是一个来自 [role="bare"] [role="bare"]https://www.cs.toronto.edu/~kriz/cifar.html 的 CIFAR100 图像分类数据集。它还有每个样本,都是一个形状为 (32, 32, 3) 的图像。 |
ImageRecordDataset (filename[, flag, transform]) |
该数据集包装在一个包含图像的 RecordIO 文件之上。在该数据集中,每个样本都是一个图像及其对应的标签。 |
ImageFolderDataset (root[, flag, transform]) |
这是一个用于加载存储在文件夹结构中的图像文件的数据集。 |
ImageListDataset ([root, imglist, flag]) |
这是一个用于加载由条目列表指定图像文件的数据集。 |
Example
在以下示例中,我们将展示 ImageListDataset() 的用法,它用于加载由条目列表指定图像文件——
# written to text file *.lst
0 0 root/cat/0001.jpg
1 0 root/cat/xxxa.jpg
2 0 root/cat/yyyb.jpg
3 1 root/dog/123.jpg
4 1 root/dog/023.jpg
5 1 root/dog/wwww.jpg
# A pure list, each item is a list [imagelabel: float or list of float, imgpath]
[[0, root/cat/0001.jpg]
[0, root/cat/xxxa.jpg]
[0, root/cat/yyyb.jpg]
[1, root/dog/123.jpg]
[1, root/dog/023.jpg]
[1, root/dog/wwww.jpg]]
gluon.utils
Gluon 在 gluon.utils 模块中提供了大量的内置并行化实用程序优化器。它提供了用于训练的各种实用程序。这就是它被称为实用程序模块的原因。
Functions and their parameters
以下是该实用程序模块中包含的功能及其参数,该模块名为 gluon.utils −
Functions and its Parameters |
Definition |
split_data(data, num_slice[, batch_axis, …]) |
此功能通常用于数据并行化,并且每个切片都会发送到一个设备,即 GPU。它将 NDArray 分割为 num_slice *slices along *batch_axis 。 |
split_and_load(data, ctx_list[, batch_axis, …]) |
此功能将 NDArray 分割为 len(ctx_list) 个沿 batch_axis. 的切片。与上述 split_data () 功能的唯一区别在于,它还将每个切片加载到 ctx_list 中的一个上下文中。 |
clip_global_norm(arrays, max_norm[, …]) |
此功能的工作是按比例缩放 NDArray,使其 2 范数之和小于 max_norm 。 |
check_sha1(filename, sha1_hash) |
此函数将检查文件内容的 sha1 哈希是否与预期哈希匹配。 |
download(url[, path, overwrite, sha1_hash, … ]) |
与名称所述一样,此函数将下载某个 URL。 |
replace_file(src, dst) |
该函数将实现原子审计 os.replace 。这将通过 Linux 和 OSX 来完成。 |
Python API Autograd and Initializer
本章介绍了 MXNet 中的自动微分和初始化器 API。
mxnet.autograd
这是 MXNet 对 NDArray 的自动微分 API。它具有以下类 -
Class: Function()
它用于自动微分中的自定义微分。它可以写为 [s2]。如果由于任何原因,用户不希望使用默认链式法则计算的梯度,那么他/她可以使用 mxnet.autograd 的 Function 类自定义微分的计算。它有两个方法,即 Forward() 和 Backward()。
让我们借助以下要点来了解此类的作用 -
-
首先,我们需要在正向方法中定义计算。
-
然后,我们需要在反向方法中提供自定义微分。
-
现在在梯度计算期间,mxnet.autograd 将使用用户定义的反向函数,而不是用户定义的反向函数。我们还可以转换为 numpy 数组,然后再进行一些操作,向前和向后。
Example
在使用 mxnet.autograd.function 类之前,让我们定义一个稳定的 sigmoid 函数及其反向和正向方法,如下所示 -
class sigmoid(mx.autograd.Function):
def forward(self, x):
y = 1 / (1 + mx.nd.exp(-x))
self.save_for_backward(y)
return y
def backward(self, dy):
y, = self.saved_tensors
return dy * y * (1-y)
现在,function 类可以用作以下 -
func = sigmoid()
x = mx.nd.random.uniform(shape=(10,))
x.attach_grad()
with mx.autograd.record():
m = func(x)
m.backward()
dx_grad = x.grad.asnumpy()
dx_grad
Output
运行代码后,你将看到以下输出 −
array([0.21458015, 0.21291625, 0.23330082, 0.2361367 , 0.23086983,
0.24060014, 0.20326573, 0.21093895, 0.24968489, 0.24301809],
dtype=float32)
Methods and their parameters
mxnet.autogard.function 类的以下方法和参数 -
Methods and its Parameters |
Definition |
forward(head[,head_grads,retain_graph,…]) |
此方法用于正向计算。 |
backward(heads[, head_grads, retain_graph, …]) |
此方法用于反向计算。它计算 head 的相对于先前标记变量的梯度。此方法的输入数量与 forward 的输出数量相同。它还返回与 forward 的输入一样多的 NDArray。 |
get_symbol(x) |
此方法用于检索记录的计算历史记录为 Symbol 。 |
grad(heads, variables[, head_grads, …]) |
此方法计算 head 相对于变量的梯度。计算完成后,梯度将作为新 NDArray 返回,而不是存储到 variable.grad 中。 |
is_recording() |
在这个方法的帮助下,我们可以获得记录和不记录的状态。 |
is_training() |
在该方法的帮助下,我们可以获得训练和预测的状态。 |
mark_variables(variables, gradients[, grad_reqs]) |
该方法会将 NDArray 标记为变量以计算 autograd 的梯度。该方法与变量中的函数 .attach_grad() 相同,但唯一的区别是我们可以使用此调用将梯度设置为任何值。 |
pause([train_mode]) |
该方法返回一个范围上下文用于不在“with”语句中的代码,不需要计算梯度。 |
predict_mode() |
该方法返回一个范围上下文用于不在“with”语句中,其中正向通过行为被设置为推断模式,并且不会更改记录状态。 |
record([train_mode]) |
它将返回一个 autograd 记录范围上下文用于“with”语句,并捕获需要计算梯度的代码。 |
set_recording(is_recording) |
与 is_recoring() 一样,在该方法的帮助下,我们可以获得记录和未记录的状态。 |
set_training(is_training) |
与 is_traininig() 一样,在该方法的帮助下,我们可以将状态设置为训练或预测。 |
train_mode() |
该方法将返回一个范围上下文用于不在“with”语句中,其中正向通过行为被设置为训练模式,并且不会更改记录状态。 |
Implementation Example
在以下示例中,我们将使用 mxnet.autograd.grad() 方法来计算目标相对于变量的梯度 −
x = mx.nd.ones((2,))
x.attach_grad()
with mx.autograd.record():
z = mx.nd.elemwise_add(mx.nd.exp(x), x)
dx_grad = mx.autograd.grad(z, [x], create_graph=True)
dx_grad
Output
输出如下:
[
[3.7182817 3.7182817]
<NDArray 2 @cpu(0)>]
我们可以使用 mxnet.autograd.predict_mode() 方法来返回一个范围用于“with”语句 −
with mx.autograd.record():
y = model(x)
with mx.autograd.predict_mode():
y = sampling(y)
backward([y])
mxnet.intializer
这是 MXNet 的 API 用于权重初始化器。它具有以下类 −
Classes and their parameters
以下为 mxnet.autogard.function 类的方法和其参数:
Classes and its Parameters |
Definition |
Bilinear() |
在该类帮助下,我们可以初始化上采样层权重。 |
Constant(value) |
该类将权重初始化到给定值。值可以是标量,也可以是与要设置的参数形状相匹配的 NDArray。 |
FusedRNN(init, num_hidden, num_layers, mode) |
顾名思义,此类为融合循环神经网络 (RNN) 初始化参数。 |
InitDesc |
它作为初始化模式描述符。 |
Initializer(**kwargs) |
这是初始化器的基类。 |
LSTMBias([forget_bias]) |
该类将 LSTMCell 的所有偏差初始化为 0.0,但除了遗忘门,其偏差被设置为一个自定义值以外。 |
Load(param[, default_init, verbose]) |
该类通过从文件或词典加载数据来初始化变量。 |
MSRAPrelu([factor_type, slope]) |
顾名思义,此类根据 MSRA 论文初始化权重。 |
Mixed(patterns, initializers) |
它使用多个初始化器来初始化参数。 |
Normal([sigma]) |
Normal() 类使用从均值为零且标准差 (SD) 为 sigma 的正态分布中抽取的随机值来初始化权重。 |
One() |
它将该参数的权重均初始化为 1。 |
Orthogonal([scale, rand_type]) |
顾名思义,此类将权重初始化为正交矩阵。 |
Uniform([scale]) |
它使用在给定范围内均匀抽取的随机值初始化权重。 |
Xavier([rnd_type, factor_type, magnitude]) |
它实际上返回一个执行权重“Xavier”初始化的初始化器。 |
Zero() |
它将该参数的权重均初始化为 0。 |
Implementation Example
在以下示例中,我们将使用 mxnet.init.Normal() 类创建初始化器并获取其参数 −
init = mx.init.Normal(0.8)
init.dumps()
Output
输出如下 −
'["normal", {"sigma": 0.8}]'
Example
init = mx.init.Xavier(factor_type="in", magnitude=2.45)
init.dumps()
Output
输出如下所示−
'["xavier", {"rnd_type": "uniform", "factor_type": "in", "magnitude": 2.45}]'
在以下示例中,我们将使用 mxnet.initializer.Mixed() 类使用多个初始化器来初始化参数 −
init = mx.initializer.Mixed(['bias', '.*'], [mx.init.Zero(),
mx.init.Uniform(0.1)])
module.init_params(init)
for dictionary in module.get_params():
for key in dictionary:
print(key)
print(dictionary[key].asnumpy())
Output
输出如下所示−
fullyconnected1_weight
[[ 0.0097627 0.01856892 0.04303787]]
fullyconnected1_bias
[ 0.]
Apache MXNet - Python API Symbol
在本章中,我们将了解 MXNet 中的一个接口,该接口被称为 Symbol。
Mxnet.ndarray
Apache MXNet 的 Symbol API 是用于符号编程的接口。Symbol API 的特点是使用以下功能 −
-
Computational graphs
-
Reduced memory usage
-
Pre-use function optimization
以下给出的示例演示了如何使用 MXNet 的 Symbol API 创建一个简单的表达式 −
通过普通 Python 列表使用 1-D 和 2-D“数组”的一组 NDArray −
import mxnet as mx
# Two placeholders namely x and y will be created with mx.sym.variable
x = mx.sym.Variable('x')
y = mx.sym.Variable('y')
# The symbol here is constructed using the plus ‘+’ operator.
z = x + y
Output
您将看到以下输出 −
<Symbol _plus0>
Example
(x, y, z)
Output
输出如下 −
(<Symbol x>, <Symbol y>, <Symbol _plus0>)
现在,让我们详细讨论 MXNet 的 ndarray API 的类、函数和参数。
Classes
下表包含了 MXNet 的 Symbol API 的类 −
Class |
Definition |
Symbol(handle) |
这个名为 symbol 的类是 Apache MXNet 的符号图。 |
Functions and their parameters
以下是一些 mxnet.Symbol API 涵盖的重要函数及其参数 −
Function and its Parameters |
Definition |
Activation([data, act_type, out, name]) |
它将激活函数逐元素应用到输入。它支持 relu, sigmoid, tanh, softrelu, softsign 激活函数。 |
BatchNorm([data, gamma, beta, moving_mean, …]) |
它用于批标准化。此函数通过均值和方差对数据批进行标准化。它应用比例 gamma *and offset *beta 。 |
BilinearSampler([data, grid, cudnn_off, …]) |
此函数对输入特征图应用双线性采样。实际上,它是“空间转换器网络”的关键。如果您熟悉 OpenCV 中的 remap 函数,此函数的使用与它非常相似。唯一的区别是它有反向传递。 |
BlockGrad([data, out, name]) |
根据名称指定,此函数停止渐变计算。它基本上阻止输入的累积梯度通过反向流过该运算符。 |
cast([data, dtype, out, name]) |
此函数将把输入的所有元素转换为新类型。 |
此函数将把输入的所有元素转换为新类型。 |
此函数,如名称所指定,返回给定形状和类型的带有零的新符号。 |
ones(shape[, dtype]) |
此函数,如名称所指定,返回给定形状和类型的带有 1 的新符号。 |
full(shape, val[, dtype]) |
此函数,如名称所指定,返回给定形状和类型的新数组,该数组填充给定的值 val 。 |
arange(start[, stop, step, repeat, …]) |
它将在给定的间隔内返回均匀间隔的值。值生成在半开区间 [start, stop) 内,这意味着该区间包括 start 但不包括 stop 。 |
linspace(start, stop, num[, endpoint, name, …]) |
它将在指定区间内返回均匀间隔的数字。与函数 arrange() 类似,值生成在半开区间 [start, stop) 内,这意味着该区间包括 start 但不包括 stop 。 |
histogram(a[, bins, range]) |
顾名思义,此函数将计算输入数据的直方图。 |
power(base, exp) |
顾名思义,此函数将返回 exp 元素中 base 元素求幂的逐元素结果。两个输入(即 base 和 exp)都可以是符号或标量。此处请注意,不允许广播。如果您想使用广播功能,可以使用 broadcast_pow 。 |
SoftmaxActivation([data, mode, name, attr, out]) |
此函数对输入应用 softmax 激活。它适用于内部层。它实际上已被弃用,我们可以改为使用 softmax() 。 |
Implementation Examples
在下面的示例中,我们将使用函数 power() ,它将返回 exp 元素中 base 元素求幂的逐元素结果:
import mxnet as mx
mx.sym.power(3, 5)
Output
您将看到以下输出 −
243
Example
x = mx.sym.Variable('x')
y = mx.sym.Variable('y')
z = mx.sym.power(x, 3)
z.eval(x=mx.nd.array([1,2]))[0].asnumpy()
Output
生成以下输出:
array([1., 8.], dtype=float32)
Example
z = mx.sym.power(4, y)
z.eval(y=mx.nd.array([2,3]))[0].asnumpy()
Output
执行以上代码时,应该看到以下输出 −
array([16., 64.], dtype=float32)
Example
z = mx.sym.power(x, y)
z.eval(x=mx.nd.array([4,5]), y=mx.nd.array([2,3]))[0].asnumpy()
Output
输出如下:
array([ 16., 125.], dtype=float32)
在下面给出的示例中,我们将使用函数 SoftmaxActivation() (or softmax()) ,它将应用于输入,并适用于内部层。
input_data = mx.nd.array([[2., 0.9, -0.5, 4., 8.], [4., -.7, 9., 2., 0.9]])
soft_max_act = mx.nd.softmax(input_data)
print (soft_max_act.asnumpy())
Output
您将看到以下输出 −
[[2.4258138e-03 8.0748333e-04 1.9912292e-04 1.7924475e-02 9.7864312e-01]
[6.6843745e-03 6.0796250e-05 9.9204916e-01 9.0463174e-04 3.0112563e-04]]
symbol.contrib
Contrib NDArray API 在 symbol.contrib 包中定义。它通常为新特性提供许多有用的实验性 API。此 API 作为社区的一个地方,社区可以在其中试用新特性。特性贡献者也将获得反馈。
Functions and their parameters
以下是一些 mxnet.symbol.contrib API 涵盖的重要函数及其参数:
Function and its Parameters |
Definition |
rand_zipfian(true_classes, num_sampled, …) |
此函数从近似的 Zipfian 分布中提取随机样本。此函数的基本分布是 Zipfian 分布。此函数随机抽取 num_sampled 候选者,并且 sampled_candidates 的元素从上面给出的基本分布中提取。 |
foreach(body, data, init_states) |
顾名思义,此函数在维度 0 上对 NDArray 运行带有用户定义计算的循环。此函数模拟 for 循环,body 为 for 循环一次迭代的计算。 |
while_loop(cond, func, loop_vars[, …]) |
顾名思义,此函数通过用户定义的计算和循环条件来运行一个 while 循环。此函数模拟一个 while 循环,如果条件得到满足,它会从容地执行自定义计算。 |
cond(pred, then_func, else_func) |
顾名思义,此函数使用用户定义的条件和计算运行 if-then-else。此函数模拟一个 if 分支,根据指定的条件选择执行两个自定义计算之一。 |
getnnz([data, axis, out, name]) |
此函数为我们提供稀疏张量的存储值数量。它还包括显式零。它仅支持 CPU 上的 CSR 矩阵。 |
requantize([data, min_range, max_range, …]) |
此函数使用最小阈值和最大阈值将以 int32 和相应阈值量化的给定数据重新量化为 int8,这些最小阈值和最大阈值的计算可以在运行时或校准时进行。 |
index_copy([old_tensor, index_vector, …]) |
此函数复制一个 new_tensor into the old_tensor by selecting the indices in the order given in index. The output of this operator will be a new tensor that contains the rest elements of old tensor and the copied elements of new tensor 的元素。 |
interleaved_matmul_encdec_qk([queries, …]) |
此算子计算多头注意力中查询和键投影之间的矩阵乘法,用作编码器-解码器。条件是输入应该是一个查询投影张量,其遵循以下布局:(seq_length, batch_size, num_heads*, head_dim)。 |
Implementation Examples
在下面的示例中,我们将使用 rand_zipfian 函数从近似齐夫分布中抽取随机样本−
import mxnet as mx
true_cls = mx.sym.Variable('true_cls')
samples, exp_count_true, exp_count_sample = mx.sym.contrib.rand_zipfian(true_cls, 5, 6)
samples.eval(true_cls=mx.nd.array([3]))[0].asnumpy()
Output
您将看到以下输出 −
array([4, 0, 2, 1, 5], dtype=int64)
Example
exp_count_true.eval(true_cls=mx.nd.array([3]))[0].asnumpy()
Output
输出如下:
array([0.57336551])
Example
exp_count_sample.eval(true_cls=mx.nd.array([3]))[0].asnumpy()
Output
您将看到以下输出 −
array([1.78103594, 0.46847373, 1.04183923, 0.57336551, 1.04183923])
在下面的示例中,我们将使用 while_loop 函数运行 while 循环以进行用户定义的计算和循环条件−
cond = lambda i, s: i <= 7
func = lambda i, s: ([i + s], [i + 1, s + i])
loop_vars = (mx.sym.var('i'), mx.sym.var('s'))
outputs, states = mx.sym.contrib.while_loop(cond, func, loop_vars, max_iterations=10)
print(outputs)
Output
输出如下:
[<Symbol _while_loop0>]
Example
Print(States)
Output
生成以下输出:
[<Symbol _while_loop0>, <Symbol _while_loop0>]
在下面的示例中,我们将使用将 new_tensor 中的元素复制到 old_tensor 中的函数 index_copy 。
import mxnet as mx
a = mx.nd.zeros((6,3))
b = mx.nd.array([[1,2,3],[4,5,6],[7,8,9]])
index = mx.nd.array([0,4,2])
mx.nd.contrib.index_copy(a, index, b)
Output
执行以上代码时,应该看到以下输出 −
[[1. 2. 3.]
[0. 0. 0.]
[7. 8. 9.]
[0. 0. 0.]
[4. 5. 6.]
[0. 0. 0.]]
<NDArray 6x3 @cpu(0)>
symbol.image
图像符号 API 在 symbol.image 包中定义。正如名称所示,它通常用于图像及其功能。
Functions and their parameters
以下是一些 mxnet.symbol.image API 涵盖的重要函数及其参数−
Function and its Parameters |
Definition |
adjust_lighting([data, alpha, out, name]) |
正如名称所示,此函数调节输入的照明级别。它遵循 AlexNet 风格。 |
crop([data, x, y, width, height, out, name]) |
借助此函数,我们可以将形状为 (H x W x C) 或 (N x H x W x C) 的图像 NDArray 裁剪到用户给定的尺寸。 |
normalize([data, mean, std, out, name]) |
它将使用 mean 和 standard deviation(SD) 对形状为 (C x H x W) 或 (N x C x H x W) 的张量进行归一化。 |
random_crop([data, xrange, yrange, width, …]) |
类似于 crop(),它将形状为 (H x W x C) 或 (N x H x W x C) 的图像 NDArray 随机裁剪为用户给定的尺寸。如果 src 小于 size ,它将对结果进行上采样。 |
random_lighting([data, alpha_std, out, name]) |
正如名称所示,此函数随机添加 PCA 噪声。它也遵循 AlexNet 风格。 |
random_resized_crop([data, xrange, yrange, …]) |
它还将形状为 (H x W x C) 或 (N x H x W x C) 的图像随机裁剪为给定尺寸。如果 src 小于大小,它将对结果进行上采样。它还将随机化区域和纵横比。 |
resize([data, size, keep_ratio, interp, …]) |
正如名称所示,此函数将形状为 (H x W x C) 或 (N x H x W x C) 的图像 NDArray 调整到用户给定的尺寸。 |
to_tensor([data, out, name]) |
它将值在 [0, 255] 范围内的形状为 (H x W x C) 或 (N x H x W x C) 的图像 NDArray 转换为值在 [0, 1] 范围内的形状为 (C x H x W) 或 (N x C x H x W) 的张量 NDArray。 |
Implementation Examples
在下面的示例中,我们将使用 to_tensor 函数将值在 [0, 255] 范围内的形状为 (H x W x C) 或 (N x H x W x C) 的图像 NDArray 转换为值在 [0, 1] 范围内的形状为 (C x H x W) 或 (N x C x H x W) 的张量 NDArray。
import numpy as np
img = mx.sym.random.uniform(0, 255, (4, 2, 3)).astype(dtype=np.uint8)
mx.sym.image.to_tensor(img)
Output
输出如下 −
<Symbol to_tensor4>
Example
img = mx.sym.random.uniform(0, 255, (2, 4, 2, 3)).astype(dtype=np.uint8)
mx.sym.image.to_tensor(img)
Output
输出如下所示:
<Symbol to_tensor5>
在下面的示例中,我们将使用 normalize() 函数对形状为 (C x H x W) 或 (N x C x H x W) 的张量使用 mean 和 standard deviation(SD) 进行归一化。
img = mx.sym.random.uniform(0, 1, (3, 4, 2))
mx.sym.image.normalize(img, mean=(0, 1, 2), std=(3, 2, 1))
Output
以下是代码的输出 −
<Symbol normalize0>
Example
img = mx.sym.random.uniform(0, 1, (2, 3, 4, 2))
mx.sym.image.normalize(img, mean=(0, 1, 2), std=(3, 2, 1))
Output
输出如下所示−
<Symbol normalize1>
symbol.random
随机符号 API 在 symbol.random 包中定义。正如名称所示,它是 MXNet 的随机分配发生器 Symbol API。
Functions and their parameters
以下是一些 mxnet.symbol.random API 涵盖的重要函数及其参数−
Function and its Parameters |
Definition |
uniform([low, high, shape, dtype, ctx, out]) |
它从均匀分布中生成随机样本。 |
normal([loc, scale, shape, dtype, ctx, out]) |
它从正态(高斯)分布中生成随机样本。 |
randn(*shape, **kwargs) |
它从正态(高斯)分布中生成随机样本。 |
poisson([lam, shape, dtype, ctx, out]) |
它根据泊松分布生成随机样本。 |
exponential([scale, shape, dtype, ctx, out]) |
它从指数分布中生成样本。 |
gamma([alpha, beta, shape, dtype, ctx, out]) |
它从伽马分布中生成随机样本。 |
multinomial(data[, shape, get_prob, out, dtype]) |
它从多个多项分布中生成并发采样。 |
negative_binomial([k, p, shape, dtype, ctx, out]) |
它从负二项分布中生成随机样本。 |
generalized_negative_binomial([mu, alpha, …]) |
它根据广义负二项分布生成随机样本。 |
shuffle(data, **kwargs) |
它随机洗牌元素。 |
randint(low, high[, shape, dtype, ctx, out]) |
它从离散均匀分布中生成随机样本。 |
exponential_like([data, lam, out, name]) |
它根据输入数组形状从指数分布中生成随机样本。 |
gamma_like([数据,阿尔法,贝塔,输出,名称]) |
根据输入数组形状从伽马分布生成随机样本。 |
generalized_negative_binomial_like([data, …]) |
它根据输入数组形状根据广义负二项分布生成随机样本。 |
negative_binomial_like([数据,k,p,输出,名称]) |
它根据输入数组形状根据负二项分布生成随机样本。 |
normal_like([数据,位置,比例,输出,名称]) |
它根据输入数组形状根据正态(高斯)分布生成随机样本。 |
poisson_like([data, lam, out, name]) |
它根据输入数组形状根据泊松分布生成随机样本。 |
uniform_like([数据,最低,最高,输出,名称]) |
它根据输入数组形状根据均匀分布生成随机样本。 |
Implementation Examples
在下面的示例中,我们将使用 shuffle() 函数随机地随机排列元素。它将沿着第一个轴随机排列数组。
data = mx.nd.array([[0, 1, 2], [3, 4, 5], [6, 7, 8],[9,10,11]])
x = mx.sym.Variable('x')
y = mx.sym.random.shuffle(x)
y.eval(x=data)
Output
您将看到以下输出:
[
[[ 9. 10. 11.]
[ 0. 1. 2.]
[ 6. 7. 8.]
[ 3. 4. 5.]]
<NDArray 4x3 @cpu(0)>]
Example
y.eval(x=data)
Output
执行以上代码时,应该看到以下输出 −
[
[[ 6. 7. 8.]
[ 0. 1. 2.]
[ 3. 4. 5.]
[ 9. 10. 11.]]
<NDArray 4x3 @cpu(0)>]
在下面的示例中,我们将从广义负二项分布中提取随机样本。为此,将使用函数 generalized_negative_binomial() 。
mx.sym.random.generalized_negative_binomial(10, 0.1)
Output
输出如下 −
<Symbol _random_generalized_negative_binomial0>
symbol.sparse
稀疏符号 API 在 mxnet.symbol.sparse 程序包中定义。顾名思义,它提供了稀疏神经网络图和 CPU 上的自动微分。
Functions and their parameters
以下一些重要的函数(包括符号创建例程、符号操作例程、数学函数、三角函数、双曲函数、减少函数、舍入、幂、神经网络)及其参数由 mxnet.symbol.sparse API 涵盖:
Function and its Parameters |
Definition |
ElementWiseSum(*args, **kwargs) |
此函数将按元素方式添加所有输入参数。例如,add_n(a1,a2,…an=a1+a2+⋯+an)。在这里,我们可以看到 add_n 可能比按 n 次调用 add 更有效。 |
Embedding([data, weight, input_dim, …]) |
它将整型索引映射到向量表示,即嵌入。它实际上将单词映射到高维空间中的实值向量,称为词嵌入。 |
LinearRegressionOutput([data, label, …]) |
它计算和优化了向后传播过程中的平方损失,在正向传播过程中仅给出输出数据。 |
LogisticRegressionOutput([data, label, …]) |
对输入应用一个称为 sigmoid 函数的逻辑函数。该函数计算为 1/1+exp (−x)。 |
MAERegressionOutput([data, label, …]) |
此算子计算输入的平均绝对误差。MAE 实际上是一个风险度量,对应于绝对误差的期望值。 |
abs([data, name, attr, out]) |
顾名思义,此函数将返回输入的逐个元素绝对值。 |
adagrad_update([weight, grad, history, lr, …]) |
它是 AdaGrad optimizer 的更新函数。 |
adam_update([weight, grad, mean, var, lr, …]) |
它是 Adam optimizer 的更新函数。 |
add_n(*args, **kwargs) |
顾名思义,它将以元素级方式添加所有输入参数。 |
arccos([data, name, attr, out]) |
该函数将返回输入数组的元素级反余弦。 |
dot([lhs, rhs, transpose_a, transpose_b, …]) |
顾名思义,它将给出两个数组的点积。它将取决于输入数组维度:1-D:向量的内积2-D:矩阵乘法N-D:第一个输入数组的最后一个轴和第二个输入数组的第一个轴上求和积。 |
elemwise_add([lhs, rhs, name, attr, out]) |
顾名思义,它将以元素级方式 add 参数。 |
elemwise_div([lhs, rhs, name, attr, out]) |
顾名思义,它将以元素级方式 divide 参数。 |
elemwise_mul([lhs, rhs, name, attr, out]) |
顾名思义,它将以元素级方式 Multiply 参数。 |
elemwise_sub([lhs, rhs, name, attr, out]) |
顾名思义,它将以元素级方式减去参数。 |
exp([data, name, attr, out]) |
该函数将返回给定输入的元素级指数值。 |
sgd_update([weight, grad, lr, wd, …]) |
它充当随机梯度下降优化器的更新函数。 |
sigmoid([data, name, attr, out]) |
正如名称所示,它将计算 sigmoid 的 x 元素。 |
sign([data, name, attr, out]) |
它会返回给定输入的元素符号。 |
sin([data, name, attr, out]) |
如名称所示,此函数将计算给定输入数组的元素正弦。 |
Implementation Example
在下面的示例中,我们将使用 ElementWiseSum() 函数随机对元素进行洗牌。它将把整数索引映射到向量表示中,即单词嵌入。
input_dim = 4
output_dim = 5
Example
/* Here every row in weight matrix y represents a word. So, y = (w0,w1,w2,w3)
y = [[ 0., 1., 2., 3., 4.],
[ 5., 6., 7., 8., 9.],
[ 10., 11., 12., 13., 14.],
[ 15., 16., 17., 18., 19.]]
/* Here input array x represents n-grams(2-gram). So, x = [(w1,w3), (w0,w2)]
x = [[ 1., 3.],
[ 0., 2.]]
/* Now, Mapped input x to its vector representation y.
Embedding(x, y, 4, 5) = [[[ 5., 6., 7., 8., 9.],
[ 15., 16., 17., 18., 19.]],
[[ 0., 1., 2., 3., 4.],
[ 10., 11., 12., 13., 14.]]]
Apache MXNet - Python API Module
Apache MXNet 的模块 API 类似于前馈模型,而且可以很容易地组合类似于 Torch 模块。它由以下的类组成:
BaseModule([logger])
它表示模块的基础类。可以将模块视为计算组件或计算机器。模块的任务是执行前向传播和反向传播。它还更新模型中的参数。
Methods
下表显示 BaseModule class 中包含的方法:
Methods |
Definition |
backward([out_grads]) |
如名称所示,此方法实现 backward 计算。 |
bind(data_shapes[, label_shapes, …]) |
它绑定符号以构造执行器,在用模块执行计算之前,此步骤是必要的。 |
fit(train_data[, eval_data, eval_metric, …]) |
此方法训练模块参数。 |
forward(data_batch[, is_train]) |
如名称所示,此方法实现正向传播计算。此方法支持具有各种形状的数据批次,如不同的批次大小或不同的图像大小。 |
forward_backward(data_batch) |
正如名称所示,它是一个便捷的函数,它同时调用前向和反向。 |
get_input_grads([merge_multi_context]) |
此方法将获取在前面的反向计算中计算得到的输入的梯度。 |
get_outputs([merge_multi_context]) |
如名称所示,此方法将获取前面正向计算的输出。 |
get_params() |
它获取参数,尤其是可能复制实际参数用于在设备上执行计算的参数。 |
get_states([merge_multi_context]) |
|
init_optimizer([kvstore, optimizer, …]) |
此方法安装并初始化优化器。它还初始化 kvstore 以进行分布训练。 |
init_params([initializer, arg_params, …]) |
如名称所示,此方法将初始化参数和辅助状态。 |
install_monitor(mon) |
此方法将在所有执行器中安装监控程序。 |
iter_predict(eval_data[, num_batch, reset, …]) |
此方法将遍历预测。 |
load_params(fname) |
正如其名称所示,它将从文件中加载模型参数。 |
predict(eval_data[, num_batch, …]) |
它将运行预测,以及收集输出结果。 |
prepare(data_batch[, sparse_row_id_fn]) |
该算子准备模块以处理给定数据批处理。 |
save_params(fname) |
正如其名称所示,此函数将模型参数保存到文件。 |
score(eval_data, eval_metric[, num_batch, …]) |
它在 eval_data 上运行预测,并且还根据给定的 eval_metric 评估性能。 |
set_params(arg_params, aux_params[, …]) |
此方法为参数和辅助状态值赋值。 |
set_states([states, value]) |
此方法(由名称暗示)为状态设置值。 |
update() |
此方法根据已安装的优化器更新给定参数。它还更新在上一个前向反向批处理中计算的梯度。 |
update_metric(eval_metric, labels[, pre_sliced]) |
此方法(由名称暗示)评估并累积最后一个前向计算的输出的评估度量。 |
backward([out_grads]) |
如名称所示,此方法实现 backward 计算。 |
bind(data_shapes[, label_shapes, …]) |
设置存储桶并绑定默认存储桶键的执行器。此方法表示 BucketingModule 的绑定。 |
forward(data_batch[, is_train]) |
如名称所示,此方法实现正向传播计算。此方法支持具有各种形状的数据批次,如不同的批次大小或不同的图像大小。 |
get_input_grads([merge_multi_context]) |
此方法将获得上一次反向计算中计算的输入梯度。 |
get_outputs([merge_multi_context]) |
正如其名称所示,此方法将从上一次前向计算中获得输出。 |
get_params() |
它获得当前参数,特别是潜在复制在设备上进行计算的实际参数。 |
get_states([merge_multi_context]) |
此方法将从所有设备中获取状态。 |
init_optimizer([kvstore, optimizer, …]) |
此方法安装并初始化优化器。它还初始化 kvstore 以进行分布训练。 |
init_params([initializer, arg_params, …]) |
如名称所示,此方法将初始化参数和辅助状态。 |
install_monitor(mon) |
此方法将在所有执行器中安装监控程序。 |
load(prefix, epoch[, sym_gen, …]) |
此方法将从以前保存的检查点创建模型。 |
load_dict([sym_dict, sym_gen, …]) |
此方法将从将 bucket_key 映射到符号的字典(dict)创建模型。它还共享 arg_params 和 aux_params 。 |
prepare(data_batch[, sparse_row_id_fn]) |
该算子准备模块以处理给定数据批处理。 |
save_checkpoint(prefix, epoch[, remove_amp_cast]) |
此方法(由名称暗示)将当前进度保存到 BucketingModule 中所有存储桶的检查点。建议将 mx.callback.module_checkpoint 用作 epoch_end_callback 以在训练期间保存进度。 |
set_params(arg_params, aux_params[,…]) |
正如其名称所示,此函数将分配参数和辅助状态值。 |
set_states([states, value]) |
此方法(由名称暗示)为状态设置值。 |
switch_bucket(bucket_key, data_shapes[, …]) |
它将切换为不同的存储桶。 |
update() |
此方法根据已安装的优化器更新给定参数。它还更新在上一个前向反向批处理中计算的梯度。 |
update_metric(eval_metric, labels[, pre_sliced]) |
此方法(由名称暗示)评估并累积最后一个前向计算的输出的评估度量。 |
Attributes
以下表列出 BaseModule 类的各个方法包含的属性 −
Attributes |
Definition |
data_names |
其中包含此模块所需数据的名称列表。 |
data_shapes |
其中包含指定此模块的数据输入的 (名称,形状) 对的列表。 |
label_shapes |
其中显示指定此模块的标签输入的 (名称,形状) 对的列表。 |
output_names |
其中包含此模块输出的名称列表。 |
output_shapes |
其中包含指定此模块的输出的 (名称,形状) 对的列表。 |
symbol |
根据所指定的名称,此属性获取与此模块关联的符号。 |
data_shapes:你可以参考 https://mxnet.apache.org 处提供的链接以了解更多详细信息。output_shapes:详细信息
output_shapes:更多信息可在 https://mxnet.apache.org/api/python 找到
BucketingModule(sym_gen[…])
它表示一个模块的 Bucketingmodule 类,它有助于有效地处理长度不一的输入。
Attributes
以下表列出 BaseModule class 的各个方法包含的属性 −
Attributes |
Definition |
data_names |
其中包含此模块所需数据的名称列表。 |
data_shapes |
其中包含指定此模块的数据输入的 (名称,形状) 对的列表。 |
label_shapes |
其中显示指定此模块的标签输入的 (名称,形状) 对的列表。 |
output_names |
其中包含此模块输出的名称列表。 |
output_shapes |
其中包含指定此模块的输出的 (名称,形状) 对的列表。 |
Symbol |
根据所指定的名称,此属性获取与此模块关联的符号。 |
data_shapes − 你可以参考 https://mxnet.apache.org/api/python/docs 处的链接了解更多信息。
output_shapes− 你可以参考 https://mxnet.apache.org/api/python/docs 处的链接了解更多信息。
Module(symbol[,data_names, label_names,…])
它表示一个包装 symbol 的基本模块。
Methods
以下表列出 Module class 中包含的方法 −
Methods |
Definition |
backward([out_grads]) |
如名称所示,此方法实现 backward 计算。 |
bind(data_shapes[, label_shapes, …]) |
它绑定符号以构造执行器,在用模块执行计算之前,此步骤是必要的。 |
borrow_optimizer(shared_module) |
正如名称暗示的那样,此方法会从共享模块中借用优化器。 |
forward(data_batch[, is_train]) |
正如名称暗示的那样,此方法会实现 Forward 计算。此方法支持具有不同形状的数据批次,如不同的批次大小或不同的图像大小。 |
get_input_grads([merge_multi_context]) |
此方法将获取在前面的反向计算中计算得到的输入的梯度。 |
get_outputs([merge_multi_context]) |
如名称所示,此方法将获取前面正向计算的输出。 |
get_params() |
它获取参数,尤其是可能复制实际参数用于在设备上执行计算的参数。 |
get_states([merge_multi_context]) |
此方法将从所有设备获取状态 |
init_optimizer([kvstore, optimizer, …]) |
此方法安装并初始化优化器。它还初始化 kvstore 以进行分布训练。 |
init_params([initializer, arg_params, …]) |
如名称所示,此方法将初始化参数和辅助状态。 |
install_monitor(mon) |
此方法将在所有执行器中安装监控程序。 |
load(prefix, epoch[, sym_gen, …]) |
此方法将从以前保存的检查点创建模型。 |
load_optimizer_states(fname) |
该方法将从文件中加载优化器,即更新器状态。 |
prepare(data_batch[, sparse_row_id_fn]) |
该算子准备模块以处理给定数据批处理。 |
reshape(data_shapes[, label_shapes]) |
顾名思义,此方法根据新的输入形状调整模块的形状。 |
save_checkpoint(prefix, epoch[, …]) |
它将当前进程保存到检查点。 |
save_optimizer_states(fname) |
该方法将优化器或更新器状态保存到文件。 |
set_params(arg_params, aux_params[,…]) |
正如其名称所示,此函数将分配参数和辅助状态值。 |
set_states([states, value]) |
此方法(由名称暗示)为状态设置值。 |
update() |
此方法根据已安装的优化器更新给定参数。它还更新在上一个前向反向批处理中计算的梯度。 |
update_metric(eval_metric, labels[, pre_sliced]) |
此方法(由名称暗示)评估并累积最后一个前向计算的输出的评估度量。 |
Attributes
下表显示了 Module class 方法包含的属性——
Attributes |
Definition |
data_names |
其中包含此模块所需数据的名称列表。 |
data_shapes |
其中包含指定此模块的数据输入的 (名称,形状) 对的列表。 |
label_shapes |
其中显示指定此模块的标签输入的 (名称,形状) 对的列表。 |
output_names |
其中包含此模块输出的名称列表。 |
output_shapes |
其中包含指定此模块的输出的 (名称,形状) 对的列表。 |
label_names |
它包含该模块所需的标签名称列表。 |
data_shapes: 访问链接 https://mxnet.apache.org/api/python/docs/api/module 以获取更多详细信息。
output_shapes: 此处给出的链接 https://mxnet.apache.org/api/python/docs/api/module/index.html 将提供其他重要信息。
PythonLossModule([name,data_names,…])
该类的基础是 mxnet.module.python_module.PythonModule. PythonLossModule 类是一个便捷的模块类,它将所有或许多模块 API 实现为空函数。
Methods
下表显示了 PythonLossModule 类中包含的方法:
Methods |
Definition |
backward([out_grads]) |
如名称所示,此方法实现 backward 计算。 |
forward(data_batch[, is_train]) |
正如名称暗示的那样,此方法会实现 Forward 计算。此方法支持具有不同形状的数据批次,如不同的批次大小或不同的图像大小。 |
get_input_grads([merge_multi_context]) |
此方法将获取在前面的反向计算中计算得到的输入的梯度。 |
get_outputs([merge_multi_context]) |
如名称所示,此方法将获取前面正向计算的输出。 |
install_monitor(mon) |
此方法将在所有执行器中安装监控程序。 |
PythonModule([data_names,label_names…])
该类的基础是 mxnet.module.base_module.BaseModule。PythonModule 类也是一个便捷的模块类,它将所有或许多模块 API 实现为空函数。
Methods
下表显示了 PythonModule 类中包含的方法——
Methods |
Definition |
bind(data_shapes[, label_shapes, …]) |
它绑定符号以构造执行器,在用模块执行计算之前,此步骤是必要的。 |
get_params() |
它获取参数,尤其是可能复制实际参数用于在设备上执行计算的参数。 |
init_optimizer([kvstore, optimizer, …]) |
此方法安装并初始化优化器。它还初始化 kvstore 以进行分布训练。 |
init_params([initializer, arg_params, …]) |
如名称所示,此方法将初始化参数和辅助状态。 |
update() |
此方法根据已安装的优化器更新给定参数。它还更新在上一个前向反向批处理中计算的梯度。 |
update_metric(eval_metric, labels[, pre_sliced]) |
此方法(由名称暗示)评估并累积最后一个前向计算的输出的评估度量。 |
Attributes
下表显示了 PythonModule 类中的方法包含的属性——
Attributes |
Definition |
data_names |
其中包含此模块所需数据的名称列表。 |
data_shapes |
其中包含指定此模块的数据输入的 (名称,形状) 对的列表。 |
label_shapes |
其中显示指定此模块的标签输入的 (名称,形状) 对的列表。 |
output_names |
其中包含此模块输出的名称列表。 |
output_shapes |
其中包含指定此模块的输出的 (名称,形状) 对的列表。 |
data_shapes - 访问链接 https://mxnet.apache.org 查看详细信息。
output_shapes - 访问链接 https://mxnet.apache.org 查看更多详细信息
SequentialModule([logger])
该类的基础是 mxnet.module.base_module.BaseModule。SequentialModule 类也是一个容器模块,它可以链接多个模块。
Methods
下表显示了 SequentialModule 类中包含的方法
Methods |
Definition |
add(module, **kwargs) |
这是该类最重要的函数。它将模块添加到链中。 |
backward([out_grads]) |
顾名思义,此方法实现反向计算。 |
bind(data_shapes[, label_shapes, …]) |
它绑定符号以构造执行器,在用模块执行计算之前,此步骤是必要的。 |
forward(data_batch[, is_train]) |
如名称所示,此方法实现正向传播计算。此方法支持具有各种形状的数据批次,如不同的批次大小或不同的图像大小。 |
get_input_grads([merge_multi_context]) |
此方法将获取在前面的反向计算中计算得到的输入的梯度。 |
get_outputs([merge_multi_context]) |
如名称所示,此方法将获取前面正向计算的输出。 |
get_params() |
它获取参数,尤其是可能复制实际参数用于在设备上执行计算的参数。 |
init_optimizer([kvstore, optimizer, …]) |
此方法安装并初始化优化器。它还初始化 kvstore 以进行分布训练。 |
init_params([initializer, arg_params, …]) |
如名称所示,此方法将初始化参数和辅助状态。 |
install_monitor(mon) |
此方法将在所有执行器中安装监控程序。 |
update() |
此方法根据已安装的优化器更新给定参数。它还更新在上一个前向反向批处理中计算的梯度。 |
update_metric(eval_metric, labels[, pre_sliced]) |
此方法(由名称暗示)评估并累积最后一个前向计算的输出的评估度量。 |
Attributes
下表显示了 BaseModule 类的方法中包含的属性 -
Attributes |
Definition |
data_names |
其中包含此模块所需数据的名称列表。 |
data_shapes |
其中包含指定此模块的数据输入的 (名称,形状) 对的列表。 |
label_shapes |
其中显示指定此模块的标签输入的 (名称,形状) 对的列表。 |
output_names |
其中包含此模块输出的名称列表。 |
output_shapes |
其中包含指定此模块的输出的 (名称,形状) 对的列表。 |
output_shapes |
其中包含指定此模块的输出的 (名称,形状) 对的列表。 |
data_shapes - 此处给出的链接 https://mxnet.apache.org 将帮助你更详细地理解属性。
output_shapes - 按照 https://mxnet.apache.org/api 上的链接了解更多详情。
Implementation Examples
在下面的示例中,我们将创建一个 mxnet 模块。
import mxnet as mx
input_data = mx.symbol.Variable('input_data')
f_connected1 = mx.symbol.FullyConnected(data, name='f_connected1', num_hidden=128)
activation_1 = mx.symbol.Activation(f_connected1, name='relu1', act_type="relu")
f_connected2 = mx.symbol.FullyConnected(activation_1, name = 'f_connected2', num_hidden = 64)
activation_2 = mx.symbol.Activation(f_connected2, name='relu2',
act_type="relu")
f_connected3 = mx.symbol.FullyConnected(activation_2, name='fc3', num_hidden=10)
out = mx.symbol.SoftmaxOutput(f_connected3, name = 'softmax')
mod = mx.mod.Module(out)
print(out)
Output
输出如下:
<Symbol softmax>
Example
print(mod)
Output
输出如下所示−
<mxnet.module.module.Module object at 0x00000123A9892F28>
在下例中,我们将实现正向计算
import mxnet as mx
from collections import namedtuple
Batch = namedtuple('Batch', ['data'])
data = mx.sym.Variable('data')
out = data * 2
mod = mx.mod.Module(symbol=out, label_names=None)
mod.bind(data_shapes=[('data', (1, 10))])
mod.init_params()
data1 = [mx.nd.ones((1, 10))]
mod.forward(Batch(data1))
print (mod.get_outputs()[0].asnumpy())
Output
执行以上代码时,应该看到以下输出 −
[[2. 2. 2. 2. 2. 2. 2. 2. 2. 2.]]
Example
data2 = [mx.nd.ones((3, 5))]
mod.forward(Batch(data2))
print (mod.get_outputs()[0].asnumpy())
Output
以下是代码的输出 −
[[2. 2. 2. 2. 2.]
[2. 2. 2. 2. 2.]
[2. 2. 2. 2. 2.]]