65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Intel® Nervana™ 技术、neon 和 Pachyderm 进行分布式、Docker 化深度学习

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2017 年 4 月 19 日

CPOL

12分钟阅读

viewsIcon

6532

在本帖中,我们将展示如何使用 Intel® Nervana™ 技术、neon 和 Pachyderm 设置一个生产就绪的机器学习工作流。

机器学习和人工智能的最新进展令人惊叹!似乎每天都有突破性的进展,从自动驾驶汽车到学习复杂游戏的 AI。然而,为了在公司内产生真正的价值,数据科学家必须能够将他们的模型从笔记本电脑转移到公司的生产数据管道和基础设施中。

此外,数据科学家应该将时间花在改进他们的机器学习应用程序上。他们不应该花费大量时间手动更新应用程序以适应不断变化的产品数据。他们也不应该浪费时间试图追溯性地识别和跟踪过去有趣的活动。

Docker*Pachyderm* 可以帮助数据科学家在生产集群上构建、部署和更新机器学习应用程序,跨大型数据集进行分布式处理,并跟踪数据管道中的输入和输出数据。在本帖中,我们将展示如何使用 Intel® Nervana™ 技术、neon* 和 Pachyderm 设置一个生产就绪的机器学习工作流。

Intel® Nervana™ 技术和 neon*

Intel Nervana 技术与 neon 是“世界上最快的深度学习框架”。它是开源的(参见 GitHub*),基于 Python*,并包含一组非常好的库用于开发深度学习模型。

您可以通过查看 neon 文档 本地安装 neon 来开始开发。

git clone https://github.com/NervanaSystems/neon.git
cd neon; make

然后,您就可以尝试 一些示例了。

Pachyderm*

Pachyderm 是一个开源框架,它提供基于容器(特别是 Docker 容器)的数据版本控制和数据管道。使用 Pachyderm,您可以创建语言无关的数据管道,其中管道每个阶段的数据输入和输出在 Pachyderm 中进行版本控制;可以将其想象成数据版的 Git。您可以查看数据的差异,并使用 Pachyderm 的提交和分支与团队成员协作。此外,如果您的数据管道产生意外结果,您可以通过了解导致结果的历史处理步骤(甚至精确地重现它们)来调试或验证它。

Pachyderm 还可以通过只将部分数据提供给 Pachyderm 管道中每个容器来轻松并行化您的计算。单个节点要么看到文件的某个切片(映射作业),要么看到一个完整的文件(归约作业)。数据本身可以存储在您选择的对象存储中(例如 S3),Pachyderm 会智能地将不同的数据块分配给不同的容器进行处理。

Pachyderm 集群可以在任何云上运行,但您也可以在本地尝试 Pachyderm。安装 Pachyderm CLI 工具 Pachctl,并安装和运行 Minikube* 后,可以通过一个命令 在本地安装 Pachyderm。

pachctl deploy local

使用 Docker的 neon

为了在生产 Pachyderm 集群中使用 Neon(或只是为了轻松部署它),我们需要能够将 Neon Docker。Docker 允许我们将机器学习应用程序打包成一个可移植的映像,我们可以在任何安装了 Docker 的系统上将其作为容器 运行。因此,它使我们的机器学习应用程序具有可移植性。

幸运的是,neon 已经有 公开可用的 Docker 映像,所以让我们看看这个映像是如何工作的。假设您已 安装了 Docker 并且只使用 CPU,您可以通过拉取以下映像(该映像得到 neon 团队的认可)来获取 Docker的 neon:

docker pull kaixhin/neon

然后,要在 Docker 中交互式地尝试 neon,您可以运行:

docker run -it kaixhin/neon /bin/bash

这将打开一个运行中的 neon 映像(或容器)的 bash shell,您可以在其中创建和运行使用 neon 的 Python 程序。您还可以导航到 Neon 的 `examples` 目录,在 Docker 中运行 neon 示例模型。

