Dostrajanie zalecanych agregacji do nauki

Zobacz na TensorFlow.org Uruchom w Google Colab Wyświetl źródło na GitHub Pobierz notatnik

tff.learning moduł zawiera szereg sposobów agregowania modelowych AKTUALIZACJE zalecaną domyślnej konfiguracji:

W tym samouczku wyjaśniamy podstawową motywację, sposób ich implementacji i przedstawiamy sugestie, jak dostosować ich konfigurację.


!pip install --quiet --upgrade tensorflow-federated-nightly
!pip install --quiet --upgrade nest-asyncio

import nest_asyncio
nest_asyncio.apply()
import math
import tensorflow_federated as tff
tff.federated_computation(lambda: 'Hello, World!')()
b'Hello, World!'

Metody agregacji są reprezentowane przez obiekty, które mogą być przekazywane do tff.learning.build_federated_averaging_process jako model_update_aggregation_factory kluczowego argumentu. Jako takie, agregatory omówione tutaj mogą być bezpośrednio wykorzystane do modyfikowania poprzedni samouczek na stowarzyszonym nauki.

Linia bazowa ważona z FedAvg algorytm może być wyrażona za pomocą tff.aggregators.MeanFactory w następujący sposób:

mean = tff.aggregators.MeanFactory()
iterative_process = tff.learning.build_federated_averaging_process(
    ...,
    model_update_aggregation_factory=mean)

Techniki, których można użyć do rozszerzenia średniej ważonej omówionej w tym samouczku, to:

  • Zerowanie
  • Obrzynek
  • Prywatność różnicowa
  • Kompresja
  • Bezpieczna agregacja

Rozszerzenie odbywa się za pomocą kompozycji, w której MeanFactory otacza wewnętrzną fabryki, do której delegaci jakaś część agregacji, lub sam jest owinięty przez innej fabryce agregacji. Aby uzyskać więcej szczegółów na temat projektu można znaleźć wykonawczych niestandardowych agregatorów tutoriala.

Najpierw wyjaśnimy, jak włączyć i skonfigurować te techniki indywidualnie, a następnie pokażemy, jak można je ze sobą łączyć.

Techniki

Zanim zagłębimy się w poszczególne techniki, najpierw przedstawimy algorytm dopasowywania kwantyli, który będzie przydatny do konfiguracji poniższych technik.

Dopasowanie kwantylowe

Kilka z poniższych technik agregacji wymaga użycia ograniczenia normy, które kontroluje pewien aspekt agregacji. Takie wiązania można podać jako stałe, ale zwykle lepiej jest je dostosować w trakcie treningu. Zalecanym sposobem jest użycie algorytmu dopasowania kwantylem Andrew et al. (2019) , początkowo zaproponowano jej zgodności z rozmazem prywatności, ale przydatne szerzej. Aby oszacować wartość w danym kwantyl, można użyć tff.aggregators.PrivateQuantileEstimationProcess . Na przykład, aby dostosować się do mediany rozkładu, możesz użyć:

median_estimate = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=1.0, target_quantile=0.5, learning_rate=0.2)

Różne techniki wykorzystujące algorytm estymacji kwantyli będą wymagały różnych wartości parametrów algorytmu, jak zobaczymy. Na ogół zwiększenie learning_rate oznacza parametr szybszą adaptację do prawidłowego kwantyl, ale z wyższą wariancji. no_noise classmethod konstruuje kwantyl proces dopasowywania że nie dodaje szum różnicowej prywatności.

Zerowanie

Zerowanie odnosi się do zastępowania niezwykle dużych wartości zerami. W tym przypadku „niezwykle duże” może oznaczać większe niż wstępnie zdefiniowany próg lub duże w stosunku do wartości z poprzednich rund obliczeń. Zerowanie może zwiększyć odporność systemu na uszkodzenia danych na wadliwych klientach.

Do obliczenia średniej wartości norm L-nieskończoność większych niż ZEROING_CONSTANT wyzerowany, na zewnątrz, to otoczyć tff.aggregators.MeanFactory z tff.aggregators.zeroing_factory że wykonuje zerowania:

zeroing_mean = tff.aggregators.zeroing_factory(
    zeroing_norm=MY_ZEROING_CONSTANT,
    inner_agg_factory=tff.aggregators.MeanFactory())

Tu owinąć MeanFactory z zeroing_factory bo chcemy (pre-agregacji) efekty zeroing_factory stosuje się do wartości do klientów, zanim zostaną one przekazane do wewnętrznej MeanFactory agregacji poprzez uśrednianie.

Jednak w przypadku większości zastosowań zalecamy adaptacyjne zerowanie z estymatorem kwantylowym. Aby to zrobić, używamy algorytmu dopasowywania kwantyli w następujący sposób:

zeroing_norm = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=10.0,
    target_quantile=0.98,
    learning_rate=math.log(10),
    multiplier=2.0,
    increment=1.0)
zeroing_mean = tff.aggregators.zeroing_factory(
    zeroing_norm=zeroing_norm,
    inner_agg_factory=tff.aggregators.MeanFactory())

# Equivalent to:
# zeroing_mean = tff.learning.robust_aggregator(clipping=False)

Parametry zostały dobrane tak, że dostosowuje proces bardzo szybko (stosunkowo duża learning_rate ) do wartości nieco większy niż największych wartości obserwowanych do tej pory. Dla oszacowania kwantylem Q , wartość progowa służy do zerowania będzie Q * multiplier + increment .

Przycinanie do ograniczonej normy L2

Przycinanie aktualizacji klienta (rzutowanie na kulę L2) może poprawić odporność na wartości odstające. tff.aggregators.clipping_factory jest skonstruowany dokładnie jak tff.aggregators.zeroing_factory omówione powyżej, można wziąć albo stałą lub tff.templates.EstimationProcess jako jego clipping_norm argument. Zalecaną najlepszą praktyką jest użycie przycinania, które umiarkowanie szybko dostosowuje się do umiarkowanie wysokiej normy, w następujący sposób:

clipping_norm = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=1.0,
    target_quantile=0.8,
    learning_rate=0.2)
clipping_mean = tff.aggregators.clipping_factory(
    clipping_norm=clipping_norm,
    inner_agg_factory=tff.aggregators.MeanFactory())

# Equivalent to:
# clipping_mean = tff.learning.robust_aggregator(zeroing=False)

Z naszych doświadczeń nad wieloma problemami, dokładna wartość target_quantile nie wydaje się zbyt wiele znaczenia, tak długo, jak stopy nauka są dostrojone odpowiednio. Jednak ustawienie go na bardzo niskim poziomie może wymagać zwiększenia szybkości uczenia się serwera w celu uzyskania najlepszej wydajności, w porównaniu z nieużywaniem przycinania, dlatego domyślnie zalecamy 0,8.

Prywatność różnicowa

TFF obsługuje również agregację prywatno-różnicową, używając adaptacyjnego obcinania i szumu Gaussa. Agregator wykonujący różnicowo prywatne uśrednianie można skonstruować w następujący sposób:

dp_mean = tff.aggregators.DifferentiallyPrivateFactory.gaussian_adaptive(
    noise_multiplier=0.1, clients_per_round=100)

# Equivalent to:
# dp_mean = tff.learning.dp_aggregator(
#   noise_multiplier=0.1, clients_per_round=100, zeroing=False)

Wytyczne dotyczące sposobu ustawiania noise_multiplier argumentu można znaleźć w poradniku TFF DP .

Kompresja stratna

W porównaniu z kompresją bezstratną, taką jak gzip, kompresja stratna generalnie daje znacznie wyższy współczynnik kompresji i nadal może być później łączona z kompresją bezstratną. Ponieważ komunikacja między klientem a serwerem zajmuje mniej czasu, rundy szkoleniowe kończą się szybciej. Ze względu na z natury losowy charakter algorytmów uczenia się, do pewnego progu, niedokładność kompresji stratnej nie ma negatywnego wpływu na ogólną wydajność.

Domyślny zaleca się stosowanie prostych jednolitego kwantyzacji (patrz Suresh i in., Na przykład), programowane przez dwie wartości: sprężania tensora wielkości threshold i liczby quantization_bits . Dla każdego tensora t , jeśli liczba elementów t jest mniejsza lub równa threshold , nie jest skompresowany. Jeżeli jest ona większa, elementy t są kwantowane przy użyciu randomizowane zaokrąglanie quantizaton_bits bitów. Oznacza to, że stosujemy operację

t = round((t - min(t)) / (max(t) - min(t)) * (2**quantizaton_bits - 1)),

w wyniku wartość całkowitą w zakresie [0, 2**quantizaton_bits-1] . Skwantowane wartości są bezpośrednio pakowane do typu liczb całkowitych w celu transmisji, a następnie stosowana jest transformacja odwrotna.

Zalecamy ustawienie quantizaton_bits równa 8 i threshold równej 20000:

compressed_mean = tff.aggregators.MeanFactory(
    tff.aggregators.EncodedSumFactory.quantize_above_threshold(
        quantization_bits=8, threshold=20000))

# Equivalent to:
# compressed_mean = tff.learning.compression_aggregator(zeroing=False, clipping=False)

Sugestie dotyczące strojenia

Oba parametry, quantization_bits i threshold może być regulowana, a liczba klientów uczestniczących w każdej rundzie treningowej mogą również wpływać na skuteczność kompresji.

Próg. Wybrano domyślną wartość 20000, ponieważ zaobserwowaliśmy, że zmienne z małą liczbą elementów, takie jak błędy systematyczne w typowych typach warstw, są znacznie bardziej wrażliwe na wprowadzany szum. Co więcej, w praktyce niewiele można zyskać na kompresji zmiennych z małą liczbą elementów, ponieważ ich nieskompresowany rozmiar jest na początku stosunkowo niewielki.

W niektórych aplikacjach sensowna może być zmiana wyboru progu. Na przykład błędy systematyczne warstwy wyjściowej modelu klasyfikacji mogą być bardziej wrażliwe na szum. Jeśli trenujesz model językowy ze słownika 20004, może chcesz ustawić threshold być 20.004.

Bity kwantyzacji. Domyślna wartość 8 dla quantization_bits powinny być dobre dla większości użytkowników. Jeśli 8 działa dobrze i chcesz wycisnąć trochę więcej wydajności, możesz spróbować zmniejszyć ją do 7 lub 6. Jeśli zasoby pozwalają na wyszukiwanie w małej siatce, zalecamy określenie wartości, dla której trening staje się niestabilny lub ostateczna jakość modelu zaczyna się pogarszać, a następnie zwiększać tę wartość o dwa. Na przykład, jeśli ustawienie quantization_bits do 5 utworów, ale ustawienie go na 4 degraduje modelu, zalecamy domyślny być 6, które należy „na wszelki wypadek”.

Klientów na rundę. Należy zauważyć, że znacznie zwiększając liczbę klientów na rundę może włączyć mniejszą wartość dla quantization_bits do działa dobrze, ponieważ randomizowane niedokładność wprowadzona przez kwantyzacji można wyrównać przez uśrednianie więcej aktualizacji klienta.

Bezpieczna agregacja

Przez Secure Aggregation (SecAgg) odnosimy się do protokołu kryptograficznego, w którym aktualizacje klienta są szyfrowane w taki sposób, że serwer może tylko odszyfrować ich sumę. Jeśli liczba klientów, którzy zgłaszają się z powrotem, jest niewystarczająca, serwer nie dowie się w ogóle niczego — iw żadnym wypadku nie będzie w stanie sprawdzić poszczególnych aktualizacji. Jest to realizowane za pomocą tff.federated_secure_sum_bitwidth operatora.

Aktualizacje modelu są wartościami zmiennoprzecinkowymi, ale SecAgg operuje na liczbach całkowitych. Dlatego musimy przyciąć wszelkie duże wartości do niektórych powiązanych przed dyskretyzacją do typu całkowitego. Granica obcinania może być stała lub określona adaptacyjnie (zalecane ustawienie domyślne). Liczby całkowite są następnie bezpiecznie sumowane, a suma jest mapowana z powrotem do domeny zmiennoprzecinkowej.

