Teil 4: Federated Learning mit mitteln der Modele

Rückblick: In Teil 2 dieses Tutorials wurde ein Model mit sehr simplem Federated Learning traininert. Es war dabei notwendig, dass jeder Daten-Besitzer dem Model-Besitzer seine persönlichen Gradienten anvertraute.

Beschreibung: In diesem Tutorial werden die fortgeschrittenen Werkzeuge aus Teil 3 genutzt, um mit ihnen die Gradienten bei einem vertrauenswürdigen "sicheren Helfer" zu sammeln, bevor das finale Model zum Model-Besitzer zurück gesendet wird.

Auf diese Weise kann nur der sichere Helfer sehen, wer welche Gradienten geschickt hat. Der Model-Besitzer kann anschließend nur erkennen wie sich das Model verändert hat, dies jedoch NICHT auf einen der Helfer (Alice oder Bob) zurückführen. Dies sorgt für grundlegende Privatsphäre.

Autoren:

Übersetzer:


In [ ]:
import torch
import syft as sy
import copy
hook = sy.TorchHook(torch)
from torch import nn, optim

Schritt 1: Erstellen der Daten Besitzer

Zuerst werden zwei Daten-Besitzer (Bob und Alice) erstellt, welche jeweils einen kleinen Anteil der Daten erhalten. Außerden wird eine sichere Maschine (secure_worker) eingesetzt. In der Praxis kann dies sichere Hardware (wie Intels SGX) oder ein vertrauenswürdiger Vermittler sein.


In [ ]:
# create a couple workers
bob = sy.VirtualWorker(hook, id="bob")
alice = sy.VirtualWorker(hook, id="alice")
secure_worker = sy.VirtualWorker(hook, id="secure_worker")


# A Toy Dataset
data = torch.tensor([[0,0],[0,1],[1,0],[1,1.]], requires_grad=True)
target = torch.tensor([[0],[0],[1],[1.]], requires_grad=True)

# get pointers to training data on each worker by
# sending some training data to bob and alice
bobs_data = data[0:2].send(bob)
bobs_target = target[0:2].send(bob)

alices_data = data[2:].send(alice)
alices_target = target[2:].send(alice)

Schritt 2: Erstellen des Models

In diesem Beispiel wird ein simples lineares Model trainiert. Es kann normal mit PyTorchs nn.Linear initialisiert werden.


In [ ]:
# Iniitalize A Toy Model
model = nn.Linear(2,1)

Schritt 3: Senden eine Kopie des Models zu Alice und Bob

Als nächstes muss eine Kopie des aktuellen Models an Alice und Bob gesendet werden. Somit können beide für sich das Model auf ihre eigenen Daten anpassen.


In [ ]:
bobs_model = model.copy().send(bob)
alices_model = model.copy().send(alice)

bobs_opt = optim.SGD(params=bobs_model.parameters(),lr=0.1)
alices_opt = optim.SGD(params=alices_model.parameters(),lr=0.1)

Schritt 4: Trainieren von Bobs und Alices Modelen (parallel)

Beim Federated Learning mit Secure Averaging ist es üblich, dass jeder Daten-Besitzer sein Model erst für mehrere Iterationen auf eigenen Daten trainiert, bevor die Gewichte der einzelnen Modele gemittelt werden.


In [ ]:
for i in range(10):

    # Train Bob's Model
    bobs_opt.zero_grad()
    bobs_pred = bobs_model(bobs_data)
    bobs_loss = ((bobs_pred - bobs_target)**2).sum()
    bobs_loss.backward()

    bobs_opt.step()
    bobs_loss = bobs_loss.get().data

    # Train Alice's Model
    alices_opt.zero_grad()
    alices_pred = alices_model(alices_data)
    alices_loss = ((alices_pred - alices_target)**2).sum()
    alices_loss.backward()

    alices_opt.step()
    alices_loss = alices_loss.get().data
    
    print("Bob:" + str(bobs_loss) + " Alice:" + str(alices_loss))

Schritt 5: Senden beider trainierten Modele zum sicheren Helfer

Da nun alle Daten-Besitzer ein eigenes teiltrainiertes Model besitzen, ist es an der Zeit diese auf eine sichere Weise zusammenzuführen. Dies wird erreicht, indem Alice und Bob ihre Modele zum (vertrauenswürdigen) sicheren Server senden.

Es ist anzumerken, dass mit dieser API jedes der Modele DIREKT zum secure_worker gesendet wird und der Model-Besitzer die einzelnen Modele nie zu Gesicht bekommt.


In [ ]:
alices_model.move(secure_worker)

In [ ]:
bobs_model.move(secure_worker)

Schritt 6: Mitteln der Modele

Der letzte Schritt dieser Trainings-Epoche ist die trainierten Modele von Bob und Alice zu mitteln und die so erhaltenen Gewichte für das globale Model zu verwenden.


