Apprentissage fédéré

Aperçu

Ce document présente des interfaces qui facilitent les tâches d'apprentissage fédéré, telles que la formation fédérée ou l'évaluation avec des modèles d'apprentissage automatique existants implémentés dans TensorFlow. En concevant ces interfaces, notre objectif principal était de permettre d'expérimenter l'apprentissage fédéré sans avoir besoin de connaître son fonctionnement sous le capot, et d'évaluer les algorithmes d'apprentissage fédéré mis en œuvre sur une variété de modèles et de données existants. Nous vous encourageons à contribuer à nouveau à la plateforme. TFF a été conçu dans un souci d'extensibilité et de composabilité, et nous apprécions les contributions ; nous sommes ravis de voir ce que vous proposez !

Les interfaces offertes par cette couche se composent des trois éléments clés suivants :

  • Des modèles . Classes et fonctions d'assistance qui vous permettent d'encapsuler vos modèles existants pour les utiliser avec TFF. L'encapsulation d'un modèle peut être aussi simple que d'appeler une seule fonction d'encapsulation (par exemple, tff.learning.models.from_keras_model ) ou de définir une sous-classe de l'interface tff.learning.models.VariableModel pour une personnalisation complète.

  • Générateurs de calculs fédérés . Fonctions d'assistance qui construisent des calculs fédérés pour la formation ou l'évaluation, à l'aide de vos modèles existants.

  • Ensembles de données . Collections de données prédéfinies que vous pouvez télécharger et accéder dans Python pour les utiliser dans la simulation de scénarios d'apprentissage fédéré. Bien que l'apprentissage fédéré soit conçu pour être utilisé avec des données décentralisées qui ne peuvent pas être simplement téléchargées dans un emplacement centralisé, aux étapes de recherche et de développement, il est souvent pratique de mener des expériences initiales en utilisant des données qui peuvent être téléchargées et manipulées localement, en particulier pour les développeurs qui pourraient être nouveau dans l’approche.

Ces interfaces sont définies principalement dans l'espace de noms tff.learning , à l'exception des ensembles de données de recherche et autres fonctionnalités liées à la simulation qui ont été regroupées dans tff.simulation . Cette couche est implémentée à l'aide d'interfaces de niveau inférieur proposées par Federated Core (FC) , qui fournit également un environnement d'exécution.

Avant de continuer, nous vous recommandons de consulter d'abord les tutoriels sur la classification d'images et la génération de texte , car ils présentent la plupart des concepts décrits ici à l'aide d'exemples concrets. Si vous souhaitez en savoir plus sur le fonctionnement de TFF, vous souhaiterez peut-être parcourir le didacticiel sur les algorithmes personnalisés comme introduction aux interfaces de niveau inférieur que nous utilisons pour exprimer la logique des calculs fédérés et étudier l'implémentation existante du interfaces tff.learning .

Des modèles

Hypothèses architecturales

Sérialisation

TFF vise à prendre en charge une variété de scénarios d'apprentissage distribué dans lesquels le code du modèle d'apprentissage automatique que vous écrivez peut s'exécuter sur un grand nombre de clients hétérogènes dotés de fonctionnalités diverses. Même si, à une extrémité du spectre, dans certaines applications, ces clients peuvent être de puissants serveurs de bases de données, de nombreuses utilisations importantes que notre plateforme entend prendre en charge impliquent des appareils mobiles et embarqués dotés de ressources limitées. Nous ne pouvons pas supposer que ces appareils sont capables d’héberger des environnements d’exécution Python ; la seule chose que nous pouvons supposer à ce stade est qu'ils sont capables d'héberger un runtime TensorFlow local. Ainsi, une hypothèse architecturale fondamentale que nous faisons dans TFF est que votre code de modèle doit être sérialisable en tant que graphique TensorFlow.

Vous pouvez (et devriez) toujours développer votre code TF en suivant les dernières bonnes pratiques, comme l'utilisation du mode impatient. Cependant, le code final doit être sérialisable (par exemple, il peut être encapsulé sous forme de tf.function pour le code en mode impatient). Cela garantit que tout état Python ou flux de contrôle nécessaire au moment de l'exécution peut être sérialisé (éventuellement à l'aide d' Autograph ).

Actuellement, TensorFlow ne prend pas entièrement en charge la sérialisation et la désérialisation de TensorFlow en mode impatient. Ainsi, la sérialisation dans TFF suit actuellement le modèle TF 1.0, où tout le code doit être construit dans un tf.Graph contrôlé par TFF. Cela signifie qu'actuellement, TFF ne peut pas utiliser un modèle déjà construit ; au lieu de cela, la logique de définition du modèle est regroupée dans une fonction sans argument qui renvoie un tff.learning.models.VariableModel . Cette fonction est ensuite appelée par TFF pour garantir que tous les composants du modèle sont sérialisés. De plus, étant un environnement fortement typé, TFF nécessitera un peu de métadonnées supplémentaires, comme une spécification du type d'entrée de votre modèle.

Agrégation

Nous recommandons fortement à la plupart des utilisateurs de créer des modèles à l'aide de Keras. Consultez la section Convertisseurs pour Keras ci-dessous. Ces wrappers gèrent automatiquement l’agrégation des mises à jour du modèle ainsi que toutes les métriques définies pour le modèle. Cependant, il peut toujours être utile de comprendre comment l'agrégation est gérée pour un tff.learning.models.VariableModel général.

Il existe toujours au moins deux couches d'agrégation dans l'apprentissage fédéré : l'agrégation locale sur l'appareil et l'agrégation inter-appareils (ou fédérée) :

  • Agrégation locale . Ce niveau d'agrégation fait référence à l'agrégation de plusieurs lots d'exemples appartenant à un client individuel. Cela s'applique à la fois aux paramètres du modèle (variables), qui continuent d'évoluer séquentiellement à mesure que le modèle est formé localement, ainsi qu'aux statistiques que vous calculez (telles que la perte moyenne, la précision et d'autres mesures), que votre modèle sera à nouveau mis à jour localement. lorsqu'il parcourt le flux de données local de chaque client individuel.

    L'agrégation à ce niveau relève de la responsabilité de votre code de modèle et est réalisée à l'aide de constructions TensorFlow standard.

    La structure générale du traitement est la suivante :

    • Le modèle construit d'abord tf.Variable s pour contenir des agrégats, tels que le nombre de lots ou le nombre d'exemples traités, la somme des pertes par lot ou par exemple, etc.

    • TFF appelle la méthode forward_pass sur votre Model plusieurs fois, de manière séquentielle sur les lots suivants de données client, ce qui vous permet de mettre à jour les variables contenant divers agrégats comme effet secondaire.

    • Enfin, TFF appelle la méthode report_local_unfinalized_metrics sur votre modèle pour permettre à votre modèle de compiler toutes les statistiques récapitulatives qu'il a collectées dans un ensemble compact de métriques à exporter par le client. C'est ici que votre code modèle pourra par exemple diviser la somme des pertes par le nombre d'exemples traités pour exporter la perte moyenne, etc.

  • Agrégation fédérée . Ce niveau d'agrégation fait référence à l'agrégation sur plusieurs clients (appareils) du système. Encore une fois, cela s'applique à la fois aux paramètres du modèle (variables), qui sont moyennés entre les clients, ainsi qu'aux métriques que votre modèle a exportées à la suite d'une agrégation locale.

    La réalisation de l'agrégation à ce niveau relève de la responsabilité de TFF. Cependant, en tant que créateur de modèles, vous pouvez contrôler ce processus (plus d'informations ci-dessous).

    La structure générale du traitement est la suivante :

    • Le modèle initial et tous les paramètres requis pour la formation sont distribués par un serveur à un sous-ensemble de clients qui participeront à une série de formation ou d'évaluation.

    • Sur chaque client, indépendamment et en parallèle, votre code de modèle est invoqué à plusieurs reprises sur un flux de lots de données locaux pour produire un nouvel ensemble de paramètres de modèle (lors de l'entraînement) et un nouvel ensemble de métriques locales, comme décrit ci-dessus (il s'agit d'un nouvel ensemble de métriques locales). agrégation).

    • TFF exécute un protocole d'agrégation distribué pour accumuler et agréger les paramètres du modèle et les métriques exportées localement à travers le système. Cette logique est exprimée de manière déclarative à l'aide du propre langage de calcul fédéré de TFF (pas dans TensorFlow). Consultez le didacticiel sur les algorithmes personnalisés pour en savoir plus sur l'API d'agrégation.

Interfaces abstraites

Cette interface constructeur de base + métadonnées est représentée par l'interface tff.learning.models.VariableModel , comme suit :

  • Les méthodes constructeur, forward_pass et report_local_unfinalized_metrics doivent construire les variables de modèle, la transmission directe et les statistiques que vous souhaitez signaler, en conséquence. Le TensorFlow construit par ces méthodes doit être sérialisable, comme indiqué ci-dessus.

  • La propriété input_spec , ainsi que les 3 propriétés qui renvoient des sous-ensembles de vos variables entraînables, non entraînables et locales représentent les métadonnées. TFF utilise ces informations pour déterminer comment connecter des parties de votre modèle aux algorithmes d'optimisation fédérés et pour définir des signatures de type internes pour aider à vérifier l'exactitude du système construit (afin que votre modèle ne puisse pas être instancié sur des données qui ne correspondent pas à ce que vous avez construit). le modèle est conçu pour consommer).

De plus, l'interface abstraite tff.learning.models.VariableModel expose une propriété metric_finalizers qui prend en compte les valeurs non finalisées d'une métrique (renvoyées par report_local_unfinalized_metrics() ) et renvoie les valeurs de métrique finalisées. Les méthodes metric_finalizers et report_local_unfinalized_metrics() seront utilisées ensemble pour créer un agrégateur de métriques inter-clients lors de la définition des processus de formation fédérés ou des calculs d'évaluation. Par exemple, un simple agrégateur tff.learning.metrics.sum_then_finalize additionnera d'abord les valeurs de métriques non finalisées des clients, puis appellera les fonctions de finalisation sur le serveur.

Vous pouvez trouver des exemples sur la façon de définir votre propre tff.learning.models.VariableModel personnalisé dans la deuxième partie de notre didacticiel de classification d'images , ainsi que dans les exemples de modèles que nous utilisons pour les tests dans model_examples.py .

Convertisseurs pour Keras

Presque toutes les informations requises par TFF peuvent être dérivées en appelant les interfaces tf.keras , donc si vous disposez d'un modèle Keras, vous pouvez compter sur tff.learning.models.from_keras_model pour construire un tff.learning.models.VariableModel .

Notez que TFF souhaite toujours que vous fournissiez un constructeur - une fonction de modèle sans argument telle que la suivante :

def model_fn():
  keras_model = ...
  return tff.learning.models.from_keras_model(keras_model, sample_batch, loss=...)

En plus du modèle lui-même, vous fournissez un échantillon de données que TFF utilise pour déterminer le type et la forme de l'entrée de votre modèle. Cela garantit que TFF peut instancier correctement le modèle pour les données qui seront réellement présentes sur les appareils clients (puisque nous supposons que ces données ne sont généralement pas disponibles au moment où vous construisez le TensorFlow à sérialiser).

L'utilisation des wrappers Keras est illustrée dans nos tutoriels de classification d'images et de génération de texte .

Générateurs de calculs fédérés

Le package tff.learning fournit plusieurs générateurs pour les tff.Computation qui effectuent des tâches liées à l'apprentissage ; nous nous attendons à ce que l’ensemble de ces calculs se développe à l’avenir.

Hypothèses architecturales

Exécution

L'exécution d'un calcul fédéré comporte deux phases distinctes.

  • Compiler : TFF compile d'abord les algorithmes d'apprentissage fédéré en une représentation sérialisée abstraite de l'ensemble du calcul distribué. C'est à ce moment-là que la sérialisation TensorFlow se produit, mais d'autres transformations peuvent se produire pour permettre une exécution plus efficace. Nous appelons la représentation sérialisée émise par le compilateur un calcul fédéré .

  • Execute TFF fournit des moyens d' exécuter ces calculs. Pour l'instant, l'exécution n'est prise en charge que via une simulation locale (par exemple, dans un notebook utilisant des données décentralisées simulées).

Un calcul fédéré généré par l'API Federated Learning de TFF, tel qu'un algorithme de formation qui utilise la moyenne de modèle fédéré , ou une évaluation fédérée, comprend un certain nombre d'éléments, notamment :

  • Une forme sérialisée de votre code de modèle ainsi qu'un code TensorFlow supplémentaire construit par le framework Federated Learning pour piloter la boucle de formation/évaluation de votre modèle (comme la construction d'optimiseurs, l'application de mises à jour de modèle, l'itération sur tf.data.Dataset s et le calcul de métriques, et appliquer la mise à jour agrégée sur le serveur, pour n'en nommer que quelques-uns).

  • Une spécification déclarative de la communication entre les clients et un serveur (généralement diverses formes d' agrégation sur les appareils clients et de diffusion du serveur vers tous les clients), et comment cette communication distribuée est entrelacée avec l'exécution client-local ou serveur-local. du code TensorFlow.

Les calculs fédérés représentés sous cette forme sérialisée sont exprimés dans un langage interne indépendant de la plate-forme, distinct de Python, mais pour utiliser l'API Federated Learning, vous n'aurez pas besoin de vous soucier des détails de cette représentation. Les calculs sont représentés dans votre code Python sous forme d'objets de type tff.Computation , que vous pouvez pour la plupart traiter comme des s callable Python opaques.

Dans les didacticiels, vous appellerez ces calculs fédérés comme s’il s’agissait de fonctions Python classiques, à exécuter localement. Cependant, TFF est conçu pour exprimer des calculs fédérés d'une manière indépendante de la plupart des aspects de l'environnement d'exécution, de sorte qu'ils puissent potentiellement être déployés, par exemple, sur des groupes d'appareils exécutant Android ou sur des clusters dans un centre de données. Encore une fois, la principale conséquence de cela réside dans des hypothèses fortes concernant la sérialisation . En particulier, lorsque vous invoquez l'une des méthodes build_... décrites ci-dessous, le calcul est entièrement sérialisé.

État de modélisation

TFF est un environnement de programmation fonctionnel, mais de nombreux processus intéressant l'apprentissage fédéré sont avec état. Par exemple, une boucle de formation qui implique plusieurs cycles de moyenne de modèle fédéré est un exemple de ce que nous pourrions qualifier de processus avec état . Dans ce processus, l'état qui évolue d'un tour à l'autre inclut l'ensemble des paramètres du modèle qui sont en cours d'apprentissage, et éventuellement un état supplémentaire associé à l'optimiseur (par exemple, un vecteur d'impulsion).

Puisque TFF est fonctionnel, les processus avec état sont modélisés dans TFF comme des calculs qui acceptent l'état actuel comme entrée, puis fournissent l'état mis à jour comme sortie. Afin de définir complètement un processus avec état, il faut également spécifier d'où vient l'état initial (sinon nous ne pouvons pas amorcer le processus). Ceci est capturé dans la définition de la classe d'assistance tff.templates.IterativeProcess , avec les 2 propriétés initialize et next correspondant respectivement à l'initialisation et à l'itération.

Constructeurs disponibles

À l'heure actuelle, TFF fournit diverses fonctions de création qui génèrent des calculs fédérés pour la formation et l'évaluation fédérées. Deux exemples notables incluent :

Ensembles de données

Hypothèses architecturales

Sélection des clients

Dans le scénario d'apprentissage fédéré typique, nous avons une grande population de centaines de millions d'appareils clients, dont seule une petite partie peut être active et disponible pour la formation à un moment donné (par exemple, cela peut être limité aux clients qui sont branché à une source d'alimentation, pas sur un réseau avec compteur, et autrement inactif). Généralement, l'ensemble des clients disponibles pour participer à la formation ou à l'évaluation échappe au contrôle du développeur. De plus, comme il n'est pas pratique de coordonner des millions de clients, une série typique de formation ou d'évaluation n'inclura qu'une fraction des clients disponibles, qui peuvent être échantillonnés au hasard .

La principale conséquence de cela est que les calculs fédérés, de par leur conception, sont exprimés d'une manière qui ne tient pas compte de l'ensemble exact des participants ; tous les traitements sont exprimés sous forme d'opérations globales sur un groupe abstrait de clients anonymes, et ce groupe peut varier d'un cycle de formation à l'autre. La liaison réelle du calcul aux participants concrets, et donc aux données concrètes qu’ils alimentent dans le calcul, est donc modélisée en dehors du calcul lui-même.

Afin de simuler un déploiement réaliste de votre code d'apprentissage fédéré, vous écrirez généralement une boucle de formation qui ressemble à ceci :

trainer = tff.learning.algorithms.build_weighted_fed_avg(...)
state = trainer.initialize()
federated_training_data = ...

def sample(federate_data):
  return ...

while True:
  data_for_this_round = sample(federated_training_data)
  result = trainer.next(state, data_for_this_round)
  state = result.state

Afin de faciliter cela, lors de l'utilisation de TFF dans des simulations, les données fédérées sont acceptées sous forme list Python, avec un élément par appareil client participant pour représenter le tf.data.Dataset local de cet appareil.

Interfaces abstraites

Afin de standardiser le traitement des ensembles de données fédérés simulés, TFF fournit une interface abstraite tff.simulation.datasets.ClientData , qui permet d'énumérer l'ensemble des clients et de construire un tf.data.Dataset qui contient les données d'un utilisateur particulier. client. Ces tf.data.Dataset s peuvent être alimentés directement en entrée des calculs fédérés générés en mode impatient.

Il convient de noter que la possibilité d'accéder aux identités des clients est une fonctionnalité fournie uniquement par les ensembles de données destinés à être utilisés dans les simulations, où la capacité de s'entraîner sur les données de sous-ensembles spécifiques de clients peut être nécessaire (par exemple, pour simuler la disponibilité diurne de différents types de clients). Les calculs compilés et le runtime sous-jacent n’impliquent aucune notion d’identité client. Une fois que les données d'un sous-ensemble spécifique de clients ont été sélectionnées comme entrée, par exemple dans un appel à tff.templates.IterativeProcess.next , les identités des clients n'y apparaissent plus.

Ensembles de données disponibles

Nous avons dédié l'espace de noms tff.simulation.datasets aux ensembles de données qui implémentent l'interface tff.simulation.datasets.ClientData à utiliser dans les simulations, et l'avons ensemencé avec des ensembles de données pour prendre en charge les didacticiels de classification d'images et de génération de texte . Nous aimerions vous encourager à contribuer vos propres ensembles de données à la plateforme.