加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

如何在多系统和网络拓扑中构建高性能模型?

发布时间:2018-04-04 03:38:42 所属栏目:大数据 来源:站长网
导读:这个文档和附带的脚本详细介绍了如何构建针对各种系统和网络拓扑的高性能可拓展模型。这个技术在本文档中用了一些低级的 Tensorflow Python 基元。在未来,这些技术将被并入高级 API。 输入管道 性能指南阐述了如何诊断输入管道可能存在的问题及其最佳解决
副标题[/!--empirenews.page--]

这个文档和附带的脚本详细介绍了如何构建针对各种系统和网络拓扑的高性能可拓展模型。这个技术在本文档中用了一些低级的 Tensorflow Python 基元。在未来,这些技术将被并入高级 API。

输入管道

性能指南阐述了如何诊断输入管道可能存在的问题及其最佳解决方法。在使用大量输入和每秒更高的采样处理中我们发现 tf.FIFOQueue 和 tf.train.queue_runner 无法使用当前多个 GPU 生成饱和,例如在使用 AlexNet 训练 ImageNet 时。这是因为使用了 Python 线程作为底层实现,而 Python 线程的开销太大了。

我们在脚本中采用的另一种方法是通过 Tensorflow 中的本机并行构建输入管道。我们的方法主要由如下 3 个阶段组成:

I/O 读取:从磁盘中选择和读取图像文件。 图像处理:将图像记录解码为像素、预处理并生成最小批量。 CPU 到 GPU 的数据传输:将图像从 CPU 传输至 GPU。

通过利用 data_flow_ops.StagingArea,每个阶段的主要部分与其他阶段并行执行。StagingArea 是一个像队列(queue)一样且类似于 tf.FIFOQueue 的运算符。不同之处在于 StagingArea 提供了更简单的功能且可在 CPU 和 GPU 中与其他阶段并行执行。将输入管道拆分为 3 个独立并行操作的阶段,并且这是可扩展的,充分利用大型的多核环境。本节的余下部分将详细介绍每个阶段以及 data_flow_ops.StagingArea 的使用细节。

并行 I/O 读取

data_flow_ops.RecordInput 用于磁盘的并行读取。给定一个代表 TFRecords 的输入文件列表,RecordInput 可使用后台线程连续读取记录。这些记录被放置在大型的内部池中,当这个池加载量达到其容量的一半时,会有相应的张量输出。这个操作有其内部线程,线程由占用最少的 CPU 资源的 I/O 时间主导,这就允许它可与模型的其余部分并行运行。

并行图像处理

从 RecordInput 读取图像后,它们作为张量被传递至图像处理管道。为了更方便解释图像处理管道,假设输入管道的目标是 8 个批量大小为 256(每个 GPU 32 个)GPU。256 个图像记录的读取和处理是独立并行的。从图中 256 个 RecordInput 读操作开始,每个读取操作后都有一个与之相匹配的图像预处理操作,这些操作是彼此独立和并行执行的。这些图像预处理操作包括诸如图像解码、失真和调整大小。

当图像通过预处理器后,它们被联接成 8 个大小为 32 的张量。为了达到这一目的,使用了 tf.parallel_stack,而不是 tf.concat ,目的作为单一操作被实现,且在将它们联结在一起之前需要所有输入准备就绪。tf.parallel_stack 将未初始化的张量作为输出,并且在有张量输入时,每个输入的张量被写入输出张量的指定部分。

当所有的张量完成输入时,输出张量在图中传递。这有效隐藏了由于产生所有输入张量的长尾(long tail)而导致的内存延迟。

并行从 CPU 到 GPU 的数据传输

继续假设目标是批量大小为 256(每个 GPU 32 个)8 个 GPU,一旦输入图像被处理完并被 CPU 联接后,我们将得到 8 个批量大小为 32 的张量。Tensorflow 可以使一个设备的张量直接用在任何其他设备上。为使张量在任何设备中可用,Tensorflow 插入了隐式副本。在张量被实际使用之前,会在设备之间调度副本运行。一旦副本无法按时完成运行,需要这些张量的计算将会停止并且导致性能下降。

