Weź udział w sympozjum Women in ML 7 grudnia Zarejestruj się teraz

Sfederowany rdzeń

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

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.

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ą one dtype i shape . Jedyna różnica polega na tym, że obiekty tego typu nie ograniczają się do instancji tf.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 typu dtype , 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 lub dtype[shape] . Na przykład int32 i int32[10] to odpowiednio typy liczb całkowitych i wektorów int.

  • Typy sekwencji ( tff.SequenceType ). Są to abstrakcyjny odpowiednik w TFF konkretnej koncepcji tf.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* , gdzie T jest typem elementów. Na przykład int32* 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> , gdzie n_k to opcjonalne nazwy elementów, a T_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 nazwach X i Y , 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) , gdzie T jest typem argumentu, a U 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 i tff.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 jest placement .

    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 jak tff.SERVER lub tff.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 bit all_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 to T@G lub {T}@G z ustawionym lub nieustawionym bitem all_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ędnych XY , 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 bit all_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 dekoratora tff.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 operatora tf.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 jak tff.federated_sum lub tff.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 funkcjonalnego T@SERVER -> T@CLIENTS .

  • Wyrażenia lambda ( tff.federated_computation ). Wyrażenie lambda w TFF jest odpowiednikiem wyrażenia lambda lub def 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 i tff.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 argumencie x . Typ tego wyrażenia to int32 .

    • tff.federated_mean(sensor_readings) reprezentuje wywołanie stowarzyszonego operatora uśredniania na sensor_readings . Typ tego wyrażenia to float32@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] lub xy , które pojawiają się w treści funkcji ozdobionych tff.federated_computation .