Ten dokument przedstawia podstawową warstwę TFF, która służy jako podstawa dla federacyjnego uczenia się i możliwych przyszłych algorytmów federacyjnych niezwiązanych z nauką.
Aby uzyskać delikatne wprowadzenie do Federated Core, przeczytaj poniższe samouczki, ponieważ przedstawiają niektóre podstawowe pojęcia na przykładach i demonstrują krok po kroku konstrukcję prostego federacyjnego algorytmu uśredniania.
Niestandardowe algorytmy federacyjne, część 1: Wprowadzenie do rdzenia federacyjnego .
Niestandardowe algorytmy federacyjne, część 2: Implementacja uśredniania federacyjnego .
Zachęcamy również do zapoznania się z Federated Learning i powiązanymi samouczkami dotyczącymi klasyfikacji obrazów i generowania tekstu , ponieważ zastosowania Federated Core API (FC API) do sfederowanego uczenia się zapewniają ważny kontekst dla niektórych wyborów, których dokonaliśmy w projektowanie tej warstwy.
Przegląd
Cele, przeznaczenie i zakres
Federated Core (FC) najlepiej rozumieć jako środowisko programistyczne do wdrażania obliczeń rozproszonych, tj. obliczeń obejmujących wiele komputerów (telefony komórkowe, tablety, urządzenia wbudowane, komputery stacjonarne, czujniki, serwery baz danych itp.), z których każdy może wykonywać inne czynności niż: trywialne przetwarzanie lokalnie i komunikowanie się w sieci w celu koordynowania ich pracy.
Termin rozproszony jest bardzo ogólny, a TFF nie obejmuje wszystkich możliwych typów algorytmów rozproszonych, dlatego wolimy używać mniej ogólnego terminu obliczenia sfederowane do opisywania typów algorytmów, które można wyrazić w tej strukturze.
Chociaż definiowanie terminu obliczeń federacyjnych w sposób w pełni formalny wykracza poza zakres tego dokumentu, pomyśl o typach algorytmów, które możesz zobaczyć w pseudokodzie w publikacji naukowej opisującej nowy algorytm uczenia rozproszonego.
Celem FC, w skrócie, jest umożliwienie podobnie zwartej reprezentacji, na podobnym do pseudokodu poziomie abstrakcji, logiki programu, która nie jest pseudokodem, ale jest wykonywalna w różnych środowiskach docelowych.
Kluczową cechą definiującą rodzaje algorytmów, które ma wyrażać FC, jest to, że działania uczestników systemu są opisywane w sposób zbiorowy. Dlatego mówimy o każdym urządzeniu lokalnie przekształcającym dane oraz o urządzeniach koordynujących pracę przez scentralizowanego koordynatora rozgłaszającego , zbierającego lub agregującego swoje wyniki.
Chociaż TFF został zaprojektowany tak, aby móc wyjść poza proste architektury klient-serwer , pojęcie przetwarzania kolektywnego ma fundamentalne znaczenie. Wynika to z początków TFF w federacyjnym uczeniu się, technologii pierwotnie zaprojektowanej do obsługi obliczeń na potencjalnie wrażliwych danych, które pozostają pod kontrolą urządzeń klienckich i których nie można po prostu pobrać do scentralizowanej lokalizacji ze względu na ochronę prywatności. Podczas gdy każdy klient w takich systemach wnosi swoje dane i moc obliczeniową do obliczania wyniku przez system (wynik, który według nas będzie wartościowy dla wszystkich uczestników), staramy się również zachować prywatność i anonimowość każdego klienta.
Tak więc, podczas gdy większość frameworków dla obliczeń rozproszonych jest zaprojektowana tak, aby wyrażać przetwarzanie z perspektywy poszczególnych uczestników – to znaczy na poziomie indywidualnych wymian komunikatów punkt-punkt oraz współzależności lokalnych przejść stanu uczestnika z komunikatami przychodzącymi i wychodzącymi Federated Core TFF ma na celu opisanie zachowania systemu z globalnej perspektywy całego systemu (podobnie jak np. MapReduce ).
W związku z tym, podczas gdy rozproszone struktury do celów ogólnych mogą oferować operacje, takie jak wysyłanie i odbieranie jako bloki konstrukcyjne, FC udostępnia bloki konstrukcyjne, takie jak tff.federated_sum
, tff.federated_reduce
lub tff.federated_broadcast
, które hermetyzują proste protokoły rozproszone.
Język
Interfejs Pythona
TFF używa języka wewnętrznego do reprezentowania obliczeń federacyjnych, którego składnia jest zdefiniowana przez reprezentację do serializacji w computation.proto . Jednak użytkownicy FC API zazwyczaj nie muszą wchodzić w bezpośrednią interakcję z tym językiem. Zamiast tego dostarczamy Pythona API (przestrzeń nazw tff
), która otacza ją jako sposób na zdefiniowanie obliczeń.
W szczególności TFF udostępnia dekoratory funkcji Pythona, takie jak tff.federated_computation
, które śledzą treść dekorowanych funkcji i tworzą serializowane reprezentacje sfederowanej logiki obliczeń w języku TFF. Funkcja ozdobiona tff.federated_computation
działa jako nośnik takiej serializowanej reprezentacji i może osadzić ją jako blok konstrukcyjny w treści innego obliczenia lub wykonać na żądanie po wywołaniu.
Oto tylko jeden przykład; więcej przykładów można znaleźć w samouczkach dotyczących algorytmów niestandardowych .
@tff.federated_computation(tff.type_at_clients(tf.float32))
def get_average_temperature(sensor_readings):
return tff.federated_mean(sensor_readings)
Czytelnicy zaznajomieni z TensorFlow, którzy nie są chętni, uznają to podejście za analogiczne do pisania kodu w Pythonie, który wykorzystuje funkcje takie jak tf.add
lub tf.reduce_sum
w sekcji kodu Pythona, która definiuje wykres TensorFlow. Chociaż kod jest technicznie wyrażony w Pythonie, jego celem jest skonstruowanie serializowanej reprezentacji znajdującego się poniżej tf.Graph
, a to graf, a nie kod Pythona, jest wewnętrznie wykonywany przez środowisko wykonawcze TensorFlow. Podobnie można myśleć o tff.federated_mean
jako o wstawianiu stowarzyszonej operacji do stowarzyszonego obliczenia reprezentowanego przez get_average_temperature
.
Część powodów, dla których FC definiuje język, ma związek z faktem, że, jak wspomniano powyżej, obliczenia sfederowane określają rozproszone zachowania zbiorowe, a zatem ich logika jest nielokalna. Na przykład TFF zapewnia operatorów, których wejścia i wyjścia mogą istnieć w różnych miejscach sieci.
Wymaga to języka i systemu typów, które uchwycą pojęcie rozproszenia.
Rodzaj systemu
Federated Core oferuje następujące kategorie typów. Opisując te typy, wskazujemy na konstruktory typów, a także wprowadzamy zwartą notację, ponieważ jest to wygodny sposób opisywania typów obliczeń i operatorów.
Po pierwsze, oto kategorie typów, które są koncepcyjnie podobne do tych występujących w istniejących językach głównego nurtu:
Typy tensorów (
tff.TensorType
). Podobnie jak w TensorFlow, mają onedtype
ishape
. Jedyna różnica polega na tym, że obiekty tego typu nie ograniczają się do instancjitf.Tensor
w Pythonie, które reprezentują wyniki operacji TensorFlow na grafie TensorFlow, ale mogą również zawierać jednostki danych, które mogą być wytworzone, np. jako wyjście rozproszonego protokół agregacji. Zatem typ tensora TFF jest po prostu abstrakcyjną wersją konkretnej fizycznej reprezentacji takiego typu w Pythonie lub TensorFlow.TensorTypes
TFF mogą być bardziej rygorystyczne w swoim (statycznym) traktowaniu kształtów niż TensorFlow. Na przykład system typów TFF traktuje tensor o nieznanej randze jako możliwy do przypisania z dowolnego innego tensora tego samego typudtype
, ale nie do przypisania do żadnego tensora o stałej randze. Ta obróbka zapobiega pewnym błędom w czasie wykonywania (np. próbom przekształcenia tensora o nieznanej randze w kształt z nieprawidłową liczbą elementów), kosztem większej ścisłości w obliczeniach, które TFF akceptuje jako prawidłowe.Zwarta notacja dla typów tensorów to
dtype
lubdtype[shape]
. Na przykładint32
iint32[10]
to odpowiednio typy liczb całkowitych i wektorów int.Typy sekwencji (
tff.SequenceType
). Są to abstrakcyjny odpowiednik w TFF konkretnej koncepcjitf.data.Dataset
s TensorFlow. Elementy sekwencji mogą być konsumowane w sposób sekwencyjny i mogą obejmować typy złożone.Kompaktowa reprezentacja typów sekwencji to
T*
, gdzieT
jest typem elementów. Na przykładint32*
reprezentuje sekwencję całkowitą.Nazwane typy krotek (
tff.StructType
). Są to sposób TFF konstruowania krotek i struktur podobnych do słownika, które mają predefiniowaną liczbę elementów o określonych typach, nazwanych lub nienazwanych. Co ważne, koncepcja nazwanych krotek TFF obejmuje abstrakcyjny odpowiednik krotek argumentów Pythona, tj. kolekcje elementów, z których niektóre, ale nie wszystkie, są nazwane, a niektóre są pozycyjne.Zwarta notacja dla nazwanych krotek to
<n_1=T_1, ..., n_k=T_k>
, gdzien_k
to opcjonalne nazwy elementów, aT_k
to typy elementów. Na przykład<int32,int32>
jest notacją zwartą dla pary nienazwanych liczb całkowitych, a<X=float32,Y=float32>
jest notacją zwartą dla pary zmiennych o nazwachX
iY
, które mogą reprezentować punkt na płaszczyźnie . Krotki mogą być zagnieżdżane, a także mieszane z innymi typami, np.<X=float32,Y=float32>*
będzie zwartą notacją dla sekwencji punktów.Typy funkcji (
tff.FunctionType
). TFF to funkcjonalna struktura programowania, w której funkcje są traktowane jako wartości pierwszej klasy . Funkcje mają co najwyżej jeden argument i dokładnie jeden wynik.Zwarta notacja dla funkcji to
(T -> U)
, gdzieT
jest typem argumentu, aU
jest typem wyniku, lub( -> U)
jeśli nie ma argumentu (chociaż funkcje bezargumentowe są zdegenerowane koncepcja, która istnieje głównie tylko na poziomie Pythona). Na przykład(int32* -> int32)
to notacja dla typu funkcji, które redukują sekwencję liczb całkowitych do pojedynczej wartości całkowitej.
Poniższe typy dotyczą aspektu systemów rozproszonych w obliczeniach TFF. Ponieważ te koncepcje są nieco unikalne dla TFF, zachęcamy do zapoznania się z samouczkiem dotyczącym algorytmów niestandardowych, aby uzyskać dodatkowe komentarze i przykłady.
Typ miejsca docelowego . Ten typ nie jest jeszcze wyeksponowany w publicznym API inaczej niż w postaci 2 literałów
tff.SERVER
itff.CLIENTS
, które można traktować jako stałe tego typu. Jest jednak używany wewnętrznie i zostanie wprowadzony do publicznego interfejsu API w przyszłych wydaniach. Kompaktową reprezentacją tego typu jestplacement
.Umiejscowienie reprezentuje zbiorowość uczestników systemu, którzy odgrywają szczególną rolę. Pierwsza wersja jest ukierunkowana na obliczenia klient-serwer, w których istnieją 2 grupy uczestników: klienci i serwer (można myśleć o tym drugim jako o grupie singleton). Jednak w bardziej rozbudowanych architekturach mogą istnieć inne role, takie jak pośrednicy agregatorzy w systemie wielowarstwowym, którzy mogą wykonywać różne typy agregacji lub używać innych typów kompresji/dekompresji danych niż te używane przez serwer lub klienci.
Podstawowym celem zdefiniowania pojęcia rozmieszczenia jest stworzenie podstawy do zdefiniowania typów stowarzyszonych .
Typy stowarzyszone (
tff.FederatedType
). Wartość typu stowarzyszonego to taka, która jest obsługiwana przez grupę uczestników systemu zdefiniowanych przez określone położenie (takie jaktff.SERVER
lubtff.CLIENTS
). Typ sfederowany jest zdefiniowany przez wartość miejsca docelowego (a zatem jest to typ zależny ), typ elementów składowych (jaki rodzaj treści jest hostowany lokalnie przez każdego z uczestników) oraz dodatkowy bitall_equal
, który określa, czy wszyscy uczestnicy są lokalnie hostowanie tego samego przedmiotu.Kompaktowa notacja dla wartości typu federacyjnego, które obejmują elementy (składniki członkowskie) typu
T
, z których każdy jest hostowany przez grupę (umieszczenie)G
toT@G
lub{T}@G
z ustawionym lub nieustawionym bitemall_equal
.Na przykład:
{int32}@CLIENTS
reprezentuje wartość federacyjną, która składa się z zestawu potencjalnie odrębnych liczb całkowitych, po jednej na urządzenie klienckie. Należy zauważyć, że mówimy o pojedynczej wartości federacyjnej obejmującej wiele elementów danych, które pojawiają się w wielu lokalizacjach w sieci. Jednym ze sposobów myślenia o tym jest rodzaj tensora o wymiarze „sieciowym”, chociaż ta analogia nie jest idealna, ponieważ TFF nie pozwala na losowy dostęp do elementów składowych o wartości sfederowanej.{<X=float32,Y=float32>*}@CLIENTS
reprezentuje stowarzyszony zestaw danych , wartość, która składa się z wielu sekwencji współrzędnychXY
, jednej sekwencji na urządzenie klienckie.<weights=float32[10,5],bias=float32[5]>@SERVER
reprezentuje nazwaną krotkę tensorów wagi i odchylenia na serwerze. Ponieważ porzuciliśmy nawiasy klamrowe, oznacza to, że ustawiony jest bitall_equal
, tj. jest tylko jedna krotka (niezależnie od tego, ile replik serwerów może znajdować się w klastrze obsługującym tę wartość).
Cegiełki
Język Federated Core jest formą rachunku lambda z kilkoma dodatkowymi elementami.
Zapewnia następujące abstrakcje programowania, które są obecnie dostępne w publicznym API:
Obliczenia TensorFlow (
tff.tf_computation
). Są to sekcje kodu TensorFlow opakowane jako komponenty wielokrotnego użytku w TFF przy użyciu dekoratoratff.tf_computation
. Zawsze mają typy funkcjonalne i w przeciwieństwie do funkcji w TensorFlow mogą przyjmować parametry strukturalne lub zwracać wyniki strukturalne typu sekwencyjnego.Oto jeden przykład, obliczenie TF typu
(int32* -> int)
, które używa operatoratf.data.Dataset.reduce
do obliczenia sumy liczb całkowitych:@tff.tf_computation(tff.SequenceType(tf.int32)) def add_up_integers(x): return x.reduce(np.int32(0), lambda x, y: x + y)
Wewnętrzne lub operatory federacyjne (
tff.federated_...
). Jest to biblioteka funkcji, takich jaktff.federated_sum
lubtff.federated_broadcast
, które stanowią większość FC API, z których większość reprezentuje operatorów komunikacji rozproszonej do użytku z TFF.Nazywamy je wewnętrznymi , ponieważ podobnie jak funkcje wewnętrzne , są one otwartym, rozszerzalnym zbiorem operatorów, które są rozumiane przez TFF i skompilowane do kodu niższego poziomu.
Większość z tych operatorów ma parametry i wyniki typów stowarzyszonych, a większość to szablony, które można zastosować do różnych rodzajów danych.
Na przykład
tff.federated_broadcast
można traktować jako operator szablonu typu funkcjonalnegoT@SERVER -> T@CLIENTS
.Wyrażenia lambda (
tff.federated_computation
). Wyrażenie lambda w TFF jest odpowiednikiem wyrażenialambda
lubdef
w Pythonie; składa się z nazwy parametru i treści (wyrażenia), które zawiera odniesienia do tego parametru.W kodzie Pythona można je utworzyć, dekorując funkcje Pythona za pomocą
tff.federated_computation
i definiując argument.Oto przykład wyrażenia lambda, o którym wspominaliśmy już wcześniej:
@tff.federated_computation(tff.type_at_clients(tf.float32)) def get_average_temperature(sensor_readings): return tff.federated_mean(sensor_readings)
Literały miejsca docelowego . Na razie tylko
tff.SERVER
itff.CLIENTS
pozwalają na definiowanie prostych obliczeń klient-serwer.Wywołania funkcji (
__call__
). Wszystko, co ma typ funkcjonalny, może zostać wywołane przy użyciu standardowej składni Pythona__call__
. Wywołanie to wyrażenie, którego typ jest taki sam jak typ wyniku wywołanej funkcji.Na przykład:
add_up_integers(x)
reprezentuje wywołanie obliczenia TensorFlow zdefiniowanego wcześniej w argumenciex
. Typ tego wyrażenia toint32
.tff.federated_mean(sensor_readings)
reprezentuje wywołanie stowarzyszonego operatora uśredniania nasensor_readings
. Typ tego wyrażenia tofloat32@SERVER
(zakładając kontekst z powyższego przykładu).
Formowanie krotek i dobieranie ich elementów. Wyrażenia Pythona w postaci
[x, y]
,x[y]
lubxy
, które pojawiają się w treści funkcji ozdobionychtff.federated_computation
.