在此实现中,data_flow_ops.StagingArea 用于明确排定并行副本。最终的结果是当 GPU 上的计算开始时,所有张量已可用。

软件管道

由于所有的阶段都可以在不同的处理器下运行,在它们之间使用 data_flow_ops.StagingArea 可使其并行运行。StagingArea 是一个与 tf.FIFOQueue  相似且像队列(queue)一样的运算符,tf.FIFOQueue  提供更简单的功能可在 CPU 和 GPU 中被执行。

在模型开始运行所有的阶段之前,输入管道阶段将被预热,以将其间的分段缓存区置于一组数据之间。在每个运行阶段中,开始时从分段缓冲区中读取一组数据,并在最后将该组数据推送。

例如有 A、B、C 三个阶段,这之间就有两个分段区域 S1 和 S2。在预热时,我们运行:

预热结束之后,S1 和 S2 各有一组数据。对于实际执行的每个步骤,会计算一组来自分段区域的数据,同时分段区域会添加一组新数据。

此方案的好处是:

所有的阶段都是非阻塞的,因为预热后分段区域总会有一组数据存在。 每个阶段都可以并行处理,因为它们可以立即启动。 分段缓存区具有固定的内存开销,并至多有一组额外的数据。 运行一个步骤的所有阶段只需要调用 singlesession.run(),这使得分析和调试更加容易。 构建高性能模型的最佳实践

以下收集的是一些额外的最佳实践,可以改善模型性能,增加模型灵活性。

使用 NHWC 和 NCHW 建模

CNN 使用的绝大多数 Tensorflow 操作都支持 NHWC 和 NCHW 数据格式。在 GPU 中,NCHW 更快;但是在 CPU 中,NHWC 只是偶尔更快。

构建一个支持日期格式的模型可增加其灵活性,能够在任何平台上良好运行。基准脚本是为了支持 NCHW 和 NHWC 而编写的。使用 GPU 训练模型时会经常用到 NCHW。NHWC 在 CPU 中有时速度更快。在 GPU 中可以使用 NCHW 对一个灵活的模型进行训练,在 CPU 中使用 NHWC 进行推理,并从训练中获得合适的权重参数。

使用融合的批处理归一化

Tensorflow 中默认的批处理归一化被实现为复合操作,这是很通用的做法,但是其性能不好。融合的批处理归一化是一种替代选择,其在 GPU 中能取得更好的性能。如下是用 tf.contrib.layers.batch_norm 实现融合批处理归一化的一个实例:

训练期间,训练的变量值通过聚合的梯度和增量进行更新。在基准脚本中,展示了通过使用灵活和通用的 Tensorflow 原语,我们可以构建各种各样的高性能分布和聚合方案。

在基准脚本中包括 3 个变量分布和聚合的例子:

参数服务器,训练模型的每个副本都从参数服务器中读取变量并独立更新变量。当每个模型需要变量时,它们将被复制到由 Tensorflow 运行时添加的标准隐式副本中。示例脚本介绍了使用此方法如何进行本地训练、分布式同步训练和分布式异步训练。 拷贝,在每个 GPU 上放置每个训练变量相同的副本,在变量数据立即可用时,正向计算和反向计算立即开始。所有 GPU 中的梯度都会被累加,累加的总和应用于每个 GPU 变量副本,以使其保持同步。 分布式复制,将每个 GPU 中的训练参数副本与参数服务器上的主副本放置在一起,在变量数据可用时,正向计算和反向计算立即开始。一台服务器上每个 GPU 的梯度会被累加,然后每个服务器中聚合的梯度会被应用到主副本中。当所有的模块都执行此操作后,每个模块都将从主副本中更新变量副本。

以下是有关每种方法的其他细节。

参数服务器变量

在 Tensorflow 模型中管理变量的最常见方式是参数服务器模式。

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读