我试图得到一个分布式TensorFlow工作的一个非常简单的例子。但是,我有一个在运行之间出现非确定性的错误。在某些运行中,它完美地运行。输出以下内容:
Worker 2 | step 0
Worker 0 | step 0
Worker 1 | step 0
Worker 3 | step 0
Worker 2 | step 1
Worker 0 | step 1
Worker 1 | step 1
Worker 3 | step 1
...
但是,每隔一段时间,一个或多个工作人员就无法运行,导致输出如下:
Worker 0 | step 0
Worker 3 | step 0
Worker 0 | step 1
Worker 3 | step 1
Worker 0 | step 2
Worker 3 | step 2
...
如果我无限期地运行循环,似乎失踪的工人总是在某个时刻启动,但仅仅几分钟后,这是不切实际的。
我发现有两件事情会导致问题消失(但使程序失效):1。不在with tf.device(tf.train.replica_device_setter())
范围内声明任何变量。如果我甚至声明一个变量(例如下面的nasty_var
),问题就会开始出现。 2.为所有工作人员is_chief
设置tf.train.MonitoredTrainingSession()
参数为True
。即使声明了变量,这也会导致bug消失,但是让所有的工作者成为首席执行官似乎是错误的。我目前在下面设置的方式 - is_chief=(task_index == 0)
- 直接来自TensorFlow教程。
这是我可以复制问题的最简单的代码。 (您可能需要多次运行以查看错误,但它几乎总是在5次运行中显示
from multiprocessing import Process
import tensorflow as tf
from time import sleep
from numpy.random import random_sample
cluster = tf.train.ClusterSpec({'ps': ['localhost:2222'],
'worker': ['localhost:2223',
'localhost:2224',
'localhost:2225',
'localhost:2226']})
def create_worker(task_index):
server = tf.train.Server(cluster, job_name='worker', task_index=task_index)
with tf.device(tf.train.replica_device_setter(worker_device="/job:worker/task:%d" % task_index, cluster=cluster)):
nasty_var = tf.Variable(0) # This line causes the problem. No issue when this is commented out.
with tf.train.MonitoredTrainingSession(master=server.target, is_chief=(task_index == 0)):
for step in xrange(10000):
sleep(random_sample()) # Simulate some work being done.
print 'Worker %d | step %d' % (task_index, step)
def create_ps(task_index):
param_server = tf.train.Server(cluster, job_name='ps',
task_index=task_index)
param_server.join()
# Launch workers and ps in separate processes.
processes = []
for i in xrange(len(cluster.as_dict()['worker'])):
print 'Forking worker process ', i
p = Process(target=create_worker, args=[i])
p.start()
processes.append(p)
for i in xrange(len(cluster.as_dict()['ps'])):
print 'Forking ps process ', i
p = Process(target=create_ps, args=[i])
p.start()
processes.append(p)
for p in processes:
p.join()
答案 0 :(得分:5)
我猜这里的原因是tf.train.MonitoredTrainingSession
如何启动的隐式协调协议,实现here:
如果这次会议是主席:
否则(如果本次会议不是主席):
(我在video about Distributed TensorFlow中讨论了该协议的基本原理。)
当每个会话都是主要会话,或者没有要初始化的变量时,tf.train.MonitoredTrainingSession
将始终立即开始。但是,一旦有一个变量,而你只有一个负责人,你会发现非首席工作人员必须等待主管采取行动。
使用此协议的原因在于它对各种进程失败具有鲁棒性,并且与在典型分布式培训作业的预期运行时间相比,在单个进程上运行所有内容时的延迟非常明显。 / p>
查看the implementation again,这个30秒的超时似乎是可配置的(作为tf.train.SessionManager()
的recovery_wait_secs
参数),但目前无法设置此超时当您创建tf.train.MonitoredTrainingSession
时,因为它使用了一组硬编码的参数for creating a session manager。
这似乎是API的疏忽,所以请随时在GitHub issues page上打开功能请求!
答案 1 :(得分:0)
正如mrry所说,问题的存在是因为:
在表现方面,在接下来的30年代等待首席执行官并没有任何区别。但是,我最近正在做一项研究,要求我强制执行严格的同步更新,这个问题需要处理。
此处的关键是使用屏障,具体取决于您的分布式设置。假设你使用thread-1来运行ps,而使用thread-2~5来运行worker,那么你只需要:
sv = tf.train.Supervisor(is_chief = is_chief, LOGDIR = ... init_op = ... ... recovery_wait_secs = 1秒)
sess = sv.prepare_or_wait_for_session(server.target, 配置= sess_config)
主要:
barrier = threading.Barrier(parties=num_workers)
for i in range(num_workers):
threads.append(threading.Thread(target=run_model, args=("worker", i, barrier, )))
threads.append(threading.Thread(target=run_model, args=("ps", 0, barrier, )))
在实际的训练功能中:
_ = sess.run([train_op], feed_dict=train_feed)
barrier.wait()
然后快乐地继续前进。障碍将确保所有模型都达到这一步,并确保没有竞争条件。