W tym dokumencie przedstawiono podstawową warstwę TFF, która służy jako podstawa dla Federated Learning i ewentualnych przyszłych algorytmów stowarzyszonych nieuczących się.
Aby uzyskać delikatne wprowadzenie do Federated Core, przeczytaj poniższe samouczki, ponieważ przedstawiają one niektóre podstawowe pojęcia na przykładach i demonstrują krok po kroku konstrukcję prostego algorytmu uśredniania stowarzyszonego.
Niestandardowe algorytmy stowarzyszone, część 1: Wprowadzenie do stowarzyszonego rdzenia .
Niestandardowe algorytmy stowarzyszone, część 2: Wdrażanie stowarzyszonego uśredniania .
Zachęcamy również do zapoznania się z Federated Learning i powiązanymi z nim samouczkami na temat klasyfikacji obrazów i generowania tekstu , ponieważ zastosowania Federated Core API (FC API) na potrzeby uczenia się stowarzyszonego zapewniają ważny kontekst dla niektórych wyborów, których dokonaliśmy w projektowania tej warstwy.
Przegląd
Cele, zamierzone zastosowania 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 niż trywialne przetwarzanie lokalnie i komunikują się poprzez sieć w celu koordynowania swojej pracy.
Termin rozproszony jest bardzo ogólny i TFF nie obejmuje wszystkich możliwych typów algorytmów rozproszonych, dlatego wolimy używać mniej ogólnego terminu obliczenia stowarzyszone do opisania typów algorytmów, które można wyrazić w tym środowisku.
Choć zdefiniowanie terminu obliczenia stowarzyszone w całkowicie formalny sposób wykracza poza zakres tego dokumentu, należy pomyśleć o typach algorytmów wyrażonych w pseudokodzie w publikacji badawczej opisującej nowy algorytm uczenia się rozproszonego.
Krótko mówiąc, celem FC jest umożliwienie podobnie zwartej reprezentacji, na podobnym poziomie abstrakcji przypominającym pseudokod, logiki programu, która nie jest pseudokodem, ale jest wykonywalna w różnych środowiskach docelowych.
Kluczową cechą definiującą rodzaje algorytmów, które FC ma wyrażać, jest to, że działania uczestników systemu są opisywane w sposób zbiorowy. Mówimy zatem zwykle o każdym urządzeniu lokalnie przetwarzającym dane oraz o urządzeniach koordynujących pracę przez scentralizowanego koordynatora transmitującego , zbierającego lub agregującego ich wyniki.
Chociaż TFF został zaprojektowany tak, aby móc wykraczać poza proste architektury klient-serwer , koncepcja zbiorowego przetwarzania ma fundamentalne znaczenie. Wynika to z początków TFF w uczeniu stowarzyszonym, technologii pierwotnie zaprojektowanej do wspierania obliczeń na potencjalnie wrażliwych danych, które pozostają pod kontrolą urządzeń klienckich i których nie można po prostu pobrać do centralnej lokalizacji ze względu na prywatność. Chociaż każdy klient w takich systemach wnosi dane i moc obliczeniową do obliczenia wyniku przez system (wynik, który, jak ogólnie rzecz biorąc, będzie wartościowy dla wszystkich uczestników), staramy się również chronić prywatność i anonimowość każdego klienta.
Tak więc, chociaż większość frameworków do przetwarzania rozproszonego ma na celu wyrażenie przetwarzania z perspektywy poszczególnych uczestników – to znaczy na poziomie indywidualnej wymiany komunikatów punkt-punkt oraz współzależności przejść stanu lokalnego 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 rezultacie, chociaż rozproszone struktury do celów ogólnych mogą oferować operacje takie jak wysyłanie i odbieranie jako elementy składowe, FC udostępnia elementy składowe, 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 wewnętrznego języka do reprezentowania obliczeń stowarzyszonych, którego składnia jest zdefiniowana przez reprezentację nadającą się do serializacji w computation.proto . Jednak użytkownicy FC API na ogół nie będą musieli bezpośrednio wchodzić w interakcję z tym językiem. Zamiast tego udostępniamy interfejs API języka Python (przestrzeń nazw tff
), który otacza go w celu zdefiniowania 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 logiki obliczeń stowarzyszonych w języku TFF. Funkcja ozdobiona tff.federated_computation
działa jako nośnik takiej serializowanej reprezentacji i może osadzić ją jako element składowy 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.FederatedType(np.float32, tff.CLIENTS))
def get_average_temperature(sensor_readings):
return tff.federated_mean(sensor_readings)
Czytelnicy zaznajomieni z TensorFlow uznają to podejście za analogiczne do pisania kodu w Pythonie, który używa funkcji takich jak tf.add
lub tf.reduce_sum
w sekcji kodu Pythona, która definiuje wykres TensorFlow. Chociaż kod jest technicznie wyrażony w języku Python, jego celem jest skonstruowanie możliwej do serializacji reprezentacji tf.Graph
znajdującej się pod spodem i to wykres, 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
.
Jednym z powodów zdefiniowania języka przez FC jest fakt, że, jak zauważono powyżej, obliczenia stowarzyszone określają rozproszone zachowania zbiorowe i jako takie ich logika jest nielokalna. Na przykład TFF udostępnia operatory, których wejścia i wyjścia mogą znajdować się w różnych miejscach sieci.
Wymaga to języka i systemu typów, które uchwyciłyby pojęcie rozproszoności.
Wpisz System
Federated Core oferuje następujące kategorie typów. Opisując te typy, wskazujemy na konstruktory typów oraz wprowadzamy zwartą notację, gdyż jest to wygodny sposób opisu typów obliczeń i operatorów.
Po pierwsze, oto kategorie typów, które są koncepcyjnie podobne do tych, które można znaleźć 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 można wygenerować, np. jako wynik rozproszonego protokół agregacji. Zatem typ tensora TFF jest po prostu abstrakcyjną wersją konkretnej fizycznej reprezentacji tego typu w Pythonie lub TensorFlow.TensorTypes
firmy TFF mogą być bardziej rygorystyczne w (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 samegodtype
, ale nie można go przypisać do żadnego tensora o ustalonej randze. To podejście 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 dokładności obliczeń uznawanych przez TFF za prawidłowe.Zwarta notacja typów tensorowych to
dtype
lubdtype[shape]
. Na przykładint32
iint32[10]
to odpowiednio typy wektorów całkowitych i int.Typy sekwencji (
tff.SequenceType
). Są to abstrakcyjne odpowiedniki TFF konkretnej koncepcjitf.data.Dataset
s firmy TensorFlow. Elementy sekwencji mogą być używane sekwencyjnie i mogą obejmować typy złożone.Zwarta reprezentacja typów sekwencji to
T*
, gdzieT
jest typem elementów. Na przykładint32*
reprezentuje sekwencję liczb całkowitych.Nazwane typy krotek (
tff.StructType
). Jest to sposób TFF na konstruowanie krotek i struktur przypominających słownik, które mają z góry określoną 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. zbiory elementów, z których niektóre, ale nie wszystkie, mają nazwy, a niektóre są pozycyjne.Notacja zwarta 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>
to zwarty zapis pary nienazwanych liczb całkowitych, a<X=float32,Y=float32>
to zwarty zapis pary liczb zmiennoprzecinkowych o nazwachX
iY
, które mogą reprezentować punkt na płaszczyźnie . Krotki można zagnieżdżać, a także mieszać z innymi typami, np.<X=float32,Y=float32>*
będzie zwartym zapisem sekwencji punktów.Typy funkcji (
tff.FunctionType
). TFF to funkcjonalny framework programowania, w którym funkcje są traktowane jako wartości najwyższej klasy . Funkcje mają co najwyżej jeden argument i dokładnie jeden wynik.Zwarty zapis 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 zapis typu funkcji, które redukują sekwencję liczb całkowitych do pojedynczej wartości całkowitej.
Poniższe typy dotyczą aspektu obliczeń TFF w systemach rozproszonych. Ponieważ te koncepcje są w pewnym stopniu specyficzne dla TFF, zachęcamy do zapoznania się z samouczkiem dotyczącym algorytmów niestandardowych w celu uzyskania dodatkowego komentarza i przykładów.
Typ miejsca docelowego . Ten typ nie jest jeszcze udostępniany w publicznym interfejsie API inaczej niż w postaci 2 literałów
tff.SERVER
itff.CLIENTS
, które można traktować jako stałe tego typu. Jest on jednak używany wewnętrznie i zostanie wprowadzony do publicznego interfejsu API w przyszłych wersjach. Kompaktową reprezentacją tego typu jestplacement
.Miejsce docelowe reprezentuje zbiorowość uczestników systemu, którzy odgrywają określoną rolę. Początkowa wersja jest przeznaczona do obliczeń klient-serwer, w których występują 2 grupy uczestników: klienci i serwer (można o nim myśleć jak o grupie pojedynczej). Jednakże w bardziej skomplikowanych architekturach mogą istnieć inne role, takie jak pośrednicy agregatorzy w systemie wielowarstwowym, którzy mogą wykonywać różne typy agregacji lub stosować inne typy kompresji/dekompresji danych niż te stosowane przez serwer lub klienci.
Podstawowym celem zdefiniowania pojęcia rozmieszczenia jest podstawa do zdefiniowania typów stowarzyszonych .
Typy stowarzyszone (
tff.FederatedType
). Wartość typu stowarzyszonego to taka, która jest hostowana przez grupę uczestników systemu zdefiniowaną przez określone miejsce docelowe (takie jaktff.SERVER
lubtff.CLIENTS
). Typ stowarzyszony jest definiowany przez wartość miejsca docelowego (jest to zatem typ zależny ), typ składników członkowskich (jaki rodzaj treści każdy z uczestników hostuje lokalnie) oraz dodatkowy bitall_equal
, który określa, czy wszyscy uczestnicy są lokalnie hostowanie tego samego elementu.Zwarty zapis wartości typu stowarzyszonego, które obejmują elementy (składniki członkowskie) typu
T
, z których każdy jest hostowany przez grupę (miejsce docelowe)G
, toT@G
lub{T}@G
z ustawionym lub nie ustawionym bitemall_equal
.Na przykład:
{int32}@CLIENTS
reprezentuje wartość stowarzyszoną składającą się z zestawu potencjalnie odrębnych liczb całkowitych, po jednej na urządzenie klienckie. Należy pamiętać, że mówimy o pojedynczej wartości stowarzyszonej obejmującej wiele elementów danych pojawiających się w wielu lokalizacjach w sieci. Można o tym pomyśleć jako o rodzaju tensora o wymiarze „sieciowym”, chociaż analogia ta nie jest doskonała, ponieważ TFF nie pozwala na przypadkowy dostęp do składników składowych o wartości stowarzyszonej.{<X=float32,Y=float32>*}@CLIENTS
reprezentuje stowarzyszony zestaw danych , wartość składającą się z wielu sekwencji współrzędnychXY
, po jednej sekwencji na urządzenie klienckie.<weights=float32[10,5],bias=float32[5]>@SERVER
reprezentuje nazwaną krotkę tensorów wagi i obciążenia na serwerze. Ponieważ usunęliśmy nawiasy klamrowe, oznacza to, że ustawiony jest bitall_equal
, tj. istnieje tylko jedna krotka (niezależnie od tego, ile replik serwerów może znajdować się w klastrze obsługującym tę wartość).
Bloki konstrukcyjne
Język Federated Core jest formą rachunku lambda z kilkoma dodatkowymi elementami.
Zawiera następujące abstrakcje programistyczne dostępne aktualnie w publicznym API:
Obliczenia TensorFlow (
tff.tensorflow.computation
). Są to sekcje kodu TensorFlow zapakowane jako komponenty wielokrotnego użytku w TFF przy użyciu dekoratoratff.tensorflow.computation
. Zawsze mają typy funkcjonalne i w przeciwieństwie do funkcji w TensorFlow mogą przyjmować parametry strukturalne lub zwracać ustrukturyzowane wyniki typu sekwencyjnego.Oto jeden przykład obliczenia TF typu
(int32* -> int)
które wykorzystuje operatortf.data.Dataset.reduce
do obliczenia sumy liczb całkowitych:@tff.tensorflow.computation(tff.SequenceType(np.int32)) def add_up_integers(x): return x.reduce(np.int32(0), lambda x, y: x + y)
Operatory wewnętrzne lub stowarzyszone (
tff.federated_...
). Jest to biblioteka funkcji, takich jaktff.federated_sum
lubtff.federated_broadcast
, które stanowią większość interfejsu API FC, a większość z nich reprezentuje operatorów komunikacji rozproszonej do użytku z TFF.Nazywamy je elementami wewnętrznymi , ponieważ podobnie jak funkcje wewnętrzne stanowią otwarty, rozszerzalny zestaw operatorów zrozumiałych dla TFF i skompilowanych do kodu niższego poziomu.
Większość z tych operatorów ma parametry i wyniki typu stowarzyszonego, a większość z nich to szablony, które można zastosować do różnych rodzajów danych.
Na przykład
tff.federated_broadcast
można traktować jako operator szablonowy typu funkcjonalnegoT@SERVER -> T@CLIENTS
.Wyrażenia lambda (
tff.federated_computation
). Wyrażenie lambda w TFF jest odpowiednikiemlambda
lubdef
w Pythonie; składa się z nazwy parametru i treści (wyrażenia) zawierającej 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 już wspominaliśmy:
@tff.federated_computation(tff.FederatedType(np.float32, tff.CLIENTS)) def get_average_temperature(sensor_readings): return tff.federated_mean(sensor_readings)
Literały rozmieszczenia . Na razie tylko
tff.SERVER
itff.CLIENTS
umożliwiają definiowanie prostych obliczeń klient-serwer.Wywołania funkcji (
__call__
). Wszystko, co ma typ funkcjonalny, można wywołać przy użyciu standardowej składni Pythona__call__
. Wywołanie jest wyrażeniem, którego typ jest taki sam jak typ wyniku wywoływanej funkcji.Na przykład:
add_up_integers(x)
reprezentuje wywołanie obliczeń TensorFlow zdefiniowanych wcześniej dla argumentux
. 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).
Tworzenie krotek i wybieranie ich elementów. Wyrażenia Pythona w postaci
[x, y]
,x[y]
lubxy
, które pojawiają się w treściach funkcji ozdobionychtff.federated_computation
.