Personalizacja na urządzeniu (ODP) została zaprojektowana z myślą o ochronie informacji użytkowników przed aplikacjami. Aplikacje używają ODP do dostosowywania produktów i usług do potrzeb użytkowników, ale nie będą mogły zobaczyć dokładnych dostosowań wprowadzonych dla użytkownika (chyba że między aplikacją a użytkownikiem dochodzi do bezpośrednich interakcji poza ODP). W przypadku aplikacji z modelami uczenia maszynowego lub analizami statystycznymi ODP udostępnia zestaw usług i algorytmów, które zapewniają prawidłową anonimizację danych za pomocą odpowiednich mechanizmów prywatności różnicowej. Więcej informacji znajdziesz w wyjaśnieniu dotyczącym personalizacji na urządzeniu.
ODP uruchamia kod dewelopera w IsolatedProcess, który nie ma bezpośredniego dostępu do sieci, dysków lokalnych ani innych usług działających na urządzeniu, ale ma dostęp do tych lokalnie przechowywanych źródeł danych:
RemoteData– niezmienne dane par klucz-wartość pobrane z zdalnych backendów obsługiwanych przez dewelopera, jeśli ma to zastosowanie.LocalData– zmienne dane w formacie klucz-wartość przechowywane lokalnie przez dewelopera (w stosownych przypadkach).UserData– dane użytkowników przekazywane przez platformę.
Obsługiwane są te dane wyjściowe:
- Trwałe dane wyjściowe: można ich używać w przyszłym przetwarzaniu lokalnym, aby generować wyświetlane dane wyjściowe, trenować modele za pomocą sfederowanego uczenia się lub przeprowadzać analizy statystyczne na różnych urządzeniach za pomocą sfederowanej analizy.
- Wyświetlone dane wyjściowe:
- Deweloperzy mogą zwracać kod HTML renderowany przez ODP w elemencie
WebVieww elemencieSurfaceView. Treści wyrenderowane w tym miejscu nie będą widoczne dla aplikacji wywołującej. - Deweloperzy mogą umieszczać w danych wyjściowych HTML adresy URL zdarzeń dostarczone przez ODP, aby wywoływać rejestrowanie i przetwarzanie interakcji użytkowników z wyrenderowanym kodem HTML. ODP przechwytuje żądania wysyłane do tych adresów URL i wywołuje kod, aby wygenerować dane, które są zapisywane w tabeli
EVENTS.
- Deweloperzy mogą zwracać kod HTML renderowany przez ODP w elemencie
Aplikacje klienckie i pakiety SDK mogą wywoływać ODP, aby wyświetlać treści HTML w SurfaceView za pomocą interfejsów API ODP. Treści renderowane w SurfaceView nie są widoczne dla aplikacji wywołującej. Aplikacja klienta lub pakiet SDK mogą należeć do innego podmiotu niż ten, który korzysta z platformy ODP.
Usługa ODP zarządza aplikacją klienta, która chce wywołać ODP, aby wyświetlać spersonalizowane treści w swoim interfejsie. Pobiera treści z punktów końcowych udostępnionych przez dewelopera i wywołuje logikę przetwarzania końcowego pobranych danych. Pośredniczy też w komunikacji między IsolatedProcess a innymi usługami i aplikacjami.
Aplikacje klienckie używają metod w klasie OnDevicePersonalizationManager do interakcji z kodem dewelopera działającym w IsolatedProcess. Kod dewelopera działający w IsolatedProcess rozszerza klasę IsolatedService i implementuje interfejs IsolatedWorker. IsolatedService musi utworzyć instancję IsolatedWorker dla każdego żądania.
Ten diagram przedstawia relację między metodami w przestrzeniach nazw OnDevicePersonalizationManager i IsolatedWorker.
OnDevicePersonalizationManager a IsolatedWorker.Aplikacja kliencka wywołuje ODP za pomocą metody execute z nazwanym parametrem IsolatedService. Usługa ODP przekazuje wywołanie do metody onExecute usługi IsolatedWorker. IsolatedWorker zwraca rekordy do zapisania i treści do wyświetlenia. Usługa ODP zapisuje trwałe dane wyjściowe w tabeli REQUESTS lub EVENTS i zwraca do aplikacji klienta nieprzezroczyste odwołanie do wyświetlanych danych wyjściowych. Aplikacja klienta może użyć tego nieprzezroczystego odwołania w przyszłym wywołaniu requestSurfacePackage, aby wyświetlić dowolne treści w swoim interfejsie.
Trwałe dane wyjściowe
Usługa ODP zapisuje rekord w tabeli REQUESTS po tym, jak implementacja onExecute dewelopera zwróci wartość. Każdy rekord w tabeli REQUESTS zawiera wspólne dane dotyczące poszczególnych żądań wygenerowane przez usługę ODP oraz listę zwróconych wartości Rows. Każdy element Row zawiera listę par (key, value). Każda wartość jest skalarem, ciągiem znaków lub obiektem binarnym. Wartości liczbowe można raportować po agregacji, a dane w postaci ciągów znaków lub obiektów binarnych dużych rozmiarów można raportować po zastosowaniu lokalnej lub centralnej prywatności różnicowej. Deweloperzy mogą też zapisywać kolejne zdarzenia interakcji użytkownika w tabeli EVENTS – każdy rekord w tabeli EVENTS jest powiązany z wierszem w tabeli REQUESTS. Usługa ODP w sposób przejrzysty rejestruje sygnaturę czasową i nazwę pakietu aplikacji wywołującej oraz pliku APK dewelopera ODP przy każdym rekordzie.
Zanim zaczniesz
Zanim zaczniesz tworzyć aplikacje za pomocą ODP, musisz skonfigurować plik manifestu pakietu i włączyć tryb programisty.
Ustawienia pliku manifestu pakietu
Aby korzystać z ODP, musisz spełniać te wymagania:
- Tag
<property>wAndroidManifest.xml, który wskazuje zasób XML w pakiecie zawierający informacje o konfiguracji ODP. - Tag
<service>wAndroidManifest.xml, który identyfikuje klasę rozszerzającąIsolatedService, jak w tym przykładzie. Usługa w tagu<service>musi mieć atrybutyexportediisolatedProcessustawione na wartośćtrue. - Tag
<service>w zasobie XML określonym w kroku 1, który identyfikuje klasę usługi z kroku 2. Tag<service>musi też zawierać dodatkowe ustawienia ODP w samym tagu, jak pokazano w drugim przykładzie.
AndroidManifest.xml
<!-- Contents of AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.odpsample" >
<application android:label="OdpSample">
<!-- XML resource that contains other ODP settings. -->
<property android:name="android.ondevicepersonalization.ON_DEVICE_PERSONALIZATION_CONFIG"
android:resource="@xml/OdpSettings"></property>
<!-- The service that ODP binds to. -->
<service android:name="com.example.odpsample.SampleService"
android:exported="true" android:isolatedProcess="true" />
</application>
</manifest>
Manifest ODP w zasobie XML
Plik zasobu XML określony w tagu <property> musi też deklarować klasę usługi w tagu <service> i określać punkt końcowy URL, z którego ODP będzie pobierać treści do wypełnienia tabeli RemoteData, jak pokazano w tym przykładzie. Jeśli korzystasz z funkcji obliczeń sfederowanych, musisz też podać adres URL serwera obliczeń sfederowanych, z którym połączy się klient obliczeń sfederowanych.
<!-- Contents of res/xml/OdpSettings.xml -->
<on-device-personalization>
<!-- Name of the service subclass -->
<service name="com.example.odpsample.SampleService">
<!-- If this tag is present, ODP will periodically poll this URL and
download content to populate REMOTE_DATA. Developers that do not need to
download content from their servers can skip this tag. -->
<download-settings url="https://example.com/get" />
<!-- If you want to use federated compute feature to train a model, you
need to specify this tag. -->
<federated-compute-settings url="https://fcpserver.example.com/" />
</service>
</on-device-personalization>
Włączanie trybu programisty
Włącz tryb dewelopera, postępując zgodnie z instrukcjami w sekcji Włączanie opcji dewelopera w dokumentacji Android Studio.
Ustawienia przełączników i flag
ODP ma zestaw przełączników i flag, które służą do sterowania określonymi funkcjami:
- _global_killswitch: globalny przełącznik wszystkich funkcji ODP; ustaw na false, aby korzystać z ODP.
- _federated_compute_kill_switch: _ przełącznik kontrolujący wszystkie funkcje trenowania (uczenia sfederowanego) w ODP; ustawiony na wartość false, aby używać trenowania.
- _caller_app_allowlist: określa, kto może wywoływać ODP. Można tu dodać aplikacje (nazwa pakietu, [opcjonalnie] certyfikat) lub ustawić * , aby zezwolić na wszystkie.
- _isolated_service_allowlist: określa, które usługi mogą działać w procesie usługi izolowanej.
Aby skonfigurować wszystkie przełączniki i flagi tak, aby używały ODP bez ograniczeń, możesz uruchomić te polecenia:
# Set flags and killswitches
adb shell device_config set_sync_disabled_for_tests persistent
adb shell device_config put on_device_personalization global_kill_switch false
adb shell device_config put on_device_personalization federated_compute_kill_switch false
adb shell device_config put on_device_personalization caller_app_allow_list \"*\"
adb shell device_config put on_device_personalization isolated_service_allow_list \"*\"
Interfejsy API po stronie urządzenia
Zapoznaj się z dokumentacją interfejsu Android API dotyczącą platformy ODP.
Interakcje z IsolatedService
Klasa IsolatedService to abstrakcyjna klasa bazowa, którą muszą rozszerzyć wszyscy deweloperzy, którzy chcą tworzyć aplikacje zgodne z ODP. Muszą oni też zadeklarować w pliku manifestu pakietu, że działa ona w izolowanym procesie. Usługa ODP uruchamia tę usługę w izolowanym procesie i wysyła do niej żądania. IsolatedService otrzymuje żądania z usługi ODP i tworzy IsolatedWorker do ich obsługi.
Aby obsługiwać żądania aplikacji klienckiej, pobieranie i zdarzenia wywoływane przez renderowany kod HTML, deweloperzy muszą zaimplementować metody z interfejsu IsolatedWorker. Wszystkie te metody mają domyślne implementacje bez operacji, więc programiści mogą pominąć implementację metod, które ich nie interesują.
Klasa OnDevicePersonalizationManager udostępnia interfejs API, który umożliwia aplikacjom i pakietom SDK interakcję z IsolatedService zaimplementowanym przez dewelopera i działającym w izolowanym procesie. Oto niektóre z przewidywanych zastosowań:
Generowanie treści HTML do wyświetlania w obiekcie SurfaceView
Aby wygenerować treść do wyświetlenia, aplikacja wywołująca może użyć zwróconego obiektu SurfacePackageToken w kolejnym wywołaniu requestSurfacePackage, aby poprosić o wyrenderowanie wyniku w obiekcie SurfaceView.OnDevicePersonalizationManager#execute
Jeśli operacja się powiedzie, odbiorca jest wywoływany z wartością SurfacePackage dla widoku renderowanego przez usługę ODP. Aplikacje klienckie muszą wstawić element SurfacePackage do elementu SurfaceView w hierarchii widoków.
Gdy aplikacja wywołuje funkcję requestSurfacePackage z obiektem SurfacePackageToken zwróconym przez wcześniejsze wywołanie funkcji OnDevicePersonalizationManager#execute, usługa ODP wywołuje funkcję IsolatedWorker#onRender, aby pobrać fragment kodu HTML do renderowania w ramce ograniczonej. Na tym etapie deweloper nie ma dostępu do LocalData ani UserData. Uniemożliwia to programiście umieszczanie potencjalnie wrażliwych informacji UserData w adresach URL pobierania zasobów w wygenerowanym kodzie HTML. Deweloperzy mogą używać IsolatedService#getEventUrlProvider do generowania linków monitorujących, które można umieszczać w wygenerowanym kodzie HTML. Gdy kod HTML zostanie wyrenderowany, usługa ODP przechwyci żądania do tych adresów URL i wywoła funkcję IsolatedWorker#onEvent. Podczas implementowania funkcji onRender() można wywołać funkcję getRemoteData().
Śledzenie zdarzeń w treści HTML
Klasa EventUrlProvider udostępnia interfejsy API do generowania linków monitorujących zdarzenia, które programiści mogą umieszczać w danych wyjściowych HTML. Gdy kod HTML zostanie wyrenderowany, ODP wywoła IsolatedWorker#onEvent z ładunkiem adresu URL zdarzenia.
Usługa ODP przechwytuje żądania do wygenerowanych w ODP adresów URL zdarzeń w renderowanym kodzie HTML, wywołuje funkcję IsolatedWorker#onEvent i zapisuje zwrócone wartości EventLogRecord w tabeli EVENTS.
Zapisywanie trwałych wyników
W przypadku OnDevicePersonalizationManager#execute usługa może zapisywać dane w pamięci trwałej (tabelach REQUESTS i EVENTS). Oto wpisy, które można umieścić w tych tabelach:
RequestLogRecord, która ma zostać dodana do tabeliREQUESTS.- lista obiektów
EventLogRecorddo dodania do tabeliEVENTS, z których każdy zawiera wskaźnik do wcześniej zapisanego obiektuRequestLogRecord.
Trwałe wyniki w pamięci urządzenia mogą być wykorzystywane przez sfederowane uczenie się do trenowania modeli.
Zarządzanie zadaniami trenowania na urządzeniu
Usługa ODP wywołuje funkcję IsolatedWorker#onTrainingExample, gdy rozpoczyna się zadanie trenowania z użyciem sfederowanych obliczeń i chce uzyskać przykłady trenowania dostarczone przez deweloperów korzystających z ODP. Podczas implementowania interfejsu onTrainingExample() możesz wywoływać interfejsy getRemoteData(), getLocalData(), getUserData() i getLogReader().
Aby zaplanować lub anulować zadania obliczeń sfederowanych, możesz użyć klasy FederatedComputeScheduler, która udostępnia interfejsy API dla wszystkich ODP IsolatedService. Każde zadanie obliczeniowe w ramach federacji można zidentyfikować na podstawie nazwy populacji.
Zanim zaplanujesz nowe zadanie obliczeń sfederowanych:
- Zadanie o tej nazwie populacji powinno być już utworzone na zdalnym serwerze obliczeń sfederowanych.
- Punkt końcowy adresu URL serwera obliczeń federacyjnych powinien być już określony w ustawieniach pliku manifestu pakietu za pomocą tagu
federated-compute-settings.
Interakcje z trwałymi danymi wyjściowymi
W sekcji poniżej opisano, jak korzystać z trwałych danych wyjściowych w ODP.
Odczytywanie tabel lokalnych
Klasa LogReader udostępnia interfejsy API do odczytywania tabel REQUESTS i EVENTS. Tabele te zawierają dane zapisane przez IsolatedService podczas połączeń onExecute() lub onEvent(). Dane w tych tabelach mogą być używane do trenowania modeli za pomocą sfederowanego uczenia się lub do analizy statystycznej na różnych urządzeniach za pomocą sfederowanej analizy.
Interakcje z pobranymi treściami
W sekcji poniżej opisano, jak korzystać z pobranych treści w ODP.
Pobieranie treści z serwerów
Usługa ODP okresowo pobiera treści z adresu URL zadeklarowanego w pliku manifestu pakietu IsolatedService i po zakończeniu pobierania wywołuje funkcję onDownloadCompleted. Pobrany plik to plik JSON zawierający pary klucz-wartość.
Deweloperzy korzystający z ODP mogą wybrać, która część pobranych treści ma zostać dodana do tabeli RemoteData, a która ma zostać pominięta. Deweloperzy nie mogą modyfikować pobranych treści, co gwarantuje, że tabela RemoteData nie zawiera żadnych danych użytkownika. Deweloperzy mogą też wypełniać tabelę LocalData w dowolny sposób, np. mogą buforować wstępnie obliczone wyniki.
Format żądania pobierania
ODP okresowo wysyła zapytania do punktu końcowego URL zadeklarowanego w pliku manifestu pakietu dewelopera, aby pobrać treści do wypełnienia tabeli RemoteData.
Punkt końcowy powinien zwrócić odpowiedź w formacie JSON, jak opisano poniżej. Odpowiedź JSON musi zawierać syncToken, które identyfikuje wersję wysyłanych danych, oraz listę par klucz-wartość do wypełnienia. Wartość syncToken musi być sygnaturą czasową w sekundach, ograniczoną do granicy godziny UTC. W ramach żądania pobierania platforma ODP podaje syncToken poprzedniego pobierania oraz kraj urządzenia jako parametry syncToken i country w adresie URL pobierania. Serwer może użyć poprzedniego syncToken, aby wdrożyć pobieranie przyrostowe.
Format pobierania pliku
Pobrany plik to plik JSON o tej strukturze: Plik JSON powinien zawierać token synchronizacji, który identyfikuje wersję pobieranych danych. Token synchronizacji musi być sygnaturą czasową UTC zaokrągloną do pełnej godziny i musi być późniejszy niż token synchronizacji z poprzedniego pobierania. Jeśli token synchronizacji nie spełnia obu tych wymagań, pobrane treści są odrzucane bez przetwarzania.
Pole contents to lista krotek (klucz, dane, kodowanie). Wartość key powinna być ciągiem znaków UTF-8. Pole encoding to opcjonalny parametr, który określa sposób kodowania pola data. Może mieć wartość „utf8” lub „base64”. Domyślnie przyjmuje wartość „utf8”. Pole key jest konwertowane na obiekt String, a pole data jest konwertowane na tablicę bajtów przed wywołaniem onDownloadCompleted()..
{
// syncToken must be a UTC timestamp clamped to an hour boundary, and must be
// greater than the syncToken of the previously completed download.
"syncToken": <timeStampInSecRoundedToUtcHour>,
"contents": [
// List of { key, data } pairs.
{ "key": "key1",
"data": "data1"
},
{ "key": "key2",
"data": "data2",
"encoding": "base64"
},
// ...
]
}
Interfejsy API po stronie serwera
W tej sekcji opisano, jak korzystać z interfejsów API serwera obliczeń federacyjnych.
Interfejsy API serwera obliczeń federacyjnych
Aby zaplanować zadanie obliczeń sfederowanych po stronie klienta, musisz mieć zadanie z nazwą populacji utworzone na zdalnym serwerze obliczeń sfederowanych. W tej sekcji opisujemy, jak utworzyć takie zadanie na serwerze obliczeń sfederowanych.
Podczas tworzenia nowego zadania w Narzędziu do tworzenia zadań deweloperzy ODP powinni podać 2 zestawy plików:
- Zapisany model tff.learning.models.FunctionalModel uzyskany przez wywołanie interfejsu API tff.learning.models.save_functional_model. Jeden z nich znajdziesz w naszym repozytorium GitHub.
- Plik fcp_server_config.json, który zawiera zasady, konfigurację uczenia sfederowanego i konfigurację prywatności różnicowej. Oto przykład pliku fcp_server_config.json:
{
# Task execution mode.
mode: TRAINING_AND_EVAL
# Identifies the set of client devices that participate.
population_name: "mnist_cnn_task"
policies {
# Policy for sampling on-device examples. It is checked every
# time a device is attempting to start a new training.
min_separation_policy {
# The minimum separation required between two successful
# consective task executions. If a client successfully contributes
# to a task at index `x`, the earliest they can contribute again
# is at index `(x + minimum_separation)`. This is required by
# DP.
minimum_separation: 1
}
data_availability_policy {
# The minimum number of examples on a device to be considered
# eligible for training.
min_example_count: 1
}
# Policy for releasing training results to developers adopting ODP.
model_release_policy {
# The maximum number of training rounds.
num_max_training_rounds: 512
}
}
# Federated learning setups. They are applied inside Task Builder.
federated_learning {
# Use federated averaging to build federated learning process.
# Options you can choose:
# * FED_AVG: Federated Averaging algorithm
# (https://arxiv.org/abs/2003.00295)
# * FED_SGD: Federated SGD algorithm
# (https://arxiv.org/abs/1602.05629)
type: FED_AVG
learning_process {
# Optimizer used at client side training. Options you can choose:
# * ADAM
# * SGD
client_optimizer: SGD
# Learning rate used at client side training.
client_learning_rate: 0.02
# Optimizer used at server side training. Options you can choose:
# * ADAM
# * SGD
server_optimizer: SGD
# Learning rate used at server side training.
server_learning_rate: 1.0
runtime_config {
# Number of participating devices for each round of training.
report_goal: 2
}
metrics {
name: "sparse_categorical_accuracy"
}
}
evaluation {
# A checkpoint selector controls how checkpoints are chosen for
# evaluation. One evaluation task typically runs per training
# task, and on each round of execution, the eval task
# randomly picks one checkpoint from the past 24 hours that has
# been selected for evaluation by these rules.
# Every_k_round and every_k_hour are definitions of quantization
# buckets which each checkpoint is placed in for selection.
checkpoint_selector: "every_1_round"
# The percentage of a populate that should delicate to this
# evaluation task.
evaluation_traffic: 0.2
# Number of participating devices for each round of evaluation.
report_goal: 2
}
}
# Differential Privacy setups. They are enforced inside the Task
# Builder.
differential_privacy {
# * fixed_gaussian: DP-SGD with fixed clipping norm described in
# "Learning Differentially Private Recurrent
# Language Models"
# (https://arxiv.org/abs/1710.06963).
type: FIXED_GAUSSIAN
# The value of the clipping norm.
clip_norm: 0.1
# Noise multiplier for the Gaussian noise.
noise_multiplier: 0.1
}
}
Więcej przykładów znajdziesz w naszym repozytorium GitHub.
Po przygotowaniu tych 2 danych wejściowych wywołaj narzędzie Task Builder, aby utworzyć artefakty i wygenerować nowe zadania. Bardziej szczegółowe instrukcje znajdziesz w naszym repozytorium GitHub.