[toc]html
本目录包括了运行时分布式TensorFlow的实现,其底层使用了gRPC 做为进程内通讯的支持库。node
首先,须要构建一个TensorFlow的服务端可执行版本(grpc_tensorflow_server
) 以及一个基于gRPC的客户端。目前只能基于源代码进行自构建, 可是会包含在将来发布的二进制版本中。可使用以下命令进行构建:python
# CPU-only build. $ bazel build -c opt //tensorflow/core/distributed_runtime/rpc:grpc_tensorflow_server # GPU build. $ bazel build -c opt --config=cuda //tensorflow/core/distributed_runtime/rpc:grpc_tensorflow_server
若是是从最新的源代码建立的Python依赖包,它会自动包含一个基于gRPC的客户端。若是使用的是一个以前发布的二进制版本,须要根据这个安装说明来从新编译安装。在你成功地构建了分布式的TensorFlow组件以后,能够经过以下方式来启动服务器而且判断你的安装是否成功:git
# Start a TensorFlow server as a single-process "cluster". $ bazel-bin/tensorflow/core/distributed_runtime/rpc/grpc_tensorflow_server \ --cluster_spec='local|localhost:2222' --job_name=local --task_index=0 &
而后启动Python的交互器而且启动一个Session:github
$ python >>> import tensorflow as tf >>> c = tf.constant("Hello, distributed TensorFlow!") >>> sess = tf.Session("grpc://localhost:2222") >>> sess.run(c) 'Hello, distributed TensorFlow!'
命令行参数 grpc_tensorflow_server
定义了集群之间的关系. 参数 --cluster_spec
决定了集群中工做对象的多少, 譬若有一系列的 jobs, 而每一个jobs又包含了多个task 终端。 全部集群中的处理过程都必须设置相同的 --cluster_spec
参数, 例子以下:shell
--cluster_spec='...' |
Available tasks | ||
---|---|---|---|
`local\ | localhost:2222` | /job:local/task:0 |
|
`local\ | localhost:2222;localhost:2223` | /job:local/task:0 `/job:local/task:1` |
|
`worker\ | worker0:2222;worker1:2222;worker2:2222,``ps\ | ps0:2222;ps1:2222` | /job:worker/task:0 `/job:worker/task:1/job:worker/task:2 /job:ps/task:0`/job:ps/task:1 |
还有 --job_name
与 --task_index
标志位指明了哪些任务会运行在当前处理过程上。 具体而言,--job_name=local --task_index=0
意思就是该过程会被标志为/job:local/task:0
, 而后全部在该过程上的TensorFlow的设备都会使用这个前缀。api
N.B.
手动来指明这些运行参数多是很是冗长的,特别是对一个大型集群而言。咱们正在研发能够程式化启动的工具,譬如使用一些相似于Kubernetes集群管理器。若是有啥集群管理工具你以为挺好的但愿加入进来,能够在GitHub issue上提出你的建议。服务器
为了将某个操做放在某个特殊的处理过程上,在分布式环境下依然可使用tf.device()
函数,以前是用来指明是放在CPU仍是GPU上的。譬如:网络
with tf.device("/job:ps/task:0"): weights_1 = tf.Variable(...) biases_1 = tf.Variable(...) with tf.device("/job:ps/task:1"): weights_2 = tf.Variable(...) biases_2 = tf.Variable(...) with tf.device("/job:worker/task:7"): input, labels = ... layer_1 = tf.nn.relu(tf.matmul(input, weights_1) + biases_1) logits = tf.nn.relu(tf.matmul(layer_1, weights_2) + biases_2) # ... train_op = ... with tf.Session("grpc://worker7:2222") as sess: for _ in range(10000): sess.run(train_op)
在上面的例子中,Variables在job ps
的两个task上被建立,而后计算密集型的部分建立在job work
上。TensorFlow会自动地在不一样的job之间传输数据。(从job
到work
是前向传递,而从worker
到ps
是梯度应用)。分布式
一个常见的训练配置(数据并行训练)包含了job ps
上共享参数以及job work
上的多个任务来训练相同的模型。每一个task通常会运行在不一样的机器上。如今仍是有不少办法能够在TensorFlow中来实现这一种结构的,咱们将来也会提供更简单的实现方式,主要途径有:
构建单一的包含了一系列参数的图(in tf.Variable
nodes pinned to /job:ps
), 而且建立多个模型的副原本映射到/job:worker
中的不一样tasks。每一个model的副本有一个不一样的train_op
,而且对于每一个worker i
而言一个或者多个的客户端线程能够调用sess.run(train_ops[i])
。这种方法使用了单一的tf.Session
,它的工做目标是集群中的某个workers。
As above, but where the gradients from all workers are averaged. See the
CIFAR-10 multi-GPU trainer
for an example of this form of replication. The implements synchronous training
另外一种分布式训练器的方法使用多张图,一张图对应一个worker,而且每张图都包含了一系列的参数的集合(/job:ps
)和一份模型的赋值。而容器的机制就是在不一样的图之间共享变量:一旦某个变量构造完成,可选的container
参数会由图中每份复制的相同值来决定。对于较大的模型而言,这种方法会更加有效,毕竟整个图更小了一点。
这种方法使用多个tf.Session
对象:每一个worker过程都会包含一个,不过不一样的Session会指向不一样的目标worker。这个tf.Session
对象便可以在单一的Python客户端中建立,也能够在多个客户端中建立。
Client
一个典型的客户端通常会构建一个TensorFlow的图而且使用tensorflow::Session
来完成与集群的交互。客户端通常会用Python或者C++编写,通常来讲一个客户端能够同时与多个服务端进行交互(参考上文的重复训练),而且一个服务端也能够同时服务于多个客户端。
Cluster
一个TensorFlow集群会包含一个或者多个TensorFlow的服务端,被切分为一系列命名的job,而每一个job又会负责一系列的tasks。一个集群通常会专一于一个相对高层的目标,譬如用多台机器并行地训练一个神经网络。
Job
一个job会包含一系列的致力于某个相同目标的task。譬如,一个叫ps
(意思是参数服务)的job会用于处理存储于更新Variables相关的工做。而一个叫worker
的job会用于承载那些用于计算密集型的无状态节点。通常来讲一个job中的tasks会运行在不一样的机器中。
Master service
Master Service是一个RPC服务用于与一系列远端的分布式设备进行交互。Master Service实现了tensorflow::Session
接口, 而且用来协调多个worker service。
Task
一个Task通常会关联到某个单一的TensorFlow服务端的处理过程,属于一个特定的job而且在该job的任务列表中有个惟一的索引。
TensorFlow server
用于运行grpc_tensorflow_server的处理过程,是一个集群中的一员,而且想外暴露了一个Master Service与一个Worker Service。
Worker service一个执行部分TensorFlow图部份内容的RPC服务。