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
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()
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)
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ó!
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 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:
¡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.
¡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
¡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".
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.
In [ ]: