Ajuste de las agregaciones recomendadas para el aprendizaje

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno

El tff.learning módulo contiene una serie de aspectos a udpates modelo agregado con la configuración por defecto recomendados:

En este tutorial, explicamos la motivación subyacente, cómo se implementan y brindamos sugerencias sobre cómo personalizar su configuración.


!pip install --quiet --upgrade tensorflow-federated-nightly
!pip install --quiet --upgrade nest-asyncio

import nest_asyncio
nest_asyncio.apply()
import math
import tensorflow_federated as tff
tff.federated_computation(lambda: 'Hello, World!')()
b'Hello, World!'

Métodos de agregación están representados por objetos que se pueden pasar a tff.learning.build_federated_averaging_process como su model_update_aggregation_factory argumento de palabra clave. Como tal, los agregadores discutidos aquí pueden ser utilizados directamente para modificar una anterior tutorial en el aprendizaje federado.

La línea de base media ponderada de la FedAvg algoritmo se puede expresar utilizando tff.aggregators.MeanFactory como sigue:

mean = tff.aggregators.MeanFactory()
iterative_process = tff.learning.build_federated_averaging_process(
    ...,
    model_update_aggregation_factory=mean)

Las técnicas que se pueden utilizar para ampliar la media ponderada tratadas en este tutorial son:

  • Puesta a cero
  • Recorte
  • Privacidad diferencial
  • Compresión
  • Agregación segura

La extensión se realiza utilizando la composición, en la que el MeanFactory envuelve una fábrica de interior a la que delega alguna parte de la agregación, o es en sí mismo envuelto por otra fábrica agregación. Para más detalles sobre el diseño, vea Implementación agregadores personalizados tutorial.

Primero, explicaremos cómo habilitar y configurar estas técnicas individualmente, y luego mostraremos cómo se pueden combinar.

Tecnicas

Antes de profundizar en las técnicas individuales, primero presentamos el algoritmo de coincidencia de cuantiles, que será útil para configurar las técnicas a continuación.

Coincidencia de cuantiles

Varias de las técnicas de agregación siguientes deben utilizar un límite de norma que controle algún aspecto de la agregación. Estos límites se pueden proporcionar como una constante, pero normalmente es mejor adaptar el límite durante el curso del entrenamiento. El método recomendado es utilizar el algoritmo de coincidencia de cuantil de Andrew et al. (2019) , propuesto inicialmente por su compatibilidad con la privacidad diferencial pero útil más ampliamente. Para estimar el valor en un determinado cuantil, puede utilizar tff.aggregators.PrivateQuantileEstimationProcess . Por ejemplo, para adaptarse a la mediana de una distribución, puede utilizar:

median_estimate = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=1.0, target_quantile=0.5, learning_rate=0.2)

Las diferentes técnicas que utilizan el algoritmo de estimación de cuantiles requerirán diferentes valores de los parámetros del algoritmo, como veremos. En general, el aumento de los learning_rate medios de parámetros de adaptación más rápida a la cuantil correcta, pero con una mayor varianza. El no_noise classmethod construcciones cuantil un proceso de adaptación que no añade ruido a la privacidad diferencial.

Puesta a cero

La puesta a cero se refiere a reemplazar valores inusualmente grandes por ceros. Aquí, "inusualmente grande" podría significar más grande que un umbral predefinido, o grande en relación con los valores de rondas previas del cálculo. La puesta a cero puede aumentar la solidez del sistema a la corrupción de datos en clientes defectuosos.

Para calcular una media de los valores con las normas L-infinity más grandes que ZEROING_CONSTANT cero de salida, nos envuelva una tff.aggregators.MeanFactory con un tff.aggregators.zeroing_factory que realiza la puesta a cero:

zeroing_mean = tff.aggregators.zeroing_factory(
    zeroing_norm=MY_ZEROING_CONSTANT,
    inner_agg_factory=tff.aggregators.MeanFactory())

Aquí nos envuelva una MeanFactory con un zeroing_factory porque queremos que el (pre-agregación) efectos de la zeroing_factory que se aplican a los valores a los clientes antes de que se pasan al interior MeanFactory para la agregación a través de promedios.

Sin embargo, para la mayoría de las aplicaciones recomendamos la puesta a cero adaptativa con el estimador de cuantiles. Para hacerlo, usamos el algoritmo de coincidencia de cuantiles de la siguiente manera:

zeroing_norm = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=10.0,
    target_quantile=0.98,
    learning_rate=math.log(10),
    multiplier=2.0,
    increment=1.0)
zeroing_mean = tff.aggregators.zeroing_factory(
    zeroing_norm=zeroing_norm,
    inner_agg_factory=tff.aggregators.MeanFactory())

# Equivalent to:
# zeroing_mean = tff.learning.robust_aggregator(clipping=False)

Los parámetros han sido elegidos de manera que los procesos se adapta muy rápidamente (relativamente grande learning_rate ) a un valor algo mayor que los valores más grandes vistos hasta ahora. Para una estimación cuantil Q , el umbral utilizado para poner a cero será Q * multiplier + increment .

