Núcleo federado

Este documento presenta la capa central de TFF que sirve como base para el aprendizaje federado y posibles algoritmos federados futuros sin aprendizaje.

Para obtener una introducción sencilla a Federated Core, lea los siguientes tutoriales, ya que presentan algunos de los conceptos fundamentales mediante ejemplos y demuestran paso a paso la construcción de un algoritmo de promedio federado simple.

También le animamos a que se familiarice con el aprendizaje federado y los tutoriales asociados sobre clasificación de imágenes y generación de texto , ya que los usos de Federated Core API (FC API) para el aprendizaje federado proporcionan un contexto importante para algunas de las decisiones que hemos tomado en diseñando esta capa.

Descripción general

Objetivos, usos previstos y alcance

Federated Core (FC) se entiende mejor como un entorno de programación para implementar cálculos distribuidos, es decir, cálculos que involucran múltiples computadoras (teléfonos móviles, tabletas, dispositivos integrados, computadoras de escritorio, sensores, servidores de bases de datos, etc.) y cada uno de los cuales puede realizar funciones no procesamiento trivial localmente y se comunican a través de la red para coordinar su trabajo.

El término distribuido es muy genérico y TFF no se dirige a todos los tipos posibles de algoritmos distribuidos que existen, por lo que preferimos utilizar el término menos genérico computación federada para describir los tipos de algoritmos que se pueden expresar en este marco.

Si bien definir el término computación federada de una manera completamente formal está fuera del alcance de este documento, piense en los tipos de algoritmos que podría ver expresados ​​en pseudocódigo en una publicación de investigación que describe un nuevo algoritmo de aprendizaje distribuido.

El objetivo de FC, en pocas palabras, es permitir una representación igualmente compacta, en un nivel de abstracción similar al de un pseudocódigo, de la lógica del programa que no es un pseudocódigo, sino que es ejecutable en una variedad de entornos de destino.

La característica clave que define los tipos de algoritmos que FC está diseñado para expresar es que las acciones de los participantes del sistema se describen de manera colectiva. Por lo tanto, tendemos a hablar de que cada dispositivo transforma datos localmente y que los dispositivos coordinan el trabajo mediante un coordinador centralizado que transmite , recopila o agrega sus resultados.

Si bien TFF ha sido diseñado para poder ir más allá de las simples arquitecturas cliente-servidor , la noción de procesamiento colectivo es fundamental. Esto se debe a los orígenes de TFF en el aprendizaje federado, una tecnología diseñada originalmente para admitir cálculos sobre datos potencialmente confidenciales que permanecen bajo el control de los dispositivos del cliente y que no pueden simplemente descargarse a una ubicación centralizada por razones de privacidad. Si bien cada cliente en dichos sistemas contribuye con datos y poder de procesamiento para calcular un resultado del sistema (un resultado que generalmente esperaríamos que fuera valioso para todos los participantes), también nos esforzamos por preservar la privacidad y el anonimato de cada cliente.

Por lo tanto, si bien la mayoría de los marcos para la computación distribuida están diseñados para expresar el procesamiento desde la perspectiva de los participantes individuales, es decir, al nivel de los intercambios de mensajes individuales punto a punto y la interdependencia de las transiciones de estado local del participante con los mensajes entrantes y salientes. , Federated Core de TFF está diseñado para describir el comportamiento del sistema desde la perspectiva global de todo el sistema (de manera similar a, por ejemplo, MapReduce ).

En consecuencia, si bien los marcos distribuidos para fines generales pueden ofrecer operaciones como enviar y recibir como bloques de construcción, FC proporciona bloques de construcción como tff.federated_sum , tff.federated_reduce o tff.federated_broadcast que encapsulan protocolos distribuidos simples.

Idioma

Interfaz de Python

TFF utiliza un lenguaje interno para representar cálculos federados, cuya sintaxis está definida por la representación serializable en computation.proto . Sin embargo, los usuarios de FC API generalmente no necesitarán interactuar directamente con este lenguaje. Más bien, proporcionamos una API de Python (el espacio de nombres tff ) que lo envuelve como una forma de definir cálculos.

Específicamente, TFF proporciona decoradores de funciones de Python como tff.federated_computation que rastrean los cuerpos de las funciones decoradas y producen representaciones serializadas de la lógica de cálculo federado en el lenguaje de TFF. Una función decorada con tff.federated_computation actúa como portadora de dicha representación serializada y puede incrustarla como un bloque de construcción en el cuerpo de otro cálculo o ejecutarla bajo demanda cuando se invoca.

Aquí hay sólo un ejemplo; Se pueden encontrar más ejemplos en los tutoriales de algoritmos personalizados .

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

Los lectores familiarizados con TensorFlow que no estén interesados ​​encontrarán este enfoque análogo a escribir código Python que utiliza funciones como tf.add o tf.reduce_sum en una sección de código Python que define un gráfico de TensorFlow. Aunque el código se expresa técnicamente en Python, su propósito es construir una representación serializable de un tf.Graph debajo, y es el gráfico, no el código Python, el que ejecuta internamente el tiempo de ejecución de TensorFlow. Del mismo modo, se puede pensar en tff.federated_mean como si se insertara una operación federada en un cálculo federado representado por get_average_temperature .

Parte de la razón por la que FC define un lenguaje tiene que ver con el hecho de que, como se señaló anteriormente, los cálculos federados especifican comportamientos colectivos distribuidos y, como tal, su lógica no es local. Por ejemplo, TFF proporciona operadores cuyas entradas y salidas pueden existir en diferentes lugares de la red.

Esto requiere un lenguaje y un sistema de tipos que capturen la noción de distribución.

Tipo de sistema

Federated Core ofrece las siguientes categorías de tipos. Al describir estos tipos, señalamos los constructores de tipos y también introducimos una notación compacta, ya que es una forma práctica de describir tipos de cálculos y operadores.

Primero, aquí están las categorías de tipos que son conceptualmente similares a las que se encuentran en los lenguajes convencionales existentes:

  • Tipos de tensor ( tff.TensorType ). Al igual que en TensorFlow, estos tienen dtype y shape . La única diferencia es que los objetos de este tipo no se limitan a instancias tf.Tensor en Python que representan salidas de operaciones de TensorFlow en un gráfico de TensorFlow, sino que también pueden incluir unidades de datos que se pueden producir, por ejemplo, como salida de un gráfico distribuido. protocolo de agregación. Por lo tanto, el tipo de tensor TFF es simplemente una versión abstracta de una representación física concreta de dicho tipo en Python o TensorFlow.

    TensorTypes de TFF pueden ser más estrictos en su tratamiento (estático) de formas que TensorFlow. Por ejemplo, el sistema de tipos de TFF trata un tensor con rango desconocido como asignable desde cualquier otro tensor del mismo dtype , pero no asignable a ningún tensor con rango fijo. Este tratamiento evita ciertos fallos en tiempo de ejecución (por ejemplo, intentar remodelar un tensor de rango desconocido en una forma con un número incorrecto de elementos), a costa de una mayor rigurosidad en los cálculos que TFF acepta como válidos.

    La notación compacta para tipos de tensor es dtype o dtype[shape] . Por ejemplo, int32 e int32[10] son ​​los tipos de números enteros y vectores int, respectivamente.

  • Tipos de secuencia ( tff.SequenceType ). Estos son el equivalente abstracto de TFF del concepto concreto de tf.data.Dataset s de TensorFlow. Los elementos de las secuencias se pueden consumir de forma secuencial y pueden incluir tipos complejos.

    La representación compacta de tipos de secuencia es T* , donde T es el tipo de elementos. Por ejemplo int32* representa una secuencia de números enteros.

  • Tipos de tuplas con nombre ( tff.StructType ). Ésta es la forma en que TFF construye tuplas y estructuras similares a diccionarios que tienen un número predefinido de elementos con tipos específicos, con o sin nombre. Es importante destacar que el concepto de tupla con nombre de TFF abarca el equivalente abstracto de las tuplas de argumentos de Python, es decir, colecciones de elementos de los cuales algunos, pero no todos, tienen nombre y algunos son posicionales.

    La notación compacta para tuplas con nombre es <n_1=T_1, ..., n_k=T_k> , donde n_k son nombres de elementos opcionales y T_k son tipos de elementos. Por ejemplo, <int32,int32> es una notación compacta para un par de números enteros sin nombre y <X=float32,Y=float32> es una notación compacta para un par de flotantes llamados X e Y que pueden representar un punto en un plano. . Las tuplas se pueden anidar y mezclar con otros tipos; por ejemplo, <X=float32,Y=float32>* sería una notación compacta para una secuencia de puntos.

  • Tipos de funciones ( tff.FunctionType ). TFF es un marco de programación funcional, con funciones tratadas como valores de primera clase . Las funciones tienen como máximo un argumento y exactamente un resultado.

    La notación compacta para funciones es (T -> U) , donde T es el tipo de argumento y U es el tipo de resultado, o ( -> U) si no hay argumento (aunque las funciones sin argumentos son degeneradas). concepto que existe principalmente solo en el nivel de Python). Por ejemplo (int32* -> int32) es una notación para un tipo de funciones que reducen una secuencia de números enteros a un único valor entero.

Los siguientes tipos abordan el aspecto de sistemas distribuidos de los cálculos TFF. Como estos conceptos son algo exclusivos de TFF, le recomendamos que consulte el tutorial de algoritmos personalizados para obtener comentarios y ejemplos adicionales.

  • Tipo de ubicación . Este tipo aún no está expuesto en la API pública excepto en forma de 2 literales tff.SERVER y tff.CLIENTS que puede considerar constantes de este tipo. Sin embargo, se usa internamente y se introducirá en la API pública en versiones futuras. La representación compacta de este tipo es placement .

    Una ubicación representa un colectivo de participantes del sistema que desempeñan un papel particular. La versión inicial está dirigida a cálculos cliente-servidor, en los que hay dos grupos de participantes: clientes y un servidor (puede pensar en este último como un grupo singleton). Sin embargo, en arquitecturas más elaboradas, podría haber otras funciones, como agregadores intermedios en un sistema de varios niveles, que podrían realizar diferentes tipos de agregación o utilizar diferentes tipos de compresión/descompresión de datos que los utilizados por el servidor o los clientes.

    El objetivo principal de definir la noción de ubicaciones es servir de base para definir los tipos federados .

  • Tipos federados ( tff.FederatedType ). Un valor de tipo federado es aquel que está alojado en un grupo de participantes del sistema definido por una ubicación específica (como tff.SERVER o tff.CLIENTS ). Un tipo federado se define por el valor de ubicación (por lo tanto, es un tipo dependiente ), el tipo de miembros constituyentes (qué tipo de contenido aloja localmente cada uno de los participantes) y el bit adicional all_equal que especifica si todos los participantes son locales. alojar el mismo artículo.

    La notación compacta para el tipo federado de valores que incluyen elementos (miembros constituyentes) de tipo T , cada uno alojado por el grupo (ubicación) G es T@G o {T}@G con el bit all_equal establecido o no establecido, respectivamente.

    Por ejemplo:

    • {int32}@CLIENTS representa un valor federado que consta de un conjunto de enteros potencialmente distintos, uno por dispositivo cliente. Tenga en cuenta que estamos hablando de un único valor federado que abarca varios elementos de datos que aparecen en varias ubicaciones de la red. Una forma de verlo es como una especie de tensor con una dimensión de "red", aunque esta analogía no es perfecta porque TFF no permite el acceso aleatorio a los constituyentes miembros de un valor federado.

    • {<X=float32,Y=float32>*}@CLIENTS representa un conjunto de datos federados , un valor que consta de múltiples secuencias de coordenadas XY , una secuencia por dispositivo cliente.

    • <weights=float32[10,5],bias=float32[5]>@SERVER representa una tupla con nombre de tensores de peso y sesgo en el servidor. Dado que eliminamos las llaves, esto indica que el bit all_equal está establecido, es decir, solo hay una tupla (independientemente de cuántas réplicas de servidor pueda haber en un clúster que albergue este valor).

