TensorFlow y Redes Neuronales
Esta notebook fue creada originalmente como un blog post por Raúl E. López Briega en Matemáticas, Analisis de datos y Python. El contenido esta bajo la licencia BSD.

Sobre TensoFlow
TensorFlow es una biblioteca open source desarrollada por Google que nos permite realizar cálculos numéricos usando diagramas de flujo de datos. Los nodos del grafo representan operaciones matemáticas, mientras que los arcos del grafo representan los arreglos de datos multidimensionales (tensores) comunicados entre ellos. Esta arquitectura flexible nos permite realizar los cálculos en más de un CPU o GPU utilizando la misma API.
¿Qué es un diagrama de flujo de datos?
Los diagramas de flujo de datos describen cálculos matemáticos con un grafo de nodos y arcos. Los nodos normalmente implementan operaciones matemáticas, pero también pueden representar los puntos para alimentarse de datos, devolver resultados, o leer / escribir variables persistentes. Los arcos o aristas describen las relaciones de entrada / salida entre los nodos. Estos arcos están representados por los arreglos de datos multidimensionales o tensores. El flujo de los tensores a través del grafo es de donde TensorFlow recibe su nombre. Los nodos se asignan a los dispositivos computacionales y se ejecutan de forma asincrónica y en paralelo una vez que todos los tensores en los arcos de entrada están disponibles.

Introducción a TensorFlow
Para poder utilizar TensorFlow primero es necesario entender cómo la librería:
- Representa cálculos en forma de grafos.
- Ejecuta los grafos en el contexto de Sesiones.
- Representa los datos como tensores.
- Mantiene el estado con variables.
- Se alimenta de datos y devuelve los resultados de cada operación.
Funcionamiento general
TensorFlow es un sistema de programación en el que representamos cálculos en forma de grafos. Los nodos en el grafo se llaman ops (abreviatura de operaciones). Una op tiene cero o más tensores, realiza algún cálculo, y produce cero o más tensores.
Un grafo de TensorFlow es una descripción de cálculos. Para calcular cualquier cosa dentro de TensorFlow, el grafo debe ser lanzado dentro de una sesión. La Sesión coloca las operaciones del grafo en los diferentes dispositivos, tales como CPU o GPU, y proporciona métodos para ejecutarlas.
Creando un Grafo
Para construir un grafo simple, podemos comenzar con ops que no necesitan ningún dato de entrada, como son las constantes y luego le pasamos su salida a ops que realizan cálculos.
Constantes
Podemos construir ops de constantes utilizando constant
, su API es bastante simple:
constant(value, dtype=None, shape=None, name='Const')
Le debemos pasar un valor, el cual puede ser cualquier tipo de tensor (un escalar, un vector, una matriz, etc) y luego opcionalmente le podemos pasar el tipo de datos, la forma y un nombre.
Sesiones
Ahora que ya definimos algunas ops constantes y algunos cálculos con ellas, debemos lanzar el grafo dentro de una Sesión. Para realizar esto utilizamos el objeto Session
. Este objeto va a encapsular el ambiente en el que las operaciones que definimos en el grafo van a ser ejecutadas y los tensores son evaluados.
Suma de las constantes: 5
Multiplicación de las constantes: 6
Constante elevada al cubo: 8
Suma de matrices:
[[2 3 7]
[8 5 0]
[3 3 3]]
Producto de matrices:
[[26 17 7]
[ 1 0 5]
[19 12 7]]
Las Sesiones deben ser cerradas para liberar los recursos, por lo que es una buena práctica incluir la Sesión dentro de un bloque “with” que la cierra automáticamente cuando el bloque termina de ejecutar.
Para ejecutar las operaciones y evaluar los tensores utilizamos Session.run()
.
Variables persistentes
Las Variables mantienen el estado a través de las ejecuciones del grafo. Son buffers en memoria que contienen tensores. Se deben inicializar explícitamente y se pueden guardar en el disco para luego restaurar su estado de necesitarlo. Se crean utilizando el objeto Variable
.
0
1
2
3
Variables simbólicas (contenedores)
Las Variables simbólicas o Contenedores nos van a permitir alimentar a las operaciones con los datos durante la ejecución del grafo. Estos contenedores deben ser alimentados antes de ser evaluados en la sesión, sino obtendremos un error.
[[ 2.27301431 2.39163661 1.22738445 1.87839973]
[ 2.66718912 2.76533985 1.08909523 1.96862805]
[ 2.38245845 2.37843513 1.0873785 1.67218387]
[ 1.68678236 1.77147484 1.0363127 1.36901033]]
Ahora ya conocemos en líneas generales como es la mecánica detrás del funcionamiento de TensorFlow y como deberíamos proceder para crear las operaciones dentro de los grafos. Veamos si podemos implementar modelos de neuronas simples con la ayuda de esta librería.
Ejemplo de neuronas simples
Una neurona simple, va a tener una forma similar al siguiente diagrama:

En donde sus componentes son:
-
: son los datos de entrada en la neurona, los cuales también puede ser que sean producto de la salida de otra neurona de la red. -
: Es la unidad de sesgo; un valor constante que se le suma a la entrada de la función de activación de la neurona. Generalmente tiene el valor 1. Este valor va a permitir cambiar la función de activación hacia la derecha o izquierda, otorgándole más flexibilidad para aprender a la neurona. -
: Los pesos relativos de cada entrada. Tener en cuenta que incluso la unidad de sesgo tiene un peso. -
a: La salida de la neurona. Que va a ser calculada de la siguiente forma:
Aquí
Ahora que ya conocemos como se construye una neurona tratemos de implementar con este modelo las funciones lógicas AND, OR y XNOR. Podemos pensar a estas funciones como un problema de clasificación en el que la salida va a ser 0 o 1, de acuerdo a la combinación de las diferentes entradas.
Las podemos modelar linealmente con la siguiente función de activación:
Neurona AND
La neurona AND puede ser modelada con el siguiente esquema:

La salida de esta neurona entonces va a ser:
Veamos como la podemos implementar en TensorFlow.
x1 | x2 | f(x) | x1 AND x2 | |
---|---|---|---|---|
0 | 0.0 | 0.0 | -1.5 | 0.0 |
1 | 1.0 | 0.0 | -0.5 | 0.0 |
2 | 0.0 | 1.0 | -0.5 | 0.0 |
3 | 1.0 | 1.0 | 0.5 | 1.0 |
Aquí podemos ver los datos de entrada de and
Neurona OR
La neurona OR puede ser modelada con el siguiente esquema:

La salida de esta neurona entonces va a ser:
Como se puede ver a simple vista, el modelo de esta neurona es similar a la de la neurona AND, con el único cambio en el valor del sesgo, por lo tanto solo tendríamos que cambiar ese valor en nuestro modelo anterior para crear esta nueva neurona.
x1 | x2 | f(x) | x1 OR x2 | |
---|---|---|---|---|
0 | 0.0 | 0.0 | -0.5 | 0.0 |
1 | 1.0 | 0.0 | 0.5 | 1.0 |
2 | 0.0 | 1.0 | 0.5 | 1.0 |
3 | 1.0 | 1.0 | 1.5 | 1.0 |
Como vemos, cambiando simplemente el peso del sesgo, convertimos a nuestra neurona AND en una neurona OR. Como muestra la tabla de verdad, el único caso en que OR
Red Neuronal XNOR
El caso de la función XNOR, ya es más complicado y no puede modelarse utilizando una sola neurona como hicimos con los ejemplos anteriores. XNOR

