In [ ]:
epochs = 10
Federated Learning ist eine spannende und aufstrebende Machine Learning Technik, die es Systemen ermöglicht auf dezentralisierten Daten zu lernen. Der Grundgedanke dabei ist die Daten an ihrem ursprünglichen Ort zu belassen und dadurch die Privatsphäre des Besitzers zu stärken. Dafür wird jedoch das Machine Learning Model an alle Daten-Besitzer verteilt. Eine direkte Anwendung dafür ist die Vorhersage des nächsten Wortes beim Tippen auf dem Smartphone: die Trainingsdaten - z. B. die gesendeten Nachrichten - sollen hierbei keinesfalls auf einem zentralen Server gesammelt werden.
Die Verbreitung von Federated Learning ist stark an das Bewusstsein für Daten-Privatsphäre geknüpft. Die DSGVO der EU, welche seit Mai 2018 den Schutz der Daten vorschreibt, kann hierbei als Auslöser angesehen werden. Um einer Regulierung zuvorzukommen, haben große Unternehmen wie Apple oder Google begonnen, stark in diesen Bereich zu investieren und die Privatsphäre der eigenen Nutzer somit zu schützen. Jedoch stellen sie ihre Werkzeuge dafür nicht der Allgemeinheit zur Verfügung.
Bei OpenMined galuben wir daran, dass jeder sein Machine Learning Projekt einfach mit Werkzeugen zum Schutz der Privatsphäre ausstatten können sollte. Aus diesem Grund wurden z. B. Werkzeuge zum Verschlüsseln der Daten in einer einzigen Zeile von uns entworfen und nun veröffentlichen wir unser Federated Learning Gerüst, welches auf PyTorch 1.0 aufbaut, um ein intuitives Interface zum Bauen sicherer und skalierbarer Machine Learning Modele anzubieten.
In diesem Tutorial wird direkt mit dem Beispiel vom Trainieren eines CNN auf MNIST mit PyTorch gearbeitet. Es wird gezeigt wie einfach es ist dies mit der PySyft Bibliothek auf Federated Learning anzupassen. Dabei wird jeder Teil des Beispiels betrachtet und die angepassten Codezeilen hervorgehoben.
Das Material steht auch auf diesem Blogpost bereit.
Autoren:
Übersetzer:
Ok, lassen Sie uns starten!
In [ ]:
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
Darauf folgen die PySyft spezifischen Importe. Auch werden die Helfer alice
und bob
erstellt.
In [ ]:
import syft as sy # <-- NEW: import the Pysyft library
hook = sy.TorchHook(torch) # <-- NEW: hook PyTorch ie add extra functionalities to support Federated Learning
bob = sy.VirtualWorker(hook, id="bob") # <-- NEW: define remote worker bob
alice = sy.VirtualWorker(hook, id="alice") # <-- NEW: and alice
Die Einstellungen für das Lernen werden festgelegt.
In [ ]:
class Arguments():
def __init__(self):
self.batch_size = 64
self.test_batch_size = 1000
self.epochs = epochs
self.lr = 0.01
self.momentum = 0.5
self.no_cuda = False
self.seed = 1
self.log_interval = 30
self.save_model = False
args = Arguments()
use_cuda = not args.no_cuda and torch.cuda.is_available()
torch.manual_seed(args.seed)
device = torch.device("cuda" if use_cuda else "cpu")
kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}
In [ ]:
federated_train_loader = sy.FederatedDataLoader( # <-- this is now a FederatedDataLoader
datasets.MNIST('../data', train=True, download=True,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
]))
.federate((bob, alice)), # <-- NEW: we distribute the dataset across all the workers, it's now a FederatedDataset
batch_size=args.batch_size, shuffle=True, **kwargs)
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=False, transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=args.test_batch_size, shuffle=True, **kwargs)
In [ ]:
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 20, 5, 1)
self.conv2 = nn.Conv2d(20, 50, 5, 1)
self.fc1 = nn.Linear(4*4*50, 500)
self.fc2 = nn.Linear(500, 10)
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, 2, 2)
x = F.relu(self.conv2(x))
x = F.max_pool2d(x, 2, 2)
x = x.view(-1, 4*4*50)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return F.log_softmax(x, dim=1)
Weil die Trainings-Daten auf alice
und bob
aufgeteilt sind, muss in der Trainings-Funktion auch das Model für jeden Trainings-Batch an den richtigen Helfer versendet werden. Dann werden alle Operationen automatisiert aus der Ferne gestartet. Dabei wird dieselbe Syntax verwendet wie beim lokalen Verwenden von PyTorch. Anschließend wird das verbesserte Model zurück geholt und auch das Ergebnis der Loss-Funktion kann betrachtet werden.
In [ ]:
def train(args, model, device, federated_train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(federated_train_loader): # <-- now it is a distributed dataset
model.send(data.location) # <-- NEW: send the model to the right location
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
model.get() # <-- NEW: get the model back
if batch_idx % args.log_interval == 0:
loss = loss.get() # <-- NEW: get the loss back
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * args.batch_size, len(federated_train_loader) * args.batch_size,
100. * batch_idx / len(federated_train_loader), loss.item()))
Die Test-Funktion wird nicht abgeändert!
In [ ]:
def test(args, model, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += F.nll_loss(output, target, reduction='sum').item() # sum up batch loss
pred = output.argmax(1, keepdim=True) # get the index of the max log-probability
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
In [ ]:
%%time
model = Net().to(device)
optimizer = optim.SGD(model.parameters(), lr=args.lr) # TODO momentum is not supported at the moment
for epoch in range(1, args.epochs + 1):
train(args, model, device, federated_train_loader, optimizer, epoch)
test(args, model, device, test_loader)
if (args.save_model):
torch.save(model.state_dict(), "mnist_cnn.pt")
Et voilà! Schon wurde ein Model mit Federated Learning auf fernen Daten trainiert!
Eine wichtige Frage bleibt zu klären: Wie lange dauert Federated Learning verglichen mit normalem PyTorch?
Die reine Rechenzeit dauert etwas weniger als doppelt so lange wie es mit normalem PyTorch dauern würde. Genau gemessen, dauert es 1.9 mal so lange, was im Hinblick auf die hinzugefügten Eigenschaften recht wenig ist.
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.
Wir haben hilfreiche Tutorials erstellt, um ein Verständnis für Federated und Privacy-Preserving Learning zu entwickeln und zu zeigen wie wir die einzelnen Bausteine weiter entwickeln.
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.
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.
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 [ ]: