【问题标题】:What exactly happens when we call IterativeProcess.next on federated training data?当我们在联邦训练数据上调用 IterativeProcess.next 时究竟会发生什么?
【发布时间】:2020-07-22 21:30:49
【问题描述】:

我完成了联邦学习教程。我想知道当我们在迭代过程中调用 .next 函数时它是如何工作的。 假设我们有训练数据,它是一个列表列表。外部列表是客户端列表,内部列表是每个客户端的数据批次。然后,我们创建一个迭代过程,例如,一个联合平均过程并初始化状态。 当我们在这个训练数据上调用 IterativeProcess.next 时究竟会发生什么。是否在每一轮中随机抽取这些数据?还是一次只从每个客户端获取数据?

假设我有一个 tf.data.Datasets 列表,每个都代表一个客户端数据。如何从该列表中为下一次联邦学习迭代添加一些随机性?

我的数据集不一定长度相同。当其中一个完全迭代时,这个数据集是否等待所有其他数据集完全迭代它们的数据?

【问题讨论】:

    标签: tensorflow-federated


    【解决方案1】:

    (迭代过程)是否在每一轮中随机抽取这些数据?还是一次只从每个客户端获取一批数据?

    TFF 教程都使用 tff.learning.build_federated_averaging_process,它构造了一个实现联合平均算法 (McMahan et al. 2017) 的 tff.templates.IterativeProcess。在此算法中,每个“轮次”(IterativePocess.next() 的一次调用)在每个客户端上处理与 tf.data.Dataset 设置为在一次迭代中生成一样多的示例批次。 tf.data: Build TensorFlow input pipelinestf.data.Dataset 的绝佳指南。

    处理示例的顺序取决于作为参数传递给next() 方法的tf.data.Datasets 的构造方式。例如,在 Federated Learning for Text Generation 教程的标题为 Load and Preprocess the Federated Shakespeare Data 的部分中,每个客户端数据集都设置了预处理管道:

    def preprocess(dataset):
      return (
          # Map ASCII chars to int64 indexes using the vocab
          dataset.map(to_ids)
          # Split into individual chars
          .unbatch()
          # Form example sequences of SEQ_LENGTH +1
          .batch(SEQ_LENGTH + 1, drop_remainder=True)
          # Shuffle and form minibatches
          .shuffle(BUFFER_SIZE).batch(BATCH_SIZE, drop_remainder=True)
          # And finally split into (input, target) tuples,
          # each of length SEQ_LENGTH.
          .map(split_input_target))
    

    下一个函数将在每次调用next() 时完整地遍历这些数据集,在这种情况下,由于没有调用tf.data.Dataset.repeat()next() 将让每个客户端查看其所有示例一次。

    假设我有一个 tf.data.Datasets 列表,每个都代表一个客户端数据。如何从该列表中为下一次联邦学习迭代添加一些随机性?

    要为每个客户端的数据集添加随机性,可以使用tf.data.Dataset.shuffle() 首先随机化生成示例的顺序,然后使用tf.data.Dataset.take() 仅获取新随机排序的样本。这可以添加到上面的preprocess() 方法中。

    另外,客户选择中的随机性(例如,随机选择参与每一轮的客户)可以使用任何 Python 库对数据集列表进行子采样来完成,例如Python 的random.sample

    我的数据集不一定长度相同。当其中一个完全迭代时,这个数据集是否等待所有其他数据集完全迭代它们的数据?

    每个数据集仅在每次调用 .next() 时迭代一次。这符合McMahan et al. 2017 中的同步通信“回合”。从某种意义上说,是的,数据集彼此“等待”。

    【讨论】:

      【解决方案2】:

      任何tff.Computation(如next)将始终运行整个指定的计算。例如,如果您的tff.templates.IterativeProcesstff.learning.build_federated_averaging_process 的结果,则其next 函数将代表一轮联合平均算法。

      联合平均算法在每个本地数据集上运行固定数量的 epochs(为简单起见,假设为 1)的训练,并按顺序在服务器上以数据加权的方式对模型更新进行平均完成一轮 - 请参阅 Algorithm 1 in the original federated averaging paper 了解算法规范。

      现在,关于 TFF 如何表示和执行该算法。在build_federated_averaging_process 的文档中,next 函数具有类型签名:

      (<S@SERVER, {B*}@CLIENTS> -> <S@SERVER, T@SERVER>)
      

      TFF 的类型系统将数据集表示为tff.SequenceType(这是上面* 的含义),因此类型签名的参数中的第二个元素表示具有元素的数据集的集合(技术上是多重集) B 类型的,放置在客户端。

      这在您的示例中的含义如下。您有一个tf.data.Datasets 列表,每个列表代表每个客户端上的本地数据——您可以将列表视为代表联合放置。在这种情况下,TFF 执行整个指定的计算意味着:TFF 将列表中的每个项目视为要在本轮中训练的客户端。根据上面链接的算法,您的数据集列表表示集合 S_t。

      TFF 将忠实地执行一轮联合平均算法,列表中的Dataset 元素代表为这一轮选择的客户。训练将在每个客户端上运行一个 epoch(并行);如果数据集具有不同数量的数据,那么每个客户端的训练可能在不同时间完成是正确的。然而,这是单轮联合平均算法的正确语义,而不是像 Reptile 这样的类似算法的参数化,它为每个客户端运行固定数量的步骤。

      如果您希望选择一个客户端子集来运行一轮训练,这应该在调用 TFF 之前在 Python 中完成,例如:

      state = iterative_process.initialize()
      
      # ls is list of datasets
      sampled_clients = random.sample(ls, N_CLIENTS)
      
      state = iterative_process.next(state, sampled_clients)
      

      通常,您可以将 Python 运行时视为“实验驱动程序”层——例如,任何客户端选择都应该发生在这一层。有关更多详细信息,请参阅this answer 的开头。

      【讨论】:

        猜你喜欢
        • 2012-06-06
        • 2023-04-01
        • 1970-01-01
        • 2023-03-29
        • 1970-01-01
        • 2013-06-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多