Assistez au symposium Women in ML le 7 décembre Inscrivez-vous maintenant

Noyau fédéré

Restez organisé à l'aide des collections Enregistrez et classez les contenus selon vos préférences.

Ce document présente la couche centrale de TFF qui sert de base à l'apprentissage fédéré et aux éventuels futurs algorithmes fédérés sans apprentissage.

Pour une introduction en douceur à Federated Core, veuillez lire les didacticiels suivants, car ils présentent certains des concepts fondamentaux par exemple et démontrent étape par étape la construction d'un algorithme de moyenne fédérée simple.

Nous vous encourageons également à vous familiariser avec l'apprentissage fédéré et les didacticiels associés sur la classification d'images et la génération de texte , car les utilisations de l'API Federated Core (API FC) pour l'apprentissage fédéré fournissent un contexte important pour certains des choix que nous avons faits dans conception de cette couche.

Aperçu

Objectifs, utilisations prévues et portée

Federated Core (FC) est mieux compris comme un environnement de programmation pour la mise en œuvre de calculs distribués, c'est-à-dire des calculs qui impliquent plusieurs ordinateurs (téléphones mobiles, tablettes, appareils embarqués, ordinateurs de bureau, capteurs, serveurs de base de données, etc.) traitement trivial localement, et communiquent à travers le réseau pour coordonner leur travail.

Le terme distribué est très générique, et TFF ne cible pas tous les types possibles d'algorithmes distribués, nous préférons donc utiliser le terme moins générique de calcul fédéré pour décrire les types d'algorithmes qui peuvent être exprimés dans ce cadre.

Bien que la définition du terme calcul fédéré de manière entièrement formelle sorte du cadre de ce document, pensez aux types d'algorithmes que vous pourriez voir exprimés en pseudocode dans une publication de recherche qui décrit un nouvel algorithme d'apprentissage distribué.

L'objectif de FC, en un mot, est de permettre une représentation compacte similaire, à un niveau d'abstraction similaire à celui d'un pseudocode, d'une logique de programme qui n'est pas un pseudocode, mais plutôt qui est exécutable dans une variété d'environnements cibles.

La principale caractéristique définissant les types d'algorithmes que FC est conçu pour exprimer est que les actions des participants au système sont décrites de manière collective. Ainsi, on a tendance à parler de chaque dispositif transformant localement les données, et des dispositifs coordonnant le travail d'un coordinateur centralisé diffusant , collectant ou agrégeant leurs résultats.

Si TFF a été conçu pour pouvoir aller au-delà des simples architectures client-serveur , la notion de traitement collectif est fondamentale. Cela est dû aux origines de TFF dans l'apprentissage fédéré, une technologie conçue à l'origine pour prendre en charge les calculs sur des données potentiellement sensibles qui restent sous le contrôle des appareils clients et qui ne peuvent pas être simplement téléchargées vers un emplacement centralisé pour des raisons de confidentialité. Alors que chaque client dans de tels systèmes contribue aux données et à la puissance de traitement pour calculer un résultat par le système (un résultat dont nous nous attendons généralement à ce qu'il soit utile à tous les participants), nous nous efforçons également de préserver la confidentialité et l'anonymat de chaque client.

Ainsi, alors que la plupart des cadres d'informatique distribuée sont conçus pour exprimer le traitement du point de vue des participants individuels - c'est-à-dire au niveau des échanges de messages point à point individuels, et l'interdépendance des transitions d'état local du participant avec les messages entrants et sortants , Federated Core de TFF est conçu pour décrire le comportement du système du point de vue global du système (similaire à, par exemple, MapReduce ).

Par conséquent, alors que les frameworks distribués à des fins générales peuvent offrir des opérations telles que l' envoi et la réception en tant que blocs de construction, FC fournit des blocs de construction tels que tff.federated_sum , tff.federated_reduce ou tff.federated_broadcast qui encapsulent des protocoles distribués simples.

Langue

Interface Python

TFF utilise un langage interne pour représenter les calculs fédérés, dont la syntaxe est définie par la représentation sérialisable dans calcul.proto . Cependant, les utilisateurs de l'API FC n'auront généralement pas besoin d'interagir directement avec ce langage. Au lieu de cela, nous fournissons une API Python (l'espace de noms tff ) qui l'entoure comme un moyen de définir des calculs.

Plus précisément, TFF fournit des décorateurs de fonctions Python tels que tff.federated_computation qui retracent les corps des fonctions décorées et produisent des représentations sérialisées de la logique de calcul fédérée dans le langage de TFF. Une fonction décorée avec tff.federated_computation agit comme un support d'une telle représentation sérialisée et peut l'intégrer en tant que bloc de construction dans le corps d'un autre calcul, ou l'exécuter à la demande lorsqu'elle est invoquée.

Voici juste un exemple; d'autres exemples peuvent être trouvés dans les didacticiels sur les algorithmes personnalisés .

@tff.federated_computation(tff.type_at_clients(tf.float32))
def get_average_temperature(sensor_readings):
  return tff.federated_mean(sensor_readings)

Les lecteurs familiarisés avec TensorFlow non enthousiaste trouveront cette approche analogue à l'écriture de code Python qui utilise des fonctions telles que tf.add ou tf.reduce_sum dans une section de code Python qui définit un graphique TensorFlow. Bien que le code soit techniquement exprimé en Python, son objectif est de construire une représentation sérialisable d'un tf.Graph en dessous, et c'est le graphique, et non le code Python, qui est exécuté en interne par le runtime TensorFlow. De même, on peut considérer tff.federated_mean comme l'insertion d'un op fédéré dans un calcul fédéré représenté par get_average_temperature .

Une partie de la raison pour laquelle FC définit un langage est liée au fait que, comme indiqué ci-dessus, les calculs fédérés spécifient des comportements collectifs distribués et, en tant que tels, leur logique est non locale. Par exemple, TFF fournit des opérateurs dont les entrées et les sorties peuvent exister à différents endroits du réseau.

Cela nécessite un langage et un système de types qui capturent la notion de distribution.

Système de types

Federated Core propose les catégories de types suivantes. En décrivant ces types, nous indiquons les constructeurs de types et introduisons une notation compacte, car c'est un moyen pratique de décrire les types de calculs et d'opérateurs.

Tout d'abord, voici les catégories de types qui sont conceptuellement similaires à celles trouvées dans les langages traditionnels existants :

  • Types de tenseur ( tff.TensorType ). Tout comme dans TensorFlow, ceux-ci ont dtype et shape . La seule différence est que les objets de ce type ne sont pas limités aux instances tf.Tensor en Python qui représentent les sorties des opérations TensorFlow dans un graphique TensorFlow, mais peuvent également inclure des unités de données qui peuvent être produites, par exemple, en tant que sortie d'un distribué protocole d'agrégation. Ainsi, le type de tenseur TFF est simplement une version abstraite d'une représentation physique concrète de ce type en Python ou TensorFlow.

    Les TensorTypes de TFF peuvent être plus stricts dans leur traitement (statique) des formes que TensorFlow. Par exemple, le système de type de TFF traite un tenseur de rang inconnu comme pouvant être attribué à partir de tout autre tenseur du même dtype , mais non attribuable à un tenseur de rang fixe. Ce traitement empêche certains échecs d'exécution (par exemple, tenter de remodeler un tenseur de rang inconnu en une forme avec un nombre incorrect d'éléments), au prix d'une plus grande rigueur dans les calculs que TFF accepte comme valides.

    La notation compacte pour les types de tenseurs est dtype ou dtype[shape] . Par exemple, int32 et int32[10] sont respectivement les types d'entiers et de vecteurs int.

  • Types de séquence ( tff.SequenceType ). Ce sont l'équivalent abstrait de TFF du concept concret de TensorFlow de tf.data.Dataset s. Les éléments de séquences peuvent être consommés de manière séquentielle et peuvent inclure des types complexes.

    La représentation compacte des types de séquence est T* , où T est le type des éléments. Par exemple, int32* représente une séquence d'entiers.

  • Types de tuple nommés ( tff.StructType ). C'est la façon dont TFF construit des tuples et des structures de type dictionnaire qui ont un nombre prédéfini d' éléments avec des types spécifiques, nommés ou non. Il est important de noter que le concept de tuple nommé de TFF englobe l'équivalent abstrait des tuples d'argument de Python, c'est-à-dire des collections d'éléments dont certains, mais pas tous, sont nommés, et certains sont positionnels.

    La notation compacte pour les tuples nommés est <n_1=T_1, ..., n_k=T_k> , où n_k sont des noms d'éléments facultatifs et T_k sont des types d'éléments. Par exemple, <int32,int32> est une notation compacte pour une paire d'entiers sans nom, et <X=float32,Y=float32> est une notation compacte pour une paire de flottants nommés X et Y qui peuvent représenter un point sur un plan . Les tuples peuvent être imbriqués ou mélangés avec d'autres types, par exemple, <X=float32,Y=float32>* serait une notation compacte pour une séquence de points.

  • Types de fonctions ( tff.FunctionType ). TFF est un cadre de programmation fonctionnel, avec des fonctions traitées comme des valeurs de première classe . Les fonctions ont au plus un argument et exactement un résultat.

    La notation compacte pour les fonctions est (T -> U) , où T est le type d'un argument et U est le type du résultat, ou ( -> U) s'il n'y a pas d'argument (bien que les fonctions sans argument soient un dégénéré concept qui n'existe principalement qu'au niveau Python). Par exemple (int32* -> int32) est une notation pour un type de fonctions qui réduisent une séquence d'entiers à une seule valeur entière.

