Tensorflow是一个流行的开源库,专为数值计算(最常见的训练神经网络)而设计。在该框架中,计算过程通过数据流图进行设计,为改变运算结构和布局提供了极大的灵活性。TensorFlow允许多个worker并行计算,这对于必须通过处理大量训练数据进行训练的神经网络是有益的。此外,如果模型足够大,有时可能需要这种并行化。在这篇文章中,我们探索了TensorFlow的分布式计算机制。TensorFlowComputationalGraph示例数据并行性VS。模型并行性在跨多个计算节点分布神经网络训练时,通常采用两种策略:数据并行性和模型并行性。在前者中,模型的单个实例建立在每个节点上,并提供不同的训练样本;这种架构允许更高的训练吞吐量。相反,在模型并行性中,模型的单个实例分布在多个节点上,这种架构允许训练更大的模型(可能不一定适合单个节点的内存)。如果需要,也可以将这两种策略组合起来,以拥有给定模型的多个实例,每个实例跨越多个节点。在本文中,我们将重点关注数据并行性。不同形式的数据并行和模型并行。左:数据并行;中间:模型并行度;右图:数据并行与模型并行TensorFlow中的数据并行在使用TensorFlow时,数据并行主要表现为两种形式:图内复制(in-graphreplication)和图间复制(between-graphreplication)。两种策略之间最显着的区别是流程图的结构及其结果。1.In-graphreplicationIn-graphreplication通常被认为是两种方法中更简单和更直接(但可扩展性较差)的方法。采用这种策略时,需要在分布式主机上创建一个流程图,其中包含所有工作设备中的副本。可以想象,随着工人数量的增加,这样的图表可能会大幅扩展,这可能会对模型性能产生不利影响。然而,对于小型系统(例如,双GPU台式计算机),图内复制由于其简单性可能是最佳选择。下面是使用单个GPU的基准TensorFlow方法与应用图内复制方法的代码片段的比较。由于与图内复制方法的缩放相关的问题,我们将只考虑单机、多GPU配置的情况。这两个代码片段的区别非常小,它们的区别仅在于:输入数据的分块,使数据在worker之间均匀分布,用worker流程图遍历每个设备,不同worker发送的数据结果是连接的。通过一个小的代码更改,我们可以利用多个设备,这种方法可以减少可扩展性的障碍,从而有利于简单的配置。#singleGPU(baseline)单个GPU(基线)importtensorflowastf#placetheinitialdataonthecpuwithtf.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.]])#用tf.device('/gpu:0'):output=tf.matmul(input_data,b)#createasessionandrunwithtf.Session()assess:sess.run(tf.global_variables_initializer())printsess.run(output)#in-graphreplication图内复制importtensorflowastfnum_gpus=2#placetheinitialdataonthecpuwithtf.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.]])#splitthedataintochunksforeachgpuinputs=tf.split(input_data,num_gpus)outputs=[]#loopoveravailablegpusandpassinputdataforiinrange(num_gpus):withtf.device('/gpu:'+str(i)):outputs.append(tf.matmul(inputs[i],b))#mergetheresultsofthedeviceswithtf。设备('/cpu:0'):输出=tf.concat(输出,轴=0)#createasessionandrunwithtf.Session()评估:sess.run(tf.global_variables_initializer())printsess.run(output)这些变化也可以通过检查下面的TensorFlow流程图来可视化。GPU模块的添加说明了原始方法的扩展方式。图中复制的可视化。左:原始图像。右:生成的图在图中复制。2.图间复制认识到图内复制在扩展上的局限性,图间复制的优势是在使用大量节点时保证模型性能。这是通过在每个worker上创建计算图的副本来实现的,并且不需要主机为每个worker保留该图的副本。这些workergraphs通过一些TensorFlow技巧进行协调——如果两个独立的节点在同一个TensorFlow设备上分配一个同名变量,这些分配将被合并,变量将共享相同的后端存储,因此两个worker将被合并在一起.但是,必须确保设备配置正确。如果两个工人在不同的设备上分配变量,则不会发生合并。为此,TensorFlow提供了replica_device_setter函数。replica_device_setter为变量分配提供了一种确定性的方式,以确保变量在同一设备上,只要每个工作人员以相同的顺序创建计算图。这在下面的代码中进行了演示。由于图间复制在很大程度上复制了原始图,因此大多数相关修改实际上是在集群中节点的配置中。因此,下面的代码片段只会针对这一点进行更改。需要注意的是,这个脚本正常情况下会在集群中的每台机器上执行,只是具体的命令行参数有所不同。让我们逐行检查代码。importsysimporttensorflowastf#specifythecluster'sarchitecturecluster=tf.train.ClusterSpec({'ps':['192.168.1.1:1111'],'worker':['192.168.1.2:1111','192.168.1.3:1111']})#parsecommand-linetospecifymachinejob_type=sys.argv[1]#jobtype:"worker"or"ps"task_idx=sys.argv[2]#indexjobintheworkerorpslist#asdefinedintheClusterSpec#createTensorFlowServer.Thisshowthemachinescommunicate.server=tf.train.Server(集群,job_name=job_type,task_index=task_idx)#parameterserverisupdatedbyremoteclients.#willnotproceedbeyondthisifstatement.ifjob_type=='ps':server.join()else:#workersonlywithtf.device(tf.train.replica_device_setter(worker_device='/job:worker/task:'+task_idx,clustercluster=cluster)):#buildyourmodelhereasifyoonlywereusingasinglemachinewithtf.Session(server.target):#trainyourmodelhere运行分布式TensorFlow的第一步是使用tf.train.ClusterSpec指定集群的架构。节点通常分为两个角色(或“作业”):包含变量的参数服务器(“ps”)和执行繁重计算的“工人”。下面提供了每个节点的IP地址和端口。接下来,脚本必须确定它在网络中的作业类型和索引;这通常是通过将命令行参数传递给脚本并解析它们来完成的。job_type指定节点是否正在运行ps或worker任务,而task_idx指定节点在ps或worker列表中的索引。使用上述变量创建一个TensorFlow服务器以连接到每个设备。接下来,如果节点是参数服务器,它只是加入它们的线程并等待它们终止。虽然似乎没有具体的ps代码,但图形元素实际上是由工作人员推送到ps的。相反,如果设备是一个工作人员,我们将使用replica_device_setter构建我们的模型,以在前面讨论的这些ps服务器之间连续分配参数。这些副本在很大程度上与独立流程图相同。***,我们创建一个tf.Session并训练我们的模型。结论希望这篇文章清楚地解释了与分布式TensorFlow相关的一些术语和技术。在以后的文章中,我们将详细探讨这个主题和其他主题。原文:https://clindatsci.com/blog/2017/5/31/distributed-tensorflow【本文为《机器之心》专栏原文翻译,微信公众号《机器之心》(id:almosthuman2014)"]点此阅读作者更多好文
