Fine-tuning con privacy differenziale tramite Opacus
Esegui il fine-tuning di un classificatore di testo o di immagini sulle etichette del tuo studio con DP-SGD, imposta epsilon e delta e leggi la privacy spesa nel log dell'esecuzione e nella model card.
Novità nella v2.14.0
Questo tutorial addestra un classificatore sulle etichette di uno studio con privacy differenziale, in modo che il modello rilasciato riveli poco su un singolo item annotato. La pagina è pensata per i responsabili di studi i cui item o le cui etichette sono sensibili (per esempio cartelle cliniche o messaggi privati) e che prevedono di condividere o pubblicare il modello. Aggiungerai un blocco dp ai parametri di hf-text-classification, eseguirai il trainer sull'esempio delle recensioni di prodotti e leggerai la privacy spesa dal log dell'esecuzione e dalla model card. Lo stesso blocco funziona su hf-image-classification, e nessun altro trainer accetta dp.
Epsilon e delta nella privacy differenziale
La privacy differenziale è una garanzia matematica su un calcolo eseguito su un dataset. Aggiungere o rimuovere un record cambia la probabilità di qualsiasi output di una quantità limitata, quindi l'output rivela poco sulla presenza di quel record. Epsilon (ε) è il limite. Un epsilon più piccolo rende più difficile distinguere gli output con e senza il record, e quindi dà una privacy più forte. Delta (δ) è la probabilità che il limite di epsilon non regga, e la documentazione di Potato descrive delta come "the chance the guarantee does not hold".
DP-SGD addestra una rete neurale sotto questa garanzia, con il metodo di Abadi et al. (2016). A ogni passo di addestramento si tronca il gradiente di ogni item a una norma massima e si aggiunge rumore gaussiano alla somma. Il troncamento limita di quanto un singolo item può spostare il modello, e il rumore maschera quello spostamento limitato. Opacus è una libreria PyTorch che implementa DP-SGD, e Potato affida il ciclo di addestramento a Opacus ogni volta che un'esecuzione porta dp. L'accountant RDP di Opacus somma l'epsilon speso a ogni passo.
Installare il trainer e Opacus
I trainer transformer richiedono torch e transformers dagli extra di addestramento di Potato. Nessun extra di Potato include Opacus, perché Opacus fissa versioni specifiche di torch. Installa entrambi sulla macchina in cui l'esecuzione si addestra:
pip install "potato-annotation[train-text]" # [train-vision] for hf-image-classification
pip install opacusUn'esecuzione con dp controlla la presenza di Opacus sulla macchina di addestramento prima che l'addestramento inizi. Su un backend ssh, SLURM o agent, Opacus va quindi sul server GPU o sul nodo di calcolo che addestra, anziché sul server di annotazione. L'addestramento remoto tratta quei backend.
Configurare il trainer
La configurazione seguente è l'esempio delle recensioni di prodotti di Addestra il tuo primo modello, con l'addestramento privato impostato come valore predefinito per hf-text-classification. Copia data/reviews.json e data/gold.json da examples/ai-assisted/model-training/ di Potato in una cartella di progetto e salva questa configurazione lì come config.yaml:
annotation_task_name: "Review Sentiment (private training)"
data_files:
- "data/reviews.json"
item_properties:
id_key: "id"
text_key: "text"
task_dir: "."
output_annotation_dir: "annotation_output"
require_password: false
admin_api_key: "demo-admin-key"
num_annotators_per_item: 1
annotation_schemes:
- annotation_type: "radio"
name: "sentiment"
description: "Is this review positive or negative?"
labels:
- "positive"
- "negative"
sequential_key_binding: true
model_training:
enabled: true
trainer_params:
hf-text-classification:
epochs: 5
batch_size: 16
dp:
epsilon: 8
max_grad_norm: 1.0
writeback:
schemas: ["sentiment"]
include_unlabeled: true
min_confidence: 0.6trainer_params imposta i valori predefiniti per ogni esecuzione di hf-text-classification, quindi il campo Parameters della pagina Training si apre con la voce dp già compilata. epsilon: 8 rientra nell'intervallo da 1 a 10 che la documentazione di Potato definisce usuale. delta è omesso, quindi Potato lo imposta a 1 / (10 × item train). max_grad_norm: 1.0 ripete il troncamento predefinito. epochs e batch_size ripetono i valori predefiniti del trainer, perché Opacus dimensiona il rumore sulla base di entrambi. require_password: false e la chiave di amministratore in chiaro vanno bene solo per una prova locale.
dp accetta tre chiavi:
| Chiave | Predefinito | Significato |
|---|---|---|
epsilon | obbligatorio | Il budget di privacy per l'intera esecuzione. Un epsilon più piccolo è più privato e aggiunge più rumore. |
delta | 1 / (10 × item train) | La probabilità che la garanzia non regga. Delta deve essere inferiore a 1 / item train. |
max_grad_norm | 1.0 | Il gradiente di ogni item viene troncato a questa norma prima che si aggiunga il rumore. |
La configurazione supera python -m potato.validate_cli config.yaml --strict. Il validatore accetta una mappa, null o false per dp e rifiuta dp: true. Il validatore controlla anche ogni chiave dentro dp e il suo intervallo. Opacus e i controlli che dipendono dal numero di item train vengono eseguiti quando un'esecuzione parte, sulla macchina che addestra, come elenca la sezione Errori all'avvio di un'esecuzione.
Etichettare gli item e avviare un'esecuzione
hf-text-classification rifiuta di adattarsi a meno di 20 item train (min_instances). Avvia il server, poi etichetta le recensioni a mano o con tre annotatori simulati dal simulatore di utenti, che rispondono dal file gold:
potato start config.yaml -p 8000
python -m potato.simulator --server http://localhost:8000 --users 3 \
--strategy gold_standard --competence good=1.0 --max-annotations 40 \
--gold-file data/gold.json --sequential --fast-mode --no-exportIl simulatore etichetta 120 delle 160 recensioni. Con i valori predefiniti di splits (70% train, 15% val, 15% test) e split_seed: 0, la nostra esecuzione ha messo 76 recensioni etichettate in train, 19 in val e 25 in test. Delta vale quindi per impostazione predefinita 1 / 760, circa 0.00132, e qualsiasi delta che imposti deve essere inferiore a 1 / 76, circa 0.0132.
Apri http://localhost:8000/admin/training con la chiave di amministratore, scegli hf-text-classification e lo schema sentiment, controlla che il campo Parameters mostri la voce dp e fai clic su Train now. La stessa esecuzione parte dall'API:
curl -X POST -H "X-API-Key: demo-admin-key" -H "Content-Type: application/json" \
http://localhost:8000/admin/training/api/runs \
-d '{"trainer": "hf-text-classification", "schemas": ["sentiment"]}'La risposta riporta il run_id. I params propri di un'esecuzione sostituiscono trainer_params, quindi "params": {"dp": {"epsilon": 2}} addestra un'esecuzione con un budget più piccolo, e "params": {"dp": null} o "params": {"dp": false} addestra un'esecuzione senza DP. Mantieni invariato split_seed tra le due esecuzioni, così entrambe si addestrano e vengono valutate sugli stessi item e i punteggi held-out si confrontano direttamente.
Righe del log dell'esecuzione sotto DP
La pagina dell'esecuzione in /admin/training/runs/<run_id> elenca gli eventi e le metriche dell'esecuzione. Un'esecuzione DP aggiunge tre tipi di riga agli eventi.
La prima riga nomina le tabelle di embedding che Potato congela. Gli embedding di posizione e di tipo di token di un transformer di testo hanno una riga condivisa dall'intero batch, e Opacus non può calcolare un gradiente per item attraverso una riga condivisa. Per il modello predefinito, distilbert/distilroberta-base, le tabelle congelate sono roberta.embeddings.position_embeddings e roberta.embeddings.token_type_embeddings. Le tabelle congelate non si addestrano e non spendono privacy, mentre gli embedding delle parole e ogni altro livello continuano ad addestrarsi.
La seconda riga inizia con DP-SGD: e indica l'epsilon obiettivo, delta, le epoche pianificate, il moltiplicatore di rumore scelto da Opacus, il troncamento per item e il tasso di campionamento. Ogni passo estrae un batch con campionamento di Poisson, quindi ogni item train entra in un batch in modo indipendente con probabilità 1 / batch per epoca. Con 76 item train in batch da 16, un'epoca ha 5 batch e il log riporta un tasso di campionamento di 0.2000. Il moltiplicatore di rumore stabilisce la deviazione standard del rumore, e le FAQ di Opacus indicano da 0.1 a 2 come intervallo usuale.
Dopo ogni epoca, una riga della forma Epoch <n>/<epochs>: loss <loss>, epsilon spent <epsilon> riporta la perdita media dell'epoca e l'epsilon speso finora. Lo stesso valore viene registrato per epoca come metrica dp_epsilon, e le metriche finali dell'esecuzione portano dp_epsilon per l'intera esecuzione. Opacus dimensiona il rumore in modo che le epoche pianificate spendano al massimo l'epsilon obiettivo. Un'esecuzione che si ferma in anticipo per patience (due epoche senza un punteggio val migliore, per impostazione predefinita) spende meno dell'obiettivo.
La voce dp nella model card
L'esecuzione scrive model_card.json in artifacts/ nella cartella dell'esecuzione, <task_dir>/<output_annotation_dir>/training/runs/<run_id>/. La card di un'esecuzione DP ha una voce dp:
| Campo | Valore |
|---|---|
epsilon_target | L'epsilon che hai richiesto |
epsilon_spent | Ciò che l'esecuzione ha speso, secondo l'accountant RDP di Opacus |
delta | Il delta usato dall'esecuzione, il tuo o quello predefinito |
max_grad_norm | Il troncamento per item |
noise_multiplier | Il moltiplicatore di rumore scelto da Opacus |
accountant | rdp |
covers | train split |
epsilon_spent conta ogni epoca addestrata dall'esecuzione. Le epoche successive al checkpoint conservato contano nel totale. La pubblicazione su Hugging Face Hub carica model_card.json insieme al modello, con i percorsi locali sostituiti dai nomi dei file, quindi la voce dp viaggia con i pesi. Anche la model card README.md sull'Hub ha una riga "Differential privacy" con l'epsilon speso rispetto all'obiettivo, il delta e la partizione train che la garanzia copre. La riga omette l'obiettivo o il delta quando l'esecuzione non ha registrato il valore.
Scegliere il budget di privacy e il troncamento
La documentazione di Potato indica da 1 a 10 come intervallo usuale per epsilon e richiede un delta inferiore a 1 / item train. Le FAQ di Opacus danno la stessa regola empirica per delta e raccomandano una piccola costante per epsilon con un delta minuscolo. Il delta predefinito di 1 / (10 × item train) sta sotto il tetto di 1 / item train, quindi la maggior parte degli studi può omettere delta.
Il troncamento, max_grad_norm, bilancia due errori. Il troncamento modifica ogni gradiente più grande della soglia, e le FAQ di Opacus affermano che il troncamento compromette la convergenza. Il rumore è scalato sul troncamento, quindi un troncamento più ampio aggiunge più rumore. Le FAQ aggiungono che una soglia sbagliata danneggia i modelli lineari più di quelli profondi. Parti dal valore predefinito di 1.0 e confronta i punteggi held-out prima di regolare il troncamento.
Opacus dimensiona il rumore per le epochs pianificate, quindi lo stesso epsilon distribuito su meno epoche significa meno rumore in ogni passo. Le FAQ di Opacus osservano che un batch più grande aumenta il tasso di campionamento e con esso il costo in privacy. Le FAQ suggeriscono un tasso di apprendimento più alto e un arresto anticipato per compensare il costo. Confronta il punteggio held-out di un'esecuzione DP con il punteggio di un'esecuzione senza dp sulla stessa partizione. La differenza tra i due punteggi misura che cosa costa la garanzia sui tuoi dati.
Ambito della garanzia
La garanzia copre la partizione train. Cambiare un item train cambia ciò che il modello rilasciato potrebbe essere al massimo dell'epsilon dichiarato. L'item conta insieme all'etichetta risolta a partire dai suoi annotatori. Potato dichiara la garanzia per item, e la documentazione non dichiara alcuna garanzia per annotatore.
La partizione val è fuori dalla garanzia. Dopo ogni epoca, il trainer valuta il modello sugli item val e conserva il checkpoint dell'epoca con il punteggio migliore. Quella scelta legge le etichette degli item val senza rumore aggiunto, quindi l'epsilon sulla model card non promette nulla sugli item val. Quando gli item val richiedono la stessa protezione degli item train, imposta la frazione val a 0 e sposta la frazione su test, per esempio splits: {train: 0.7, val: 0, test: 0.3}. Senza item val, il trainer conserva l'ultima epoca, patience non ferma mai l'esecuzione in anticipo e il punteggio held-out proviene da test. Lasciare invariata la frazione train mantiene gli stessi item in train, perché Potato assegna le partizioni tramite un hash con seed dell'id di ciascun item.
L'elenco delle etichette del modello è fuori dalla garanzia. Potato legge l'elenco delle etichette da quelle che compaiono nei dati, quindi un'etichetta che gli annotatori hanno usato su un solo item compare comunque tra gli output del modello.
Differenze di addestramento sotto DP
DP-SGD richiede un gradiente per ogni item, quindi un'esecuzione DP differisce da un'esecuzione ordinaria dello stesso trainer in questi modi:
- L'addestramento avviene in precisione piena, qualunque cosa dica
precision, perché la precisione mista è disattivata sotto DP. gradient_accumulationdeve essere 1. Ogni passo addestra un batch campionato con Poisson.- Un modello di base quantizzato (
lora.quantize) viene rifiutato. - Le tabelle di embedding di posizione e di tipo di token di un transformer di testo sono congelate, come riporta il log dell'esecuzione.
- Un modello con un livello che Opacus non supporta, come BatchNorm, fallisce all'inizio dell'addestramento con il livello nominato.
Solo hf-text-classification e hf-image-classification accettano dp. Ogni altro trainer rifiuta un parametro che non accetta, quindi dp su sklearn-text, setfit o hf-token-classification fallisce all'avvio sotto trainer_params e con un 409 quando un'esecuzione parte.
Errori all'avvio di un'esecuzione
potato validate segnala una chiave che dp non accetta e un valore fuori intervallo prima che il server parta. Un'esecuzione controlla di nuovo il blocco dp quando parte, insieme a Opacus e ai limiti che dipendono dalla partizione train. Un'esecuzione che non supera quei controlli termina con un errore prima dell'addestramento, con il codice validation_failed e ogni problema in un solo messaggio. I messaggi provengono dai controlli di Potato:
| Problema | Messaggio |
|---|---|
| Opacus non installato | dp needs opacus, which is not installed (pip install opacus). |
Nessun epsilon | dp needs epsilon, the privacy budget for the run (1 to 10 is usual). |
Una chiave che dp non accetta | dp does not take bogus; it takes epsilon, delta and max_grad_norm. |
delta pari o superiore a 1 / item train | dp.delta is 0.05, at least 1 / 76 train items: at that delta one item's data could be released outright. Use less than 0.0131579. |
gradient_accumulation superiore a 1 | dp trains one sampled batch per step; set gradient_accumulation to 1. |
lora.quantize impostato | dp cannot train a quantized (4bit or 8bit) base model; drop lora.quantize. |
Una mappa vuota, dp: {}, chiede DP senza budget e fallisce con il messaggio di epsilon mancante. Quando trainer_params imposta dp, il "dp": null o "dp": false di un'esecuzione disattiva DP per quell'esecuzione. La route di stato, GET /admin/training/api/status, elenca gli stessi messaggi sotto errors.
Ulteriori letture
- Panoramica sull'addestramento di modelli, per la pagina Training e la pubblicazione sull'Hub
- Trainer, per ciò che
hf-text-classificationehf-image-classificationadattano - Configurazione dell'addestramento di modelli, per partizioni, punteggi held-out e write-back
- Addestra il tuo primo modello, per lo stesso progetto senza GPU né DP
- Addestramento remoto, per eseguire il fine-tuning DP su un server GPU
- Differential privacy (
dp) nel riferimento sull'addestramento di modelli di Potato
Riferimenti
- Abadi, M., Chu, A., Goodfellow, I., McMahan, H. B., Mironov, I., Talwar, K., and Zhang, L. (2016). Deep learning with differential privacy. Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security, 308-318. https://doi.org/10.1145/2976749.2978318
- Opacus. FAQ. https://opacus.ai/docs/faq