Path: blob/master/site/es-419/federated/tutorials/sparse_federated_learning.ipynb
25118 views
Copyright 2021 The TensorFlow Federated Authors.
Aprendizaje federado de modelos grandes eficiente para el cliente a través de federated_select
y agregación dispersa
Este tutorial muestra cómo se puede usar TFF para entrenar un modelo muy grande donde cada dispositivo cliente solo descarga y actualiza una pequeña parte del modelo, con ayuda de tff.federated_select
y agregación dispersa. Si bien este tutorial es bastante completo, el tutorial tff.federated_select
y el tutorial de algoritmos de FL personalizados sirven de introducción a algunas de las técnicas que se utilizan aquí.
Concretamente, en este tutorial consideramos la regresión logística para la clasificación de etiquetas múltiples, prediciendo qué "etiquetas" están asociadas con una cadena de texto basada en una representación de características de bolsa de palabras. Es importante destacar que los costos de comunicación y cálculo del lado del cliente están controlados por una constante fija (MAX_TOKENS_SELECTED_PER_CLIENT
) y no escalan con el tamaño general del vocabulario, que podría ser extremadamente grande en la práctica.
Cada cliente usará federated_select
para seleccionar las filas de las ponderaciones del modelo para, como máximo, esta cantidad de tokens únicos. Esto limita el tamaño del modelo local del cliente y la cantidad de comunicación servidor -> cliente (federated_select
) y cliente - > servidor (federated_aggregate
).
Este tutorial debería ejecutarse correctamente incluso si se ajusta a un valor tan pequeño como 1 (lo que garantiza que no se seleccionen todas las fichas de cada cliente) o a un valor grande, aunque la convergencia del modelo puede verse afectada.
También definimos algunas constantes para varios tipos. Para esta colaboración, un token es un identificador entero para una palabra en particular después de analizar el conjunto de datos.
Configuración del problema: conjunto de datos y modelo
En este tutorial construimos un pequeño conjunto de datos de juguete para facilitar la experimentación. Sin embargo, el formato del conjunto de datos es compatible con Federated StackOverflow y la arquitectura del modelo y el preprocesamiento se adoptan del problema de predicción de etiquetas StackOverflow de Adaptive Federated Optimization.
Parseo y preprocesamiento de conjuntos de datos
Un pequeño conjunto de datos de juguete
Construimos un pequeño conjunto de datos de juguete con un vocabulario global de 12 palabras y 3 clientes. Este pequeño ejemplo sirve para probar casos extremos (por ejemplo, tenemos dos clientes con menos de MAX_TOKENS_SELECTED_PER_CLIENT = 6
tokens distintos y uno con más) y desarrollar el código.
No obstante, los casos de uso de este enfoque en el mundo real serían vocabularios globales de decenas de millones o más, con quizás miles de tokens distintos en cada cliente. Como el formato de los datos es el mismo, la extensión a problemas de banco de pruebas más realistas, por ejemplo, el conjunto de datos tff.simulation.datasets.stackoverflow.load_data()
, debería ser sencilla.
En primer lugar, definimos nuestros vocabularios de palabras y etiquetas.
Ahora, creamos 3 clientes con pequeños conjuntos de datos locales. Si está ejecutando este tutorial en Colab, quizá le resulte útil la característica "reflejar celda en pestaña" para fijar esta celda y su salida con el fin de interpretar/comprobar la salida de las funciones que se desarrollan a continuación.
Defina constantes para los números brutos de características de entrada (tokens/palabras) y etiquetas (etiquetas de publicación). Nuestros espacios de entrada/salida reales son NUM_OOV_BUCKETS = 1
más grandes porque agregamos un token/etiqueta OOV.
Cree versiones por lotes de los conjuntos de datos y lotes individuales, que serán útiles para probar el código a medida que avanzamos.
Definición de un modelo con entradas dispersas
Utilizamos un modelo de regresión logística independiente y simple para cada etiqueta.
Hagamos predicciones para asegurarnos de que funciona:
Y algún entrenamiento centralizado simple:
Bloques de creación para el cálculo federado
Vamos a implementar una versión simple del algoritmo de promediado federado con la diferencia clave de que cada dispositivo solo descarga un subconjunto relevante del modelo y solo aporta actualizaciones a ese subconjunto.
Usamos M
como abreviatura de MAX_TOKENS_SELECTED_PER_CLIENT
. A un nivel alto, una ronda de entrenamiento implica estos pasos:
Cada cliente participante escanea su conjunto de datos local, a la vez que parsea las cadenas de entrada y las asigna a los tokens correctos (índices int). Esto requiere acceso al (enorme) diccionario global (esto podría evitarse si se usan técnicas de hash de características). A continuación, contamos de forma dispersa cuántas veces aparece cada token. Si aparecen
U
tokens únicos en el dispositivo, elegimos los tokensnum_actual_tokens = min(U, M)
más frecuentes para entrenar.Los clientes usan
federated_select
para recuperar los coeficientes del modelo para los tokensnum_actual_tokens
seleccionados del servidor. Cada segmento del modelo es un tensor de forma(TAG_VOCAB_SIZE, )
, por lo que los datos totales que se transmiten al cliente tienen como máximo el tamañoTAG_VOCAB_SIZE * M
(consulte la nota a continuación).Los clientes construyen una asignación
global_token -> local_token
donde el token local (índice int) es el índice del token global en la lista de tokens seleccionados.Los clientes usan una versión "pequeña" del modelo global que solo tiene coeficientes para como máximo
M
tokens, del rango[0, num_actual_tokens)
. La asignaciónglobal -> local
sirve para inicializar los parámetros densos de este modelo a partir de los sectores seleccionados del modelo.Los clientes entrenan su modelo local con SGD en datos preprocesados con la asignación
global -> local
.Los clientes convierten los parámetros de su modelo local en actualizaciones
IndexedSlices
con ayuda de la asignaciónlocal -> global
para indexar las filas. El servidor agrega estas actualizaciones mediante una agregación de suma dispersa.El servidor toma el resultado (denso) de la agregación anterior, lo divide por la cantidad de clientes participantes y aplica la actualización promedio resultante al modelo global.
En esta sección, construimos los bloques de creación de estos pasos, que luego se combinarán en un federated_computation
final que captura la lógica completa de una ronda de entrenamiento.
NOTA: La descripción anterior oculta un detalle técnico: tanto
federated_select
como la construcción del modelo local requieren formas estáticamente conocidas, por lo que no podemos usar el tamaño dinámico denum_actual_tokens
por cliente. En vez de eso, usamos el valor estáticoM
y agregamos amortiguado cuando sea necesario. Esto no afecta la semántica del algoritmo.
Cuente los tokens cliente y decida qué modelo se divide en federated_select
Cada dispositivo debe decidir qué "porciones" del modelo son relevantes para su conjunto de datos de entrenamiento local. Para nuestro problema, hacemos esto contando (¡de forma dispersa!) cuántos ejemplos contiene cada token en el conjunto de datos de entrenamiento del cliente.
Seleccionaremos los parámetros del modelo correspondientes a los tokens MAX_TOKENS_SELECTED_PER_CLIENT
que aparecen con más frecuencia en el dispositivo. Si hay menos tokens de esta cantidad en el dispositivo, rellenamos la lista para permitir el uso de federated_select
.
Tenga en cuenta que es posible que otras estrategias sean mejores, por ejemplo, seleccionar tokens aleatoriamente (quizás en función de su probabilidad de aparición). Esto garantizaría que todos los sectores del modelo (para los cuales el cliente tiene datos) tengan alguna posibilidad de actualizarse.
Asignación de tokens globales a tokens locales
La selección anterior nos brinda un conjunto denso de tokens en el rango [0, actual_num_tokens)
que usaremos para el modelo en el dispositivo. Sin embargo, el conjunto de datos que leemos tiene tokens de un rango de vocabulario global mucho más amplio [0, WORD_VOCAB_SIZE)
.
Por lo tanto, necesitamos asignar los tokens globales a sus tokens locales correspondientes. Los identificadores de tokens locales simplemente vienen dados por los índices en el tensor selected_tokens
calculado en el paso anterior.
Entrenamiento del (sub)modelo local en cada cliente
Observe que federated_select
devolverá los sectores seleccionados como tf.data.Dataset
en el mismo orden que las claves de selección. Entonces, primero definimos una función de utilidad para tomar dicho conjunto de datos y convertirlo en un único tensor denso que pueda usarse como ponderaciones del modelo del cliente.
Ahora tenemos todos los componentes que necesitamos para definir un ciclo de entrenamiento local simple que se ejecutará en cada cliente.
Agregación de IndexedSlices
Usamos tff.federated_aggregate
para construir una suma dispersa federada para IndexedSlices
. Esta implementación simple tiene la restricción de que la dense_shape
se conoce estáticamente de antemano. Tenga en cuenta también que esta suma es solo semidispersa, en el sentido de que la comunicación cliente -> servidor es dispersa, pero el servidor mantiene una representación densa de la suma en accumulate
y merge
, y genera esta representación densa.
Construya un federated_computation
mínimo como prueba
Todo se combina en federated_computation
Ahora usamos TFF para unir los componentes en un tff.federated_computation
.
Usamos una función básica de entrenamiento del servidor basada en el promediado federado, aplicando la actualización con una tasa de aprendizaje del servidor de 1,0. Es importante que apliquemos una actualización (delta) al modelo, en lugar de simplemente promediar los modelos que proporciona el cliente, ya que, de lo contrario, si ningún cliente entrena una porción determinada del modelo en una ronda determinada, sus coeficientes podrían reducirse a cero.
Necesitamos un par de componentes tff.tf_computation
más:
¡Ya estamos listos para armar todo!
¡Entrenemos un modelo!
Ahora que tenemos nuestra función de entrenamiento, probémosla.