Recorte para limitar la norma L2

Recortar las actualizaciones del cliente (proyectarlas en una bola L2) puede mejorar la solidez frente a los valores atípicos. Un tff.aggregators.clipping_factory está estructurado exactamente como tff.aggregators.zeroing_factory discutió anteriormente, y puede tomar ya sea una constante o una tff.templates.EstimationProcess como su clipping_norm argumento. La mejor práctica recomendada es utilizar un recorte que se adapte moderadamente rápido a una norma moderadamente alta, de la siguiente manera:

clipping_norm = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=1.0,
    target_quantile=0.8,
    learning_rate=0.2)
clipping_mean = tff.aggregators.clipping_factory(
    clipping_norm=clipping_norm,
    inner_agg_factory=tff.aggregators.MeanFactory())

# Equivalent to:
# clipping_mean = tff.learning.robust_aggregator(zeroing=False)

En nuestra experiencia de muchos problemas, el valor preciso del target_quantile no parece importar demasiado, siempre y cuando las tasas de aprendizaje están sintonizados adecuadamente. Sin embargo, establecerlo en un valor muy bajo puede requerir aumentar la tasa de aprendizaje del servidor para obtener el mejor rendimiento, en relación con no usar el recorte, por lo que recomendamos 0.8 por defecto.

Privacidad diferencial

TFF también admite la agregación privada diferencial, utilizando recorte adaptativo y ruido gaussiano. Un agregador para realizar promedios privados diferencialmente se puede construir de la siguiente manera:

dp_mean = tff.aggregators.DifferentiallyPrivateFactory.gaussian_adaptive(
    noise_multiplier=0.1, clients_per_round=100)

# Equivalent to:
# dp_mean = tff.learning.dp_aggregator(
#   noise_multiplier=0.1, clients_per_round=100, zeroing=False)

Orientación sobre cómo establecer el noise_multiplier argumento se puede encontrar en el tutorial TFF DP .

Compresión con pérdida

En comparación con la compresión sin pérdida como gzip, la compresión con pérdida generalmente da como resultado una relación de compresión mucho más alta y aún se puede combinar con la compresión sin pérdida posteriormente. Dado que es necesario dedicar menos tiempo a la comunicación entre el cliente y el servidor, las rondas de capacitación se completan más rápido. Debido a la naturaleza inherentemente aleatoria de los algoritmos de aprendizaje, hasta cierto umbral, la inexactitud de la compresión con pérdida no tiene un impacto negativo en el rendimiento general.

La recomendación predeterminada es utilizar sencilla de cuantificación uniforme (ver Suresh et al. , Por ejemplo), parametrizado por dos valores: la compresión tamaño tensor threshold y el número de quantization_bits . Por cada tensor t , si el número de elementos de t es menor o igual que threshold , no se comprime. Si es mayor, los elementos de t se cuantifican usando redondeo aleatorio para quantizaton_bits bits. Es decir, aplicamos la operación

t = round((t - min(t)) / (max(t) - min(t)) * (2**quantizaton_bits - 1)),

resultando en valores enteros en el rango de [0, 2**quantizaton_bits-1] . Los valores cuantificados se empaquetan directamente en un tipo entero para su transmisión y luego se aplica la transformación inversa.

Se recomienda ajustar quantizaton_bits igual a 8 y el threshold igual a 20000:

compressed_mean = tff.aggregators.MeanFactory(
    tff.aggregators.EncodedSumFactory.quantize_above_threshold(
        quantization_bits=8, threshold=20000))

# Equivalent to:
# compressed_mean = tff.learning.compression_aggregator(zeroing=False, clipping=False)

Sugerencias de ajuste

Ambos parámetros, quantization_bits y threshold se pueden ajustar, y el número de clientes que participan en cada ronda de entrenamiento también pueden afectar a la eficacia de la compresión.

Umbral. Se elige el valor predeterminado de 20000 porque hemos observado que las variables con un número pequeño de elementos, como los sesgos en los tipos de capas comunes, son mucho más sensibles al ruido introducido. Además, en la práctica se gana poco comprimiendo variables con un número reducido de elementos, ya que su tamaño sin comprimir es relativamente pequeño para empezar.

En algunas aplicaciones, puede tener sentido cambiar la elección del umbral. Por ejemplo, los sesgos de la capa de salida de un modelo de clasificación pueden ser más sensibles al ruido. Si usted está entrenando a un modelo de lenguaje con un vocabulario de 20.004, es posible que desee establecer threshold para ser 20.004.

Bits de cuantificación. El valor por defecto de 8 para quantization_bits debe estar bien para la mayoría de usuarios. Si 8 funciona bien y desea exprimir un poco más el rendimiento, podría intentar reducirlo a 7 o 6. Si los recursos lo permiten hacer una pequeña búsqueda en la cuadrícula, le recomendamos que identifique el valor por el cual el entrenamiento se vuelve inestable o La calidad final del modelo comienza a degradarse y luego aumenta ese valor en dos. Por ejemplo, si la configuración quantization_bits a 5 obras, pero poniéndolo a 4 degrada el modelo, recomendaríamos el valor predeterminado a ser de 6 a estar "en el lado seguro".

