TensorFlow: guardar y restaurar modelos

Entrenar un modelo de red neuronal profunda puede llevar bastante tiempo, dependiendo de la complejidad de su modelo, la cantidad de datos que tenga, el hardware que esté ejecutando...

Entrenar un modelo de red neuronal profunda puede llevar bastante tiempo, dependiendo de la complejidad de su modelo, la cantidad de datos que tenga, el hardware en el que está ejecutando sus modelos, etc. En la mayoría de las ocasiones, necesitará para guardar su progreso en un archivo, por lo que en caso de interrupción (o error), podrá continuar donde lo dejó.

Aún más, después de un entrenamiento exitoso, seguramente necesitará reutilizar los parámetros aprendidos del modelo para hacer predicciones sobre nuevos datos. Este es el caso de cualquier plataforma de aprendizaje profundo, como TensorFlow.

En esta publicación, analizamos cómo guardar y restaurar un modelo de TensorFlow, describimos algunas de las opciones más útiles en el camino y brindamos algunos ejemplos.

Introducción rápida del modelo TensorFlow

La funcionalidad principal de TensorFlow se entrega a través de tensores, su estructura de datos básica similar a las matrices multidimensionales en NumPy, y gráficos, que representan los cálculos de los datos. Es una biblioteca simbólica, lo que significa que definir un gráfico y tensores solo crearía un modelo, mientras que los tensores obtienen valores concretos y las operaciones se ejecutan dentro de una sesión, un mecanismo para ejecutar las operaciones modeladas en un gráfico. Cualquier valor concreto de los tensores se pierde cuando se cierra una sesión, que es otra razón para guardar sus modelos en un archivo después de ejecutar una sesión.

Siempre es más fácil de entender a través de ejemplos, así que vamos a crear un modelo TensorFlow simple para la regresión lineal de datos bidimensionales.

Primero, importaremos nuestras bibliotecas:

1
2
3
4
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

El siguiente paso es crear el modelo. Generaremos un modelo que estimará el desplazamiento horizontal y vertical de una función cuadrática en la forma:

1
y = (x - h) ^ 2 + v

donde h y v son los desplazamientos horizontal y vertical.

Las siguientes líneas generan el modelo (ver comentarios en el código para más detalles):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# Clear the current graph in each run, to avoid variable duplication
tf.reset_default_graph()

# Create placeholders for the x and y points
X = tf.placeholder("float")
Y = tf.placeholder("float")

# Initialize the two parameters that need to be learned
h_est = tf.Variable(0.0, name='hor_estimate')
v_est = tf.Variable(0.0, name='ver_estimate')

# y_est holds the estimated values on y-axis
y_est = tf.square(X - h_est) + v_est

# Define a cost function as the squared distance between Y and y_est
cost = (tf.pow(Y - y_est, 2))

# The training operation for minimizing the cost function. The
# learning rate is 0.001
trainop = tf.train.GradientDescentOptimizer(0.001).minimize(cost)

En este punto tenemos el modelo que se debe ejecutar en una Sesión, pasándole algunos datos reales. Generemos algunos datos cuadráticos de ejemplo y agreguemos ruido.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Use some values for the horizontal and vertical shift
h = 1
v = -2

# Generate training data with noise
x_train = np.linspace(-2,4,201)
noise = np.random.randn(*x_train.shape) * 0.4
y_train = (x_train - h) ** 2 + v + noise

# Visualize the data 
plt.rcParams['figure.figsize'] = (10, 6)
plt.scatter(x_train, y_train)
plt.xlabel('x_train')
plt.ylabel('y_train')

Estimación de función cuadrática{.img-responsive}

La clase Saver

La clase Saver proporcionada por la biblioteca TensorFlow es la forma recomendada de guardar la estructura y las variables del gráfico.

Modelos de ahorro {#modelos de ahorro}

En las siguientes líneas, definimos un objeto Saver y dentro del método train_graph() realizamos 100 iteraciones para minimizar la función de costo. Luego, el modelo se guarda en el disco en cada iteración, así como después de que finaliza la optimización. Cada guardado crea archivos binarios en el disco llamados "puntos de control".

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Create a Saver object
saver = tf.train.Saver()

init = tf.global_variables_initializer()

# Run a session. Go through 100 iterations to minimize the cost
def train_graph():
    with tf.Session() as sess:
        sess.run(init)
        for i in range(100):
            for (x, y) in zip(x_train, y_train):
                
                # Feed actual data to the train operation
                sess.run(trainop, feed_dict={X: x, Y: y})
            
            # Create a checkpoint in every iteration
            saver.save(sess, 'model_iter', global_step=i)
        
        # Save the final model
        saver.save(sess, 'model_final')
        h_ = sess.run(h_est)
        v_ = sess.run(v_est)
    return h_, v_

Ahora entrenemos el modelo con la función anterior e imprimamos los parámetros aprendidos.

1
2
result = train_graph()
print("h_est = %.2f, v_est = %.2f" % result)
1
2
$ python tf_save.py
h_est = 1.01, v_est = -1.96

De acuerdo, los parámetros se estimaron con bastante precisión. Si revisamos nuestro sistema de archivos, hay archivos guardados para las últimas 4 iteraciones, así como el modelo final.

Al guardar el modelo, notará que se necesitan 4 tipos de archivos para guardarlo:

  • Archivos ".meta": que contienen la estructura del gráfico
  • Archivos ".data": que contienen los valores de las variables
  • Archivos ".index": identificación del punto de control
  • Archivo "punto de control": un búfer de protocolo con una lista de puntos de control recientes

Saved model files{.img-responsive}

Figura 1: Archivos de puntos de control guardados en el disco

Llamar al método tf.train.Saver(), como se muestra arriba, guardaría todas las variables en un archivo. Es posible guardar un subconjunto de sus variables pasándolas como un argumento a través de una lista o un dictado, por ejemplo: tf.train.Saver({'hor_estimate': h_est}).

Algunos otros argumentos útiles del constructor Saver, que permiten el control de todo el proceso, son:

  • max_to_keep: número máximo de puntos de control a mantener,
  • keep_checkpoint_every_n_hours: un intervalo de tiempo para guardar puntos de control

Para obtener más información, consulte la documentación oficial para la clase Saver, que ofrece otros argumentos útiles que puede explorar.

Restauración de modelos

Lo primero que debe hacer al restaurar un modelo de TensorFlow es cargar la estructura del gráfico desde el archivo ".meta" en el gráfico actual.

1
2
tf.reset_default_graph()
imported_meta = tf.train.import_meta_graph("model_final.meta")

El gráfico actual podría explorarse usando el siguiente comando tf.get_default_graph(). Ahora, el segundo paso es cargar los valores de las variables.

Un recordatorio: los valores solo existen dentro de una sesión.

1
2
3
4
5
with tf.Session() as sess:
    imported_meta.restore(sess, tf.train.latest_checkpoint('./'))
    h_est2 = sess.run('hor_estimate:0')
    v_est2 = sess.run('ver_estimate:0')
    print("h_est: %.2f, v_est: %.2f" % (h_est2, v_est2))
1
2
3
$ python tf_restore.py
INFO:tensorflow:Restoring parameters from ./model_final
h_est: 1.01, v_est: -1.96

Como se mencionó anteriormente, este enfoque solo guarda la estructura del gráfico y las variables, lo que significa que los datos de entrenamiento que se ingresan a través de nuestros marcadores de posición 'X' e 'Y' no se guardan.

De todos modos, para este ejemplo usaremos nuestros datos de entrenamiento definidos a partir de tf y visualizaremos el ajuste del modelo.

1
2
3
4
5
plt.scatter(x_train, y_train, label='train data')
plt.plot(x_train, (x_train - h_est2) ** 2 + v_est2, color='red', label='model')
plt.xlabel('x_train')
plt.ylabel('y_train')
plt.legend()

Visualized model fit{.img-responsive}

Como resultado final de esta parte, la clase Saver permite una manera fácil de guardar y restaurar su modelo de TensorFlow (gráfico y variables) a/desde un archivo, y mantener múltiples puntos de control de su trabajo que podrían ser útiles para probar su modelo. en nuevos datos, continuar entrenándolos y ajustándolos aún más.

El formato del modelo guardado

Un nuevo enfoque para guardar y restaurar un modelo en TensorFlow es usar la funcionalidad GuardadoModelo, constructor y cargador . En realidad, esto envuelve la clase Saver para proporcionar una serialización de nivel superior, que es más adecuada para fines de producción.

Si bien el enfoque SavedModel parece no ser completamente aceptado por los desarrolladores todavía, sus creadores señalan que es claramente el futuro. En comparación con la clase Saver, que se centra principalmente en las variables, SavedModel intenta abarcar muchas funciones útiles en un solo paquete, como Signatures, que permite guardar gráficos que tienen un conjunto de entradas y salidas, y Activos que contiene archivos externos utilizados en la inicialización.

Guardar modelos con el Generador de modelos guardados

El guardado de un modelo se realiza utilizando la clase SavedModelBuilder. En nuestro ejemplo, no usamos firmas ni activos, pero es suficiente para ilustrar el proceso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
tf.reset_default_graph()

# Re-initialize our two variables
h_est = tf.Variable(h_est2, name='hor_estimate2')
v_est = tf.Variable(v_est2, name='ver_estimate2')

# Create a builder
builder = tf.saved_model.builder.SavedModelBuilder('./SavedModel/')

# Add graph and variables to builder and save
with tf.Session() as sess:
    sess.run(h_est.initializer)
    sess.run(v_est.initializer)
    builder.add_meta_graph_and_variables(sess,
                                       [tf.saved_model.tag_constants.TRAINING],
                                       signature_def_map=None,
                                       assets_collection=None)
builder.save()
1
2
3
4
$ python tf_saved_model_builder.py
INFO:tensorflow:No assets to save.
INFO:tensorflow:No assets to write.
INFO:tensorflow:SavedModel written to: b'./SavedModel/saved_model.pb'

Al ejecutar este código, notará que nuestro modelo se guarda en el archivo ubicado en "./SavedModel/saved_model.pb".

Restauración de modelos con el cargador de modelos guardados

La restauración del modelo se realiza mediante tf.saved_model.loader y restaura las variables, firmas y activos guardados en el ámbito de una sesión.

En el siguiente ejemplo, cargaremos el modelo e imprimiremos los valores de nuestros dos coeficientes h_est y v_est.

1
2
3
4
5
with tf.Session() as sess:
    tf.saved_model.loader.load(sess, [tf.saved_model.tag_constants.TRAINING], './SavedModel/')
    h_est = sess.run('hor_estimate2:0')
    v_est = sess.run('ver_estimate2:0')
    print("h_est: %.2f, v_est: %.2f" % (h_est, v_est))
1
2
3
$ python tf_saved_model_loader.py
INFO:tensorflow:Restoring parameters from b'./SavedModel/variables/variables'
h_est: 1.01, v_est: -1.96

Y nuevamente, como se esperaba, nuestro modelo se restauró con éxito con los parámetros entrenados correctos.

Conclusión

Guardar y restaurar un modelo de TensorFlow es una función muy útil, sabiendo que el entrenamiento de redes profundas puede llevar mucho tiempo. El tema es demasiado amplio para cubrirlo en detalle en una sola publicación de blog, por lo que podemos volver a tratarlo en una publicación futura.

De todos modos, en esta publicación presentamos dos herramientas: la clase básica Saver que guarda el modelo en forma de puntos de control, y SavedModel builder/loader que se construye sobre Saver y crea un archivo estructura que es fácil de usar en la producción. Se utilizó una regresión lineal simple para ilustrar los ejemplos. ejemplos.