Affinage avec confidentialité différentielle et Opacus
Affinez un classifieur de texte ou d'images sur les étiquettes de votre étude avec DP-SGD, fixez epsilon et delta, puis lisez la confidentialité dépensée dans le journal de l'exécution et la fiche du modèle.
Nouveauté de la v2.14.0
Ce tutoriel entraîne un classifieur sur les propres étiquettes d'une étude avec une confidentialité différentielle, de sorte que le modèle publié révèle peu de choses sur chaque item annoté. La page s'adresse aux responsables d'étude dont les items ou les étiquettes sont sensibles (par exemple des dossiers de santé ou des messages privés) et qui prévoient de partager ou de publier le modèle. Vous ajouterez un bloc dp aux paramètres de hf-text-classification, lancerez le module sur l'exemple des avis de produits et lirez la confidentialité dépensée dans le journal de l'exécution et la fiche du modèle. Le même bloc fonctionne sur hf-image-classification, et aucun autre module d'entraînement ne prend dp.
Epsilon et delta dans la confidentialité différentielle
La confidentialité différentielle est une garantie mathématique sur un calcul effectué sur un jeu de données. L'ajout ou le retrait d'un enregistrement modifie la probabilité de toute sortie d'une quantité bornée, de sorte que la sortie révèle peu de choses sur la présence de cet enregistrement. Epsilon (ε) est cette borne. Un epsilon plus petit rend plus difficile de distinguer les sorties avec et sans l'enregistrement, et donne donc une confidentialité plus forte. Delta (δ) est la probabilité que la borne d'epsilon échoue, et la documentation de Potato décrit delta comme « the chance the guarantee does not hold », c'est-à-dire la probabilité que la garantie ne tienne pas.
DP-SGD entraîne un réseau de neurones sous cette garantie, selon la méthode d'Abadi et al. (2016). À chaque pas d'entraînement, le gradient de chaque item est écrêté à une norme maximale et un bruit gaussien est ajouté à la somme. L'écrêtage borne de combien un item peut déplacer le modèle, et le bruit masque ce déplacement borné. Opacus est une bibliothèque PyTorch qui implémente DP-SGD, et Potato confie la boucle d'entraînement à Opacus dès qu'une exécution porte dp. Le comptable RDP d'Opacus additionne l'epsilon que dépense chaque pas.
Installer le module d'entraînement et Opacus
Les modules à transformeurs demandent torch et transformers, issus des extras d'entraînement de Potato. Aucun extra de Potato n'inclut Opacus, car Opacus épingle des versions précises de torch. Installez les deux sur la machine où l'exécution s'entraîne :
pip install "potato-annotation[train-text]" # [train-vision] for hf-image-classification
pip install opacusUne exécution avec dp vérifie la présence d'Opacus sur la machine d'entraînement avant le début de l'entraînement. Sur un backend ssh, SLURM ou agent, Opacus se place donc sur le serveur GPU ou le nœud de calcul qui entraîne, et non sur le serveur d'annotation. L'entraînement à distance traite de ces backends.
Configurer le module d'entraînement
La configuration ci-dessous est l'exemple des avis de produits de Entraîner votre premier modèle, avec l'entraînement privé réglé par défaut pour hf-text-classification. Copiez data/reviews.json et data/gold.json depuis le dossier examples/ai-assisted/model-training/ de Potato dans un dossier de projet, et enregistrez cette configuration sous le nom 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 fixe les valeurs par défaut de chaque exécution de hf-text-classification, de sorte que le champ Parameters de la page Training s'ouvre avec l'entrée dp déjà remplie. epsilon: 8 se situe dans la plage de 1 à 10 que la documentation de Potato qualifie d'usuelle. delta est omis, de sorte que Potato fixe delta à 1 / (10 × items train). max_grad_norm: 1.0 reprend l'écrêtage par défaut. epochs et batch_size reprennent les valeurs par défaut du module, car Opacus dimensionne le bruit d'après les deux. require_password: false et la clé d'administration en clair ne conviennent qu'à un essai local.
dp prend trois clés :
| Clé | Valeur par défaut | Signification |
|---|---|---|
epsilon | obligatoire | Le budget de confidentialité de toute l'exécution. Un epsilon plus petit est plus confidentiel et ajoute plus de bruit. |
delta | 1 / (10 × items train) | La probabilité que la garantie ne tienne pas. Delta doit être inférieur à 1 / items train. |
max_grad_norm | 1.0 | Le gradient de chaque item est écrêté à cette norme avant l'ajout du bruit. |
La configuration passe python -m potato.validate_cli config.yaml --strict. Le validateur accepte un mapping, null ou false pour dp et refuse dp: true. Le validateur vérifie aussi chaque clé à l'intérieur de dp et sa plage. Opacus et les vérifications qui dépendent du nombre d'items train s'exécutent au démarrage d'une exécution, sur la machine qui entraîne, comme le liste Erreurs au démarrage d'une exécution.
Étiqueter des items et lancer une exécution
hf-text-classification refuse d'ajuster moins de 20 items train (min_instances). Démarrez le serveur, puis étiquetez les avis à la main ou avec trois annotateurs simulés du simulateur d'utilisateurs, qui répondent à partir du fichier de référence :
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-exportLe simulateur étiquette 120 des 160 avis. Avec les splits par défaut (70 % train, 15 % val, 15 % test) et split_seed: 0, notre exécution a placé 76 avis étiquetés dans train, 19 dans val et 25 dans test. Delta vaut donc par défaut 1 / 760, soit environ 0,00132, et tout delta que vous fixez doit être inférieur à 1 / 76, soit environ 0,0132.
Ouvrez http://localhost:8000/admin/training avec la clé d'administration, choisissez hf-text-classification et le schéma sentiment, vérifiez que le champ Parameters montre l'entrée dp, puis cliquez sur Train now. La même exécution se lance depuis l'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 réponse contient le run_id. Les params propres à une exécution remplacent trainer_params, de sorte que "params": {"dp": {"epsilon": 2}} entraîne une exécution avec un budget plus petit, et "params": {"dp": null} ou "params": {"dp": false} entraîne une exécution sans DP. Gardez split_seed inchangé entre les deux exécutions, afin que les deux s'entraînent et soient évaluées sur les mêmes items et que les scores sur items réservés se comparent directement.
Lignes du journal de l'exécution sous DP
La page de l'exécution à l'adresse /admin/training/runs/<run_id> liste les événements et les métriques de l'exécution. Une exécution DP ajoute trois types de lignes aux événements.
La première ligne nomme les tables d'embeddings que Potato gèle. Les embeddings de position et de type de segment d'un transformeur de texte occupent une ligne partagée par tout le lot, et Opacus ne peut pas calculer un gradient par item à travers une ligne partagée. Pour le modèle par défaut, distilbert/distilroberta-base, les tables gelées sont roberta.embeddings.position_embeddings et roberta.embeddings.token_type_embeddings. Les tables gelées ne s'entraînent pas et ne dépensent aucune confidentialité, et les embeddings de mots et toutes les autres couches s'entraînent toujours.
La deuxième ligne commence par DP-SGD: et indique l'epsilon cible, delta, les époques prévues, le multiplicateur de bruit qu'Opacus a choisi, l'écrêtage par item et le taux d'échantillonnage. Chaque pas tire un lot par échantillonnage de Poisson, de sorte que chaque item train rejoint un lot indépendamment, avec la probabilité 1 / lots par époque. Avec 76 items train en lots de 16, une époque compte 5 lots et le journal donne un taux d'échantillonnage de 0.2000. Le multiplicateur de bruit fixe l'écart type du bruit, et la FAQ d'Opacus donne 0,1 à 2 comme plage usuelle.
Après chaque époque, une ligne de la forme Epoch <n>/<epochs>: loss <loss>, epsilon spent <epsilon> rapporte la perte moyenne de l'époque et l'epsilon dépensé jusque-là. La même valeur est enregistrée par époque sous la métrique dp_epsilon, et les métriques finales de l'exécution portent dp_epsilon pour toute l'exécution. Opacus dimensionne le bruit de sorte que les époques prévues dépensent au plus l'epsilon cible. Une exécution qui s'arrête tôt à cause de patience (deux époques sans meilleur score val, par défaut) dépense moins que la cible.
L'entrée dp de la fiche du modèle
L'exécution écrit model_card.json dans artifacts/ du répertoire de l'exécution, <task_dir>/<output_annotation_dir>/training/runs/<run_id>/. La fiche d'une exécution DP contient une entrée dp :
| Champ | Valeur |
|---|---|
epsilon_target | L'epsilon que vous avez demandé |
epsilon_spent | Ce que l'exécution a dépensé, d'après le comptable RDP d'Opacus |
delta | Le delta qu'a utilisé l'exécution, le vôtre ou celui par défaut |
max_grad_norm | L'écrêtage par item |
noise_multiplier | Le multiplicateur de bruit qu'Opacus a choisi |
accountant | rdp |
covers | train split |
epsilon_spent compte chaque époque que l'exécution a entraînée. Les époques postérieures au point de contrôle conservé comptent dans le total. La publication sur le Hugging Face Hub téléverse model_card.json avec le modèle, les chemins locaux étant remplacés par des noms de fichiers, de sorte que l'entrée dp accompagne les poids. La fiche README.md du Hub comporte aussi une ligne « Differential privacy » avec l'epsilon dépensé face à la cible, delta et la partition train que couvre la garantie. La ligne omet la cible ou delta lorsque l'exécution n'a pas enregistré la valeur.
Choisir le budget de confidentialité et l'écrêtage
La documentation de Potato donne 1 à 10 comme plage usuelle d'epsilon et exige un delta inférieur à 1 / items train. La FAQ d'Opacus donne la même règle empirique pour delta et recommande une petite constante pour epsilon avec un delta minuscule. Le delta par défaut de 1 / (10 × items train) se situe sous le plafond de 1 / items train, de sorte que la plupart des études peuvent omettre delta.
L'écrêtage, max_grad_norm, arbitre entre deux erreurs. L'écrêtage modifie chaque gradient supérieur au seuil, et la FAQ d'Opacus dit que l'écrêtage nuit à la convergence. Le bruit est proportionnel à l'écrêtage, de sorte qu'un écrêtage plus grand ajoute plus de bruit. La FAQ ajoute qu'un mauvais seuil nuit davantage aux modèles linéaires qu'aux modèles profonds. Partez de la valeur par défaut de 1,0 et comparez les scores sur items réservés avant de régler l'écrêtage.
Opacus dimensionne le bruit pour les epochs prévues, de sorte que le même epsilon réparti sur moins d'époques signifie moins de bruit à chaque pas. La FAQ d'Opacus note qu'un lot plus grand augmente le taux d'échantillonnage et, avec lui, le coût de confidentialité. La FAQ suggère un taux d'apprentissage plus élevé et un arrêt plus précoce pour compenser ce coût. Comparez le score sur items réservés d'une exécution DP avec celui d'une exécution sans dp sur la même partition. L'écart entre les deux scores mesure ce que la garantie coûte sur vos données.
Portée de la garantie
La garantie couvre la partition train. Modifier un item train change ce que pourrait être le modèle publié d'au plus l'epsilon indiqué. L'item compte avec l'étiquette résolue à partir des annotateurs de l'item. Potato énonce la garantie par item, et la documentation n'énonce aucune garantie par annotateur.
La partition val est hors de la garantie. Après chaque époque, le module évalue le modèle sur les items val et conserve le point de contrôle de l'époque qui a le meilleur score. Ce choix lit les étiquettes des items val sans bruit ajouté, de sorte que l'epsilon de la fiche du modèle ne promet rien sur les items val. Lorsque les items val demandent la même protection que les items train, fixez la fraction val à 0 et reportez la fraction sur test, par exemple splits: {train: 0.7, val: 0, test: 0.3}. Sans items val, le module conserve la dernière époque, patience n'arrête jamais l'exécution plus tôt et le score sur items réservés vient de test. Laisser la fraction train inchangée conserve les mêmes items dans train, car Potato attribue les partitions par un hachage à graine fixe de l'identifiant de chaque item.
La liste des étiquettes du modèle est hors de la garantie. Potato lit la liste des étiquettes à partir des étiquettes qui apparaissent dans les données, de sorte qu'une étiquette que les annotateurs ont utilisée sur un seul item apparaît tout de même parmi les sorties du modèle.
Différences d'entraînement sous DP
DP-SGD demande un gradient pour chaque item, de sorte qu'une exécution DP diffère d'une exécution ordinaire du même module sur les points suivants :
- L'entraînement se fait en pleine précision, quelle que soit la valeur de
precision, car la précision mixte est désactivée sous DP. gradient_accumulationdoit valoir 1. Chaque pas entraîne un lot échantillonné par Poisson.- Un modèle de base quantifié (
lora.quantize) est refusé. - Les tables d'embeddings de position et de type de segment d'un transformeur de texte sont gelées, comme le rapporte le journal de l'exécution.
- Un modèle doté d'une couche qu'Opacus ne prend pas en charge, comme BatchNorm, échoue au début de l'entraînement avec la couche nommée.
Seuls hf-text-classification et hf-image-classification prennent dp. Tout autre module refuse un paramètre qu'il ne prend pas, de sorte que dp sur sklearn-text, setfit ou hf-token-classification échoue au démarrage sous trainer_params et avec un 409 au lancement d'une exécution.
Erreurs au démarrage d'une exécution
potato validate signale une clé que dp ne prend pas et une valeur hors plage avant le démarrage du serveur. Une exécution revérifie le bloc dp à son démarrage, avec Opacus et les limites qui dépendent de la partition train. Une exécution qui échoue à ces vérifications se termine par une erreur avant l'entraînement, avec le code validation_failed et tous les problèmes dans un seul message. Les messages viennent des vérifications de Potato :
| Problème | Message |
|---|---|
| Opacus non installé | dp needs opacus, which is not installed (pip install opacus). |
Pas d'epsilon | dp needs epsilon, the privacy budget for the run (1 to 10 is usual). |
Une clé que dp ne prend pas | dp does not take bogus; it takes epsilon, delta and max_grad_norm. |
delta supérieur ou égal à 1 / items 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 supérieur à 1 | dp trains one sampled batch per step; set gradient_accumulation to 1. |
lora.quantize défini | dp cannot train a quantized (4bit or 8bit) base model; drop lora.quantize. |
Un mapping vide, dp: {}, demande du DP sans budget et échoue avec le message d'epsilon manquant. Lorsque trainer_params définit dp, un "dp": null ou "dp": false dans une exécution désactive le DP pour cette exécution. La route d'état, GET /admin/training/api/status, liste les mêmes messages sous errors.
Pour aller plus loin
- Vue d'ensemble de l'entraînement de modèles, pour la page Training et la publication sur le Hub
- Modules d'entraînement, pour ce qu'ajustent
hf-text-classificationethf-image-classification - Configuration de l'entraînement de modèles, pour les partitions, les scores sur items réservés et l'écriture en retour
- Entraîner votre premier modèle, pour le même projet sans GPU ni DP
- Entraînement à distance, pour exécuter l'affinage DP sur un serveur GPU
- Confidentialité différentielle (
dp) dans la référence d'entraînement de modèles de Potato
Références
- 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