Núcleo Federado

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

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 simples de média federada.

Também recomendamos que você se familiarize com o Federated Learning e os tutoriais associados sobre classificação de imagens e geração de texto , pois os usos da Federated Core API (FC API) para aprendizado federado fornecem um contexto importante para algumas das escolhas que fizemos em projetando esta camada.

Visão geral

Metas, usos pretendidos e escopo

Federated Core (FC) é melhor entendido como um ambiente de programação para implementar computações distribuídas, ou seja, computações que envolvem vários computadores (telefones celulares, tablets, dispositivos embarcados, computadores desktop, sensores, servidores de banco de dados, etc.) que podem, cada um, executar tarefas não operacionais. processamento trivial localmente e se comunicar através da rede para coordenar seu trabalho.

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

Embora a definição do termo computação federada de 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 poucas palavras, é permitir uma representação compacta semelhante, em um nível de abstração semelhante ao pseudocódigo, da lógica do programa que não é pseudocódigo, mas sim 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 que transforma dados localmente, e os dispositivos que coordenam o trabalho de um coordenador centralizado que transmite , coleta ou agrega seus resultados.

Embora o TFF tenha sido projetado para ir além das simples arquiteturas cliente-servidor , a noção de processamento coletivo é fundamental. Isto deve-se às origens do TFF na aprendizagem federada, uma tecnologia originalmente concebida para suportar cálculos em dados potencialmente sensíveis que permanecem sob controlo de dispositivos clientes e que não podem ser simplesmente descarregados para um local centralizado por razões de privacidade. Embora cada cliente em tais sistemas contribua com dados e poder de processamento para calcular um resultado pelo sistema (um resultado que geralmente esperamos que seja 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 para computação distribuída sejam projetadas para expressar o processamento da perspectiva de participantes individuais - isto é, no nível de trocas individuais de mensagens ponto a ponto e a interdependência das transições de estado local do participante com mensagens recebidas e enviadas , o Federated Core do TFF é projetado para descrever o comportamento do sistema a partir da perspectiva global do sistema (semelhante a, por exemplo, MapReduce ).

Conseqüentemente, embora estruturas distribuídas para fins gerais possam oferecer operações como envio e recebimento 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.

Linguagem

Interface Python

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

Especificamente, o TFF fornece decoradores de funções 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 do TFF. Uma função decorada com tff.federated_computation atua como portadora 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 invocada.

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

@tff.federated_computation(tff.FederatedType(np.float32, tff.CLIENTS))
def get_average_temperature(sensor_readings):
  return tff.federated_mean(sensor_readings)

Os leitores não familiarizados com o TensorFlow 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 de 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 subjacente, e é o gráfico, e 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 uma operação federada em uma computação federada representada por get_average_temperature .

Uma parte da razão para o FC definir uma linguagem tem a ver com o fato de que, como 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 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 forma 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 convencionais existentes:

  • Tipos de tensor ( tff.TensorType ). Assim como no TensorFlow, eles possuem dtype e shape . A única diferença é que 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 arquivo distribuído. 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.

    TensorTypes do TFF podem ser mais rígidos no tratamento (estático) das formas do que o TensorFlow. Por exemplo, o sistema de tipos do TFF trata um tensor com classificação desconhecida como atribuível a qualquer outro tensor do mesmo dtype , mas não atribuível a qualquer tensor com classificação fixa. Este tratamento evita certas falhas de tempo de execução (por exemplo, tentativa de remodelar um tensor de classificação desconhecida em uma forma com número incorreto de elementos), ao custo de maior rigor nos cálculos que o TFF aceita como válidos.

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

  • Tipos de sequência ( tff.SequenceType ). Esses são o equivalente abstrato do TFF ao conceito concreto de tf.data.Dataset s do TensorFlow. Elementos de 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 do TFF construir tuplas e estruturas semelhantes a dicionários que possuem um número predefinido de elementos com tipos específicos, nomeados ou não. É importante ressaltar que o conceito de tupla nomeada do 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 números inteiros sem nome e <X=float32,Y=float32> é uma notação compacta para um par de pontos flutuantes chamados X e Y que podem representar um ponto em um plano . Tuplas podem ser aninhadas e também 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 é um framework 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 Python). Por exemplo (int32* -> int32) é uma notação para um tipo de função que reduz uma sequência inteira a um único valor inteiro.

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

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

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

    O objetivo principal da definição da noção de canais é servir de base para a definição de tipos federados .

  • Tipos federados ( tff.FederatedType ). Um valor de tipo federado é aquele 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 do posicionamento (portanto, é um tipo dependente ), pelo tipo de constituintes do membro (que tipo de conteúdo cada um dos participantes hospeda localmente) e pelo bit adicional all_equal que especifica se todos os participantes estão localmente hospedando o mesmo item.

    A notação compacta para tipos federados de valores que incluem itens (constituintes de membros) do tipo T , cada um hospedado pelo grupo (posicionamento) 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 de um único valor federado que abrange vários itens de dados que aparecem em vários locais da rede. Uma maneira de pensar nisso é como uma espécie de tensor com dimensão de “rede”, embora esta analogia não seja perfeita porque o TFF não permite 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 diversas 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 polarização no servidor. Como eliminamos 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 possam existir 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.tensorflow.computation ). Estas são seções do código do TensorFlow agrupadas como componentes reutilizáveis ​​no TFF usando o decorador tff.tensorflow.computation . Eles sempre têm tipos funcionais e, diferentemente das funções do TensorFlow, podem receber 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 números inteiros:

    @tff.tensorflow.computation(tff.SequenceType(np.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, assim como as 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 possui parâmetros e resultados de tipos federados e a maioria são modelos que podem ser aplicados a vários tipos de dados.

    Por exemplo, tff.federated_broadcast pode ser pensado como um operador de modelo de 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 esse 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 expressão lambda que já mencionamos anteriormente:

    @tff.federated_computation(tff.FederatedType(np.float32, tff.CLIENTS))
    def get_average_temperature(sensor_readings):
      return tff.federated_mean(sensor_readings)
    
  • Literais de posicionamento . Por enquanto, apenas tff.SERVER e tff.CLIENTS permitem definir cálculos cliente-servidor simples.

  • Invocações de função ( __call__ ). Qualquer coisa que tenha um tipo funcional pode ser invocada usando a sintaxe __call__ padrão do Python. 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 desta expressão é int32 .

    • tff.federated_mean(sensor_readings) representa uma invocação do operador de média federado 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 no formato [x, y] , x[y] ou xy que aparecem nos corpos das funções decoradas com tff.federated_computation .