Concurrency 在分布式张量流中制造障碍的正确方法是什么?

Concurrency 在分布式张量流中制造障碍的正确方法是什么?,concurrency,tensorflow,Concurrency,Tensorflow,在分布式培训期间,我希望在每个历元之后进行同步,对主工进行一些计算,然后根据这些计算继续或停止培训。我需要一个屏障来做到这一点 我在文档中没有看到任何类似的内容,所以我实现了基于队列的解决方案(类似于梯度在分布式培训中的存储和应用): 其思想是为每个工作人员创建一个队列。对于“signal”,我在每个队列中推送一个令牌,对于“join”,我从相应的队列中取出这么多令牌,我要同步多少任务 问题是:这是正确的方法还是有更好的方法?您的解决方案与。在SyncReplicasOptimizer中,它使用

在分布式培训期间,我希望在每个历元之后进行同步,对主工进行一些计算,然后根据这些计算继续或停止培训。我需要一个屏障来做到这一点

我在文档中没有看到任何类似的内容,所以我实现了基于队列的解决方案(类似于梯度在分布式培训中的存储和应用):

其思想是为每个工作人员创建一个队列。对于“signal”,我在每个队列中推送一个令牌,对于“join”,我从相应的队列中取出这么多令牌,我要同步多少任务


问题是:这是正确的方法还是有更好的方法?

您的解决方案与。在SyncReplicasOptimizer中,它使用一个同步令牌队列来模拟屏障,并为每个变量使用一个累加器来累加和平均梯度更新。这是一个非常典型的批量同步并行,而它还有一个额外的任务,就是在Tensorflow中实现陈旧的同步并行


此外,Tensorflow在最新版本中提供了一个模拟屏障的解决方案,您可以查看该解决方案以了解更多信息。

这里是一个模拟屏障的纯Tensorflow解决方案。请注意使用两个队列,因为tensorflow似乎没有一个适当的解决方案来在分布式会话中原子地增加变量,但是
queue.size()
谢天谢地满足了这一要求:

def tf_barrier(shared_name: str, n_workers: int):
    passing_q = tf.FIFOQueue(n_workers, tf.bool, (), shared_name=shared_name + '_count_q')
    blocking_q = tf.FIFOQueue(n_workers, tf.bool, (), shared_name=shared_name + '_barrier_q')
    increment_size = passing_q.enqueue(True) # Atomically increment queue size
    with tf.control_dependencies([increment_size]):
        incremented_size = passing_q.size()
        return tf.cond(tf.equal(incremented_size, n_workers),
                       lambda: tf.group([blocking_q.enqueue_many([[True] * n_workers]), passing_q.dequeue_many(n_workers)]),
                       lambda: blocking_q.dequeue()
                       )
虽然内部很复杂,但它可以非常简单地使用

with create_session(job.name, task_index) as sess: # Assume 6 workers
    start_barrier = tf_barrier('start', 6)
    sess.run(start_barrier)
    # Every 6th run of start_barrier unblocks the 5 runs before it

SyncReplaces optimizer中有这样一个健壮的实现(即,即使在某些进程死机/重新启动时也能工作)
with create_session(job.name, task_index) as sess: # Assume 6 workers
    start_barrier = tf_barrier('start', 6)
    sess.run(start_barrier)
    # Every 6th run of start_barrier unblocks the 5 runs before it