但是,假设我们已经有一个名为 `mymodel.py` 的 Python 程序,它使用了 neon,并且我们想在 Docker 中运行该程序。我们想创建一个包含我们程序的自定义 Docker 映像。要做到这一点,您只需创建一个名为 `Dockerfile` 的文件,该文件与您的 `mymodel.py` 脚本位于同一目录。

my_project_directory
├── mymodel.py
└── Dockerfile

这个 `Dockerfile` 将告诉 Docker 如何构建一个包含 neon 和我们自定义的基于 neon 的脚本的自定义映像。对于 `mymodel.py` 只使用 Neon 和 Python 标准库的情况,`Dockerfile` 可以简单地是:

FROM kaixhin/neon
ADD mymodel.py /

然后,要构建您的自定义 Docker 映像,请运行:

docker build -t mycustomimage .

从您的项目根目录执行。然后可以使用生成的映像在任何运行 Docker 的机器上运行您的 neon 模型,只需运行:

docker run -it mycustomimage python /mymodel.py

在生产集群上分发 Docker的 neon

如上所述运行 Docker的 neon 对于可移植性来说非常棒,但我们不一定想手动登录到生产机器来部署单个模型实例。我们希望将 neon 模型集成到一个在生产集群上运行的分布式数据管道中,并确保我们的模型能够扩展到处理大型数据集。这就是 Pachyderm 可以帮助我们的地方。

我们将把模型训练和推理都实现到一个可持续的、生产就绪的数据管道中。为了说明这个过程,我们将使用一个示例 LSTM 模型,该模型根据来自 IMDB 的训练数据集来预测电影评论的情感。有关该模型的更多信息

培训

Pachyderm 允许我们使用 Docker 容器作为处理阶段来创建数据管道。这些容器化处理阶段以数据存储库 中的版本化数据作为输入,并将输出到相应的的数据存储库。因此,每个处理阶段的输入/输出数据都在 Pachyderm 中进行版本控制。

我们将设置其中一个管道阶段来执行我们 LSTM 模型的训练。这个模型管道阶段将以标记的训练数据集 `labeledTrainData.tsv` 作为输入,并以模型参数 `imdb.p` 和模型词汇表 `imdb.vocab` 的形式输出持久化(或保存到磁盘)的模型版本。该阶段的实际处理将使用 一个 Python 脚本 `train.py`,并且该脚本已包含在 公共 kaixhin/neon Docker 映像 中。

Figure 1

要创建上述管道,我们首先需要创建将作为我们模型 管道阶段输入的训练 数据存储库:

pachctl create-repo training

然后我们可以通过以下方式确认存储库已创建:

pachctl list-repo

接下来,我们可以创建模型 管道阶段来处理训练存储库中的数据。为此,我们只需向 Pachyderm 提供一个 JSON 管道规范 ,告知 Pachyderm 如何处理数据。在这种情况下,JSON 规范如下所示:

{
  "pipeline": {
    "name": "model"
  },
  "transform": {
    "image": "kaixhin/neon",
    "cmd": [ 
	"python", 
	"examples/imdb/train.py", 
	"-f", 
	"/pfs/training/labeledTrainData.tsv", 
	"-e", 
	"2", 
	"-eval", 
	"1", 
	"-s", 
	"/pfs/out/imdb.p", 
	"--vocab_file", 
	"/pfs/out/imdb.vocab" 
    ]
  },
  "inputs": [
    {
      "repo": {
        "name": "training"
      },
      "glob": "/"
    }
  ]
}

这看起来可能很复杂,但它实际上只说明了几点:(1)创建一个名为model 的管道阶段,(2)为此管道阶段使用kaixhin/neon Docker 映像,(3)运行提供的 Python cmd 来处理数据,以及(4)处理输入存储库training 中的任何数据。还有其他选项,我们将暂时忽略它们,但所有这些字段都在 Pachyderm 文档 中进行了讨论。

一旦我们有了这个 JSON 文件(保存在 `train.json` 中),在生产就绪的 Pachyderm 集群上创建上述管道就如同运行:

pachctl create-pipeline -f train.json

现在,Pachyderm 知道它应该执行上述处理,在我们的例子中是训练training 存储库中的 neon 模型。事实上,由于 Pachyderm 会对数据进行版本控制,并且知道哪些数据是新的,Pachyderm 将会使我们的模型输出(在 Pachyderm 创建的相应model 存储库中进行版本控制)与我们训练数据的最新更新保持同步。当我们向训练存储库提交新的训练数据时,Pachyderm 将自动更新我们在模型存储库中持久化的、训练好的模型。

但是,我们还没有向训练存储库中添加任何数据,所以让我们继续这样做。具体来说,让我们将文件 `labeledTrainData.tsv` 放入训练存储库的master 分支(同样具有类似 Git 的语义)。

pachctl put-file training master labeledTrainData.tsv -c -f labeledTrainData.tsv

现在,当您运行 `pachctl list-repo` 时,您将看到数据已添加到训练存储库。此外,如果您运行 `pachctl list-job`,您将看到 Pachyderm 已启动一个作业来处理训练数据并将我们持久化的模型输出到模型存储库。一旦该作业完成,我们就完成了模型的训练。我们可以随时通过将新的训练数据推送到训练存储库或更新管道以使用模型管道阶段的新映像来重新训练我们的生产模型。

为了确认我们的模型已训练好,您应该在 Pachyderm 为该管道阶段创建的输出数据存储库中看到 `imdb.p` 和 `imdb.vocab`:

pachctl list-file model master

请注意,我们实际上是通过将文件保存到 Pachyderm 的特殊 `/pfs/out` 目录来告诉 Pachyderm 要写入此存储库的内容,该目录指定了与我们处理阶段相对应的输出存储库。

预测/推理

接下来,我们希望在我们的生产管道中添加一个推理阶段,该阶段将利用我们版本化、持久化的模型。这个推理阶段将接收新的电影评论(模型尚未见过)作为输入,并使用我们持久化的模型输出这些电影评论的推断情感。这次推理将再次运行一个 Python 脚本 `auto_inference.py`,该脚本使用了 neon。

Figure 2

要创建这个推理管道阶段,我们首先需要创建将存储和版本化输入reviews 的 Pachyderm 存储库:

pachctl create-repo reviews

然后我们可以创建另一个 JSON 块,它将告诉 Pachyderm 如何执行推理阶段的处理:

{
  "pipeline": {
    "name": "inference"
  },
  "transform": {
    "image": "dwhitena/neon-inference",
    "cmd": [ 
	"python",
	"examples/imdb/auto_inference.py",
	"--model_weights",
	"/pfs/model/imdb.p",
	"--vocab_file",
	"/pfs/model/imdb.vocab",
	"--review_files",
	"/pfs/reviews",
	"--output_dir",
	"/pfs/out"
    ]
  },
  "parallelism_spec": {
    "strategy": "CONSTANT",
    "constant": "1"
  },
  "inputs": [
    {
      "repo": {
        "name": "reviews"
      },
      "glob": "/*"
    },
    {
      "repo": {
	"name": "model"
      },
      "glob": "/"
    }
  ]
}

这与我们上次的 JSON 规范类似,只是在这种情况下,我们有两个输入存储库(reviews model ),并且我们正在使用一个包含 `auto_inference.py` 的不同 Docker 映像。该映像的 Dockerfile 可以在 这里 找到。

要创建推理阶段,我们只需运行:

pachctl create-pipeline -f infer.json

现在,每当有新评论被推送到reviews 存储库时,Pachyderm 都会看到这些新评论,执行推理,并将推断结果输出到相应的inference 存储库。

事实上,假设我们已经将一百万条评论推送到 reviews 存储库。如果我们再向该存储库推送一条评论,Pachyderm 会知道只有这一条评论是新的,并且只会更新这一条新评论的结果。无需再次处理我们所有的数据,因为 Pachyderm 了解差异 并使我们的处理与最新数据更改保持同步。

我们的推理管道实际上既可以作为批量推理管道,也可以作为流式推理管道。您可以定期将多条评论推送到 reviews 存储库以对这些评论批次执行批量推理。但是,您也可以在创建时流式传输单个评论到存储库。无论哪种方式,Pachyderm 都会自动对新评论执行推理并将结果输出。