Clientes por ronda. Tenga en cuenta que el aumento significativo del número de clientes por ronda puede permitir a un valor menor para quantization_bits para trabajar bien, debido a la inexactitud aleatorio introducido por la cuantificación puede ser igualado por un promedio de más de más actualizaciones del cliente.

Agregación segura

Por Secure Aggregation (SecAgg) nos referimos a un protocolo criptográfico en el que las actualizaciones del cliente se cifran de tal manera que el servidor solo puede descifrar su suma. Si la cantidad de clientes que informan es insuficiente, el servidor no aprenderá nada en absoluto, y en ningún caso el servidor podrá inspeccionar actualizaciones individuales. Esto se realiza mediante el tff.federated_secure_sum_bitwidth operador.

Las actualizaciones del modelo son valores de punto flotante, pero SecAgg opera con números enteros. Por lo tanto, necesitamos recortar cualquier valor grande a algún límite antes de la discretización a un tipo entero. El límite de recorte puede ser constante o determinado de forma adaptativa (el valor predeterminado recomendado). A continuación, los números enteros se suman de forma segura y la suma se asigna de nuevo al dominio de coma flotante.

Para calcular una media con valores ponderados sumadas utilizando SecAgg con MY_SECAGG_BOUND como el recorte unido, pasar SecureSumFactory a MeanFactory como:

secure_mean = tff.aggregators.MeanFactory(
    tff.aggregators.SecureSumFactory(MY_SECAGG_BOUND))

Para hacer lo mismo mientras determina los límites de forma adaptativa:

secagg_bound = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=50.0,
    target_quantile=0.95,
    learning_rate=1.0,
    multiplier=2.0)
secure_mean = tff.aggregators.MeanFactory(
    tff.aggregators.SecureSumFactory(secagg_bound))

# Equivalent to:
# secure_mean = tff.learning.secure_aggregator(zeroing=Fasle, clipping=False)

Sugerencias de ajuste

Los parámetros adaptativos se han elegido para que los límites sean estrechos (no perderemos mucha precisión en la discretización) pero el recorte ocurre raramente.

Si ajusta los parámetros, tenga en cuenta que el protocolo SecAgg suma las actualizaciones del modelo ponderado, después de ponderar la media. Los pesos son típicamente el número de puntos de datos procesados ​​localmente, por lo tanto, entre diferentes tareas, el límite correcto puede depender de esta cantidad.

No se recomienda utilizar el increment argumento de palabra clave en la creación de adaptación secagg_bound , ya que esto podría resultar en una gran pérdida de precisión relativa, en el caso de que los extremos reales estimación siendo pequeña.

El fragmento de código anterior utilizará SecAgg solo los valores ponderados. Si también se debe usar SecAgg para la suma de pesos, recomendamos que los límites se establezcan como constantes, ya que en una configuración de entrenamiento común, el mayor peso posible se conocerá de antemano:

secure_mean = tff.aggregators.MeanFactory(
    value_sum_factory=tff.aggregators.SecureSumFactory(secagg_bound),
    weight_sum_factory=tff.aggregators.SecureSumFactory(
        upper_bound_threshold=MAX_WEIGHT, lower_bound_threshold=0.0))

Técnicas de composición

Las técnicas individuales para extender una media introducidas anteriormente se pueden combinar juntas.

Recomendamos que el orden en el que se apliquen estas técnicas a los clientes sea

  1. Puesta a cero
  2. Recorte
  3. Otras tecnicas

Los agregadores en tff.aggregators módulo están compuestos por de envoltura "agregadores internas" (cuya pre-agregación efectos suceder últimos y post-agregación efectos ocurren primero) en el interior "agregadores exteriores". Por ejemplo, para realizar la puesta a cero, el recorte y la compresión (en ese orden), se escribiría:

# Compression is innermost because its pre-aggregation effects are last.
compressed_mean = tff.aggregators.MeanFactory(
    tff.aggregators.EncodedSumFactory.quantize_above_threshold(
        quantization_bits=8, threshold=20000))
# Compressed mean is inner aggregator to clipping...
clipped_compressed_mean = tff.aggregators.clipping_factory(
    clipping_norm=MY_CLIPPING_CONSTANT,
    inner_agg_factory=compressed_mean)
# ...which is inner aggregator to zeroing, since zeroing happens first.
final_aggregator = tff.aggregators.zeroing_factory(
    zeroing_norm=MY_ZEROING_CONSTANT,
    inner_agg_factory=clipped_compressed_mean)

Tenga en cuenta que esta estructura coincide con los agregadores por defecto para los algoritmos de aprendizaje.

También son posibles otras composiciones. Extendemos este documento cuando estamos seguros de que podemos proporcionar una configuración predeterminada que funcione en múltiples aplicaciones diferentes. Para la implementación de nuevas ideas, vea Implementación agregadores personalizados tutorial.