Tensorflow federated TensorFlowFederated:将张量传递给tff.federated\u计算

Tensorflow federated TensorFlowFederated:将张量传递给tff.federated\u计算,tensorflow-federated,Tensorflow Federated,我已经在我的单机上试用了TFF教程(MNIST),现在我正在尝试使用MNIST数据执行一个多机进程 显然,我不能使用create\u tf\u dataset\u for\u client,因此我使用GRPC来学习如何将数据从一台机器传递到另一台机器 我的场景是,服务器将把初始模型(带零)分派给所有参与的客户机,在这些客户机上,模型将在本地数据上运行。每个客户机都会将新的权重分配给将执行联邦平均值的服务器 我曾考虑使用tff.learning.build\u federated\u averag

我已经在我的单机上试用了TFF教程(MNIST),现在我正在尝试使用MNIST数据执行一个多机进程

显然,我不能使用
create\u tf\u dataset\u for\u client
,因此我使用GRPC来学习如何将数据从一台机器传递到另一台机器

我的场景是,服务器将把初始模型(带零)分派给所有参与的客户机,在这些客户机上,模型将在本地数据上运行。每个客户机都会将新的权重分配给将执行联邦平均值的服务器

我曾考虑使用
tff.learning.build\u federated\u averaging\u process
来定制
next
函数(第二个参数),但我失败了。。。我甚至不确定我们是否使用这种方法发送模型并从远程客户端获取权重

然后我想我可以在
@tff.federated\u computation
装饰器下使用
tff.federated\u mean
。但是,由于权重是数组,并且我有一个数组列表(因为我有许多客户端),因此我无法理解如何创建指向列表列表的
tff.FederatedType
。任何在分布式数据集上对联邦进行建模的人的帮助都很容易理解

问候,,
开发人员

TFF计算被设计为平台/运行时不可知;单个计算可以由多个不同的后端执行,这些后端具有不同的语义

TFF的类型系统在这里有助于推断数据在计算中的流动方式。有关TFF如何看待类型的介绍,请参见

build\u federated\u averacing\u过程的结果
需要放置在客户端的数据集参数;对于元素类型为
T
的数据集,用TFF的常用符号表示为
{T*}@C
。这个签名对于数据集如何到达客户机,或者实际上如何表示客户机本身是不可知的

具体化数据并表示客户机实际上是运行时的工作。TFF在这里提供了一些所谓的选项

例如,在本地运行时中,客户端由本地计算机上的线程表示。数据集是简单的eager
tf.data.Dataset
对象,线程在训练期间从数据集中提取数据

在远程运行时中,客户端由远程工作线程表示,因此单个远程工作线程可以运行多个客户端。在这种情况下,正如您所注意到的,数据必须在远程工作者上具体化,以便进行培训

实现这一点有多种选择

首先,TFF将实际为您处理通过此RPC连接的急切数据集的序列化和反序列化,因此您可以使用与在本地运行时中相同的指定数据模式,并且它应该“正常工作”(有几个注意事项;以某种方式有状态的数据集,例如无序数据集,不能序列化)

然而,也许更好地映射到联邦计算的概念是使用一些最近引入的库函数来简单地实例化worker上的数据集

假设您有一个迭代过程
ip
,它接受
状态
数据
参数,其中
数据
类型为
{T*}@C
。进一步假设我们有一个TFF计算
get\u dataset\u for\u client\u id
,它接受一个字符串并返回一个适当类型的数据集(即,它的TFF类型签名是
tf.str->T*

然后我们可以将这两个计算组合成另一个:

@tff.federated\u计算(STATE\u类型,tff.FederatedType(tf.string,tff.CLIENTS))
def new_next(状态、客户端ID):
客户端上的数据集\u=tff.federated\u映射(获取客户端id的数据集\u,客户端id)
返回ip.next(状态、客户端上的数据集)
new\u next
现在要求控制器只指定要培训的客户机的ID,并将指向数据存储的责任委托给代表客户机的人

我认为这种模式很可能是你想要的;最近,它的使用在TFF中通过上的
dataset\u computation
属性和类似的帮助程序进行了推广,这将或多或少地为您执行我们上面所做的连接


这里还有一些进一步的警告;鉴于此更改是相对较新的,并非每个具体的
ClientData
类都有实现,因此您可能最终会遇到
NotImplementedError
(使用HDF5文件进行此操作有点麻烦)。但我认为,从高层次上讲,这是我们的两个选择。

让我们一步一步来做。请让我们知道下面的解释是否回答了您的问题

  • 让我们从一个TF(非联邦,仅本地)代码的示例开始,它获取一个数据集并使用它做一些事情,比如添加数字:
  • 这段代码在输入时获取一个整数数据集,并在输出时返回一个带和的整数

    您可以通过查看类型签名来确认这一点,如下所示:

    str(process_data.type_signature)
    
    您应该看到:

    (int32* -> int32)
    
    ({int32*}@CLIENTS -> {int32}@CLIENTS)
    
    因此,
    process_data
    获取一组整数,并返回一个整数

  • 现在,使用TFF的联邦运算符,我们可以创建一个在多个客户端上执行此操作的联邦计算,如下所示:
  • 如果查看此新计算的类型签名(如上所示),您将看到:

    (int32* -> int32)
    
    ({int32*}@CLIENTS -> {int32}@CLIENTS)
    
    这意味着
    process\u客户端上的数据\u
    获取一组联合整数(每个客户端一组),并返回一个联合整数(每个客户端一个整数的总和)

    上述情况下,
    process\u data
    中的TF逻辑将在每个客户机上执行一次。这就是
    联邦映射
    操作符的工作方式

  • 现在,
    处理客户机上的数据有点像您正在进行的迭代过程
    
    @tff.tf_computation(tf.int32)
    def make_data(n):
      return tf.data.Dataset.range(tf.cast(n, tf.int64)).map(lambda x: tf.cast(x + 1, tf.int32))
    
    (int32 -> int32*)
    
    @tff.federated_computation(tff.FederatedType(tf.int32, tff.CLIENTS))
    def make_data_on_clients(federated_n):
      return tff.federated_map(make_data, federated_n)
    
    ({int32}@CLIENTS -> {int32*}@CLIENTS)
    
    federated_n = [2, 3, 4]
    federated_ds = make_data_on_clients(federated_n)
    result = process_data_on_clients(federated_ds)
    result
    
    [<tf.Tensor: shape=(), dtype=int32, numpy=3>,
     <tf.Tensor: shape=(), dtype=int32, numpy=6>,
     <tf.Tensor: shape=(), dtype=int32, numpy=10>]
    
    @tff.federated_computation(tff.FederatedType(tf.int32, tff.CLIENTS))
    def make_and_process_data_on_clients(federated_n):
      federated_ds = make_data_on_clients(federated_n)
      return process_data_on_clients(federated_ds)
    
    make_and_process_data_on_clients(federated_n)