Les types suivants traitent de l'aspect systèmes distribués des calculs TFF. Comme ces concepts sont quelque peu uniques à TFF, nous vous encourageons à vous référer au didacticiel sur les algorithmes personnalisés pour des commentaires et des exemples supplémentaires.

  • Type d'emplacement . Ce type n'est pas encore exposé dans l'API publique autrement que sous la forme de 2 littéraux tff.SERVER et tff.CLIENTS que vous pouvez considérer comme des constantes de ce type. Cependant, il est utilisé en interne et sera introduit dans l'API publique dans les prochaines versions. La représentation compacte de ce type est placement .

    Un placement représente un collectif de participants au système qui jouent un rôle particulier. La version initiale cible les calculs client-serveur, dans lesquels il y a 2 groupes de participants : les clients et un serveur (vous pouvez considérer ce dernier comme un groupe singleton). Cependant, dans des architectures plus élaborées, il pourrait y avoir d'autres rôles, tels que des agrégateurs intermédiaires dans un système à plusieurs niveaux, qui pourraient effectuer différents types d'agrégation ou utiliser des types de compression/décompression de données différents de ceux utilisés par le serveur ou les clients.

    Le but principal de la définition de la notion de placement est de servir de base à la définition des types fédérés .

  • Types fédérés ( tff.FederatedType ). Une valeur d'un type fédéré est une valeur qui est hébergée par un groupe de participants système définis par un emplacement spécifique (tel que tff.SERVER ou tff.CLIENTS ). Un type fédéré est défini par la valeur de placement (il s'agit donc d'un type dépendant ), le type de constituants membres (quel type de contenu chacun des participants héberge localement) et le bit supplémentaire all_equal qui spécifie si tous les participants sont localement hébergeant le même élément.

    La notation compacte pour le type fédéré de valeurs qui incluent des éléments (constituants membres) de type T , chacun hébergé par le groupe (placement) G est T@G ou {T}@G avec le bit all_equal défini ou non défini, respectivement.

    Par exemple:

    • {int32}@CLIENTS représente une valeur fédérée composée d'un ensemble d'entiers potentiellement distincts, un par appareil client. Notez que nous parlons d'une seule valeur fédérée englobant plusieurs éléments de données qui apparaissent à plusieurs endroits sur le réseau. On peut l'envisager comme une sorte de tenseur à dimension « réseau », même si cette analogie n'est pas parfaite car la TFF ne permet pas un accès aléatoire aux constituants membres d'une valeur fédérée.

    • {<X=float32,Y=float32>*}@CLIENTS représente un ensemble de données fédérées , une valeur composée de plusieurs séquences de coordonnées XY , une séquence par appareil client.

    • <weights=float32[10,5],bias=float32[5]>@SERVER représente un tuple nommé de tenseurs de poids et de biais sur le serveur. Puisque nous avons supprimé les accolades, cela indique que le bit all_equal est défini, c'est-à-dire qu'il n'y a qu'un seul tuple (quel que soit le nombre de répliques de serveur dans un cluster hébergeant cette valeur).

