【问题标题】:Is it possible to send different subset of weights to different clients?是否可以将不同的权重子集发送给不同的客户?
【发布时间】:2020-12-22 15:10:51
【问题描述】:

我正在尝试使用 tensorflow-federated 在服务器上选择不同的权重子集并将它们发送给客户端。然后,客户将训练并发回训练后的权重。服务器汇总结果并开始新一轮通信。

主要问题是我无法访问权重的 numpy 版本,因此我不知道如何访问每一层的权重子集。我尝试使用 tf.gather_nd 和 tf.tensor_scatter_nd_update 来执行选择和更新,但它们仅适用于张量,而不适用于张量列表(因为 server_state 处于 tensorflow-federated 中)。

有没有人有任何提示可以解决这个问题?甚至可以向每个客户发送不同的权重吗?

【问题讨论】:

    标签: tensorflow tensorflow2.0 tensorflow-federated


    【解决方案1】:

    如果我按照正确的方式,编写 TFF 类型速记中描述的高级计算的方法是:

    @tff.federated_computation(...)
    def run_one_round(server_state, client_datasets):
      weights_subset = tff.federated_map(subset_fn, server_state)
      clients_weights_subset = tff.federated_broadcast(weights_subset)
      client_models = tff.federated_map(client_training_fn, 
                                        (clients_weights_subset, client_datasets))
      aggregated_update = tff.federated_aggregate(client_models, ...)
      new_server_state = tff.federated_map(apply_aggregated_update_fn, server_state)
      return new_server_state
    

    如果这是真的,似乎大部分工作都需要在subset_fn 中进行,它获取服务器状态并返回全局模式权重的子集。通常,模型是tf.Tensor 的结构(listdict,可能是嵌套的),正如您所观察到的,它不能用作tf.gather_ndtf.tensor_scatter_nd_update 的参数。但是,它们可以逐点应用于使用tf.nest.map_structure 的张量结构。例如,从三个张量的嵌套结构中选择 [0, 0] 处的值:

    import tensorflow as tf
    import pprint
    struct_of_tensors = {
        'trainable': [tf.constant([[2.0, 4.0, 6.0]]), tf.constant([[5.0]])],
        'non_trainable': [tf.constant([[1.0]])],
    }
    pprint.pprint(tf.nest.map_structure(
        lambda tensor: tf.gather_nd(params=tensor, indices=[[0, 0]]),
        struct_of_tensors))
    
    >>> {'non_trainable': [<tf.Tensor: shape=(1,), dtype=float32, numpy=array([1.], dtype=float32)>],
         'trainable': [<tf.Tensor: shape=(1,), dtype=float32, numpy=array([2.], dtype=float32)>,
                       <tf.Tensor: shape=(1,), dtype=float32, numpy=array([5.], dtype=float32)>]}
    

    【讨论】:

    • 感谢您的帮助!我刚刚注意到使用 tff.federated_broadcast() 所有客户端都会收到相同的权重。假设我对不同的客户有不同的权重(例如,在一个列表中),我怎样才能将它们发送给客户?
    • 在这种情况下,您可以使用subset_fn 创建两个子集并拥有两个不同的广播。 run_one_round(...) 需要为其他客户端子集获取额外的数据集参数,因此类似于 def run_one_round(server_state, client_a_datasets, client_b_datasets)
    • 我实际上是在尝试为每个客户端发送不同的权重子集(由布尔掩码列表定义)。我认为拆分数据集是不切实际的。您认为可能有不同的解决方案吗?
    • tff.federated_broadcast 的语义是将 same 值广播到一组客户端(一对多)操作。目前我能想到的唯一方法是为每个客户端进行广播,并使用不同的权重子集参数。请记住,每个客户端获得不同的权重,或者使用更多的内存,或者一次按顺序广播一个子集,都可能存在扩展问题。
    猜你喜欢
    • 1970-01-01
    • 2017-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多