Apprentissage profond. Apprentissage fédéré

image Salut, habrozhiteli! Nous avons récemment remis le livre à Andrew W. Trask, jetant les bases d'une maîtrise accrue des technologies d'apprentissage en profondeur. Il commence par une description des bases des réseaux de neurones, puis examine en détail les couches et architectures supplémentaires.

Nous vous proposons une revue du passage "Federated Learning"

L'idée de l'apprentissage fédéré est née du fait que de nombreuses données contenant des informations utiles pour résoudre les problèmes (par exemple, pour le diagnostic du cancer par IRM) sont difficiles à obtenir en quantité suffisante pour enseigner un puissant modèle d'apprentissage en profondeur. En plus des informations utiles nécessaires à la formation du modèle, les ensembles de données contiennent également d'autres informations qui ne sont pas pertinentes pour la tâche à accomplir, mais leur divulgation à quelqu'un pourrait potentiellement être nuisible.

L'apprentissage fédéré est une technique pour enfermer un modèle dans un environnement sécurisé et l'enseigner sans déplacer les données n'importe où. Prenons un exemple.

import numpy as np from collections import Counter import random import sys import codecsnp.random.seed(12345) with codecs.open('spam.txt',"r",encoding='utf-8',errors='ignore') as f: ←     http://www2.aueb.gr/users/ion/data/enron-spam/ raw = f.readlines() vocab, spam, ham = (set(["<unk>"]), list(), list()) for row in raw: spam.append(set(row[:-2].split(" "))) for word in spam[-1]: vocab.add(word) with codecs.open('ham.txt',"r",encoding='utf-8',errors='ignore') as f: raw = f.readlines() for row in raw: ham.append(set(row[:-2].split(" "))) for word in ham[-1]: vocab.add(word) vocab, w2i = (list(vocab), {}) for i,w in enumerate(vocab): w2i[w] = i def to_indices(input, l=500): indices = list() for line in input: if(len(line) < l): line = list(line) + ["<unk>"] * (l - len(line)) idxs = list() for word in line: idxs.append(w2i[word]) indices.append(idxs) return indices 

Apprendre à détecter le spam.


Disons que nous devons former un modèle pour détecter le spam des e-mails des gens

Dans ce cas, nous parlons de la classification des e-mails. Nous formerons notre premier modèle sur un ensemble de données public appelé Enron. Il s'agit d'un énorme corpus d'e-mails publiés lors des audiences d'Enron (désormais un organe d'analyse standard des e-mails). Un fait intéressant: je connaissais des gens qui, par la nature de leurs activités, devaient lire / commenter cet ensemble de données, et ils notent que les gens se sont envoyés dans ces lettres une variété d'informations (souvent très personnelles). Mais comme ce corps a été rendu public lors du procès, il peut désormais être utilisé sans restriction.

Le code de la section précédente et de cette section implémente uniquement les opérations préparatoires. Les fichiers d'entrée (ham.txt et spam.txt) sont disponibles sur la page Web du livre: www.manning.com/books/grokking-deep-learning et dans le référentiel GitHub: github.com/iamtrask/Grokking-Deep-Learning . Nous devons le pré-traiter afin de le préparer pour le transfert vers la classe Embedding du chapitre 13, où nous avons créé notre cadre d'apprentissage en profondeur. Comme précédemment, tous les mots de ce corpus sont convertis en listes d'index. De plus, nous apportons toutes les lettres à la même longueur de 500 mots, soit en les réduisant, soit en ajoutant des jetons. Grâce à cela, nous obtenons un ensemble de données rectangulaire.

 spam_idx = to_indices(spam) ham_idx = to_indices(ham) train_spam_idx = spam_idx[0:-1000] train_ham_idx = ham_idx[0:-1000] test_spam_idx = spam_idx[-1000:] test_ham_idx = ham_idx[-1000:] train_data = list() train_target = list() test_data = list() test_target = list() for i in range(max(len(train_spam_idx),len(train_ham_idx))): train_data.append(train_spam_idx[i%len(train_spam_idx)]) train_target.append([1]) train_data.append(train_ham_idx[i%len(train_ham_idx)]) train_target.append([0]) for i in range(max(len(test_spam_idx),len(test_ham_idx))): test_data.append(test_spam_idx[i%len(test_spam_idx)]) test_target.append([1]) test_data.append(test_ham_idx[i%len(test_ham_idx)]) test_target.append([0]) def train(model, input_data, target_data, batch_size=500, iterations=5): n_batches = int(len(input_data) / batch_size) for iter in range(iterations): iter_loss = 0 for b_i in range(n_batches): #         model.weight.data[w2i['<unk>']] *= 0 input = Tensor(input_data[b_i*bs:(b_i+1)*bs], autograd=True) target = Tensor(target_data[b_i*bs:(b_i+1)*bs], autograd=True) pred = model.forward(input).sum(1).sigmoid() loss = criterion.forward(pred,target) loss.backward() optim.step() iter_loss += loss.data[0] / bs sys.stdout.write("\r\tLoss:" + str(iter_loss / (b_i+1))) print() return model def test(model, test_input, test_output): model.weight.data[w2i['<unk>']] *= 0 input = Tensor(test_input, autograd=True) target = Tensor(test_output, autograd=True) pred = model.forward(input).sum(1).sigmoid() return ((pred.data > 0.5) == target.data).mean() 

Après avoir défini les fonctions auxiliaires train () et test (), nous pouvons initialiser le réseau neuronal et le former en écrivant quelques lignes de code. Après trois itérations, le réseau est capable de classer l'ensemble de données de contrôle avec une précision de 99,45% (l'ensemble de données de contrôle est bien équilibré, donc ce résultat peut être considéré comme excellent):

 model = Embedding(vocab_size=len(vocab), dim=1) model.weight.data *= 0 criterion = MSELoss() optim = SGD(parameters=model.get_parameters(), alpha=0.01) for i in range(3): model = train(model, train_data, train_target, iterations=1) print("% Correct on Test Set: " + \ str(test(model, test_data, test_target)*100)) ______________________________________________________________________________ Loss:0.037140416860871446 % Correct on Test Set: 98.65 Loss:0.011258669226059114 % Correct on Test Set: 99.15 Loss:0.008068268387986223 % Correct on Test Set: 99.45 

Rendons le modèle fédéral


Ci-dessus, l'apprentissage en profondeur le plus courant a été effectué. Maintenant, ajoutez de la confidentialité

Dans la section précédente, nous avons implémenté un exemple d'analyse d'e-mails. Maintenant, mettez tous les e-mails en un seul endroit. Il s'agit d'une bonne vieille méthode de travail (qui est encore largement utilisée dans le monde). Pour commencer, nous imiterons l'environnement de l'enseignement fédéral, dans lequel il existe plusieurs collections de lettres différentes:

 bob = (train_data[0:1000], train_target[0:1000]) alice = (train_data[1000:2000], train_target[1000:2000]) sue = (train_data[2000:], train_target[2000:]) 

Rien de compliqué pour l'instant. Nous pouvons maintenant effectuer la même procédure de formation qu'auparavant, mais déjà sur trois ensembles de données distincts. Après chaque itération, nous allons faire la moyenne des valeurs dans les modèles de Bob, Alice et Sue et évaluer les résultats. Veuillez noter que certaines méthodes d'apprentissage fédérées impliquent la combinaison après chaque package (ou collection de packages); J'ai décidé de garder le code aussi simple que possible:

 for i in range(3): print("Starting Training Round...") print("\tStep 1: send the model to Bob") bob_model = train(copy.deepcopy(model), bob[0], bob[1], iterations=1) print("\n\tStep 2: send the model to Alice") alice_model = train(copy.deepcopy(model), alice[0], alice[1], iterations=1) print("\n\tStep 3: Send the model to Sue") sue_model = train(copy.deepcopy(model), sue[0], sue[1], iterations=1) print("\n\tAverage Everyone's New Models") model.weight.data = (bob_model.weight.data + \ alice_model.weight.data + \ sue_model.weight.data)/3 print("\t% Correct on Test Set: " + \ str(test(model, test_data, test_target)*100)) print("\nRepeat!!\n") 


Ci-dessous un extrait avec les résultats. Ce modèle a atteint presque le même niveau de précision que le précédent, et théoriquement nous n'avions pas accès aux données d'entraînement - ou pas? Quoi qu'il en soit, mais chaque personne change le modèle dans le processus d'apprentissage, non? Ne pouvons-nous pas vraiment tirer quelque chose de leurs ensembles de données?

 Starting Training Round... Step 1: send the model to Bob Loss:0.21908166249699718 ...... Step 3: Send the model to Sue Loss:0.015368461608470256 Average Everyone's New Models % Correct on Test Set: 98.8 

Pirater un modèle fédéré


Regardons un exemple simple de comment extraire des informations d'un ensemble de données de formation.

L'apprentissage fédéré souffre de deux gros problèmes, particulièrement difficiles à résoudre, lorsque chaque personne ne dispose que de quelques exemples de formation: rapidité et confidentialité. Il s'avère que si quelqu'un n'a que quelques exemples de formation (ou si le modèle qui vous a été envoyé a été formé avec seulement quelques exemples: un module de formation), vous pouvez toujours en apprendre beaucoup sur les données source. Si vous imaginez que vous avez 10000 personnes (et que tout le monde a une très petite quantité de données), vous passerez la plupart du temps à envoyer le modèle d'avant en arrière et pas tellement de formation (surtout si le modèle est très grand).

Mais n'allons pas de l'avant. Voyons ce que vous pouvez découvrir après que l'utilisateur a mis à jour les poids sur un package:

 import copy bobs_email = ["my", "computer", "password", "is", "pizza"] bob_input = np.array([[w2i[x] for x in bobs_email]]) bob_target = np.array([[0]]) model = Embedding(vocab_size=len(vocab), dim=1) model.weight.data *= 0 bobs_model = train(copy.deepcopy(model), bob_input, bob_target, iterations=1, batch_size=1) 

Bob crée et forme le modèle par e-mail dans sa boîte de réception. Mais il se trouve qu'il a enregistré son mot de passe en s'envoyant une lettre avec le texte: "Le mot de passe de mon ordinateur est pizza." Naive Bob! Après avoir vu quels poids ont changé, nous pouvons comprendre le dictionnaire (et comprendre le sens) de la lettre de Bob:

 for i, v in enumerate(bobs_model.weight.data - model.weight.data): if(v != 0): print(vocab[i]) 

D'une manière si simple, nous avons découvert le mot de passe top secret de Bob (et peut-être ses préférences culinaires). Et que faire? Comment faire confiance à l'apprentissage fédéré s'il est si facile de savoir quelles données de formation ont provoqué le changement de poids?

 is pizza computer password my 

»Plus d'informations sur le livre sont disponibles sur le site Web de l'éditeur
» Contenu
» Extrait

30% de réduction pour les livres de précommande Habrozhiteli sur un coupon - Grokking Deep Learning

Source: https://habr.com/ru/post/fr458800/


All Articles