Parte 12: Entrenar una Red Neuronal Encriptada con Datos Encriptados

En este cuarderno vamos a usar todas las técnicas que aprendimos hasta ahora para entrenar redes neuronales (y hacer predicciones) cuando ambos el modelo y los datos están encriptados.

En particular, presentamos nuestro motor Autograd personalizado, el cual funciona en cálculos encriptados.

Autores:

Traducción

Paso 1: Crear Trabajadores y Datos de juguete


In [ ]:
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import syft as sy

In [ ]:
# Preparar todo
hook = sy.TorchHook(torch) 

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

In [ ]:
# Un conjunto de Datos de juguete
data = torch.tensor([[0,0],[0,1],[1,0],[1,1.]])
target = torch.tensor([[0],[0],[1],[1.]])

# Un Modelo de juguete
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(2, 2)
        self.fc2 = nn.Linear(2, 1)

    def forward(self, x):
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        return x
model = Net()

Paso 2: Encriptar el Modelo y los Datos

La encriptación aquí viene en dos pasos. Dado que la Computación Segura Multiparte sólo funciona en enteros, para poder operar en números con punto decimal (tales como los pesos y activaciones), debemos codificar todos nuestros números usando Precisión Fija, la cual nos dará varios bits de precisión decimal. Hacemos esto llamando a .fix_precision().

Entonces podemos llamar a .share() como lo hicimos para otras demostraciones, lo cual encriptará todos los valores compartiéndolos entre Alice y Bob. Nota que también ponemos requires_grad a True lo cual agrega un método autograd especial para datos encriptados. Ciertamente, dado que la Computación Segura Multiparte no funciona en valores flotantes, no podemos usar el usual autograd en PyTorch. Por lo tanto, necesitamos agregar un nodo AutogradTensor especial que calcule el grafo del gradiente para la retropropagación. Puedes imprimir cualquier parte de este elemento para ver que incluye un AutogradTensor.


In [ ]:
# Codificamos todo
data = data.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True)
target = target.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True)
model = model.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True)

In [ ]:
print(data)

Paso 3: Entrenamiento

Y ahora podemos entrenar usando la lógica tensorial simple


In [ ]:
opt = optim.SGD(params=model.parameters(),lr=0.1).fix_precision()

for iter in range(20):
    # 1) Borrar gradientes previos (si existen) 
    opt.zero_grad()

    # 2) Hacer una predicción
    pred = model(data)

    # 3) Calcular que tanto fallamos (la pérdida)
    loss = ((pred - target)**2).sum()

    # 4) Averiguar que pesos nos hicieron fallar
    loss.backward()

    # 5) Cambiar dichos pesos
    opt.step()

    # 6) Imprimir nuestro progreso
    print(loss.get().float_precision())

La perdida ciertamente disminuyó!

Impacto de la Precisión Fija

Tal vez te estés preguntando como encriptar todo impacta la disminución de la pérdida. De hecho, porque el cálculo teórico es el mismo, los números están muy cerca al entrenamiento no-encriptado. Puedes verificar esto corriendo el mismo ejemplo sin la encripción y con una inicialización determinística del modelo como este en el modelo __init__:

with torch.no_grad():
    self.fc1.weight.set_(torch.tensor([[ 0.0738, -0.2109],[-0.1579,  0.3174]], requires_grad=True))
    self.fc1.bias.set_(torch.tensor([0.,0.1], requires_grad=True))
    self.fc2.weight.set_(torch.tensor([[-0.5368,  0.7050]], requires_grad=True))
    self.fc2.bias.set_(torch.tensor([-0.0343], requires_grad=True))

La ligera diferencia que podrás observar es debido al redondeo de los valores realizado durante la transformación a Precisión Fija. La precision_fractional es 3 y si se reduce a 2 la divergencia con entrenamiento de texto claro aumenta, mientras que si elijes precision_fractional = 4 se reduce.

¡¡Felicidades!! - Hora de Unirte a la Comunidad

¡Felicidades por completar este cuaderno tutorial! Si lo disfrutaste y te gustaría unirte al movimiento hacia la preservación de la privacidad, propiedad decentralizada de Inteligencia Artificial y la Inteligencia Artificial de Cadena de Valores (de Datos), puedes hacerlo de las siguientes maneras:

Dale una Estrella a PySyft en Github

¡La forma más fácil de ayudar a nuestra comunidad es guardando con una estrella los Repos! Esto ayuda a crear consciencia de las geniales herramientas que estamos construyendo.

¡Únete a nuestro Slack!

¡La mejor manera de estar al día con los últimos avances es unirte a nuestra comunidad! Puedes hacerlo llenando la forma en http://slack.openmined.org

¡Únete a un Proyecto de Programación!

¡La mejor manera de contribuir a nuestra comunidad es haciéndote un contribuidor de código! Puedes ir a PySyft Github Issues en cualquier momento y filtrar por "Projects". Esto te mostrará todos los Tickets de alto nivel, dando un resumen de los proyectos a los que puedes unirte. Si no quieres unirte a un proyecto, pero te gustaría programar un poco, puedes buscar mini-proyectos únicos buscando en Github Issues con "good first issue".

Donaciones

Si no tienes tiempo para contribuir a nuestra base de código, pero quieres brindarnos tu apoyo, puedes respaldarnos en nuestro Open Collective. Todas las donaciones van hacia nuestro alojamiento web y otros gastos de la comunidad como hackatones y reuniones.

OpenMined's Open Collective Page


In [ ]: