Nucleo federato

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

Questo documento introduce il livello centrale di TFF che funge da base per l' apprendimento federato e possibili futuri algoritmi federati non di apprendimento.

Per una breve introduzione a Federated Core, leggi i seguenti tutorial, poiché introducono alcuni dei concetti fondamentali tramite esempi e dimostrano passo dopo passo la costruzione di un semplice algoritmo di media federato.

Ti invitiamo inoltre a familiarizzare con l' apprendimento federato e i tutorial associati sulla classificazione delle immagini e la generazione di testo , poiché gli usi dell'API di base federata (API FC) per l'apprendimento federato forniscono un contesto importante per alcune delle scelte che abbiamo fatto in progettare questo livello.

Panoramica

Obiettivi, usi previsti e ambito

Federated Core (FC) è meglio inteso come un ambiente di programmazione per l'implementazione di calcoli distribuiti, ovvero calcoli che coinvolgono più computer (telefoni cellulari, tablet, dispositivi incorporati, computer desktop, sensori, server di database, ecc.) che possono eseguire ciascuno non- elaborazione banale a livello locale e comunicare attraverso la rete per coordinare il proprio lavoro.

Il termine distribuito è molto generico e TFF non prende di mira tutti i possibili tipi di algoritmi distribuiti, quindi preferiamo usare il termine meno generico calcolo federato per descrivere i tipi di algoritmi che possono essere espressi in questo framework.

Sebbene la definizione del termine calcolo federato in modo completamente formale esula dallo scopo di questo documento, pensa ai tipi di algoritmi che potresti vedere espressi in pseudocodice in una pubblicazione di ricerca che descrive un nuovo algoritmo di apprendimento distribuito.

L'obiettivo di FC, in poche parole, è consentire una rappresentazione altrettanto compatta, a un livello di astrazione simile a uno pseudocodice, della logica del programma che non è pseudocodice, ma piuttosto eseguibile in una varietà di ambienti di destinazione.

La caratteristica chiave che definisce i tipi di algoritmi che FC è progettato per esprimere è che le azioni dei partecipanti al sistema sono descritte in modo collettivo. Pertanto, tendiamo a parlare di ciascun dispositivo che trasforma i dati localmente e dei dispositivi che coordinano il lavoro da parte di un coordinatore centralizzato che trasmette , raccoglie o aggrega i risultati.

Mentre TFF è stato progettato per essere in grado di andare oltre le semplici architetture client-server , la nozione di elaborazione collettiva è fondamentale. Ciò è dovuto alle origini di TFF nell'apprendimento federato, una tecnologia originariamente progettata per supportare i calcoli su dati potenzialmente sensibili che rimangono sotto il controllo dei dispositivi client e che potrebbero non essere semplicemente scaricati in una posizione centralizzata per motivi di privacy. Mentre ogni cliente in tali sistemi contribuisce con dati e potenza di elaborazione al calcolo di un risultato dal sistema (un risultato che generalmente ci aspetteremmo essere di valore per tutti i partecipanti), ci sforziamo anche di preservare la privacy e l'anonimato di ogni cliente.

Pertanto, mentre la maggior parte dei framework per il calcolo distribuito sono progettati per esprimere l'elaborazione dal punto di vista dei singoli partecipanti, ovvero a livello di scambi di messaggi da punto a punto individuali e l'interdipendenza delle transizioni statali locali del partecipante con i messaggi in entrata e in uscita , Federated Core di TFF è progettato per descrivere il comportamento del sistema dalla prospettiva globale del sistema (in modo simile, ad esempio, a MapReduce ).

Di conseguenza, mentre i framework distribuiti per scopi generali possono offrire operazioni come invio e ricezione come blocchi predefiniti, FC fornisce blocchi predefiniti come tff.federated_sum , tff.federated_reduce o tff.federated_broadcast che incapsulano semplici protocolli distribuiti.

Lingua

Interfaccia Python