Bloques de construcción

El lenguaje de Federated Core es una forma de cálculo lambda , con algunos elementos adicionales.

Proporciona las siguientes abstracciones de programación actualmente expuestas en la API pública:

  • Cálculos de TensorFlow ( tff.tf_computation ). Estas son secciones de código de TensorFlow empaquetadas como componentes reutilizables en TFF usando el decorador tff.tf_computation . Siempre tienen tipos funcionales y, a diferencia de las funciones de TensorFlow, pueden tomar parámetros estructurados o devolver resultados estructurados de un tipo de secuencia.

    A continuación se muestra un ejemplo, un cálculo TF de tipo (int32* -> int) que utiliza el operador tf.data.Dataset.reduce para calcular una suma de números enteros:

    @tff.tf_computation(tff.SequenceType(np.int32))
    def add_up_integers(x):
      return x.reduce(np.int32(0), lambda x, y: x + y)
    
  • Operadores intrínsecos o federados ( tff.federated_... ). Esta es una biblioteca de funciones como tff.federated_sum o tff.federated_broadcast que constituyen la mayor parte de la API FC, la mayoría de las cuales representan operadores de comunicación distribuidos para usar con TFF.

    Nos referimos a estos como intrínsecos porque, algo así como funciones intrínsecas , son un conjunto de operadores extensibles y abiertos que TFF entiende y compila en código de nivel inferior.

    La mayoría de estos operadores tienen parámetros y resultados de tipos federados y la mayoría son plantillas que se pueden aplicar a diversos tipos de datos.

    Por ejemplo, tff.federated_broadcast se puede considerar como un operador de plantilla de tipo funcional T@SERVER -> T@CLIENTS .

  • Expresiones lambda ( tff.federated_computation ). Una expresión lambda en TFF es el equivalente de una lambda o def en Python; consta del nombre del parámetro y un cuerpo (expresión) que contiene referencias a este parámetro.

    En el código Python, estos se pueden crear decorando funciones de Python con tff.federated_computation y definiendo un argumento.

    Aquí hay un ejemplo de una expresión lambda que ya mencionamos anteriormente:

    @tff.federated_computation(tff.FederatedType(np.float32, tff.CLIENTS))
    def get_average_temperature(sensor_readings):
      return tff.federated_mean(sensor_readings)
    
  • Literales de colocación . Por ahora, solo tff.SERVER y tff.CLIENTS permiten definir cálculos simples cliente-servidor.

  • Invocaciones de funciones ( __call__ ). Cualquier cosa que tenga un tipo funcional se puede invocar utilizando la sintaxis estándar __call__ de Python. La invocación es una expresión cuyo tipo es el mismo que el tipo del resultado de la función que se invoca.

    Por ejemplo:

    • add_up_integers(x) representa una invocación del cálculo de TensorFlow definido anteriormente en un argumento x . El tipo de esta expresión es int32 .

    • tff.federated_mean(sensor_readings) representa una invocación del operador de promedio federado en sensor_readings . El tipo de esta expresión es float32@SERVER (asumiendo el contexto del ejemplo anterior).

  • Formar tuplas y seleccionar sus elementos. Expresiones de Python de la forma [x, y] , x[y] o xy que aparecen en los cuerpos de funciones decoradas con tff.federated_computation .