Parte 2: Introdução ao Federated Learning

Na última seção, nós aprendemos sobre PointerTensors, que criam a infraestrutura necessária que precisamos para proteção de privacidade em Deep Learning. Nessa seção, nós iremos ver como usar essas ferramentas básicas para implementar nosso primeiro algoritmo de proteção de privacidade em Deep Learning: Federated Learning.

Autores:

Tradução:

O que é Federated Learning?

É uma simples, porém poderosa maneira de treinar modelos de Deep Learning. Pense em dados de treinamento, são sempre o resultado de algum processo de coleta. As pessoas (via dispositivos) geram dados ao gravar eventos no mundo real. Normalmente, esses dados são agregados em uma simples localização central em que você pode treinar um modelo de aprendizegam de máquina. O Federated Learning vira isso de ponta a cabeça!

Ao invés de trazer dados de treinamento para o modelo (um servidor central), você trás o modelo para os dados de treinamento (onde quer que ele esteja).

A ideia é que isso permita que quem estiver criando os dados possua a única cópia permanente e, assim, mantenha o controle sobre quem já teve acesso a eles. Muito legal, não acha?

Seção 2.1 - Um exemplo brinquedo de Federated Learning

Vamos começar treinando um modelo de exemplo da maneira centralizada. Isso é tão simples quanto obter o modelo. Primeiro precisamos:

  • um conjunto de dados para brincarmos
  • um modelo
  • alguma lógica básica de treinamento para treinar um modelo que se ajusta aos dados

Obs.: Se para você, a seguinte API ainda não é familar. Visite o fast.ai e faça os seus cursos antes de continuar esse tutorial.


In [ ]:
import torch
from torch import nn
from torch import optim

In [ ]:
# Dataset de exemplo
data = torch.tensor([[0,0],[0,1],[1,0],[1,1.]], requires_grad=True)
target = torch.tensor([[0],[0],[1],[1.]], requires_grad=True)

# Modelo simples de exemplo
model = nn.Linear(2,1)

def train():
    # Lógica de treinamento
    opt = optim.SGD(params=model.parameters(),lr=0.1)
    for iter in range(20):

        # 1) apague os gradientes anteriores (caso eles existam)
        opt.zero_grad()

        # 2) faça uma predição
        pred = model(data)

        # 3) calcule o erro, isto é, o quanto perdemos
        loss = ((pred - target)**2).sum()

        # 4) descubra quais pesos nos causaram essa perda
        loss.backward()

        # 5) altere esses pesos
        opt.step()

        # 6) mostre o progresso até então
        print(loss.data)

In [ ]:
train()

E aí está! Nós treinamos um modelo simples da maneira convencional. Todos os nossos dados estão agregados em nossa máquina local e podemos usá-los para fazer atualizações em nosso modelo. O aprendizado federado, no entanto, não funciona dessa maneira. Então, vamos modificar este exemplo para fazê-lo da maneira federada!

Então, o que precisamos:

  • criar alguns workers, isto é, nós de computação
  • obter apontadores para dados de treinamento de cada worker
  • atualizadar a lógica de treinamento para fazer o aprendizado federado

    Novas etapas de treinamento:

    • enviar modelo para um worker e fazer correções/atualizações
    • treinar com os dados que lá estão localizados
    • pegar o modelo de volta e repetir o processo com o próximo worker

In [ ]:
import syft as sy
hook = sy.TorchHook(torch)

In [ ]:
# cria dois nós (ou duas entidades de computação)

bob = sy.VirtualWorker(hook, id="bob")
alice = sy.VirtualWorker(hook, id="alice")

In [ ]:
# Nosso dataset de exemplo
data = torch.tensor([[0,0],[0,1],[1,0],[1,1.]], requires_grad=True)
target = torch.tensor([[0],[0],[1],[1.]], requires_grad=True)

# obtenha apontadores para os dados de treinamento de cada worker 
# enviando alguns dados de treinamento para bob e alice
data_bob = data[0:2]
target_bob = target[0:2]

data_alice = data[2:]
target_alice = target[2:]

# Inicialize o modelo
model = nn.Linear(2,1)

data_bob = data_bob.send(bob)
data_alice = data_alice.send(alice)
target_bob = target_bob.send(bob)
target_alice = target_alice.send(alice)

# organize os apontadores numa lista
datasets = [(data_bob,target_bob),(data_alice,target_alice)]

opt = optim.SGD(params=model.parameters(),lr=0.1)

In [ ]:
def train():
    # Lógica de treinamento
    opt = optim.SGD(params=model.parameters(),lr=0.1)
    for iter in range(10):
        
        # NOVO) itere através do dataset de cada worker
        for data,target in datasets:
            
            # NOVO) envie o modelo para corrigir/atualizar o worker
            model.send(data.location)

            # 1) apague os gradientes anteriores (caso eles existam)
            opt.zero_grad()

            # 2) faça uma predição
            pred = model(data)

            # 3) calcule o erro, isto é, o quanto perdemos
            loss = ((pred - target)**2).sum()

            # 4) descubra quais pesos nos causaram essa perda
            loss.backward()

            # 5) atualize os pesos
            opt.step()
            
            # NOVO) pegue o modelo (com gradientes)
            model.get()

            # 6) mostre o progresso até então
            print(loss.get()) # NOVO) leve edição... precisa usar o .get() a partir do loss\
    
# média federada

In [ ]:
train()

Pronto!

E voilà! Agora estamos treinando um modelo muito simples de Deep Learning usando o Federated Learning! Enviamos o modelo para cada worker, geramos um novo gradiente e, em seguida, devolvemos o gradiente ao servidor local, onde atualizamos nosso modelo global. Nunca, neste processo, jamais vemos ou solicitamos acesso aos dados subjacentes ao treinamento! Preservamos a privacidade de Bob e Alice!!!

Problemas deste exemplo

Embora este exemplo seja uma boa introdução ao Federated Learning, ele ainda apresenta algumas falhas importantes. A mais notável, é que quando chamamos model.get() e recebemos o modelo atualizado de Bob ou Alice, podemos aprender muito sobre os dados de treinamento de ambos apenas observando seus gradientes. Em alguns casos, podemos restaurar os dados de treinamento de forma completa!

Então o que poderíamos fazer? Bem, a primeira estratégia empregada pelas pessoas é calcular a média do gradiente em vários indivíduos antes de carregá-lo no servidor central. Essa estratégia, no entanto, exigirá um uso mais sofisticado dos objetos PointerTensor. Portanto, na próxima seção, vamos passar um algum tempo aprendendo sobre funcionalidades mais avançada ao utilizar ponteiros e, em seguida, iremos atualizar este exemplo de Federated Learning.

Parabéns!!! - Hora de se juntar a comunidade!

Parabéns por concluir esta etapa do tutorial! Se você gostou e gostaria de se juntar ao movimento em direção à proteção de privacidade, propriedade descentralizada e geração, demanda em cadeia, de dados em IA, você pode fazê-lo das seguintes maneiras!

Dê-nos uma estrela em nosso repo do PySyft no GitHub

A maneira mais fácil de ajudar nossa comunidade é adicionando uma estrela nos nossos repositórios! Isso ajuda a aumentar a conscientização sobre essas ferramentas legais que estamos construindo.

Junte-se ao Slack!

A melhor maneira de manter-se atualizado sobre os últimos avanços é se juntar à nossa comunidade! Você pode fazer isso preenchendo o formulário em http://slack.openmined.org

Contribua com o projeto!

A melhor maneira de contribuir para a nossa comunidade é se tornando um contribuidor do código! A qualquer momento, você pode acessar a página de Issues (problemas) do PySyft no GitHub e filtrar por "Projetos". Isso mostrará todas as etiquetas (tags) na parte superior, com uma visão geral de quais projetos você pode participar! Se você não deseja ingressar em um projeto, mas gostaria de codificar um pouco, também pode procurar mais mini-projetos "independentes" pesquisando problemas no GitHub marcados como "good first issue".

Doar

Se você não tem tempo para contribuir com nossa base de códigos, mas ainda deseja nos apoiar, também pode se tornar um Apoiador em nosso Open Collective. Todas as doações vão para hospedagem na web e outras despesas da comunidade, como hackathons e meetups!

Página do Open Collective do OpenMined


In [ ]: