Ter uma questão? Conecte-se com a comunidade no Fórum TensorFlow Visite o Fórum

Federated Core

Este documento apresenta a camada central do TFF que serve como base para o Aprendizado Federado e possíveis algoritmos federados de não aprendizagem futuros.

Para uma introdução suave ao Federated Core, leia os tutoriais a seguir, pois eles apresentam alguns dos conceitos fundamentais por exemplo e demonstram passo a passo a construção de um algoritmo de média federado simples.

Também encorajamos você a se familiarizar com o Federated Learning e os tutoriais associados sobre classificação de imagens e geração de texto , já que os usos da Federated Core API (FC API) para federated learning fornecem um contexto importante para algumas das escolhas que fizemos em projetar esta camada.

Visão geral

Metas, usos pretendidos e escopo

Federated Core (FC) é mais bem entendido como um ambiente de programação para a implementação de cálculos distribuídos, ou seja, cálculos que envolvem vários computadores (telefones celulares, tablets, dispositivos incorporados, computadores desktop, sensores, servidores de banco de dados, etc.) que podem cada um não executar processamento trivial localmente e comunicação através da rede para coordenar seu trabalho.

O termo distribuído é muito genérico e o TFF não visa todos os tipos possíveis de algoritmos distribuídos, então preferimos usar o termo menos genérico computação federada para descrever os tipos de algoritmos que podem ser expressos nesta estrutura.

Embora definir o termo computação federada de uma maneira totalmente formal esteja fora do escopo deste documento, pense nos tipos de algoritmos que você pode ver expressos em pseudocódigo em uma publicação de pesquisa que descreve um novo algoritmo de aprendizado distribuído.

O objetivo do FC, em um nusthell, é permitir uma representação compacta similar, em um nível semelhante de pseudocódigo de abstração, da lógica do programa que não é um pseudocódigo, mas sim, que é executável em uma variedade de ambientes de destino.

A principal característica definidora dos tipos de algoritmos que o FC foi projetado para expressar é que as ações dos participantes do sistema são descritas de maneira coletiva. Assim, tendemos a falar sobre cada dispositivo transformando localmente os dados e os dispositivos que coordenam o trabalho por um coordenador centralizado transmitindo , coletando ou agregando seus resultados.

Embora o TFF tenha sido projetado para ser capaz de ir além das simples arquiteturas cliente-servidor , a noção de processamento coletivo é fundamental. Isso se deve às origens da TFF na aprendizagem federada, uma tecnologia originalmente projetada para dar suporte a cálculos em dados potencialmente confidenciais que permanecem sob controle de dispositivos clientes e que não podem ser simplesmente baixados para um local centralizado por motivos de privacidade. Embora cada cliente em tais sistemas contribua com dados e poder de processamento para computar um resultado pelo sistema (um resultado que geralmente esperamos ser de valor para todos os participantes), também nos esforçamos para preservar a privacidade e o anonimato de cada cliente.

Assim, embora a maioria das estruturas de computação distribuída sejam projetadas para expressar o processamento da perspectiva de participantes individuais - ou seja, no nível de trocas de mensagens individuais ponto a ponto e a interdependência das transições de estado local do participante com mensagens de entrada e saída , O Federated Core da TFF é projetado para descrever o comportamento do sistema da perspectiva global do sistema (de forma semelhante, por exemplo, MapReduce ).

Consequentemente, enquanto estruturas distribuídas para fins gerais podem oferecer operações como enviar e receber como blocos de construção, o FC fornece blocos de construção como tff.federated_sum , tff.federated_reduce ou tff.federated_broadcast que encapsulam protocolos distribuídos simples.

Língua

Interface Python

A TFF usa uma linguagem interna para representar computações federadas, cuja sintaxe é definida pela representação serializável em computation.proto . No entanto, os usuários da API FC geralmente não precisam interagir com essa linguagem diretamente. Em vez disso, fornecemos uma API Python (o namespace tff ) que o envolve como uma forma de definir cálculos.

Especificamente, a TFF fornece decoradores de função Python, como tff.federated_computation que rastreiam os corpos das funções decoradas e produzem representações serializadas da lógica de computação federada na linguagem da TFF. Uma função decorada com tff.federated_computation atua como um portador de tal representação serializada e pode incorporá-la como um bloco de construção no corpo de outra computação ou executá-la sob demanda quando chamada.

Aqui está apenas um exemplo; mais exemplos podem ser encontrados nos tutoriais de algoritmos personalizados .

@tff.federated_computation(tff.type_at_clients(tf.float32))
def get_average_temperature(sensor_readings):
  return tff.federated_mean(sensor_readings)

Os leitores familiarizados com o TensorFlow não ansioso acharão essa abordagem análoga a escrever código Python que usa funções como tf.add ou tf.reduce_sum em uma seção do código Python que define um gráfico do TensorFlow. Embora o código seja tecnicamente expresso em Python, seu objetivo é construir uma representação serializável de um tf.Graph embaixo, e é o gráfico, não o código Python, que é executado internamente pelo tempo de execução do TensorFlow. Da mesma forma, pode-se pensar em tff.federated_mean como a inserção de um op federado em uma computação federada representada por get_average_temperature .

Uma parte da razão para FC definir uma linguagem tem a ver com o fato de que, conforme observado acima, as computações federadas especificam comportamentos coletivos distribuídos e, como tal, sua lógica não é local. Por exemplo, a TFF fornece operadores cujas entradas e saídas podem existir em diferentes locais da rede.

Isso exige uma linguagem e um sistema de tipos que capturem a noção de distribuição.

Tipo de sistema

Federated Core oferece as seguintes categorias de tipos. Ao descrever esses tipos, apontamos para os construtores de tipo e também introduzimos uma notação compacta, pois é uma maneira prática de descrever tipos de cálculos e operadores.

Primeiro, aqui estão as categorias de tipos que são conceitualmente semelhantes aos encontrados nas linguagens tradicionais existentes:

  • Tipos de tensor ( tff.TensorType ). Assim como no TensorFlow, eles têm dtype e shape . A única diferença é que os objetos desse tipo não estão limitados a instâncias tf.Tensor em Python que representam saídas de operações do TensorFlow em um gráfico do TensorFlow, mas também podem incluir unidades de dados que podem ser produzidas, por exemplo, como uma saída de um protocolo de agregação. Assim, o tipo de tensor TFF é simplesmente uma versão abstrata de uma representação física concreta desse tipo em Python ou TensorFlow.

    A notação compacta para tipos de tensores é dtype ou dtype[shape] . Por exemplo, int32 e int32[10] são os tipos de vetores inteiros e int, respectivamente.

  • Tipos de sequência ( tff.SequenceType ). Esses são o equivalente abstrato da TFF do conceito concreto dotf.data.Dataset detf.data.Dataset s. Os elementos das sequências podem ser consumidos de maneira sequencial e podem incluir tipos complexos.

    A representação compacta dos tipos de sequência é T* , onde T é o tipo de elementos. Por exemplo, int32* representa uma sequência inteira.

  • Tipos de tupla nomeados ( tff.StructType ). Essa é a maneira da TFF de construir tuplas e estruturas semelhantes a dicionários que possuem um número predefinido de elementos com tipos específicos, nomeados ou não nomeados. É importante ressaltar que o conceito de tupla nomeada da TFF abrange o equivalente abstrato das tuplas de argumento do Python, ou seja, coleções de elementos dos quais alguns, mas não todos, são nomeados e alguns são posicionais.

    A notação compacta para tuplas nomeadas é <n_1=T_1, ..., n_k=T_k> , onde n_k são nomes de elementos opcionais e T_k são tipos de elementos. Por exemplo, <int32,int32> é uma notação compacta para um par de inteiros não nomeados e <X=float32,Y=float32> é uma notação compacta para um par de flutuadores chamados X e Y que podem representar um ponto em um plano . As tuplas podem ser aninhadas ou misturadas com outros tipos, por exemplo, <X=float32,Y=float32>* seria uma notação compacta para uma sequência de pontos.

  • Tipos de função ( tff.FunctionType ). TFF é uma estrutura de programação funcional, com funções tratadas como valores de primeira classe . As funções têm no máximo um argumento e exatamente um resultado.

    A notação compacta para funções é (T -> U) , onde T é o tipo de um argumento e U é o tipo do resultado, ou ( -> U) se não houver argumento (embora funções sem argumento sejam degeneradas conceito que existe principalmente apenas no nível do Python). Por exemplo (int32* -> int32) é uma notação para um tipo de funções que reduzem uma sequência inteira a um único valor inteiro.