Veamos entonces si podemos implementar este modelo en TensorFlow.
x1 | x2 | x1 XNOR x2 | |
---|---|---|---|
0 | 0.0 | 0.0 | 1.0 |
1 | 1.0 | 0.0 | 0.0 |
2 | 0.0 | 1.0 | 0.0 |
3 | 1.0 | 1.0 | 1.0 |
Como vemos, la red neuronal nos da el resultado correcto para la función lógica XNOR, solo es verdadera si ambos valores son verdaderos, o ambos son falsos.
Hasta aquí implementamos simples neuronas y les pasamos los valores de sus pesos y sesgo a mano; esto es sencillo para los ejemplos; pero en la vida real, si queremos utilizar redes neuronales necesitamos implementar un procesos que vaya actualizando los pesos a medida que la red vaya aprendiendo con el entrenamiento. Este proceso se conoce con el nombre de propagación hacia atrás o backpropagation.
Propagación hacia atrás
La propagación hacia atrás o backpropagation es un algoritmo que funciona mediante la determinación de la pérdida (o error) en la salida y luego propagándolo de nuevo hacia atrás en la red. De esta forma los pesos se van actualizando para minimizar el error resultante de cada neurona. Este algoritmo es lo que les permite a las redes neuronales aprender.
Veamos un ejemplo de como podemos implementar una red neuronal que pueda aprender por sí sola con la ayuda de TensorFlow.
Ejemplo de Perceptron multicapa para reconocer dígitos escritos
En este ejemplo vamos a construir un peceptron multicapa para clasificar dígitos escritos. Antes de pasar a la construcción del modelo, exploremos un poco el conjunto de datos con el que vamos a trabajar en la clasificación.
MNIST dataset
MNIST es un simple conjunto de datos para reconocimiento de imágenes por computadora. Se compone de imágenes de dígitos escritos a mano como los siguientes:
Para más información sobre el dataset pueden visitar el siguiente enlace, en donde hacen un análisis detallado del mismo.
Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting MNIST_data/train-images-idx3-ubyte.gz
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
Explorando MNIST dataset
(55000, 784)
7
Construyendo el perceptron multicapa
Ahora que ya conocemos los datos con los que vamos a trabajar, ya estamos en condiciones de construir el modelo. Vamos a construir un peceptron multicapa que es una de las redes neuronales más simples. El modelo va a tener dos capas ocultas, que se van a activar con la función de activación ReLU y vamos a optimizar los pesos reduciendo la entropía cruzada utilizando el algoritmo Adam que es un método para optimización estocástica.
Iteración: 001 costo = 190.739139247
Iteración: 002 costo = 42.639138275
Iteración: 003 costo = 26.239370855
Iteración: 004 costo = 18.236157751
Iteración: 005 costo = 13.129509245
Iteración: 006 costo = 9.765473726
Iteración: 007 costo = 7.159448563
Iteración: 008 costo = 5.309303818
Iteración: 009 costo = 3.940411947
Iteración: 010 costo = 2.904317733
Iteración: 011 costo = 2.179349244
Iteración: 012 costo = 1.597618810
Iteración: 013 costo = 1.215200688
Iteración: 014 costo = 0.875238173
Iteración: 015 costo = 0.760177279
Optimización Terminada!
Precisión: 0.94
Ejecutar el comando:
--> tensorboard --logdir=/tmp/tensorflow_logs
Luego abir https://0.0.0.0:6006/ en el navegador
Como vemos TensorFlow nos da mucha flexibilidad para construir el modelo, modificando muy pocas líneas podríamos cambiar el algoritmo de optimización o el calculo del error y obtener otros resultados; de esta forma vamos a poder personalizar el modelo para alcanzar mayores niveles de precisión.
TensorBoard
Otra gran herramienta que nos proporciona TensorFlow es TensorBoard que nos permite visualizar nuestros grafos y nos ayudan a alcanzar un mayor entendimiento del flujo de cálculos que ocurre en nuestro modelo.
Para crear la información de la que se va a nutrir el TensorBoard, podemos definir algunos scopes utilizando tf.name_scope
; también podemos incluir algunos gráficos sumarizados con tf.scalar_summary
y luego llamamos a la función tf.train.SummaryWriter
dentro de una Sesión.
Luego podemos iniciar el board con el comando tensorboard --logdir=logpath
como se puede ver en la salida del último ejemplo.
Los grafos de los casos que vimos por ejemplo, se ven así.

Los invito a explorar la herramienta y adentrarse en el fascinante mundo de las redes neuronales.
Saludos!
Este post fue escrito utilizando IPython notebook. Pueden descargar este notebook o ver su version estática en nbviewer.