Aby obliczyć średnią z wartości ważonych zsumowanych korzystających SecAgg z MY_SECAGG_BOUND jako wycinek związany przechodzą SecureSumFactory do MeanFactory jako:

secure_mean = tff.aggregators.MeanFactory(
    tff.aggregators.SecureSumFactory(MY_SECAGG_BOUND))

Aby zrobić to samo podczas adaptacyjnego określania granic:

secagg_bound = tff.aggregators.PrivateQuantileEstimationProcess.no_noise(
    initial_estimate=50.0,
    target_quantile=0.95,
    learning_rate=1.0,
    multiplier=2.0)
secure_mean = tff.aggregators.MeanFactory(
    tff.aggregators.SecureSumFactory(secagg_bound))

# Equivalent to:
# secure_mean = tff.learning.secure_aggregator(zeroing=Fasle, clipping=False)

Sugestie dotyczące strojenia

Parametry adaptacyjne zostały dobrane tak, aby granice były wąskie (nie stracimy zbytniej precyzji w dyskretyzacji), ale przycinanie zdarza się rzadko.

Podczas strojenia parametrów należy pamiętać, że protokół SecAgg sumuje aktualizacje ważonego modelu po ważeniu w średniej. Wagi to zazwyczaj liczba punktów danych przetwarzanych lokalnie, stąd między różnymi zadaniami prawe ograniczenie może zależeć od tej ilości.

Nie zaleca się korzystania z increment kluczowego argumentu podczas tworzenia adaptacyjnego secagg_bound , ponieważ może to doprowadzić do utraty dużej względnej precyzji w przypadku rzeczywistych końce dane szacunkowe są małe.

Powyższy fragment kodu użyje SecAgg tylko wartości ważonych. Jeśli SecAgg ma być również używany do sumy wag, zalecamy ustawienie granic jako stałych, ponieważ w powszechnym ustawieniu treningowym największa możliwa waga będzie znana z góry:

secure_mean = tff.aggregators.MeanFactory(
    value_sum_factory=tff.aggregators.SecureSumFactory(secagg_bound),
    weight_sum_factory=tff.aggregators.SecureSumFactory(
        upper_bound_threshold=MAX_WEIGHT, lower_bound_threshold=0.0))

Techniki komponowania

Wprowadzone powyżej poszczególne techniki wydłużania średniej można łączyć ze sobą.

Zalecamy, aby kolejność stosowania tych technik u klientów była

  1. Zerowanie
  2. Obrzynek
  3. Inne techniki

Do zbierania informacji w tff.aggregators moduł składa się owijając „wewnętrznych czytniki kanałów” (których wstępnie agregacji działanie stało ostatni i po agregacji działanie stało pierwszy) wewnątrz „zewnętrznej” czytniki kanałów. Na przykład, aby wykonać zerowanie, obcinanie i kompresję (w tej kolejności), należy napisać:

# Compression is innermost because its pre-aggregation effects are last.
compressed_mean = tff.aggregators.MeanFactory(
    tff.aggregators.EncodedSumFactory.quantize_above_threshold(
        quantization_bits=8, threshold=20000))
# Compressed mean is inner aggregator to clipping...
clipped_compressed_mean = tff.aggregators.clipping_factory(
    clipping_norm=MY_CLIPPING_CONSTANT,
    inner_agg_factory=compressed_mean)
# ...which is inner aggregator to zeroing, since zeroing happens first.
final_aggregator = tff.aggregators.zeroing_factory(
    zeroing_norm=MY_ZEROING_CONSTANT,
    inner_agg_factory=clipped_compressed_mean)

Należy zauważyć, że struktura ta odpowiada agregatorów domyślne dla algorytmów uczenia.

Możliwe są również inne kompozycje. Rozszerzamy ten dokument, gdy jesteśmy pewni, że możemy zapewnić domyślną konfigurację, która działa w wielu różnych aplikacjach. Do wdrażania nowych pomysłów, zobacz wykonawczych niestandardowych agregatorów tutoriala.