资源 | TensorFlow分布式计算机制解读:以数据并行为重

选自clindatsci

作者:Neil Tenenholtz

机器之心编译

参与:Jane W、黄小天

Tensorflow 是一个为数值计算(最常见的是训练神经网络)设计的流行开源库。在这个框架中,计算流程通过数据流程图(data flow graph)设计,这为更改操作结构与安置提供了很大灵活性。TensorFlow 允许多个 worker 并行计算,这对必须通过处理的大量训练数据训练的神经网络是有益的。此外,如果模型足够大,这种并行化有时可能是必须的。在本文中,我们将探讨 TensorFlow 的分布式计算机制。

TensorFlow 计算图示例

数据并行 VS. 模型并行

当在多个计算节点间分配神经网络训练时,通常采用两种策略:数据并行和模型并行。在前者中,在每个节点上单独创建模型的实例,并馈送不同的训练样本;这种架构允许更高的训练吞吐量。相反,在模型并行中,模型的单一实例在多个节点间分配,这种架构允许训练更大的模型(可能不一定适合单节点的存储器)。如果需要,也可以组合这两种策略,使给定模型拥有多个实例,每个实例跨越多个节点。在本文中,我们将重点关注数据并行。

数据并行与模型并行的不同形式。左:数据并行;中:模型并行;右:数据并行与模型并行。

TensorFlow 中的数据并行

当使用 TensorFlow 时,数据并行主要表现为两种形式:图内复制(in-graph replication)和图间复制(between-graph replication)。两种策略之间最显著的区别在于流程图的结构与其结果。

图内复制

图内复制通常被认为是两种方法中更简单和更直接(但更不可扩展的)的方法。当采用这种策略时,需要在分布式的主机上创建一个包含所有 worker 设备中副本的流程图。可以想象,随着 worker 数量的增长,这样的流程图可能会大幅扩展,这可能会对模型性能产生不利影响。然而,对于小系统(例如,双 GPU 台式计算机),由于其简单性,图内复制可能是最优的。

以下是使用单个 GPU 的基线 TensorFlow 方法与应用图内复制方法的代码片段的对比。考虑到图内复制方法与扩展(scaling)相关的问题,我们将仅考虑单机、多 GPU 配置的情况。这两个代码片段之间的差异非常小,它们的差异仅存在于:对输入数据的分块,使得数据在各 worker 间均匀分配,遍历每个含有 worker 流程图的设备,并将来自不同 worker 的结果连接起来。通过少量代码更改,我们可以利用多个设备,这种方法使可扩展性不再成为大障碍,从而在简单配置下更受欢迎。

# single GPU (baseline) 单个 GPU(基线) import tensorflow as tf # place the initial data on the cpu with tf.device('/cpu:0'): input_data = tf.Variable([[1., 2., 3.],[4., 5., 6.],[7., 8., 9.],[10., 11., 12.]]) b = tf.Variable([[1.], [1.], [2.]])# compute the result on the 0th gpuwith tf.device('/gpu:0'): output = tf.matmul(input_data, b)# create a session and runwith tf.Session() as sess: sess.run(tf.global_variables_initializer())print sess.run(output)

# in-graph replication 图内复制 import tensorflow as tf num_gpus = 2 # place the initial data on the cpu with tf.device('/cpu:0'): input_data = tf.Variable([[1., 2., 3.],[4., 5., 6.],[7., 8., 9.],[10., 11., 12.]]) b = tf.Variable([[1.], [1.], [2.]])# split the data into chunks for each gpu inputs = tf.split(input_data, num_gpus) outputs = []# loop over available gpus and pass input datafor i in range(num_gpus):with tf.device('/gpu:'+str(i)): outputs.append(tf.matmul(inputs[i], b))# merge the results of the deviceswith tf.device('/cpu:0'): output = tf.concat(outputs, axis=0)# create a session and runwith tf.Session() as sess: sess.run(tf.global_variables_initializer())print sess.run(output)

这些更改也可以通过检查下面的 TensorFlow 流程图来可视化。增加的 GPU 模块说明了原始方法的扩展方式。

图内复制的可视化。左:原始图。右:图内复制的结果图。

图间复制

认识到图内复制在扩展上的局限性,图间复制的优势在于运用大量节点时保证模型性能。这是通过在每个 worker 上创建计算图的副本来实现的,并且不需要主机保存每个 worker 的图副本。通过一些 TensorFlow 技巧来协调这些 worker 的图——如果两个单独的节点在同一个 TensorFlow 设备上分配一个具有相同名称的变量,则这些分配将被合并,变量将共享相同的后端存储,从而这两个 worker 将合并在一起。

但是,必须确保设备的正确配置。如果两个 worker 在不同的设备上分配变量,则不会发生合并。对此,TensorFlow 提供了 replica_device_setter 函数。只要每个 worker 以相同的顺序创建计算图,replica_device_setter 为变量分配提供了确定的方法,确保变量在同一设备上。这将在下面的代码中演示。

由于图间复制在很大程度上重复了原始图,因此多数相关的修改实际上都在集群中节点的配置上。因此,下面的代码段将只针对这一点进行改动。重要的是要注意,这个脚本通常会在集群中的每台机器上执行,但具体的命令行参数不同。下面来逐行研究代码。