影响

通过将我们的训练和推理合并到一个处理版本化数据的管道中,我们已经为利用一些非常有价值的功能做好了准备。在任何时候,数据科学家或工程师都可以更新模型使用的训练数据集,以触发在我们模型存储库中创建新持久化的、版本化的模型。当模型更新时,任何进入reviews 存储库的新评论都将使用更新后的模型进行处理。

此外,旧的预测可以使用更新后的模型重新计算,或者可以使用前一个版本化的输入来测试新模型。告别手动更新历史结果或担心如何在生产环境中替换模型!

此外,尽管我们上面跳过了它,但我们 Pachyderm 管道中的每个管道阶段都可以通过并行度规范 单独扩展。如果我们突然一次收到数万条评论,我们可以通过设置以下命令来调整我们推理管道阶段的并行度:

  "parallelism_spec": {
    "strategy": "CONSTANT",
    "constant": "10"
  }

或者将我们的constant 设置为任何大于一的数字。这将告诉 Pachyderm 启动多个工作进程来执行我们的推理(以上面的例子为例,是 10 个),Pachyderm 会自动将我们的评论数据分配给工作进程进行并行处理。

Figure 3

我们可以专注于开发和改进我们的建模,让 Pachyderm 负责在生产集群上分发我们的推理。这还可以使我们的实现保持简单和易读。我们可以将我们在本地机器上开发的 Python/neon 脚本扩展到生产级数据,而无需考虑数据分片、使用 Dask* 等框架使代码复杂化,甚至无需将建模转移到另一种语言或框架以供生产使用。

优化

尽管 Pachyderm 为我们处理了数据分片、并行度和编排部分,但我们还可以利用该管道中的一些不错的优化。

首先,我们的训练和推理阶段都在运行导入 Neon 的 Python。因此,我们可以通过使用 Intel® Distribution for Python* 来进一步优化我们的处理,而无需更改一行代码。它会自动将强大的 Intel® Math Kernel Library (Intel® MKL)、Intel® Data Analytics Acceleration Library (Intel® DAAL) 和 pyDAAL、Intel® MPI Library 以及 Intel® Threading Building Blocks (Intel® TBB) 集成到核心 Python 包中,包括 NumPy*、SciPy* 和 pandas*。

事实上,要在 Pachyderm 中利用 Intel 优化的 Python,我们可以简单地将当前的 Neon 映像替换为基于其中一个公开的 Intel Python 映像 的自定义 Docker 映像。一个此类映像的示例可以 一个 Dockerfile 构建。我们只需向映像添加一个我们选择的 Python 脚本(如 此处 所示),将映像上传到 DockerHub (或其他注册表),然后更改 Pachyderm 管道规范中引用的映像名称。

此外,我们可以选择将我们的管道部署在 Intel® Xeon Phi™ 处理器 架构上,这将自动为我们的机器学习工作流带来更大的提升。这些芯片针对深度学习训练和推理中涉及的处理类型进行了进一步优化。

结论/资源

我们能够将 neon 中一个快速的深度学习实现部署到生产集群。我们还能够在不担心代码中的数据分片和并行化的情况下,在集群上分发处理。我们的生产管道将跟踪模型的版本,并使我们的处理与数据更新保持同步。

上面数据管道的所有代码和配置都可以在 此处 找到。

Pachyderm 资源

Intel Nervana 技术与 Neon 资源

关于作者

Daniel (@dwhitena) 是一位拥有博士学位的训练有素的数据科学家,与 Pachyderm (@pachydermIO) 合作。Daniel 开发创新的分布式数据管道,包括预测模型、数据可视化、统计分析等。他曾在世界各地的会议上发表演讲(ODSC、Spark Summit、Datapalooza、DevFest Siberia、GopherCon 等),通过 Ardan Labs (@ardanlabs) 教授数据科学/工程,维护 Jupyter 的 Go 内核,并积极帮助组织对各种开源数据科学项目的贡献。

© . All rights reserved.