La personalizzazione on-device (ODP) è progettata per proteggere le informazioni degli utenti finali dalle applicazioni. Le applicazioni utilizzano ODP per personalizzare i propri prodotti e servizi per gli utenti finali, ma non saranno in grado di visualizzare le personalizzazioni esatte apportate per l'utente (a meno che non ci siano interazioni dirette al di fuori di ODP tra l'applicazione e l'utente finale). Per le applicazioni con modelli di machine learning o analisi statistiche, ODP fornisce una serie di servizi e algoritmi per garantire che vengano anonimizzati correttamente utilizzando i meccanismi di privacy differenziale appropriati. Per ulteriori dettagli, consulta la spiegazione sulla personalizzazione sul dispositivo.
L'ODP esegue il codice sviluppatore in un IsolatedProcess
che non ha accesso diretto alla rete, ai dischi locali o ad altri servizi in esecuzione sul dispositivo, ma ha accesso alle seguenti origini dati persistenti a livello locale:
RemoteData
: dati chiave-valore immutabili scaricati da backend remoti gestiti dagli sviluppatori, se applicabili.LocalData
: dati chiave-valore mutabili persistenti a livello locale dallo sviluppatore, se applicabile.UserData
: dati utente forniti dalla piattaforma.
Sono supportati i seguenti output:
- Output persistente: questi output possono essere utilizzati in un'elaborazione locale futura, per produrre output visualizzati, per l'addestramento dei modelli facilitato da Federated Learning o per l'analisi statistica cross-device facilitata da Federated Analytics.
- Output visualizzato:
- Gli sviluppatori possono restituire HTML visualizzato da ODP in un
WebView
all'interno di unSurfaceView
. I contenuti visualizzati lì non saranno visibili all'app che li ha richiamati. - Gli sviluppatori possono incorporare gli URL evento forniti dall'ODP nell'output HTML per attivare la registrazione e l'elaborazione delle interazioni degli utenti con l'HTML visualizzato. ODP intercetta le richieste a questi URL e richiama il codice per generare i dati che vengono scritti nella tabella
EVENTS
.
- Gli sviluppatori possono restituire HTML visualizzato da ODP in un
Le app client e gli SDK possono richiamare ODP per visualizzare contenuti HTML in un SurfaceView
utilizzando le API ODP. I contenuti visualizzati in un SurfaceView
non sono visibili all'app chiamante. L'app client o l'SDK può essere un'entità diversa da quella in fase di sviluppo con ODP.
Il servizio ODP gestisce l'app client che vuole richiamare ODP per mostrare i contenuti personalizzati all'interno della sua UI. Scarica i contenuti dagli endpoint forniti dallo sviluppatore e richiama la logica per la post-elaborazione dei dati scaricati. Inoltre, agisce da mediatore di tutte le comunicazioni tra IsolatedProcess
e altri servizi e app.
Le app client utilizzano metodi della classe OnDevicePersonalizationManager
per interagire con il codice dello sviluppatore eseguito in un IsolatedProcess
. Il codice dello sviluppatore in esecuzione in un IsolatedProcess
estende la classe IsolatedService
e implementa l'interfaccia IsolatedWorker
. IsolatedService
deve creare un'istanza di IsolatedWorker
per ogni richiesta.
Il seguente diagramma mostra la relazione tra i metodi in OnDevicePersonalizationManager
e IsolatedWorker
.
Un'app client chiama ODP utilizzando il metodo execute
con un IsolatedService
denominato. Il servizio ODP inoltra la chiamata al metodo onExecute
di IsolatedWorker
. IsolatedWorker
restituisce i record da mantenere e i contenuti da visualizzare. Il servizio ODP scrive l'output persistente nella tabella REQUESTS
o EVENTS
e restituisce un riferimento opaco all'output visualizzato all'app client. L'app client può utilizzare questo riferimento opaco in una chiamata requestSurfacePackage
futura per visualizzare qualsiasi contenuto della visualizzazione all'interno della sua UI.
Output permanente
Il servizio ODP mantiene un record nella tabella REQUESTS
dopo il ritorno dell'implementazione di onExecute
da parte dello sviluppatore. Ogni record nella tabella REQUESTS
contiene alcuni dati per richiesta comuni generati dal servizio ODP, nonché un elenco di Rows
restituiti. Ogni Row
contiene un elenco di (key, value)
coppie. Ogni valore è uno scalare, una stringa o un blob. I valori numerici possono essere riportati dopo l'aggregazione e i dati della stringa o del blob possono essere riportati dopo l'applicazione della privacy differenziale locale o centrale. Gli sviluppatori possono anche scrivere eventi di interazione utente successivi nella tabella EVENTS
: ogni record della tabella EVENTS
è associato a una riga della tabella REQUESTS
. Il servizio ODP registra in modo trasparente un timestamp, il nome del pacchetto dell'app chiamante e l'APK dello sviluppatore ODP per ogni record.
Prima di iniziare
Prima di iniziare a sviluppare con ODP, devi configurare il manifest del pacchetto e attivare la modalità sviluppatore.
Impostazioni del file manifest del pacchetto
Per utilizzare ODP, sono necessari i seguenti requisiti:
- Un tag
<property>
inAndroidManifest.xml
che punta a una risorsa XML nel pacchetto contenente informazioni sulla configurazione ODP. - Un tag
<service>
inAndroidManifest.xml
che identifica la classe che estendeIsolatedService
, come mostrato nell'esempio seguente. Il servizio nel tag<service>
deve avere gli attributiexported
eisolatedProcess
impostati sutrue
. - Un tag
<service>
nella risorsa XML specificata nel passaggio 1 che identifica la classe di servizio del passaggio 2. Il tag<service>
deve includere anche ulteriori impostazioni specifiche per ODP all'interno del tag stesso, come mostrato nel secondo esempio.
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 specifico per ODP nella risorsa XML
Il file di risorse XML specificato nel tag <property>
deve inoltre dichiarare la classe di servizio in un tag <service>
e specificare l'endpoint URL da cui ODP scaricherà i contenuti per completare la tabella RemoteData
, come mostrato nell'esempio seguente. Se utilizzi le funzionalità di calcolo federato, devi anche specificare l'endpoint URL del server di calcolo federato a cui si connetterà il client di computing federato.
<!-- 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>
Attivare la modalità sviluppatore
Attiva la modalità sviluppatore seguendo le istruzioni riportate nella sezione Attivare le Opzioni sviluppatore della documentazione di Android Studio.
Impostazioni di Switch e Flag
ODP ha una serie di opzioni e flag utilizzati per controllare alcune funzionalità:
- _global_killswitch: l'opzione globale per tutte le funzionalità ODP; impostala su false per utilizzare ODP
- _federated_compute_kill_switch: _l'opzione che controlla tutte le funzionalità di addestramento (apprendimento federato) di ODP; impostata su false per utilizzare l'addestramento
- _caller_app_allowlist: consente di stabilire chi è autorizzato a chiamare ODP. È possibile aggiungere app (nome pacchetto, certificato [facoltativo]) o impostarlo come * per consentire tutte.
- _isolated_service_allowlist: controlla quali servizi possono essere eseguiti nel processo del servizio isolato.
Puoi eseguire questi comandi per configurare tutte le opzioni e i flag in modo che utilizzino ODP senza limitazioni:
# 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 \"*\"
API lato dispositivo
Consulta la documentazione di riferimento dell'API Android per ODP.
Interazioni con IsolatedService
La classe IsolatedService
è una classe base astratta che tutti gli sviluppatori che intendono sviluppare rispetto a ODP devono estendere e dichiarare nel file manifest del pacchetto come in esecuzione in un processo isolato. Il servizio ODP avvia questo servizio in un processo isolato e invia richieste. IsolatedService
riceve richieste dal servizio ODP e crea un IsolatedWorker
per gestire la richiesta.
Gli sviluppatori devono implementare i metodi dall'interfaccia di IsolatedWorker
per gestire le richieste dell'app client, i completamenti dei download e gli eventi attivati dal codice HTML sottoposto a rendering. Tutti questi metodi hanno implementazioni no-op predefinite, quindi gli sviluppatori possono saltare l'implementazione dei metodi che non li interessano.
La classe OnDevicePersonalizationManager
fornisce un'API per consentire ad app e SDK di interagire con un IsolatedService
implementato dallo sviluppatore in esecuzione in un processo isolato. Di seguito sono riportati alcuni casi d'uso previsti:
Generare contenuti HTML da visualizzare in un SurfaceView
Per generare contenuti da visualizzare, con OnDevicePersonalizationManager#execute
l'app chiamante può utilizzare l'oggetto SurfacePackageToken
restituito in una chiamata requestSurfacePackage
successiva per richiedere il rendering del risultato in un SurfaceView
.
Se l'operazione riesce, il ricevitore viene chiamato con SurfacePackage
per una visualizzazione visualizzata dal servizio ODP. Le applicazioni client devono inserire SurfacePackage
in un SurfaceView
all'interno della gerarchia di visualizzazione.
Quando un'app effettua una chiamata requestSurfacePackage
con un SurfacePackageToken
restituito da una chiamata OnDevicePersonalizationManager#execute
precedente, il servizio ODP chiama IsolatedWorker#onRender
per recuperare lo snippet HTML da visualizzare all'interno di un frame delimitato. Uno sviluppatore non ha accesso a LocalData
o UserData
durante questa fase. In questo modo, lo sviluppatore non può incorporare UserData
potenzialmente sensibile all'interno degli URL di recupero degli asset nel codice HTML generato. Gli sviluppatori possono utilizzare IsolatedService#getEventUrlProvider
per generare URL di monitoraggio da includere nel codice HTML generato. Quando viene eseguito il rendering dell'HTML, il servizio ODP intercetta le richieste a questi URL e chiama IsolatedWorker#onEvent
. È possibile richiamare getRemoteData()
durante l'implementazione di onRender()
.
Monitorare gli eventi all'interno dei contenuti HTML
La classe EventUrlProvider
fornisce API per generare URL di monitoraggio eventi che gli sviluppatori possono includere nell'output HTML. Dopo il rendering dell'HTML, ODP richiama IsolatedWorker#onEvent
con il payload dell'URL dell'evento.
Il servizio ODP intercetta le richieste agli URL degli eventi generati da ODP all'interno del codice HTML visualizzato, chiama IsolatedWorker#onEvent
e registra il EventLogRecord
restituito nella tabella EVENTS
.
Scrivere risultati permanenti
Con OnDevicePersonalizationManager#execute
, il servizio ha la possibilità di scrivere dati nell'archiviazione permanente (tabelle REQUESTS
e EVENTS
). Di seguito sono riportate le voci che è possibile scrivere in queste tabelle:
- un
RequestLogRecord
da aggiungere alla tabellaREQUESTS
. - un elenco di oggetti
EventLogRecord
da aggiungere alla tabellaEVENTS
, ciascuno contenente un puntatore a unRequestLogRecord
scritto in precedenza.
I risultati permanenti nello spazio di archiviazione sul dispositivo possono essere utilizzati dall'apprendimento federato per l'addestramento dei modelli.
Gestisci le attività di formazione sul dispositivo
Il servizio ODP chiama IsolatedWorker#onTrainingExample
all'avvio di un job di addestramento di computing federato e vuole ottenere esempi di addestramento forniti dagli sviluppatori che adottano ODP. Puoi richiamare getRemoteData()
, getLocalData()
, getUserData()
e getLogReader()
quando implementi onTrainingExample()
.
Per pianificare o annullare i job di calcolo federato, puoi utilizzare la classe FederatedComputeScheduler
che fornisce API per tutti gli ODP IsolatedService
. Ogni job di calcolo federato può essere identificato dal nome della popolazione.
Prima di pianificare un nuovo job di calcolo federato:
- Un'attività con questo nome della popolazione dovrebbe essere già stata creata sul server di calcolo federato remoto.
- L'endpoint URL del server di computing federato deve essere già specificato nelle impostazioni del file manifest del pacchetto con il tag
federated-compute-settings
.
Interazioni con output permanente
La sezione seguente descrive come interagire con l'output permanente in ODP.
Lettura tabelle locali
La classe LogReader
fornisce API per leggere le tabelle REQUESTS
e EVENTS
. Queste tabelle contengono i dati scritti da IsolatedService
durante le chiamate onExecute()
o onEvent()
. I dati in queste tabelle possono essere utilizzati per l'addestramento dei modelli facilitato dall'apprendimento federato o per l'analisi statistica cross-device facilitata da Federated Analytics.
Interazioni con i contenuti scaricati
La sezione seguente descrive come interagire con i contenuti scaricati in ODP.
Scaricare contenuti dai server
Il servizio ODP scarica periodicamente i contenuti dall'URL dichiarato nel manifest del pacchetto di IsolatedService
e chiama onDownloadCompleted
al termine del download. Il download è un file JSON contenente coppie chiave-valore.
Gli sviluppatori che adottano ODP possono scegliere quale sottoinsieme dei contenuti scaricati deve essere aggiunto alla tabella RemoteData
e quale deve essere eliminato. Gli sviluppatori non possono modificare i contenuti scaricati. Questo garantisce che la tabella RemoteData
non contenga dati utente. Inoltre, gli sviluppatori sono liberi di compilare la tabella LocalData
come preferiscono; ad esempio, possono memorizzare nella cache alcuni risultati precomputati.
Formato richiesta di download
ODP esegue periodicamente il polling dell'endpoint URL dichiarato nel manifest del pacchetto per sviluppatori per recuperare i contenuti da inserire nella tabella RemoteData
.
L'endpoint dovrebbe restituire una risposta JSON come descritto di seguito. La risposta JSON deve contenere un valore syncToken
che identifica la versione dei dati inviati, insieme a un elenco di coppie chiave-valore da compilare. Il valore syncToken
deve essere un timestamp in secondi, vincolato al limite di ore UTC. Nell'ambito della richiesta di download, ODP fornisce syncToken
del download completato in precedenza e il paese del dispositivo come syncToken e parametri paese nell'URL di download. Il server può utilizzare l'oggetto syncToken
precedente per implementare i download incrementali.
Scarica formato file
Il file scaricato è un file JSON con la seguente struttura. Il file JSON deve contenere un syncToken per identificare la versione dei dati che viene scaricato. Il syncToken deve essere un timestamp UTC limitato a un'ora e deve superare il syncToken del download precedente. Se il token di sincronizzazione non soddisfa entrambi i requisiti, i contenuti scaricati vengono ignorati senza essere elaborati.
Il campo dei contenuti è un elenco di tuple (chiave, dati, codifica). key
deve essere una stringa UTF-8. Il campo encoding
è un parametro facoltativo che specifica la codifica del campo data
. Può essere impostato su "utf8" o "base64" e per impostazione predefinita si presume che sia "utf8". Il campo key
viene convertito in un oggetto String
e il campo data
viene convertito in un array di byte prima di chiamare 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"
},
// ...
]
}
API lato server
Questa sezione descrive come interagire con le API di server di calcolo federati.
API di server di calcolo federato
Per pianificare un job di calcolo federato sul lato client, è necessaria un'attività con un nome popolato creato sul server di calcolo federato remoto. In questa sezione viene spiegato come creare un'attività di questo tipo sul server di calcolo federato.
Quando creano una nuova attività per Task Builder, gli sviluppatori ODP devono fornire due insiemi di file:
- Un modello tff.learning.models.FunctionalModel salvato tramite la chiamata alla chiamata API tff.learning.models.save_functional_model. Puoi trovare un esempio nel nostro repository GitHub.
- Un file fcp_server_config.json che include criteri, configurazione dell'apprendimento federato e configurazione della privacy differenziale. Di seguito è riportato un esempio di 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
}
}
Puoi trovare altri esempi nel nostro repository GitHub.
Dopo aver preparato questi due input, invoca Task Builder per creare elementi e generare nuove attività. Istruzioni più dettagliate sono disponibili nel nostro repository GitHub.