import sysimport tensorflow as tf # specify the cluster's architecture cluster = tf.train.ClusterSpec({'ps': ['192.168.1.1:1111'],'worker': ['192.168.1.2:1111','192.168.1.3:1111']})# parse command-line to specify machine job_type = sys.argv[1] # job type: "worker" or "ps" task_idx = sys.argv[2] # index job in the worker or ps list# as defined in the ClusterSpec# create TensorFlow Server. This is how the machines communicate. server = tf.train.Server(cluster, job_name=job_type, task_index=task_idx)# parameter server is updated by remote clients.# will not proceed beyond this if statement.if job_type == 'ps': server.join()else:# workers onlywith tf.device(tf.train.replica_device_setter( worker_device='/job:worker/task:'+task_idx, cluster=cluster)):# build your model here as if you only were using a single machinewith tf.Session(server.target):# train your model here

运行分布式 TensorFlow 的第一步是使用 tf.train.ClusterSpec 来指定集群的架构。节点通常分为两个角色(或「job」):含有变量的参数服务器(「ps」)和执行大量计算的「worker」。下面提供每个节点的 IP 地址和端口。接下来,脚本必须确定其 job 类型和在网络中的索引;这通常是通过将命令行参数传递给脚本并解析来实现的。job_type 指定节点是运行 ps 还是 worker 任务,而 task_idx 指定节点在 ps 或 worker 列表中的索引。使用以上变量创建 TensorFlow 服务器,用于连接各设备。

接下来,如果节点是参数服务器,它只连接它们的线程并等待它们终止。虽然似乎没有特定的 ps 代码,但图元素实际上是由 worker 推送到 ps 的。

相反,如果设备是 worker,则使用 replica_device_setter 构建我们的模型,以便在前面讨论的这些 ps 服务器上连续分配参数。这些副本将在很大程度上与单机的流程图相同。最后,我们创建一个 tf.Session 并训练我们的模型。

总结

希望本文清楚地阐述了与分布式 TensorFlow 相关的一些术语和技术。在以后的文章中,我们将详细探讨与此相关及其它的主题。

原文链接:https://clindatsci.com/blog/2017/5/31/distributed-tensorflow

本文为机器之心编译,转载请联系本公众号获得授权。

原文发布于微信公众号 - 机器之心(almosthuman2014)

原文发表时间:2017-06-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏深度学习那些事儿

pytorch中读取模型权重数据、保存数据方法总结

pytorch中保存数据策略在长时间的深度训练中有很大的作用,我们可以通过保存训练好的权重,然后等到下次使用的时候再取出来。另外我们也可以通过迁移学习使用别人训...

9K80
来自专栏人工智能LeadAI

TensorFlow分布式全套(原理,部署,实例)

TF的实现分为了单机实现和分布式实现,在分布式实现中,需要实现的是对client,master,worker process不在同一台机器上时的支持。数据量很大...

1.1K60
来自专栏AI研习社

一个应用于物体识别的迁移学习工具链

迁移学习指的是,通过对预训练模型的参数进行微调,将训练好的模型应用到相似或者只有细微差异的不同任务中。通过这个方法,我们可以基于一些性能顶尖的深度学习模型得到别...

14720
来自专栏专知

【干货】快速上手图像识别:用TensorFlow API实现图像分类实例

【导读】1月17日,Arduino社区的编辑SAGAR SHARMA发布一篇基于TensorFlow API的图像识别实例教程。作者通过TensorFlow A...

99770
来自专栏祝威廉

MLSQL如何支持部署SKLearn,Tensorflow,MLLib模型提供API预测服务

部署成API服务时,除了要把raw数据特征化成向量外,研发还要想着怎么加载模型,产生模型的框架五花八门,比如Tensorflow,SKlearn,Spark M...

15540
来自专栏人工智能

基于自制数据集的MobileNet-SSD模型训练

“本文主要内容:基于自制的仿VOC数据集,利用caffe框架下的MobileNet-SSD模型训练。” 本文的base是https://github.com/c...

3.5K100
来自专栏深度学习思考者

Caffe for windows 训练minst和cifar-10

前言 今天刚看了看Theano,本来打算试着改改,再深入学习学习(这就是所谓的深度学习啊,亲们!哈哈)。由于扣扣好友在训练CIFAR-10数据集,所以就在昨天配...

28160
来自专栏MelonTeam专栏

Windows下Tensorflow的环境安装和Hello world

导语 深度学习 数字识别 Tensorflow 环境搭建 本人对深度学习是0基础,python也是没有用过,最近很流行深度学习,因此也想学习一下,...

26850
来自专栏ATYUN订阅号

Machine Box创始人教你快速建立一个ML图像分类器

AiTechYun 编辑:Yining Machine Box的创始人Mat Ryer在medium上分享了一篇博文,意在教你在硬盘上快速的建立一个机器学习图像...

37260
来自专栏芋道源码1024

Dubbo 源码解析 —— LoadBalance

前言 终于到了集群容错中的最后一个关键词,也就是 LoadBalance(负载均衡),负载均衡必然会涉及一些算法.但是也不用太担心,算法这个词虽然高大上,但是算...

41040

扫码关注云+社区

领取腾讯云代金券