Os seguintes tipos abordam o aspecto de sistemas distribuídos de cálculos TFF. Como esses conceitos são um tanto exclusivos da TFF, recomendamos que você consulte o tutorial de algoritmos personalizados para comentários e exemplos adicionais.

  • Tipo de posicionamento . Esse tipo ainda não foi exposto na API pública, a não ser na forma de 2 literais tff.SERVER e tff.CLIENTS que você pode considerar como constantes desse tipo. Ele é usado internamente, no entanto, e será introduzido na API pública em versões futuras. A representação compacta deste tipo é a placement .

    Uma colocação representa um coletivo de participantes do sistema que desempenham uma função específica. A versão inicial é destinada a cálculos cliente-servidor, nos quais há 2 grupos de participantes: clientes e um servidor (você pode pensar no último como um grupo único). No entanto, em arquiteturas mais elaboradas, pode haver outras funções, como agregadores intermediários em um sistema multicamadas, que podem realizar diferentes tipos de agregação ou usar diferentes tipos de compactação / descompressão de dados do que aqueles usados ​​pelo servidor ou os clientes.

    O objetivo principal de definir a noção de canais é como uma base para definir os tipos federados .

  • Tipos federados ( tff.FederatedType ). Um valor de um tipo federado é aquele que é hospedado por um grupo de participantes do sistema definido por um posicionamento específico (como tff.SERVER ou tff.CLIENTS ). Um tipo federado é definido pelo valor de posicionamento (portanto, é um tipo dependente ), o tipo de constituintes membros (que tipo de conteúdo cada um dos participantes está hospedando localmente) e o bit adicional all_equal que especifica se todos os participantes estão localmente hospedando o mesmo item.

    A notação compacta para o tipo federado de valores que incluem itens (constituintes do membro) do tipo T , cada um hospedado pelo grupo (colocação) G é T@G ou {T}@G com o bit all_equal definido ou não definido, respectivamente.

    Por exemplo:

    • {int32}@CLIENTS representa um valor federado que consiste em um conjunto de números inteiros potencialmente distintos, um por dispositivo cliente. Observe que estamos falando sobre um único valor federado que engloba vários itens de dados que aparecem em vários locais na rede. Uma maneira de pensar sobre isso é como uma espécie de tensor com uma dimensão de "rede", embora essa analogia não seja perfeita porque a TFF não permite o acesso aleatório aos constituintes membros de um valor federado.

    • {<X=float32,Y=float32>*}@CLIENTS representa um conjunto de dados federado , um valor que consiste em várias sequências de coordenadas XY , uma sequência por dispositivo cliente.

    • <weights=float32[10,5],bias=float32[5]>@SERVER representa uma tupla nomeada de tensores de peso e bias no servidor. Como all_equal as chaves, isso indica que o bit all_equal está definido, ou seja, há apenas uma única tupla (independentemente de quantas réplicas de servidor possa haver em um cluster que hospeda esse valor).

Blocos de construção

A linguagem do Federated Core é uma forma de cálculo lambda , com alguns elementos adicionais.

Ele fornece as seguintes abstrações de programação atualmente expostas na API pública:

  • Cálculos do TensorFlow ( tff.tf_computation ). Essas são seções do código do TensorFlow agrupadas como componentes reutilizáveis ​​no TFF usando o decorador tff.tf_computation . Eles sempre têm tipos funcionais e, ao contrário das funções do TensorFlow, podem usar parâmetros estruturados ou retornar resultados estruturados de um tipo de sequência.

    Aqui está um exemplo, um cálculo TF do tipo (int32* -> int) que usa o operador tf.data.Dataset.reduce para calcular uma soma de inteiros:

    @tff.tf_computation(tff.SequenceType(tf.int32))
    def add_up_integers(x):
      return x.reduce(np.int32(0), lambda x, y: x + y)
    
  • Operadores intrínsecos ou federados ( tff.federated_... ). Esta é uma biblioteca de funções como tff.federated_sum ou tff.federated_broadcast que constituem a maior parte da API FC, a maioria das quais representa operadores de comunicação distribuída para uso com TFF.

    Nós nos referimos a eles como intrínsecos porque, de certa forma como funções intrínsecas , eles são um conjunto aberto e extensível de operadores que são compreendidos pelo TFF e compilados em código de nível inferior.

    A maioria desses operadores tem parâmetros e resultados de tipos federados e muitos são modelos que podem ser aplicados a vários tipos de dados.

    Por exemplo, tff.federated_broadcast pode ser considerado um operador de modelo de um tipo funcional T@SERVER -> T@CLIENTS .

  • Expressões lambda ( tff.federated_computation ). Uma expressão lambda em TFF é equivalente a lambda ou def em Python; consiste no nome do parâmetro e em um corpo (expressão) que contém referências a este parâmetro.

    No código Python, eles podem ser criados decorando funções Python com tff.federated_computation e definindo um argumento.

    Aqui está um exemplo de uma expressão lambda que já mencionamos anteriormente:

    @tff.federated_computation(tff.type_at_clients(tf.float32))
    def get_average_temperature(sensor_readings):
      return tff.federated_mean(sensor_readings)
    
  • Literais de posicionamento . Por enquanto, apenas tff.SERVER e tff.CLIENTS para permitir a definição de cálculos cliente-servidor simples.

  • Invocações de função ( __call__ ). Qualquer coisa que tenha um tipo funcional pode ser invocada usando a sintaxe Python __call__ padrão. A invocação é uma expressão, cujo tipo é igual ao tipo do resultado da função que está sendo invocada.

    Por exemplo:

    • add_up_integers(x) representa uma invocação do cálculo do TensorFlow definido anteriormente em um argumento x . O tipo dessa expressão é int32 .

    • tff.federated_mean(sensor_readings) representa uma chamada do operador de média federada em sensor_readings . O tipo desta expressão é float32@SERVER (assumindo o contexto do exemplo acima).

  • Formando tuplas e selecionando seus elementos. Expressões Python da forma [x, y] , x[y] ou xy que aparecem nos corpos das funções decoradas com tff.federated_computation .