In [ ]:
with torch.no_grad():
    model.weight.set_(((alices_model.weight.data + bobs_model.weight.data) / 2).get())
    model.bias.set_(((alices_model.bias.data + bobs_model.bias.data) / 2).get())

Endlos wiederholen

Nun muss dies nur noch mehrere Male wiederholt werden!


In [ ]:
iterations = 10
worker_iters = 5

for a_iter in range(iterations):
    
    bobs_model = model.copy().send(bob)
    alices_model = model.copy().send(alice)

    bobs_opt = optim.SGD(params=bobs_model.parameters(),lr=0.1)
    alices_opt = optim.SGD(params=alices_model.parameters(),lr=0.1)

    for wi in range(worker_iters):

        # Train Bob's Model
        bobs_opt.zero_grad()
        bobs_pred = bobs_model(bobs_data)
        bobs_loss = ((bobs_pred - bobs_target)**2).sum()
        bobs_loss.backward()

        bobs_opt.step()
        bobs_loss = bobs_loss.get().data

        # Train Alice's Model
        alices_opt.zero_grad()
        alices_pred = alices_model(alices_data)
        alices_loss = ((alices_pred - alices_target)**2).sum()
        alices_loss.backward()

        alices_opt.step()
        alices_loss = alices_loss.get().data
    
    alices_model.move(secure_worker)
    bobs_model.move(secure_worker)
    with torch.no_grad():
        model.weight.set_(((alices_model.weight.data + bobs_model.weight.data) / 2).get())
        model.bias.set_(((alices_model.bias.data + bobs_model.bias.data) / 2).get())
    
    print("Bob:" + str(bobs_loss) + " Alice:" + str(alices_loss))

Zu guter Letzt muss noch sicher gestellt werden, dass das finale Model korrekt gelernt hat. Deshalb wird es auf einem Test-Datensatz evaluiert. In diesem Fall wird dafür der Original-Datensatz verwendet. In der Praxis sollte jedoch ein neuer Datensatz genutzt werden, um zu prüfen wie gut sich das Model auf Ungesehenes generalisieren lässt.


In [ ]:
preds = model(data)
loss = ((preds - target) ** 2).sum()

In [ ]:
print(preds)
print(target)
print(loss.data)

In diesem kleinen Beispiel weist das gemittelte Model eine zu kleine Anpassung, verglichen mit dem lokal auf Rohdaten trainierten Model, auf. Jedoch konnte das Model trainiert werden ohne dabei die Daten des Einzelnen preiszugeben.
Auch war es möglich die Model-Updates von den einzelnen Helfern auf einem vertrauenswürdigen Helfer zu sammeln und somit den Verlust der Privatsphäre an den Model-Besitzer zu verhinden.

In einem noch kommenden Tutorial wird es darum gehen mit dem vertrauenswürdigen Mitteln die Gradienten selbst zu nutzen und dann mit diesen besseren Gradienten zu einem stabileren Model zu gelangen.

Herzlichen Glückwunsch!!! - Zeit, der Community beizutreten!

Herzlichen Glückwunsch zum Abschluss dieses Notebook-Tutorials! Wenn es Ihnen gefallen hat und Sie sich der Bewegung zur Wahrung der Privatsphäre, zum dezentralisiertenen Besitz von KI und der KI-Lieferkette (Daten) anschließen möchten, können Sie dies auf folgende Weise tun!

PySyft auf GitHub einen Stern geben!

Der einfachste Weg, unserer Community zu helfen, besteht darin, die GitHub-Repos mit Sternen auszuzeichnen! Dies hilft, das Bewusstsein für die coolen Tools zu schärfen, die wir bauen.

Mach mit bei Slack!

Der beste Weg, um über die neuesten Entwicklungen auf dem Laufenden zu bleiben, ist, sich unserer Community anzuschließen! Sie können dies tun, indem Sie das Formular unter http://slack.openmined.org ausfüllen.

Treten Sie einem Code-Projekt bei!

Der beste Weg, um zu unserer Community beizutragen, besteht darin, Entwickler zu werden! Sie können jederzeit zur PySyft GitHub Issues-Seite gehen und nach "Projects" filtern. Dies zeigt Ihnen alle Top-Level-Tickets und gibt einen Überblick darüber, an welchen Projekten Sie teilnehmen können! Wenn Sie nicht an einem Projekt teilnehmen möchten, aber ein wenig programmieren möchten, können Sie auch nach weiteren "einmaligen" Miniprojekten suchen, indem Sie nach GitHub-Problemen suchen, die als "good first issue" gekennzeichnet sind.

Spenden

Wenn Sie keine Zeit haben, zu unserer Codebase beizutragen, aber dennoch Unterstützung leisten möchten, können Sie auch Unterstützer unseres Open Collective werden. Alle Spenden fließen in unser Webhosting und andere Community-Ausgaben wie Hackathons und Meetups!


In [ ]: