Tutorial de red neuronal TensorFlow

TensorFlow es una biblioteca de código abierto para aplicaciones de aprendizaje automático. Es el sistema de segunda generación de Google Brain, después de reemplazar el Dist...

TensorFlow es una biblioteca de código abierto para aplicaciones de aprendizaje automático. Es el sistema de segunda generación de Google Brain, después de reemplazar el DistBelief de código cerrado, y Google lo utiliza para aplicaciones de investigación y producción. Las aplicaciones de TensorFlow se pueden escribir en algunos lenguajes: Python, Go, Java y C. Esta publicación se ocupa de su versión de Python y analiza la instalación de la biblioteca, los componentes básicos de bajo nivel y la creación de una red neuronal de avance. red desde cero para realizar el aprendizaje en un conjunto de datos real.

La duración del entrenamiento de las redes neuronales de aprendizaje profundo suele ser un cuello de botella en escenarios más complejos. Dado que las redes neuronales, pero también otros algoritmos de ML, funcionan principalmente con multiplicaciones de matrices, es mucho más rápido ejecutarlas en unidades de procesamiento gráfico (GPU) que en unidades de procesamiento central (CPU) estándar.

TensorFlow es compatible tanto con CPU como con GPU, y Google incluso ha producido su propio hardware especializado para computación en la nube, llamado Unidad de procesamiento de tensores (TPU), que produce la Mejor presentación entre las diferentes unidades de procesamiento.

Instalación

Si bien las TPU solo están disponibles en la nube, la instalación de TensorFlow en una computadora local puede tener como objetivo una arquitectura de procesamiento de CPU o GPU. Para utilizar la versión de GPU, su computadora debe tener una tarjeta gráfica NVIDIA y también cumplir algunos [requisitos] más (https://www.tensorflow.org/install/install_linux#nvidia_requirements_to_run_tensorflow_with_gpu_support).

Básicamente, hay al menos 5 opciones diferentes para la instalación, usando: virtualenv, pip, Docker, Anaconda e instalación desde la fuente.

  • La instalación con entorno virtual y Docker nos permite instalar TensorFlow en un entorno separado, aislado de sus otras bibliotecas de Python.
  • Anaconda es una distribución de Python que contiene un gran conjunto de bibliotecas para computación científica, incluido TensorFlow.
  • pip se considera el instalador "nativo" de los paquetes de Python sin utilizar ningún entorno separado.
  • Por último, la instalación desde la fuente pasa por Git y es la mejor manera de seleccionar una versión de software en particular, siendo la versión estable actual de TensorFlow r1.4 (al momento de escribir este artículo).

La forma más común y fácil de instalar es a través de virtualenv y pip, por lo que se explicarán en esta publicación.

Si ha usado Python por un tiempo, probablemente conozca pip. Así es como puede obtenerlo en una máquina Ubuntu:

1
2
3
# Install pip
sudo apt-get install python-pip python-dev   # Python 2.7
sudo apt-get install python3-pip python3-dev # Python 3.x

Las siguientes líneas explican la instalación de TensorFlow en una máquina Ubuntu y Mac OSX:

1
2
3
4
5
6
7
# CPU support
pip install tensorflow      # Python 2.7
pip3 install tensorflow     # Python 3.x

# GPU support
pip install tensorflow-gpu  # Python 2.7
pip3 install tensorflow-gpu # Python 3.x

Los comandos anteriores también funcionarán en una máquina con Windows, pero solo para las versiones de Python 3.5.x y 3.6.x.

La instalación de TensorFlow en un entorno separado se puede realizar a través de virtualenv o conda (que es parte de Anaconda). El proceso en general sigue las mismas líneas anteriores, solo que esta vez primero debe crear y activar un nuevo entorno con:

1
2
virtualenv --system-site-packages ~/tensorflow
source ~/tensorflow/bin/activate

Esto mantendrá todos los paquetes requeridos separados de aquellos que haya instalado globalmente en su sistema.

Componentes principales de la API

Hay varias API disponibles para programar TensorFlow. El nivel más bajo se conoce como Centro y funciona con los componentes básicos: tensores, gráficos y sesiones.

Las API de nivel superior, como tf.estimator, están diseñadas para simplificar el flujo de trabajo y automatizar procesos como la gestión de conjuntos de datos, el aprendizaje, la evaluación, etc. De todos modos, conocer las funciones principales de la biblioteca es vital para crear aplicaciones de aprendizaje de última generación. .

El objetivo de Core API es construir un gráfico computacional que contenga una serie de operaciones organizadas en un gráfico de nodos. Cada nodo puede tener múltiples tensores (la estructura básica de datos) como entradas y realiza operaciones sobre ellos para calcular una salida, que luego puede representar una entrada para otros nodos en una red multicapa. Este tipo de arquitectura es adecuada para aplicaciones de aprendizaje automático, como las redes neuronales.

Tensores

Tensores son la estructura de datos básica en TensorFlow que almacena datos en cualquier cantidad de dimensiones, similar a las matrices multidimensionales en NumPy. Hay tres tipos básicos de tensores: constantes, variables y marcadores de posición.

  • Constantes son tipos de tensores inmutables. Podrían verse como nodos sin entradas, generando un solo valor que almacenan internamente.
  • Variables son tipos de valores mutables cuyo valor puede cambiar durante la ejecución de un gráfico. En las aplicaciones de ML, las variables suelen almacenar los parámetros que deben optimizarse (por ejemplo, los pesos entre nodos en una red neuronal). Las variables deben inicializarse antes de ejecutar el gráfico llamando explícitamente a una operación especial.
  • Marcadores de posición son tensores que almacenan datos de fuentes externas. Representan una "promesa" de que se proporcionará un valor cuando se ejecute el gráfico. En las aplicaciones de ML, los marcadores de posición generalmente se usan para ingresar datos en el modelo de aprendizaje.

Las siguientes pocas líneas dan un ejemplo de los tres tipos de tensores:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import tensorflow as tf

tf.reset_default_graph()

# Define a placeholder
a = tf.placeholder("float", name='pholdA')
print("a:", a)

# Define a variable 
b = tf.Variable(2.0, name='varB')
print("b:", b)

# Define a constant
c = tf.constant([1., 2., 3., 4.], name='consC')
print("c:", c)
1
2
3
a: Tensor("pholdA:0", dtype=float32)
b: <tf.Variable 'varB:0' shape=() dtype=float32_ref>
c: Tensor("consC:0", shape=(4,), dtype=float32)

Tenga en cuenta que los tensores no contienen un valor en este punto, y sus valores solo podrían estar disponibles cuando el gráfico se ejecuta en una Sesión.

Gráficos

En este punto, el gráfico solo contiene tensores de árbol que no están conectados. Ejecutemos algunas operaciones en nuestros tensores:

1
2
d = a * b + c
d
1
<tf.Tensor 'add:0' shape=<unknown> dtype=float32>

La salida resultante es nuevamente un tensor llamado 'add', y nuestro modelo ahora se ve como en la imagen a continuación. Puede explorar su gráfico, así como otros parámetros, utilizando la característica integrada de TensorFlow [TensorTablero] (https://github.com/tensorflow/tensorboard).

Gráfico de TensorFlow{.img-responsive}

Figura 1: El gráfico de TensorFlow que consiste en una multiplicación y suma.

Otra herramienta útil para explorar su gráfico es la siguiente, que imprime todas las operaciones en él.

1
2
3
4
5
6
# call the default graph
graph = tf.get_default_graph()

# print operations in the graph
for op in graph.get_operations():
    print(op.name)
1
2
3
4
5
6
7
8
pholdA
varB/initial_value
varB
varB/Assign
varB/read
consC
mul
add

Sesiones

Finalmente, nuestro gráfico debe ejecutarse dentro de una sesión. Tenga en cuenta que las variables se inicializan de antemano, mientras que el tensor de marcador de posición recibe valores concretos a través del atributo feed_dict.

1
2
3
4
5
6
7
8
# Initialize variables
init = tf.global_variables_initializer()

# Run a session and calculate d
sess = tf.Session()
sess.run(init)
print(sess.run(d, feed_dict={a: [[0.5], [2], [3]]}))
sess.close()
1
2
3
[[  2.   3.   4.   5.]
 [  5.   6.   7.   8.]
 [  7.   8.   9.  10.]]

El ejemplo anterior es una gran simplificación de un modelo de aprendizaje. De cualquier manera, mostró cómo los componentes básicos tf pueden combinarse en un gráfico y ejecutarse en una sesión. Además, ilustró cómo se ejecutan las operaciones en tensores de diferentes formas.

En la siguiente sección, usaremos Core API para crear una red neuronal para el aprendizaje automático en datos reales.

Un modelo de red neuronal

En esta parte, construimos una red neuronal de avance desde cero utilizando los componentes principales de TensorFlow. Comparamos tres arquitecturas de una red neuronal, que variarán en la cantidad de nodos en una sola capa oculta.

Conjunto de datos de iris

Usamos el simple Conjunto de datos de iris, que consta de 150 ejemplos de plantas, cada una con sus 4 dimensiones (usadas como características de entrada) y su tipo (el valor de salida que debe predecirse). Una planta puede pertenecer a uno de los tres tipos posibles (setosa, virginica y versicolor). Primero descarguemos los datos del sitio web de TensorFlow: se dividen en subconjuntos de entrenamiento y prueba con 120 y 30 ejemplos cada uno.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Import the needed libraries
import numpy as np
import pandas as pd
import tensorflow as tf
import urllib.request as request
import matplotlib.pyplot as plt

# Download dataset
IRIS_TRAIN_URL = "http://download.tensorflow.org/data/iris_training.csv"
IRIS_TEST_URL = "http://download.tensorflow.org/data/iris_test.csv"

names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'species']
train = pd.read_csv(IRIS_TRAIN_URL, names=names, skiprows=1)
test = pd.read_csv(IRIS_TEST_URL, names=names, skiprows=1)

# Train and test input data
Xtrain = train.drop("species", axis=1)
Xtest = test.drop("species", axis=1)

# Encode target values into binary ('one-hot' style) representation
ytrain = pd.get_dummies(train.species)
ytest = pd.get_dummies(test.species)

Modelo y aprendizaje

La forma de las capas de entrada y salida de nuestra red neuronal se corresponderá con la forma de los datos, es decir, la capa de entrada contendrá cuatro neuronas que representan las cuatro características de entrada, mientras que la capa de salida contendrá tres neuronas debido a los tres bits utilizados para codificar una especie de planta en estilo uno-caliente. Por ejemplo, la especie 'setosa' podría codificarse con un vector [1, 0, 0], la 'virginica' con [0, 1, 0], etc.

Seleccionamos tres valores para el número de neuronas en la capa oculta: 5, 10 y 20, lo que da como resultado tamaños de red de (4-5-3), (4-10-3) y (4-20-3). Esto significa que nuestra primera red, por ejemplo, tendrá 4 neuronas de entrada, 5 neuronas "ocultas" y 3 neuronas de salida.

Red neuronal{.img-responsive}

Figura 2: Nuestra red neuronal feed-forward de tres capas.

El siguiente código define una función en la que creamos el modelo, definimos una función de pérdida que debe minimizarse y ejecutamos una sesión con 2000 iteraciones para aprender los pesos óptimos W_1 y W_2. Como se mencionó anteriormente, las matrices de entrada y salida se alimentan a los tensores tf.placeholder y los pesos se representan como variables porque sus valores cambian en cada iteración. La función de pérdida se define como el error cuadrático medio entre nuestra predicción y_est y el tipo de especie real y, y la función de activación que usamos es sigmoideo . La función create_train_model devuelve los pesos aprendidos e imprime el valor final de la función de pérdida.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# Create and train a tensorflow model of a neural network
def create_train_model(hidden_nodes, num_iters):
    
    # Reset the graph
    tf.reset_default_graph()

    # Placeholders for input and output data
    X = tf.placeholder(shape=(120, 4), dtype=tf.float64, name='X')
    y = tf.placeholder(shape=(120, 3), dtype=tf.float64, name='y')

    # Variables for two group of weights between the three layers of the network
    W1 = tf.Variable(np.random.rand(4, hidden_nodes), dtype=tf.float64)
    W2 = tf.Variable(np.random.rand(hidden_nodes, 3), dtype=tf.float64)

    # Create the neural net graph
    A1 = tf.sigmoid(tf.matmul(X, W1))
    y_est = tf.sigmoid(tf.matmul(A1, W2))

    # Define a loss function
    deltas = tf.square(y_est - y)
    loss = tf.reduce_sum(deltas)

    # Define a train operation to minimize the loss
    optimizer = tf.train.GradientDescentOptimizer(0.005)
    train = optimizer.minimize(loss)

    # Initialize variables and run session
    init = tf.global_variables_initializer()
    sess = tf.Session()
    sess.run(init)

    # Go through num_iters iterations
    for i in range(num_iters):
        sess.run(train, feed_dict={X: Xtrain, y: ytrain})
        loss_plot[hidden_nodes].append(sess.run(loss, feed_dict={X: Xtrain.as_matrix(), y: ytrain.as_matrix()}))
        weights1 = sess.run(W1)
        weights2 = sess.run(W2)
        
    print("loss (hidden nodes: %d, iterations: %d): %.2f" % (hidden_nodes, num_iters, loss_plot[hidden_nodes][-1]))
    sess.close()
    return weights1, weights2

Ok, vamos a crear las tres arquitecturas de red y trazar la función de pérdida sobre las iteraciones.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Run the training for 3 different network architectures: (4-5-3) (4-10-3) (4-20-3)

# Plot the loss function over iterations
num_hidden_nodes = [5, 10, 20]
loss_plot = {5: [], 10: [], 20: []}
weights1 = {5: None, 10: None, 20: None}
weights2 = {5: None, 10: None, 20: None}
num_iters = 2000

plt.figure(figsize=(12,8))
for hidden_nodes in num_hidden_nodes:
    weights1[hidden_nodes], weights2[hidden_nodes] = create_train_model(hidden_nodes, num_iters)
    plt.plot(range(num_iters), loss_plot[hidden_nodes], label="nn: 4-%d-3" % hidden_nodes)
    
plt.xlabel('Iteration', fontsize=12)
plt.ylabel('Loss', fontsize=12)
plt.legend(fontsize=12)
1
2
3
4
5
loss (hidden nodes: 5, iterations: 2000): 31.82
loss (hidden nodes: 10, iterations: 2000): 5.90
loss (hidden nodes: 20, iterations: 2000): 5.61

<matplotlib.legend.Legend at 0x123b157f0>

Función de pérdida durante el entrenamiento{.img-responsive}

Figura 3: La función de pérdida en 2000 iteraciones para diferentes arquitecturas de red.

Podemos ver que la red con 20 neuronas ocultas tarda más en llegar al mínimo, lo que se debe a su mayor complejidad. La red con 5 neuronas ocultas se atasca en un mínimo local y no dará buenos resultados.

De todos modos, para un conjunto de datos tan simple como Iris, incluso la pequeña red con 5 neuronas ocultas debería poder aprender un buen modelo. En nuestro caso, fue solo un evento aleatorio que el modelo se atascó en un mínimo local, y no sucedería muy a menudo si ejecutamos el código una y otra vez.

Evaluación del modelo

Finalmente, vamos a evaluar nuestros modelos. Usamos los pesos aprendidos W_1 y W_2 y propagamos hacia adelante los ejemplos del conjunto de prueba. La métrica de precisión se define como el porcentaje de ejemplos predichos correctamente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Evaluate models on the test set
X = tf.placeholder(shape=(30, 4), dtype=tf.float64, name='X')
y = tf.placeholder(shape=(30, 3), dtype=tf.float64, name='y')

for hidden_nodes in num_hidden_nodes:

    # Forward propagation
    W1 = tf.Variable(weights1[hidden_nodes])
    W2 = tf.Variable(weights2[hidden_nodes])
    A1 = tf.sigmoid(tf.matmul(X, W1))
    y_est = tf.sigmoid(tf.matmul(A1, W2))

    # Calculate the predicted outputs
    init = tf.global_variables_initializer()
    with tf.Session() as sess:
        sess.run(init)
        y_est_np = sess.run(y_est, feed_dict={X: Xtest, y: ytest})

    # Calculate the prediction accuracy
    correct = [estimate.argmax(axis=0) == target.argmax(axis=0) 
               for estimate, target in zip(y_est_np, ytest.as_matrix())]
    accuracy = 100 * sum(correct) / len(correct)
    print('Network architecture 4-%d-3, accuracy: %.2f%%' % (hidden_nodes, accuracy))
1
2
3
Network architecture 4-5-3, accuracy: 90.00%
Network architecture 4-10-3, accuracy: 96.67%
Network architecture 4-20-3, accuracy: 96.67%

En general, logramos lograr una precisión bastante alta con una red neuronal de avance simple, lo que es especialmente sorprendente al usar un conjunto de datos bastante pequeño.

Puedes echar un vistazo a un ejemplo aún más simple usando la API de alto nivel de TensorFlow aquí.

Recursos

Este tutorial solo cubrió una pequeña fracción de lo que TensorFlow puede hacer. Aquí hay algunos recursos excelentes para obtener más información sobre TensorFlow y el aprendizaje profundo en general:

Conclusiones

En esta publicación, presentamos la biblioteca TensorFlow para el aprendizaje automático, brindamos guías breves para la instalación, presentamos los componentes básicos de la API central de bajo nivel de TensorFlow: tensores, gráficos y sesiones, y finalmente construimos un modelo de red neuronal para la clasificación de datos reales. datos del conjunto de datos Iris.

En general, puede tomar algún tiempo comprender la filosofía de codificación de TensorFlow, ya que es una biblioteca simbólica, pero una vez que se familiariza con los componentes principales, es bastante conveniente para crear aplicaciones de aprendizaje automático. En esta publicación, usamos la API central de bajo nivel para presentar los componentes básicos y tener un control completo del modelo, pero generalmente es mucho más simple usar una API de nivel superior, como tf.estimator , o incluso una biblioteca externa, como Keras.