Blocs de construction

Le langage de Federated Core est une forme de lambda-calcul , avec quelques éléments supplémentaires.

Il fournit les abstractions de programmation suivantes actuellement exposées dans l'API publique :

  • Calculs TensorFlow ( tff.tf_computation ). Il s'agit de sections de code TensorFlow encapsulées sous forme de composants réutilisables dans TFF à l'aide du décorateur tff.tf_computation . Ils ont toujours des types fonctionnels et, contrairement aux fonctions de TensorFlow, ils peuvent prendre des paramètres structurés ou renvoyer des résultats structurés d'un type de séquence.

    Voici un exemple, un calcul TF de type (int32* -> int) qui utilise l'opérateur tf.data.Dataset.reduce pour calculer une somme d'entiers :

    @tff.tf_computation(tff.SequenceType(tf.int32))
    def add_up_integers(x):
      return x.reduce(np.int32(0), lambda x, y: x + y)
    
  • Opérateurs intrinsèques ou fédérés ( tff.federated_... ). Il s'agit d'une bibliothèque de fonctions telles que tff.federated_sum ou tff.federated_broadcast qui constituent l'essentiel de l'API FC, dont la plupart représentent des opérateurs de communication distribués à utiliser avec TFF.

    Nous les appelons intrinsèques car, un peu comme les fonctions intrinsèques , il s'agit d'un ensemble ouvert et extensible d'opérateurs compris par TFF et compilés dans du code de niveau inférieur.

    La plupart de ces opérateurs ont des paramètres et des résultats de types fédérés, et la plupart sont des modèles qui peuvent être appliqués à différents types de données.

    Par exemple, tff.federated_broadcast peut être considéré comme un opérateur modèle d'un type fonctionnel T@SERVER -> T@CLIENTS .

  • Expressions lambda ( tff.federated_computation ). Une expression lambda dans TFF est l'équivalent d'un lambda ou d'un def en Python ; il se compose du nom du paramètre et d'un corps (expression) qui contient des références à ce paramètre.

    Dans le code Python, ceux-ci peuvent être créés en décorant les fonctions Python avec tff.federated_computation et en définissant un argument.

    Voici un exemple d'expression lambda que nous avons déjà mentionné plus tôt :

    @tff.federated_computation(tff.type_at_clients(tf.float32))
    def get_average_temperature(sensor_readings):
      return tff.federated_mean(sensor_readings)
    
  • Littéraux de placement . Pour l'instant, seuls tff.SERVER et tff.CLIENTS permettent de définir des calculs client-serveur simples.

  • Appels de fonction ( __call__ ). Tout ce qui a un type fonctionnel peut être appelé en utilisant la syntaxe standard Python __call__ . L'invocation est une expression dont le type est le même que le type du résultat de la fonction invoquée.

    Par exemple:

    • add_up_integers(x) représente une invocation du calcul TensorFlow défini précédemment sur un argument x . Le type de cette expression est int32 .

    • tff.federated_mean(sensor_readings) représente une invocation de l'opérateur de moyennage fédéré sur sensor_readings . Le type de cette expression est float32@SERVER (en supposant le contexte de l'exemple ci-dessus).

  • Former des tuples et sélectionner leurs éléments. Expressions Python de la forme [x, y] , x[y] ou xy qui apparaissent dans le corps des fonctions décorées avec tff.federated_computation .