From 53157705a7629bd1f8d0ea2ac0ff159d33bf5204 Mon Sep 17 00:00:00 2001 From: Arturo Date: Fri, 7 Feb 2020 18:04:04 -0600 Subject: [PATCH 1/2] feat: Translation to Spanish of Parts 09, 13 (a, b and c). Credits to: @thefirebanks This comes as a response to the initiative to translate all the PySyft tutorials, as it is desirable to learn PySyft in our native language. As requested, every part of the tutorial is done via pull request separately to: - Track better the changes in every document. - Avoid double work. Resolves: #2775 See also: #2782 --- ...- Intro a los Programas Encriptados.ipynb" | 621 ++++++++++++++++++ ... y TFE - Aprendizaje P\303\272blico.ipynb" | 179 +++++ ...Predicciones desde un Modelo Seguro.ipynb" | 257 ++++++++ ... TFE - Prediccion Privada (Cliente).ipynb" | 194 ++++++ 4 files changed, 1251 insertions(+) create mode 100644 "examples/tutorials/translations/espa\303\261ol/Parte 09 - Intro a los Programas Encriptados.ipynb" create mode 100644 "examples/tutorials/translations/espa\303\261ol/Parte 13a - Clasificaci\303\263n Segura con Syft Keras y TFE - Aprendizaje P\303\272blico.ipynb" create mode 100644 "examples/tutorials/translations/espa\303\261ol/Parte 13b - Clasificaci\303\263n Segura con Syft Keras y TFE - Proveer Predicciones desde un Modelo Seguro.ipynb" create mode 100644 "examples/tutorials/translations/espa\303\261ol/Parte 13c - Clasificaci\303\263n Segura con Syft Keras y TFE - Prediccion Privada (Cliente).ipynb" diff --git "a/examples/tutorials/translations/espa\303\261ol/Parte 09 - Intro a los Programas Encriptados.ipynb" "b/examples/tutorials/translations/espa\303\261ol/Parte 09 - Intro a los Programas Encriptados.ipynb" new file mode 100644 index 00000000000..90721d9de8e --- /dev/null +++ "b/examples/tutorials/translations/espa\303\261ol/Parte 09 - Intro a los Programas Encriptados.ipynb" @@ -0,0 +1,621 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Parte 9 - Intro a Programas Encriptados\n", + "\n", + "Lo crean o no, es posible hacer cálculos con datos encriptados. En otras palabras, es posible ejecutar un programa donde **TODAS las variables** están **encriptadas**!\n", + "\n", + "En este tutorial, vamos a ir paso a paso por las herramientas más básicas de la computación encriptada. Específicamente, veremos un enfoque popular llamado Computación Segura Multi-Parte (Secure Multi-Party Computation). En esta lección, aprenderemos cómo construir una calculadora encriptada que puede hacer operaciones en números encriptados. \n", + "\n", + "Autores:\n", + "- Andrew Trask - Twitter: [@iamtrask](https://twitter.com/iamtrask)\n", + "- Théo Ryffel - GitHub: [@LaRiffle](https://github.com/LaRiffle)\n", + "\n", + "Referencias: \n", + "- Morten Dahl - [Blog](https://mortendahl.github.io) - Twitter: [@mortendahlcs](https://twitter.com/mortendahlcs)\n", + "\n", + "Traductores:\n", + "- Daniel Firebanks-Quevedo - GitHub: [@thefirebanks](https://www.github.com/thefirebanks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Paso 1: Encripción Usando Computación Segura Multi-Parte (CSMP)\n", + "\n", + "A primera vista, CSMP es una manera extraña de \"encripción\". En vez de usar una clave pública/privada para encriptar una variable, cada valor es dividido en múltiples `acciones`, cada una funcionando como una clave privada. Típicamente, éstas `acciones` serán distribuidas entre 2 o más dueños. Por lo tanto, para descifrar la variable, todos los dueños deben de estar de acuerdo en permitir el desciframiento. En esencia, cada persona tiene una clave privada. \n", + "\n", + "### Encrypt()\n", + "\n", + "Digamos que queremos \"encriptar\" una variable `x`, podríamos hacerlo de la siguiente manera.\n", + "\n", + " > La encripción no usa decimales o números reales, sino que ocurre en un espacio matemático llamado [anillo cociente](https://es.wikipedia.org/wiki/Anillo_cociente), el cual abarca los números enteros entre `0` y `Q-1`, donde `Q` es un número primo y \"suficientemente grande\" para que el espacio pueda contener todos los números que usamos en nuestros experimentos. En la práctica, dado un número entero `x`, nosotros hacemos `x % Q` para encajar en el anillo. (Esa es la razón por la que evitamos usar un número `x' > Q`)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Q = 1234567891011" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 25" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "def encrypt(x):\n", + " share_a = random.randint(-Q,Q)\n", + " share_b = random.randint(-Q,Q)\n", + " share_c = (x - share_a - share_b) % Q\n", + " return (share_a, share_b, share_c)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "encrypt(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Como pueden ver aquí, hemos dividido nuestra variable `x` en 3 diferentes acciones, las cuales pueden ser enviadas a 3 dueños diferentes.\n", + "\n", + "### Decrypt()\n", + "\n", + "Si quisiéramos descifrar estas 3 acciones, podríamos simplemente sumarlas y tomar el módulo del resultado (mod Q)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def decrypt(*shares):\n", + " return sum(shares) % Q" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a,b,c = encrypt(25)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "decrypt(a, b, c)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nótese que si tratamos de descifrar el valor de `x` con solo dos acciones, el descifrado no funciona!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "decrypt(a, b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Por lo tanto, necesitamos a todos los dueños para poder hacer el descifrado. De esta manera, las `acciones` sirven como claves privadas, las cuales tienen que estar presente para descifrar un valor." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Paso 2: Aritmética Básica Utilizando CSMP\n", + "\n", + "Sin embargo, la propiedad de la Computación Segura Multi-Parte que es realmente extraordinaria es la habilidad para hacer computaciones **mientras las variables están encriptadas**. Vamos a demostrar una simple adición." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = encrypt(25)\n", + "y = encrypt(5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def add(x, y):\n", + " z = list()\n", + " # el primer trabajador suma sus acciones\n", + " z.append((x[0] + y[0]) % Q)\n", + " \n", + " # el segundo trabajador suma sus acciones\n", + " z.append((x[1] + y[1]) % Q)\n", + " \n", + " # el tercer trabajador suma sus acciones\n", + " z.append((x[2] + y[2]) % Q)\n", + " \n", + " return z" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "decrypt(*add(x,y))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Éxito!!!\n", + "\n", + "Y aquí lo tienen! Si cada trabajador (de manera separada) suma sus acciones, las acciones resultantes van a descifrar el valor correcto (25 + 5 == 30).\n", + "\n", + "Resulta que existen protocolos de CSMP que permiten esta computación encriptada para las siguientes operaciones:\n", + "- adición (que acabamos de ver)\n", + "- multiplicación\n", + "- comparación\n", + "\n", + "y utilizando estas operaciones primitivas, podemos hacer computaciones arbitrarias!!\n", + "\n", + "En la siguiente sección, vamos a aprender a cómo usar la librería PySyft para hacer tales operaciones!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Paso 3: CSMP Usando PySyft\n", + "\n", + "En las secciones anteriores, describimos la intuición básica sobre como la CSMP debe de funcionar. Sin embargo, en la práctica no queremos escribir todas las operaciones primitivas nosotros cuando escribimos nuestros programas encriptados. En esta sección vamos a aprender lo básico sobre de la computación encriptada usando PySyft. Específicamente, nos vamos a enfocar en cómo ejecutar los 3 primitivos antes mencionados: adición, multiplicación y comparación.\n", + "\n", + "Primero, necesitamos crear unos cuantos Trabajadores Virtuales (con los cuales esperemos que estén ya familiarizados dados nuestros tutoriales previos)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "import syft as sy\n", + "hook = sy.TorchHook(torch)\n", + "\n", + "bob = sy.VirtualWorker(hook, id=\"bob\")\n", + "alice = sy.VirtualWorker(hook, id=\"alice\")\n", + "bill = sy.VirtualWorker(hook, id=\"bill\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Encripción/Descifrado Básico\n", + "\n", + "La encripción es tan simple como tomar cualquier tensor de PySyft y llamar .share(). El descifrado es tan simple como llamar .get() en la variable compartida." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = torch.tensor([25])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "encrypted_x = x.share(bob, alice, bill)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "encrypted_x.get()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Introspección de los Valores Encriptados\n", + "\n", + "Si vemos de cerca a los trabajadores de Bob, Alice y Bill podemos ver las acciones que se crean!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bob._objects" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = torch.tensor([25]).share(bob, alice, bill)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Las acciones de Bob\n", + "bobs_share = list(bob._objects.values())[0]\n", + "bobs_share" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Las acciones de Alice\n", + "alices_share = list(alice._objects.values())[0]\n", + "alices_share" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Las acciones de Bill\n", + "bills_share = list(bill._objects.values())[0]\n", + "bills_share" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Y si quisiéramos, podríamos descifrar estos valores utilizando EL MISMO enfoque del que hablamos antes!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Q = x.child.field\n", + "\n", + "(bobs_share + alices_share + bills_share) % Q" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Como pueden ver, cuando llamamos `.share()`, simplemente partió el valor en 3 acciones y envió una acción a cada una de las partes!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Aritmética Encriptada\n", + "\n", + "Ahora pueden ver que podemos hacer aritmética con los valores! La API está construida de tal manera que podemos hacer aritmética como haríamos con los tensores de Pytorch." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = torch.tensor([25]).share(bob,alice)\n", + "y = torch.tensor([5]).share(bob,alice)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "z = x + y\n", + "z.get()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "z = x - y\n", + "z.get()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Multiplicación Encriptada\n", + "\n", + "Para la multiplicación necesitamos una parte adicional, quien es responsable de generar números aleatorios constantemente (y que no colude con ninguna de las otras partes). Denominamos a esta persona la \"proveedora de encripción\". Para nuestros propósitos, la proveedora de encripción es solo una VirtualWorker (Trabajadora Virtual) adicional, pero es importante reconocer que la proveedora no es una \"dueña\", en el sentido que ella no posee acciones propias pero es alguien en quien confiamos que no coludirá con los dueños existentes de las acciones." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "crypto_provider = sy.VirtualWorker(hook, id=\"crypto_provider\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = torch.tensor([25]).share(bob,alice, crypto_provider=crypto_provider)\n", + "y = torch.tensor([5]).share(bob,alice, crypto_provider=crypto_provider)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# multiplicación\n", + "\n", + "z = x * y\n", + "z.get()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "También pueden hacer multiplicación de matrices" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = torch.tensor([[1, 2],[3,4]]).share(bob,alice, crypto_provider=crypto_provider)\n", + "y = torch.tensor([[2, 0],[0,2]]).share(bob,alice, crypto_provider=crypto_provider)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# multiplicación de matrices\n", + "\n", + "z = x.mm(y)\n", + "z.get()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Comparación Encriptada\n", + "\n", + "Es también posible el hacer comparaciones privadas entre valores privados. En este caso contamos con el protocolo SecureNN, cuyos detalles pueden encontrar [aquí](https://eprint.iacr.org/2018/442.pdf). El resultado de la comparación es también un tensor compartido privado." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = torch.tensor([25]).share(bob,alice, crypto_provider=crypto_provider)\n", + "y = torch.tensor([5]).share(bob,alice, crypto_provider=crypto_provider)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "z = x > y\n", + "z.get()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "z = x <= y\n", + "z.get()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "z = x == y\n", + "z.get()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "z = x == y + 20\n", + "z.get()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "También pueden hacer operaciones de max." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = torch.tensor([2, 3, 4, 1]).share(bob,alice, crypto_provider=crypto_provider)\n", + "x.max().get()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = torch.tensor([[2, 3], [4, 1]]).share(bob,alice, crypto_provider=crypto_provider)\n", + "max_values, max_ids = x.max(dim=0)\n", + "max_values.get()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# !Felicitaciones! - !Es hora de unirte a la comunidad!\n", + "\n", + "¡Felicitaciones por completar esta parte del tutorial! Si te gustó y quieres unirte al movimiento para preservar la privacidad, propiedad descentralizada de IA y la cadena de suministro de IA (datos), puedes hacerlo de las siguientes formas!\n", + "\n", + "### Dale una estrella a PySyft en GitHub\n", + "\n", + "La forma más fácil de ayudar a nuestra comunidad es por darle estrellas a los repositorios de Github! Esto ayuda a crear consciencia de las interesantes herramientas que estamos construyendo.\n", + "\n", + "- [Dale una estrella a PySyft](https://github.com/OpenMined/PySyft)\n", + "\n", + "### ¡Únete a nuestro Slack!\n", + "\n", + "La mejor manera de mantenerte actualizado con los últimos avances es ¡unirte a la comunidad! Tú lo puedes hacer llenando el formulario en [http://slack.openmined.org](http://slack.openmined.org)\n", + "\n", + "### ¡Únete a un proyecto de código!\n", + "\n", + "La mejor manera de contribuir a nuestra comunidad es convertirte en un ¡contribuidor de código! En cualquier momento puedes ir al Github Issues de PySyft y filtrar por \"Proyectos\". Esto mostrará todos los tiquetes de nivel superior dando un resumen de los proyectos a los que ¡te puedes unir! Si no te quieres unir a un proyecto, pero quieres hacer un poco de código, también puedes mirar más mini-proyectos \"de una persona\" buscando por Github Issues con la etiqueta \"good first issue\".\n", + "\n", + "- [Proyectos de PySyft](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n", + "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n", + "\n", + "### Donar\n", + "\n", + "Si no tienes tiempo para contribuir a nuestra base de código, pero quieres ofrecer tu ayuda, también puedes aportar a nuestro Open Collective\". Todas las donaciones van a nuestro web hosting y otros gastos de nuestra comunidad como ¡hackathons y meetups!\n", + "\n", + "[OpenMined's Open Collective Page](https://opencollective.com/openmined)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git "a/examples/tutorials/translations/espa\303\261ol/Parte 13a - Clasificaci\303\263n Segura con Syft Keras y TFE - Aprendizaje P\303\272blico.ipynb" "b/examples/tutorials/translations/espa\303\261ol/Parte 13a - Clasificaci\303\263n Segura con Syft Keras y TFE - Aprendizaje P\303\272blico.ipynb" new file mode 100644 index 00000000000..eaa8e5a1d28 --- /dev/null +++ "b/examples/tutorials/translations/espa\303\261ol/Parte 13a - Clasificaci\303\263n Segura con Syft Keras y TFE - Aprendizaje P\303\272blico.ipynb" @@ -0,0 +1,179 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Predicciones Privadas con Syft Keras" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Paso 1: Aprendizaje Público\n", + "\n", + "Bienvenidos a este tutorial! En los siguientes notebooks aprenderán a cómo proveer predicciones privadas. Por predicciones privadas, nos referimos a que los datos están constantemente encriptados durante todo el proceso. En ningún punto el usuario comparte datos originales, sino mas bien encriptados (es decir, compartidos en secreto). Para proveer estas predicciones privadas, Syft Keras utiliza una librería llamada [TF Encrypted](https://github.com/tf-encrypted/tf-encrypted). TF Encrypted combina estados del arte en técnicas de criptografía y aprendizaje de máquinas, pero no se tienen que preocupar por esto y en su lugar pueden enfocarse en la aplicación de aprendizaje de máquinas.\n", + "\n", + "Podemos empezar a proveer predicciones privadas con solo 3 pasos:\n", + "- **Paso 1**: Entrena tu modelo con Keras normal.\n", + "- **Paso 2**: Asegura y cuelga tu modelo de aprendizaje de máquinas (servidor). \n", + "- **Paso 3**: Consulta al modelo seguro para recibir la predicción privada (cliente).\n", + "\n", + "Bueno, vamos a seguir estos 3 pasos para que puedan desplegar servicios de aprendizaje de máquinas impactantes sin sacrificar la privacidad del usuario o la seguridad del modelo.\n", + "\n", + "Autores:\n", + "- Jason Mancuso - Twitter: [@jvmancuso](https://twitter.com/jvmancuso)\n", + "- Yann Dupis - Twitter: [@YannDupis](https://twitter.com/YannDupis)\n", + "- Morten Dahl - Twitter: [@mortendahlcs](https://github.com/mortendahlcs)\n", + "\n", + "Traductores:\n", + "- Daniel Firebanks-Quevedo - GitHub: [@thefirebanks](https://www.github.com/thefirebanks)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Entrena tu modelo con Keras" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Para utilizar técnicas de aprendizaje de máquinas que preservan la privacidad en tus proyectos, no deberías tener que aprender un nuevo framework. Si tienes conocimientos básicos de [Keras](https://keras.io/), puedes empezar usando estas técnicas con Syft Keras. Si nunca antes has utilizado Keras, puedes aprender un poco más en la [documentación](https://keras.io). \n", + "\n", + "Antes de proveer predicciones privadas, el primer paso es entrenar tu modelo con la versión normal de Keras. Como un ejemplo, vamos a entrenar un modelo para clasificar dígitos escritos a mano. Para entrenar este modelo usaremos el conjunto de datos canónico de [MNIST](http://yann.lecun.com/exdb/mnist/).\n", + "\n", + "Usaremos [este ejemplo](https://github.com/keras-team/keras/blob/master/examples/mnist_cnn.py) tomado del repositorio de Keras. Para entrenar tu modelo de clasificación, solo corre la célula siguiente." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import print_function\n", + "import tensorflow.keras as keras\n", + "from tensorflow.keras.datasets import mnist\n", + "from tensorflow.keras.models import Sequential\n", + "from tensorflow.keras.layers import Dense, Dropout, Flatten\n", + "from tensorflow.keras.layers import Conv2D, AveragePooling2D\n", + "from tensorflow.keras.layers import Activation\n", + "\n", + "batch_size = 128\n", + "num_classes = 10\n", + "epochs = 2\n", + "\n", + "# Dimensiones de la imagen\n", + "img_rows, img_cols = 28, 28\n", + "\n", + "# Dividir los datos en aprendizaje y evaluación\n", + "(x_train, y_train), (x_test, y_test) = mnist.load_data()\n", + "\n", + "x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)\n", + "x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)\n", + "input_shape = (img_rows, img_cols, 1)\n", + "\n", + "x_train = x_train.astype('float32')\n", + "x_test = x_test.astype('float32')\n", + "x_train /= 255\n", + "x_test /= 255\n", + "print('x_train shape:', x_train.shape)\n", + "print(x_train.shape[0], 'train samples')\n", + "print(x_test.shape[0], 'test samples')\n", + "\n", + "# Convertir los vectores de clase a vectores binarios\n", + "y_train = keras.utils.to_categorical(y_train, num_classes)\n", + "y_test = keras.utils.to_categorical(y_test, num_classes)\n", + "\n", + "model = Sequential()\n", + "\n", + "model.add(Conv2D(10, (3, 3), input_shape=input_shape))\n", + "model.add(AveragePooling2D((2, 2)))\n", + "model.add(Activation('relu'))\n", + "model.add(Conv2D(32, (3, 3)))\n", + "model.add(AveragePooling2D((2, 2)))\n", + "model.add(Activation('relu'))\n", + "model.add(Conv2D(64, (3, 3)))\n", + "model.add(AveragePooling2D((2, 2)))\n", + "model.add(Activation('relu'))\n", + "model.add(Flatten())\n", + "model.add(Dense(num_classes, activation='softmax'))\n", + "\n", + "model.compile(loss=keras.losses.categorical_crossentropy,\n", + " optimizer=keras.optimizers.Adam(),\n", + " metrics=['accuracy'])\n", + "\n", + "model.fit(x_train, y_train,\n", + " batch_size=batch_size,\n", + " epochs=epochs,\n", + " verbose=1,\n", + " validation_data=(x_test, y_test))\n", + "score = model.evaluate(x_test, y_test, verbose=0)\n", + "print('Test loss:', score[0])\n", + "print('Test accuracy:', score[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Guarda los pesos (weights) para predicciones privadas futuras" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Excelente! Tu modelo ya está entrenado. Vamos a guardar los pesos del modelo con `model.save()`. En el siguiente notebook, vamos a cargar estos pesos en Syft Keras para empezar a proveer predicciones privadas." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model.save('short-conv-mnist.h5')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git "a/examples/tutorials/translations/espa\303\261ol/Parte 13b - Clasificaci\303\263n Segura con Syft Keras y TFE - Proveer Predicciones desde un Modelo Seguro.ipynb" "b/examples/tutorials/translations/espa\303\261ol/Parte 13b - Clasificaci\303\263n Segura con Syft Keras y TFE - Proveer Predicciones desde un Modelo Seguro.ipynb" new file mode 100644 index 00000000000..27d5ea31510 --- /dev/null +++ "b/examples/tutorials/translations/espa\303\261ol/Parte 13b - Clasificaci\303\263n Segura con Syft Keras y TFE - Proveer Predicciones desde un Modelo Seguro.ipynb" @@ -0,0 +1,257 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Paso 2: Proveyendo modelos de manera segura con Syft Keras\n", + "\n", + "Ahora que has entrenado un modelo con Keras, estás listo para proveer predicciones privadas. Podemos hacer eso usando Syft Keras.\n", + "\n", + "Para asegurar y proveer este modelo, vamos a necesitar tres TFEWorkers (servidores). La razón es que TF Encrypted utiliza una técnica de encripción llamada [Computación Multi-Parte (CMP, o MPC en inglés)](https://en.wikipedia.org/wiki/Secure_multi-party_computation). La idea es dividir los pesos del modelo y los datos de entrada en \"acciones\", para luego enviar una acción de cada valor a los servidores diferentes. La propiedad clave es que si observas a la acción de un servidor, no se revela nada sobre el valor original (sea de los datos de entrada o los pesos del modelo).\n", + "\n", + "Vamos a definir un modelo Syft Keras como hicimos en el notebook anterior. Sin embargo, hay un truco: antes de instanciar este modelo, correremos `hook = sy.KerasHook(tf.keras)`. Esto agregará tres nuevos métodos importantes a la clase de Keras Sequential: \n", + "\n", + " - `share`: Esto asegurará tu modelo usando 'secret sharing' (convirtiendo el modelo en un \"secreto\" para luego ser dividido); por defecto, usará el protocolo SecureNN de TF Encrupted para compartir el secreto entre los tres TFEWorkers. Esto agregará la capacidad de proveer predicciones en datos encriptados\n", + "\n", + " - `serve`: Esta función empezará una cola de provisiones, donde los TFEWorkers pueden aceptar pedidos de predicciones. Estas predicciones vendrán de un modelo que está protegido del exterior. \n", + "\n", + " - `shutdown_workers`: Una vez hayas terminado de proveer predicciones, puedes apagar tu modelo usando esta función. Te redirigirá a apagar los procesos del servidor manualmente si has optado por manejar cada trabajador manualmente. \n", + " \n", + "Si quieres aprender más sobre CMP, visita este excelente [blog](https://mortendahl.github.io/2017/04/17/private-deep-learning-with-mpc/) (en inglés)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import tensorflow as tf\n", + "from tensorflow.keras import Sequential\n", + "from tensorflow.keras.layers import AveragePooling2D, Conv2D, Dense, Activation, Flatten, ReLU, Activation\n", + "\n", + "import syft as sy\n", + "hook = sy.KerasHook(tf.keras)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Modelo" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Como puedes ver, definimos casi el mismo modelo que antes, excepto que esta vez proveemos un `batch_input_shape` (tamaño del batch de los datos de entrada). Esto permite a TF Encrypted optimizar las computaciones seguras a través de tamaños predeterminados de tensores. Para este demo con MNIST, enviaremos datos de entrada con un tamaño de (1, 28, 28, 1). \n", + "También obtendremos el logit en vez del resultado de softmax porque esta operación es complicada de hacer usando CMP, y no la necesitamos para responder a los pedidos de predicciones. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "num_classes = 10\n", + "input_shape = (1, 28, 28, 1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model = Sequential()\n", + "\n", + "model.add(Conv2D(10, (3, 3), batch_input_shape=input_shape))\n", + "model.add(AveragePooling2D((2, 2)))\n", + "model.add(Activation('relu'))\n", + "model.add(Conv2D(32, (3, 3)))\n", + "model.add(AveragePooling2D((2, 2)))\n", + "model.add(Activation('relu'))\n", + "model.add(Conv2D(64, (3, 3)))\n", + "model.add(AveragePooling2D((2, 2)))\n", + "model.add(Activation('relu'))\n", + "model.add(Flatten())\n", + "model.add(Dense(num_classes, name=\"logit\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Cargando pesos pre-entrenados" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Con `load_weights` puedes cargar los pesos que has guardado anteriormente después de entrenar tu modelo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pre_trained_weights = 'short-conv-mnist.h5'\n", + "model.load_weights(pre_trained_weights)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Usando los trabajadores" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Ahora crearemos TFEWorkers (`alice`, `bob` y `carol`) requeridos por TF Encrypted para calcular predicciones privadas. Por cada TFEWorker, necesitas especificar un host. Luego, combinamos estos trabajadores en un clúster. \n", + "\n", + "Estos trabajadores corren en un [servidor de TensorFlow](https://www.tensorflow.org/api_docs/python/tf/distribute/Server), el cual puedes manejar manualmente (`AUTO = False`) o pedir a los trabajadores que lo manejen por ti (`AUTO = True`). Si escoges manejarlos manualmente, tendrás que ejecutar un comando en el terminal en cada dispositivo de host por cada trabajador después de llamar `cluster.start()` abajo. Si es que todos los trabajadores están bajo el mismo host en un solo dispositivo (e.g `localhost`), puedes escoger que Syft maneje el servidor Tensorflow de los trabajadores." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "AUTO = False\n", + "\n", + "alice = sy.TFEWorker(host='localhost:4000', auto_managed=AUTO)\n", + "bob = sy.TFEWorker(host='localhost:4001', auto_managed=AUTO)\n", + "carol = sy.TFEWorker(host='localhost:4002', auto_managed=AUTO)\n", + "\n", + "cluster = sy.TFECluster(alice, bob, carol)\n", + "cluster.start()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Asegurando el modelo, calculando los pesos" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Gracias a `sy.KerasHook(tf.keras)`, puedes llamar al método `share` para transformar tu modelo en un modelo de TF Encrypted.\n", + "\n", + "Si has decidido manejar los servidores manualmente en el código de arriba, entonces este paso no completará hasta que todos los servidores hayan empezado a correr. Puede que tu firewall te pida permiso para que Python acepte la conexión." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model.share(cluster)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Proveyendo el modelo" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Perfecto! Ahora al llamar `model.serve`, tu modelo está listo para proveer predicciones privadas. Puedes ajustar `num_requests` para delimitar el número de predicciones que el modelo podrá proveer; Si no está especificado, entonces el modelo proveerá predicciones hasta que sea interrumpido." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model.serve(num_requests=3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Estamos listos para proseguir al notebook **Parte 13c** para pedir predicciones privadas." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Limpieza!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Una vez hayas topado el límite de pedidos, el modelo no podrá estar disponible para proveer predicciones, pero aun mantendrá el secreto entre los tres trabajadores. Puedes apagar a los trabajadores ejecutando el código siguiente. \n", + "\n", + "**Felicidades** por terminar la parte 13b: Clasificación Segura con Syft Keras y TFE!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model.stop()\n", + "cluster.stop()\n", + "\n", + "if not AUTO:\n", + " process_ids = !ps aux | grep '[p]ython -m tf_encrypted.player --config' | awk '{print $2}'\n", + " for process_id in process_ids:\n", + " !kill {process_id}\n", + " print(\"Process ID {id} has been killed.\".format(id=process_id))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git "a/examples/tutorials/translations/espa\303\261ol/Parte 13c - Clasificaci\303\263n Segura con Syft Keras y TFE - Prediccion Privada (Cliente).ipynb" "b/examples/tutorials/translations/espa\303\261ol/Parte 13c - Clasificaci\303\263n Segura con Syft Keras y TFE - Prediccion Privada (Cliente).ipynb" new file mode 100644 index 00000000000..f19da9a693f --- /dev/null +++ "b/examples/tutorials/translations/espa\303\261ol/Parte 13c - Clasificaci\303\263n Segura con Syft Keras y TFE - Prediccion Privada (Cliente).ipynb" @@ -0,0 +1,194 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Predicciones Privadas con Syft Keras" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Paso 3: Solicitando Predicciones (Cliente)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Felicidades! Después de entrenar tu modelo con Keras y asegurarlo con Syft Keras, estás listo para solicitar predicciones privadas" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import tensorflow as tf\n", + "from tensorflow.keras.datasets import mnist\n", + "\n", + "import syft as sy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Datos" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Aquí vamos a preprocesar nuestros datos de MNIST. Esto es idéntico a como preprocesamos durante el aprendizaje" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Dimensiones de la imagen de entrada\n", + "img_rows, img_cols = 28, 28\n", + "\n", + "# Divide los datos en aprendizaje y evaluación\n", + "(x_train, y_train), (x_test, y_test) = mnist.load_data()\n", + "\n", + "x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)\n", + "x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)\n", + "input_shape = (img_rows, img_cols, 1)\n", + "\n", + "x_train = x_train.astype('float32')\n", + "x_test = x_test.astype('float32')\n", + "x_train /= 255\n", + "x_test /= 255" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conectando con el modelo" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Antes de enviar solicitudes al modelo, necesitas conectarte a él. Para esto, puedes crear un cliente. Luego define los mismos 3 TFEWorkers (`alice`, `bob` y `carol`) y clúster. Finalmente, llama `connect_to_model`. Esto crea un servidor TFE de colas en el lado del cliente que conecta al servidor de solicitudes que ha sido instaurado por `model.serve()` en la **Parte 13b**. La cola será responsable de compartir el secreto de datos antes de entregar las acciones en una solicitud de predicción." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "num_classes = 10\n", + "input_shape = (1, 28, 28, 1)\n", + "output_shape = (1, num_classes)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "client = sy.TFEWorker()\n", + "\n", + "alice = sy.TFEWorker(host='localhost:4000')\n", + "bob = sy.TFEWorker(host='localhost:4001')\n", + "carol = sy.TFEWorker(host='localhost:4002')\n", + "cluster = sy.TFECluster(alice, bob, carol)\n", + "\n", + "client.connect_to_model(input_shape, output_shape, cluster)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Consultar el modelo!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Todo listo para obtener predicciones privadas! Ejecutando `query_model` insertará la `image` en la cola creada arriba, compartir el secreto de datos localmente, y entregar las acciones al servidor del modelo de la **Parte 13b**." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Parámetros del usuario\n", + "num_tests = 3\n", + "images, expected_labels = x_test[:num_tests], y_test[:num_tests]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for image, expected_label in zip(images, expected_labels):\n", + "\n", + " res = client.query_model(image.reshape(1, 28, 28, 1))\n", + " predicted_label = np.argmax(res)\n", + "\n", + " print(\"The image had label {} and was {} classified as {}\".format(\n", + " expected_label,\n", + " \"correctly\" if expected_label == predicted_label else \"wrongly\",\n", + " predicted_label))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Esto es genial. Ahora eres capaz de clasificar estas tres imágenes correctamente! Pero lo que es especial sobre estas predicciones es que tú no has tenido que revelar ninguna información privada para obtener este servicio. El host del modelo nunca vio tus datos de entrada o tus predicciones, y tu nunca descargaste el modelo. Pudiste obtener las predicciones de manera privada, con datos encriptados y un modelo encriptado!\n", + "\n", + "Antes de que nos apuremos a aplicar esto en nuestras apps, regresemos a la **Parte 13b** y limpiemos nuestro modelo!\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.5" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 82a56eea5e1f2da779057e5286d5c5f19ae02a18 Mon Sep 17 00:00:00 2001 From: Arturo Date: Tue, 11 Feb 2020 11:47:21 -0600 Subject: [PATCH 2/2] Fix typos in Spanish tutorials parts 9 and 13b --- .../Parte 09 - Intro a los Programas Encriptados.ipynb" | 6 +++--- ...TFE - Proveer Predicciones desde un Modelo Seguro.ipynb" | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git "a/examples/tutorials/translations/espa\303\261ol/Parte 09 - Intro a los Programas Encriptados.ipynb" "b/examples/tutorials/translations/espa\303\261ol/Parte 09 - Intro a los Programas Encriptados.ipynb" index 90721d9de8e..c9a8e60f06e 100644 --- "a/examples/tutorials/translations/espa\303\261ol/Parte 09 - Intro a los Programas Encriptados.ipynb" +++ "b/examples/tutorials/translations/espa\303\261ol/Parte 09 - Intro a los Programas Encriptados.ipynb" @@ -25,15 +25,15 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Paso 1: Encripción Usando Computación Segura Multi-Parte (CSMP)\n", + "# Paso 1: Encriptación Usando Computación Segura Multi-Parte (CSMP)\n", "\n", - "A primera vista, CSMP es una manera extraña de \"encripción\". En vez de usar una clave pública/privada para encriptar una variable, cada valor es dividido en múltiples `acciones`, cada una funcionando como una clave privada. Típicamente, éstas `acciones` serán distribuidas entre 2 o más dueños. Por lo tanto, para descifrar la variable, todos los dueños deben de estar de acuerdo en permitir el desciframiento. En esencia, cada persona tiene una clave privada. \n", + "A primera vista, CSMP es una manera extraña de \"encriptación\". En vez de usar una clave pública/privada para encriptar una variable, cada valor es dividido en múltiples `acciones`, cada una funcionando como una clave privada. Típicamente, éstas `acciones` serán distribuidas entre 2 o más dueños. Por lo tanto, para descifrar la variable, todos los dueños deben de estar de acuerdo en permitir el desciframiento. En esencia, cada persona tiene una clave privada. \n", "\n", "### Encrypt()\n", "\n", "Digamos que queremos \"encriptar\" una variable `x`, podríamos hacerlo de la siguiente manera.\n", "\n", - " > La encripción no usa decimales o números reales, sino que ocurre en un espacio matemático llamado [anillo cociente](https://es.wikipedia.org/wiki/Anillo_cociente), el cual abarca los números enteros entre `0` y `Q-1`, donde `Q` es un número primo y \"suficientemente grande\" para que el espacio pueda contener todos los números que usamos en nuestros experimentos. En la práctica, dado un número entero `x`, nosotros hacemos `x % Q` para encajar en el anillo. (Esa es la razón por la que evitamos usar un número `x' > Q`)." + " > La encriptación no usa decimales o números reales, sino que ocurre en un espacio matemático llamado [anillo cociente](https://es.wikipedia.org/wiki/Anillo_cociente), el cual abarca los números enteros entre `0` y `Q-1`, donde `Q` es un número primo y \"suficientemente grande\" para que el espacio pueda contener todos los números que usamos en nuestros experimentos. En la práctica, dado un número entero `x`, nosotros hacemos `x % Q` para encajar en el anillo. (Esa es la razón por la que evitamos usar un número `x' > Q`)." ] }, { diff --git "a/examples/tutorials/translations/espa\303\261ol/Parte 13b - Clasificaci\303\263n Segura con Syft Keras y TFE - Proveer Predicciones desde un Modelo Seguro.ipynb" "b/examples/tutorials/translations/espa\303\261ol/Parte 13b - Clasificaci\303\263n Segura con Syft Keras y TFE - Proveer Predicciones desde un Modelo Seguro.ipynb" index 27d5ea31510..60624850da2 100644 --- "a/examples/tutorials/translations/espa\303\261ol/Parte 13b - Clasificaci\303\263n Segura con Syft Keras y TFE - Proveer Predicciones desde un Modelo Seguro.ipynb" +++ "b/examples/tutorials/translations/espa\303\261ol/Parte 13b - Clasificaci\303\263n Segura con Syft Keras y TFE - Proveer Predicciones desde un Modelo Seguro.ipynb" @@ -8,7 +8,7 @@ "\n", "Ahora que has entrenado un modelo con Keras, estás listo para proveer predicciones privadas. Podemos hacer eso usando Syft Keras.\n", "\n", - "Para asegurar y proveer este modelo, vamos a necesitar tres TFEWorkers (servidores). La razón es que TF Encrypted utiliza una técnica de encripción llamada [Computación Multi-Parte (CMP, o MPC en inglés)](https://en.wikipedia.org/wiki/Secure_multi-party_computation). La idea es dividir los pesos del modelo y los datos de entrada en \"acciones\", para luego enviar una acción de cada valor a los servidores diferentes. La propiedad clave es que si observas a la acción de un servidor, no se revela nada sobre el valor original (sea de los datos de entrada o los pesos del modelo).\n", + "Para asegurar y proveer este modelo, vamos a necesitar tres TFEWorkers (servidores). La razón es que TF Encrypted utiliza una técnica de encriptación llamada [Computación Multi-Parte (CMP, o MPC en inglés)](https://en.wikipedia.org/wiki/Secure_multi-party_computation). La idea es dividir los pesos del modelo y los datos de entrada en \"acciones\", para luego enviar una acción de cada valor a los servidores diferentes. La propiedad clave es que si observas a la acción de un servidor, no se revela nada sobre el valor original (sea de los datos de entrada o los pesos del modelo).\n", "\n", "Vamos a definir un modelo Syft Keras como hicimos en el notebook anterior. Sin embargo, hay un truco: antes de instanciar este modelo, correremos `hook = sy.KerasHook(tf.keras)`. Esto agregará tres nuevos métodos importantes a la clase de Keras Sequential: \n", "\n",