TFF utilizza un linguaggio interno per rappresentare i calcoli federati, la cui sintassi è definita dalla rappresentazione serializzabile in computation.proto . Tuttavia, gli utenti dell'API FC generalmente non avranno bisogno di interagire direttamente con questa lingua. Piuttosto, forniamo un'API Python (lo spazio dei nomi tff ) che lo avvolge come un modo per definire i calcoli.

In particolare, TFF fornisce decoratori di funzioni Python come tff.federated_computation che tracciano i corpi delle funzioni decorate e producono rappresentazioni serializzate della logica di calcolo federata nel linguaggio di TFF. Una funzione decorata con tff.federated_computation funge da vettore di tale rappresentazione serializzata e può incorporarla come un blocco di costruzione nel corpo di un altro calcolo o eseguirla su richiesta quando viene invocata.

Ecco solo un esempio; altri esempi possono essere trovati nei tutorial sugli algoritmi personalizzati .

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

I lettori che hanno familiarità con TensorFlow non desiderosi troveranno questo approccio analogo alla scrittura di codice Python che utilizza funzioni come tf.add o tf.reduce_sum in una sezione del codice Python che definisce un grafico TensorFlow. Sebbene il codice sia tecnicamente espresso in Python, il suo scopo è costruire una rappresentazione serializzabile di un tf.Graph sottostante, ed è il grafico, non il codice Python, che viene eseguito internamente dal runtime TensorFlow. Allo stesso modo, si può pensare a tff.federated_mean come all'inserimento di un op federato in un calcolo federato rappresentato da get_average_temperature .

Una parte del motivo per cui FC definisce un linguaggio ha a che fare con il fatto che, come notato sopra, i calcoli federati specificano comportamenti collettivi distribuiti e, in quanto tali, la loro logica non è locale. Ad esempio, TFF fornisce operatori, input e output di cui possono esistere in diversi punti della rete.

Ciò richiede un linguaggio e un sistema di tipi che catturino la nozione di distribuzione.

Tipo Sistema

Federated Core offre le seguenti categorie di tipi. Nella descrizione di questi tipi, indichiamo i costruttori di tipi e introduciamo una notazione compatta, poiché è un modo pratico per descrivere tipi di calcoli e operatori.

Innanzitutto, ecco le categorie di tipi che sono concettualmente simili a quelle che si trovano nelle lingue tradizionali esistenti:

  • Tipi di tensore ( tff.TensorType ). Proprio come in TensorFlow, questi hanno dtype e shape . L'unica differenza è che gli oggetti di questo tipo non sono limitati alle istanze tf.Tensor in Python che rappresentano gli output delle operazioni TensorFlow in un grafico TensorFlow, ma possono anche includere unità di dati che possono essere prodotte, ad esempio, come output di un protocollo di aggregazione. Pertanto, il tipo tensore TFF è semplicemente una versione astratta di una rappresentazione fisica concreta di tale tipo in Python o TensorFlow.

    I TensorTypes di TFF possono essere più severi nel trattamento (statico) delle forme rispetto a TensorFlow. Ad esempio, il typesystem di TFF tratta un tensore con rango sconosciuto come assegnabile da qualsiasi altro tensore dello stesso dtype , ma non assegnabile a nessun tensore con rango fisso. Questo trattamento previene alcuni errori di runtime (ad esempio, il tentativo di rimodellare un tensore di rango sconosciuto in una forma con un numero errato di elementi), a costo di una maggiore rigidità nei calcoli che TFF accetta come validi.

    La notazione compatta per i tipi tensor è dtype o dtype[shape] . Ad esempio, int32 e int32[10] sono rispettivamente i tipi di interi e int vettori.

  • Tipi di sequenza ( tff.SequenceType ). Questi sono l'equivalente astratto di TFF del concetto concreto di TensorFlow di tf.data.Dataset s. Gli elementi delle sequenze possono essere consumati in modo sequenziale e possono includere tipi complessi.

    La rappresentazione compatta dei tipi di sequenza è T* , dove T è il tipo di elementi. Ad esempio int32* rappresenta una sequenza intera.

  • Tipi di tupla denominati ( tff.StructType ). Questo è il modo in cui TFF costruisce tuple e strutture simili a dizionari che hanno un numero predefinito di elementi con tipi specifici, denominati o senza nome. È importante sottolineare che il concetto di tupla denominata di TFF comprende l'equivalente astratto delle tuple di argomento di Python, ovvero raccolte di elementi di cui alcuni, ma non tutti, sono denominati e alcuni sono posizionali.

    La notazione compatta per le tuple con nome è <n_1=T_1, ..., n_k=T_k> , dove n_k sono nomi di elementi facoltativi e T_k sono tipi di elementi. Ad esempio, <int32,int32> è una notazione compatta per una coppia di numeri interi senza nome e <X=float32,Y=float32> è una notazione compatta per una coppia di float denominati X e Y che possono rappresentare un punto su un piano . Le tuple possono essere annidate così come mescolate con altri tipi, ad esempio, <X=float32,Y=float32>* sarebbe una notazione compatta per una sequenza di punti.

  • Tipi di funzione ( tff.FunctionType ). TFF è un framework di programmazione funzionale, con funzioni trattate come valori di prima classe . Le funzioni hanno al massimo un argomento ed esattamente un risultato.

    La notazione compatta per le funzioni è (T -> U) , dove T è il tipo di un argomento e U è il tipo del risultato, oppure ( -> U) se non ci sono argomenti (sebbene le funzioni senza argomento siano degenerate concetto che esiste principalmente solo a livello di Python). Ad esempio (int32* -> int32) è una notazione per un tipo di funzioni che riducono una sequenza intera a un singolo valore intero.

I seguenti tipi affrontano l'aspetto dei sistemi distribuiti dei calcoli TFF. Poiché questi concetti sono in qualche modo esclusivi di TFF, ti invitiamo a fare riferimento al tutorial sugli algoritmi personalizzati per ulteriori commenti ed esempi.

  • Tipo di posizionamento . Questo tipo non è ancora esposto nell'API pubblica se non sotto forma di 2 letterali tff.SERVER e tff.CLIENTS che puoi considerare come costanti di questo tipo. Tuttavia, viene utilizzato internamente e verrà introdotto nell'API pubblica nelle versioni future. La rappresentazione compatta di questo tipo è il placement .

    Un posizionamento rappresenta un collettivo di partecipanti al sistema che svolgono un ruolo particolare. La versione iniziale mira ai calcoli client-server, in cui ci sono 2 gruppi di partecipanti: client e un server (puoi pensare a quest'ultimo come a un gruppo singleton). Tuttavia, in architetture più elaborate, potrebbero esserci altri ruoli, come aggregatori intermedi in un sistema multilivello, che potrebbero eseguire diversi tipi di aggregazione o utilizzare tipi diversi di compressione/decompressione dei dati rispetto a quelli utilizzati dal server o i clienti.

    Lo scopo principale della definizione della nozione di posizionamenti è come base per definire i tipi federati .

  • Tipi federati ( tff.FederatedType ). Un valore di tipo federato è un valore ospitato da un gruppo di partecipanti al sistema definito da un posizionamento specifico (come tff.SERVER o tff.CLIENTS ). Un tipo federato è definito dal valore di posizionamento (quindi è un tipo dipendente ), dal tipo di membri costituenti (che tipo di contenuto ospita localmente ciascuno dei partecipanti) e dal bit aggiuntivo all_equal che specifica se tutti i partecipanti sono localmente ospitare lo stesso oggetto.

    La notazione compatta per il tipo federato di valori che include elementi (costituenti membri) di tipo T , ciascuno ospitato da gruppo (posizionamento) G è T@G o {T}@G con il bit all_equal impostato o non impostato, rispettivamente.

    Per esempio:

    • {int32}@CLIENTS rappresenta un valore federato costituito da un insieme di interi potenzialmente distinti, uno per dispositivo client. Si noti che stiamo parlando di un singolo valore federato in quanto comprende più elementi di dati che appaiono in più posizioni nella rete. Un modo per pensarci è come una sorta di tensore con una dimensione di "rete", sebbene questa analogia non sia perfetta perché TFF non consente l'accesso casuale ai membri costituenti di un valore federato.

    • {<X=float32,Y=float32>*}@CLIENTS rappresenta un set di dati federato , un valore costituito da più sequenze di coordinate XY , una sequenza per dispositivo client.

    • <weights=float32[10,5],bias=float32[5]>@SERVER rappresenta una tupla denominata di tensori di peso e bias sul server. Dato che abbiamo eliminato le parentesi graffe, questo indica che il bit all_equal è impostato, cioè c'è solo una singola tupla (indipendentemente dal numero di repliche del server che potrebbero esserci in un cluster che ospita questo valore).

Costruzioni

Il linguaggio di Federated Core è una forma di lambda-calculus , con alcuni elementi aggiuntivi.

Fornisce le seguenti astrazioni di programmazione attualmente esposte nell'API pubblica:

  • Calcoli TensorFlow ( tff.tf_computation ). Queste sono sezioni del codice TensorFlow racchiuse come componenti riutilizzabili in TFF utilizzando il decoratore tff.tf_computation . Hanno sempre tipi funzionali e, a differenza delle funzioni in TensorFlow, possono accettare parametri strutturati o restituire risultati strutturati di un tipo di sequenza.

    Ecco un esempio, un calcolo TF di tipo (int32* -> int) che utilizza l'operatore tf.data.Dataset.reduce per calcolare una somma di interi:

    @tff.tf_computation(tff.SequenceType(tf.int32))
    def add_up_integers(x):
      return x.reduce(np.int32(0), lambda x, y: x + y)
    
  • Operatori intrinseci o federati ( tff.federated_... ). Questa è una libreria di funzioni come tff.federated_sum o tff.federated_broadcast che costituiscono la maggior parte delle API FC, la maggior parte delle quali rappresentano operatori di comunicazione distribuiti da utilizzare con TFF.

    Ci riferiamo a questi come intrinseci perché, un po' come le funzioni intrinseche , sono un insieme estensibile e aperto di operatori che sono compresi da TFF e compilati in codice di livello inferiore.

    La maggior parte di questi operatori ha parametri e risultati di tipi federati e la maggior parte sono modelli che possono essere applicati a vari tipi di dati.

    Ad esempio, tff.federated_broadcast può essere pensato come un operatore modello di tipo funzionale T@SERVER -> T@CLIENTS .

  • Espressioni Lambda ( tff.federated_computation ). Un'espressione lambda in TFF è l'equivalente di una lambda o def in Python; è costituito dal nome del parametro e da un corpo (espressione) che contiene riferimenti a questo parametro.

    Nel codice Python, questi possono essere creati decorando le funzioni Python con tff.federated_computation e definendo un argomento.

    Ecco un esempio di un'espressione lambda che abbiamo già menzionato in precedenza:

    @tff.federated_computation(tff.type_at_clients(tf.float32))
    def get_average_temperature(sensor_readings):
      return tff.federated_mean(sensor_readings)
    
  • Letterali di posizionamento . Per ora, solo tff.SERVER e tff.CLIENTS consentono di definire semplici calcoli client-server.

  • Richiami di funzioni ( __call__ ). Tutto ciò che ha un tipo funzionale può essere invocato usando la sintassi standard di Python __call__ . L'invocazione è un'espressione il cui tipo è uguale al tipo del risultato della funzione richiamata.

    Per esempio:

    • add_up_integers(x) rappresenta un'invocazione del calcolo TensorFlow definito in precedenza su un argomento x . Il tipo di questa espressione è int32 .

    • tff.federated_mean(sensor_readings) rappresenta un'invocazione dell'operatore di media federato su sensor_readings . Il tipo di questa espressione è float32@SERVER (assumendo il contesto dell'esempio precedente).

  • Formare tuple e selezionare i loro elementi. Espressioni Python nella forma [x, y] , x[y] o xy che appaiono nei corpi delle funzioni decorate con tff.federated_computation .