Dzisiejszy artykuł jest inny niż wszystkie do tej pory…
Jakiś czas temu napisał do mnie Adam Narożniak, Data Scientist z Flower z pytaniem, czy mógłby napisać artykuł na moim blogu o uczeniu federacyjnym. Przyznam, iż wcześniej nie miałem bladego pojęcia o tej działce uczenia maszynowego i stwierdziłem, iż pewnie nie jestem jedynym data scientistem, który kilka wie na ten temat. Odpisałem Adamowi, iż chętnie zamieszczę jego wpis, aby z jednej strony samemu nauczyć się czegoś nowego, ale z drugiej aby dać moim czytelnikom taką samą możliwość.
Adam tak pisze o sobie:
Jestem entuzjastą uczenia maszynowego, szczególnie ciekawi mnie audio i sektor medyczny. Wierzę, iż przyszłość przyniesie nam wiele uczenia federacyjnego i zamierzam jej w tym pomóc poprzez implementację wielu praktycznych zastosowań i rozwój potrzebnej teorii.Chciałem jeszcze uściślić, iż poniższy artykuł nie jest w żaden sposób sponsorowany. Służy jedynie szerzeniu wiedzy o nowym (przynajmniej dla mnie nowym) zagadnieniu związanym z uczeniem maszynowym.
Zatem zapraszam do lektury!
Wstęp
Aby zrozumieć uczenie federacyjne przypomnijmy sobie, jak wygląda uczenie klasyczne i pomyślmy, jakie potencjalne problemy możemy napotkać.
Na nasze potrzeby wyróżnimy dwa niezbędne faktory potrzebne do zastosowania sztucznej inteligencji:
- dane,
- model.
Uczymy model przy użyciu danych, aby wykonać przydatne zadanie. Zadaniem może być wykrywanie obiektów na obrazach, transkrypcja nagrania dźwiękowego lub granie w grę taką jak Go.
Wiele wyborów dotyczących modelu takich jak architektura, optymalizator, hiperparametry zależy od nas.
Dane najczęściej wymagają dodatkowego przetwarzania tak, aby stworzyć wartościowe dane wejściowe do modelu. Dodatkowo wypełniamy brakujące wartości, usuwamy niepotrzebne cechy i na przykład całe dane normalizujemy przed wpuszczeniem do modelu.
Najprawdopodobniej znasz ten schemat. Zastanówmy się jednak, jak dane stały się dla nas dostępne. Często po prostu mamy je zgromadzone i nie musimy martwić się, czy ktoś miał problemy np. z wrzuceniem ich na dysk. Nie interesuje nas także, czy ktoś przesyłał je do chmury, czy dzięki płyty DVD lub pendrive, ani czy zostały stworzone przez jedną osobę, czy wiele. Dane mamy po prostu zgromadzone i scentralizowane w jednym miejscu.
Gdzie leży problem?
W praktyce dane, z którymi pracujemy, nie pochodzą z jednego urządzenia/użytkownika, szczególnie z maszyny, na której trenujemy model. Dane są tworzone lub gromadzone w innym miejscu, na przykład:
- w telefonie podczas interakcji z aplikacją,
- w samochodzie, który zbiera dane z czujników,
- w laptopie, który odbiera dane z klawiatury,
- w inteligentnym asystencie głosowym z mikrofonu, który słucha wydawanych poleceń,
- w oddziale szpitala.
Jak sam widzisz, źródeł danych może być wiele, tzn. może to być każda osoba z zainstalowaną na telefonie aplikacją (kilkaset tysięcy) lub kilka oddziałów banków, natomiast nie jest to jedna jednostka.
Uczenie federacyjne vs klasyczne
Kiedy dane dostępne są w wielu miejscach, możemy zastosować uczenie federacyjne.
Główną różnicę pomiędzy uczeniem klasycznym a federacyjnym dobrze obrazują dwie następujące instrukcje:
- klasyczne uczenie maszynowe: przenieś dane w jedno miejsce (gdzie nastąpi trening),
- federacyjne uczenie maszynowe: przenieś obliczenia do “(miejsca) danych” (urządzeń, na których dane się znajdują).
Miejsce ze zgromadzonymi danymi nazywane jest często serwerem, natomiast poszczególne urządzenia z małymi fragmentami danych (np. wyprodukowanymi i/lub zgromadzonymi tylko przez urządzenia samodzielnie) klientami, węzłami klienckimi lub po prostu węzłami.
Możesz się zastanawiać, dlaczego po prostu nie prześlemy danych w jedno miejsce. Niestety nie zawsze jest to możliwe.
Dlaczego klasyczne scentralizowane podejście do uczenia maszynowego nie działa?
Istnieje wiele powodów, natomiast najważniejsze to:
- przepisy – regulacje takie jak m.in. GDPR (Europa), CCPA (Kalifornia), PIPEDA (Kanada), LGPD (Brazylia), PDPL (Argentyna), KVKK (Turcja), POPI (RPA), FSS (Rosja), CDPR (Chiny), PDPB (Indie), PIPA (Korea), APPI (Japonia), PDP (Indonezja), PDPA (Singapur), APP (Australia) chronią dane przed ich przenoszeniem. W rzeczywistości przepisy te czasami choćby uniemożliwiają pojedynczym organizacjom łączenie danych własnych użytkowników w celu trenowania modeli sztucznej inteligencji. Wynika to z faktu, iż użytkownicy mieszkają w różnych częściach świata, więc ich dane podlegają różnym przepisom dotyczącym ochrony danych,
- prywatność danych / preferencje użytkowników – np. w finansach ze względu na konieczność zachowania prywatności klientów nie ma możliwości udostępniania sobie nawzajem przez instytucje finansowe wrażliwych danych, które mogłyby posłużyć do budowy wspólnych modeli (np. identyfikujących nieuczciwe transakcje, przewidujących ceny akcji lub zarządzania ryzykiem),
- ilość danych – niektóre czujniki, takie jak kamery, wytwarzają tak dużą ilość danych, iż zebranie ich wszystkich nie jest ani wykonalne, ani opłacalne. Pomyślmy o krajowej sieci kolejowej z setkami stacji kolejowych w całym kraju. jeżeli każdy z dworców jest wyposażony w pewną liczbę kamer bezpieczeństwa, to ilość danych, które one wytwarzają, wymaga niezwykle wydajnej i kosztownej infrastruktury do przetwarzania i przechowywania. A większość z tych danych nie jest choćby przydatna.
Jak sam widzisz uczenie federacyjne może być przydatne oraz ma wiele zastosowań i potencjalnie świetlaną przyszłość!
Uczenie federacyjne vs klasyczne (graficznie)
Zobrazujmy to, co wiemy, dzięki grafik.
Zaczniemy od legendy, aby wszystkie ilustracje były jasne.
Uczenie klasyczne możemy przedstawić dzięki poniższej grafiki.
Uczenie federacyjne pozostawia parę pytań. Na ten moment wiemy, iż mamy do czynienia z wieloma klientami, którzy mają dostęp do danych lokalnych oraz wiemy, iż trening musi odbywać się lokalnie. Możemy się domyślać, iż muszą istnieć jakieś relacje pomiędzy lokalnymi modelami. Moglibyśmy pomyśleć o połączeniu każdego urządzenia z każdym, natomiast nie jest to praktyczne rozwiązanie. Wprowadzimy zatem pojęcie serwera, który w niewiadomy (na razie) dla nas sposób współpracuje z klientami. Spójrzmy na grafikę poniżej.
Przejdźmy teraz do detali pokazujących, jak to jest możliwe.
Jak działa uczenie federacyjne?
Krok 0: Inicjalizacja modelu globalnego
Zaczynamy od inicjalizacji modelu na serwerze. Jest to dokładnie to samo, co w klasycznym uczeniu scentralizowanym: inicjalizujemy parametry modelu losowo lub z wcześniej zapisanego punktu kontrolnego.
Krok 1: Wysyłamy model do pewnej liczby połączonych organizacji/urządzeń (klientów)
Następnie wysyłamy parametry modelu globalnego do podłączonych klientów. Ma to na celu zapewnienie, iż każdy uczestniczący węzeł rozpoczyna swoje lokalne szkolenie przy użyciu tych samych parametrów modelu (oczywiście architektura modelu też jest taka sama, natomiast teoretycznie optymalizator mógłby być inny, nie jest to jednak spotykane zastosowanie). Często używamy tylko jakiejś frakcji (np. kilku/kilkunastu) połączonych węzłów zamiast wszystkich. Powodem tego jest to, iż wybieranie coraz większej liczby węzłów klienckich przynosi malejące zyski.
Krok 2: Trenujemy modele lokalnie na danych każdej organizacji/urządzenia (węzła klienckiego)
Teraz gdy wybrane do treningu węzły klienckie (całość lub część – ta, o której wspomniałem wyżej) mają najnowszą wersję parametrów modelu globalnego, rozpoczynają trening lokalny. Używają własnego lokalnego zbioru danych do trenowania własnych modeli lokalnych. Nie trenują modelu aż do pełnego zbiegnięcia. Trenują go tylko przez chwilę. To może być tak mało, jak jedna epoka lub choćby tylko kilka kroków (mini-batch’ów) na lokalnych danych.
Krok 3: Zwracanie aktualizacji modeli (lokalnych) do serwera
Po lokalnym treningu każdy węzeł kliencki ma nieco inną wersję parametrów modelu, które pierwotnie otrzymał. Parametry są różne, ponieważ każdy węzeł kliencki ma inne przykłady w swoim lokalnym zbiorze danych. Węzły klienckie wysyłają następnie te aktualizacje modelu z powrotem do serwera. Wysyłane aktualizacje modelu mogą być albo pełnymi parametrami modelu, albo tylko gradientami, które zostały zgromadzone podczas lokalnego treningu.
Krok 4: Agregacja aktualizacji modeli lokalnych w nowy model globalny
Serwer otrzymuje aktualizację modelu (jego wagi lub gradienty) od wybranych węzłów klienckich. jeżeli wybrał 100 węzłów klienckich, ma teraz 100 nieco różnych wersji oryginalnego modelu globalnego, z których każda została wytrenowana na lokalnych danych jednego klienta. Ale czy nie chcieliśmy mieć jednego modelu, który uczyłby się na danych ze wszystkich 100 węzłów klienckich?
Aby uzyskać jeden model, musimy połączyć wszystkie aktualizacje modelu, które otrzymaliśmy od węzłów klienckich. Proces ten nazywany jest agregacją i istnieje wiele różnych sposobów, aby to zrobić. Najbardziej podstawowy to Federated Averaging (można to przetłumaczyć jako sfederalizowane uśrednianie) (McMahan et al., 2016), często skracany jako FedAvg.
FedAvg bierze 100 aktualizacji modelu i, jak sama nazwa wskazuje, uśrednia je. Aby być bardziej precyzyjnym, bierze średnią ważoną aktualizacji modelu, ważoną przez liczbę przykładów, które każdy klient użył do szkolenia. Na przedstawionej grafice dla ułatwienia i, nie jest brana pod uwagę wielkość danych każdego klienta. W praktyce jest to istotny krok i powinien być zastosowany. Waga jest ważna, aby upewnić się, iż każdy przykład danych ma taki sam wpływ na wynikowy model globalny. jeżeli jeden klient ma 10 przykładów, a inny klient ma 100 przykładów, to bez ważenia każdy z 10 przykładów wpłynąłby na model globalny dziesięć razy bardziej niż te ze 100 przykładów.
Krok 5: Powtarzaj kroki od 1 do 4, aż do zbieżności
Kroki od 1 do 4 są tym, co nazywamy pojedynczą rundą uczenia federacyjnego. Parametry modelu globalnego są wysyłane do uczestniczących węzłów klienckich (krok 1), węzły klienckie trenują na swoich lokalnych danych (krok 2), wysyłają swoje zaktualizowane modele do serwera (krok 3), a serwer następnie agreguje aktualizacje modelu, aby uzyskać nową wersję modelu globalnego (krok 4).
Podczas pojedynczej rundy każdy węzeł kliencki, który w niej uczestniczy, trenuje tylko przez chwilę. Oznacza to, iż po etapie agregacji (krok 4) mamy model, który został wytrenowany na danych ze wszystkich węzłów klienckich, ale tylko przez chwilę. Następnie musimy powtarzać ten proces w kółko, aby w końcu uzyskać w pełni wytrenowany model, który działa dobrze na danych wszystkich węzłów.
Kod w Python
Do implementacji użyjemy biblioteki Flower. Pozwala ona na tworzenie zarówno lokalnych symulacji (my użyjemy tej funkcjonalności), jak i implementacji gotowych do produkcji (firmy, które używają Flower to m.in. Brave, Nokia, czy Banking Circle). Trenując model, możesz używać ulubionego frameworku do uczenia maszynowego, takiego jak Tensorflow, PyTorch, Hugging Face czy fastai.
Jeśli chciałbyś sam sprawdzić, jak działa kod bez instalacji bibliotek lokalnie, to możesz użyć identycznej kopii kodu dostępnej w Google Colab (KLIKNIJ TUTAJ).
Mirek: Na wszelki wypadek gdyby kiedyś link od Adama wygasł to przygotowałem dla Was też notebook do pobrania bezpośrednio z bloga wraz z informacją o wersjach bibliotek itp. Możecie go bezpośrednio załadować sobie na Colaba, by działał.
Zależności
Przygotujmy potrzebne biblioteki.
Skonfigurujmy jeszcze TensorFlow tak, aby używać tylko CPU.
Dane
Do tego eksperymentu pobierzmy jeszcze standardowy dobrze wszystkim znany zbiór cyfr pisanych manualnie MNIST.
Po pobraniu danych należy podzielić je tak, aby każdy klient miał unikalną część danych.
Uwaga! Symulujemy uczenie federacyjne, w normalnym scenariuszu dane będą znajdowały się u różnych klientów.
Każdy klient będzie miał dane treningowe i testowe, co nie jest wymogiem uczenia federacyjnego, ale powszechnym sposobem ewaluacji.
Istnieją dwa powszechne sposoby ewaluacji:
- scentralizowana (inaczej mówiąc po stronie serwera) – co oznacza, iż mamy jakąś część danych na serwerze i oceniamy globalny model na tej części danych,
- sfederalizowana (inaczej mówiąc po stronie klienta) – w tym przypadku potrzebujemy, aby każdy klient miał podzielone dane;liczba ewaluacji na rundę jest równa liczbie klientów, których wybieramy do ewaluacji.
Wybierzemy drugi sposób do oceny w analizowanym przykładzie.
Potwierdźmy sobie jeszcze rozmiar danych dla każdej próbki:
Model
Zdefiniujemy model (dokładnie w ten sam sposób, jak pod klasyczne uczenie maszynowe).
Uczenie federacyjne
Teraz stworzymy kilka klas i funkcji, aby wykorzystać framework Flower.
Do uruchomienia symulacji potrzebne będą następujące elementy:
- klasa Klient Flower z trzema metodami do zaimplementowania,
- funkcja, która tworzy Klienta Flower,
- strategia, która definiuje algorytm federacji.
Klient Flower
Nadpiszemy (eng. overwrite) klasę NumpyClient. Musimy zaimplementować trzy metody klasy FlowerClient: fit, evaluate i get_parameters.
Funkcja tworząca klienta
Symulacja Flower wymaga funkcji, która tworzy Klienta Flower. Wymaga ona tylko jednego argumentu: id klienta (w skrócie cid). W tej funkcji używamy mapy, której kluczami są cid, a wartościami są partycje zbioru danych. Tę mapę i inne parametry można przekazać dzięki funkcji partial z biblioteki functools Pythona.
Strategia
Po każdej rundzie uczenia federacyjnego, potrzebujemy sposobu, aby zagregować wagi. Istnieje kilka powszechnie stosowanych metod. My użyjemy domyślnej i najbardziej powszechnej strategii zwanej Federated Averaging (w skrócie FedAvg).
Potrzebujemy też funkcji, która opisuje jak obliczane będą uśrednione metryki.
Trening
W start_simulation określmy szczegóły treningu. Będziemy trenować przez dziesięć rund i będziemy trenować klientów sekwencyjnie (jeden za drugim). Ostatni argument w poniższym kodzie konfiguruje Ray (bibliotekę, której używamy do uruchomienia symulacji) tak, aby działała wydajniej. Podawanie go nie będzie potrzebne w przyszłych wersjach Flower (≥1.4.0).
Gratulacje, wytrenowałeś swój pierwszy model przy użyciu uczenia federacyjnego.
Terminologia
Uczenie federacyjne jest na razie stosunkowo mało popularne w Polsce. Z tego powodu uniwersalne nazwy nie są jeszcze przyjęte. Możecie spotkać następujące tłumaczenia: “sfederowana nauka, “uczenie się federacyjne” lub uczenie sfederalizowane. Wszystkie dotyczą tego samego konceptu. Terminologia użyta w tym artykule, to moja propozycja nomenklatury.
Podsumowanie
Właśnie dowiedziałeś się czym jest uczenie federacyjne oraz jak wytrenować model przy użyciu Flower i TensorFlow. jeżeli chciałbyś dowiedzieć się więcej, to zapraszam na oryginalną stronę i dokumentację Flower (strona jest w języku angielskim) https://flower.dev/. jeżeli masz jakieś pytania, możesz je zadać na slack’u Flower https://friendly-flower.slack.com/join/shared_invite/zt-q1t73p0h-fcGXz6lRDPdSrwYhBvaDFA#/shared-invite/email.
Kilka słów ode mnie
Bardzo dziękuję Adamowi za podzielenie się swoją wiedzą i za czas poświęcony na napisanie artykułu. Mam nadzieję, iż nie będzie to nasza ostatnia współpraca.
Jestem interesujący Waszych opinii na temat gościnnych wpisów na blogu. Dajcie znać, co o tym myślicie.