Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/es-419/guide/migrate/migrating_checkpoints.ipynb
25118 views
Kernel: Python 3
#@title Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

Migración de los puntos de verificación del modelo

Nota: Se suele llamar a los puntos de verificación guardados con tf.compat.v1.Saver como puntos de verificación TF1 o basados en nombres. A los puntos de verificación guardados con tf.train.Checkpoint se les llama puntos de verificación TF2 o basados en objetos.

Descripción general

Esta guía asume que usted tiene un modelo que guarda y carga puntos de verificación con tf.compat.v1.Saver, y desea migrar el código para usar la API tf.train.Checkpoint de TF2, o usar puntos de verificación preexistentes en su modelo TF2.

A continuación le presentamos algunos escenarios comunes con los que puede encontrarse:

Escenario 1

Existen puntos de verificación TF1 de entrenamientos anteriores que deben cargarse o convertirse a TF2.

Escenario 2

Está ajustando su modelo de forma que corre el riesgo de cambiar los nombres y las rutas de las variables (como cuando migra incrementalmente de get_variable a la creación explícita de tf.Variable), y le gustaría mantener el guardado/carga de los puntos de verificación existentes a lo largo del camino.

Consulte la sección sobre Cómo mantener la compatibilidad de puntos de verificación durante la migración de modelos

Escenario 3

Usted está migrando su código de entrenamiento y sus puntos de verificación a TF2, pero su canalización de inferencia sigue necesitando por ahora puntos de verificación de TF1 (para la estabilidad de la producción).

Option 1

Guarde los puntos de verificación de TF1 y TF2 durante el entrenamiento.

Option 2

Convierta el punto de verificación TF2 en TF1.


Los ejemplos siguientes muestran todas las combinaciones de guardado y carga de puntos de verificación en TF1/TF2, para que tenga cierta flexibilidad para determinar cómo migrar su modelo.

Preparación

import tensorflow as tf import tensorflow.compat.v1 as tf1 def print_checkpoint(save_path): reader = tf.train.load_checkpoint(save_path) shapes = reader.get_variable_to_shape_map() dtypes = reader.get_variable_to_dtype_map() print(f"Checkpoint at '{save_path}':") for key in shapes: print(f" (key='{key}', shape={shapes[key]}, dtype={dtypes[key].name}, " f"value={reader.get_tensor(key)})")

Cambios de TF1 a TF2

Esta sección se incluye por si tiene curiosidad sobre lo que ha cambiado entre el TF1 y el TF2, y lo que entendemos por puntos de verificación "basados en nombres" (TF1) frente a "basados en objetos" (TF2).

Los dos tipos de puntos de verificación se guardan en realidad en el mismo formato, que es esencialmente una tabla clave-valor. La diferencia radica en cómo se generan las claves.

Las claves en los puntos de verificación basados en nombres son los nombres de las variables. Las claves en los puntos de verificación basados en objetos se refieren a la ruta desde el objeto raíz hasta la variable (para comprender mejor lo que esto significa, vea los ejemplos siguientes).

En primer lugar, guarde algunos puntos de verificación:

with tf.Graph().as_default() as g: a = tf1.get_variable('a', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) b = tf1.get_variable('b', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) c = tf1.get_variable('scoped/c', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) with tf1.Session() as sess: saver = tf1.train.Saver() sess.run(a.assign(1)) sess.run(b.assign(2)) sess.run(c.assign(3)) saver.save(sess, 'tf1-ckpt') print_checkpoint('tf1-ckpt')
a = tf.Variable(5.0, name='a') b = tf.Variable(6.0, name='b') with tf.name_scope('scoped'): c = tf.Variable(7.0, name='c') ckpt = tf.train.Checkpoint(variables=[a, b, c]) save_path_v2 = ckpt.save('tf2-ckpt') print_checkpoint(save_path_v2)

Si observa las claves en tf2-ckpt, todas ellas se refieren a las rutas de los objetos de cada variable. Por ejemplo, la variable a es el primer elemento de la lista variables, por lo que su clave pasa a ser variables/0/... (siéntase libre de ignorar la constante .ATTRIBUTES/VARIABLE_VALOR).

A continuación, una inspección más detallada del objeto Checkpoint:

a = tf.Variable(0.) b = tf.Variable(0.) c = tf.Variable(0.) root = ckpt = tf.train.Checkpoint(variables=[a, b, c]) print("root type =", type(root).__name__) print("root.variables =", root.variables) print("root.variables[0] =", root.variables[0])

Experimente con el siguiente fragmento y vea cómo cambian las claves del punto de verificación con la estructura del objeto:

module = tf.Module() module.d = tf.Variable(0.) test_ckpt = tf.train.Checkpoint(v={'a': a, 'b': b}, c=c, module=module) test_ckpt_path = test_ckpt.save('root-tf2-ckpt') print_checkpoint(test_ckpt_path)

¿Por qué TF2 usa este mecanismo?

Como ya no hay grafo global en TF2, los nombres de las variables no son fiables y pueden ser inconsistentes entre programas. TF2 fomenta el enfoque de modelado orientado a objetos, en el que las variables son propiedad de capas, y las capas son propiedad de un modelo:

variable = tf.Variable(...) layer.variable_name = variable model.layer_name = layer

Cómo mantener la compatibilidad de los puntos de verificación durante la migración de modelos

Un paso importante en el proceso de migración es asegurarse de que todas las variables se inicializan con los valores correctos, que le permitirá a su vez validar que las op/funciones realizan los cálculos correctos. Para lograrlo, debe tener en cuenta la compatibilidad de puntos de verificación entre los modelos en las distintas etapas de la migración. Básicamente, esta sección responde a la pregunta cómo conservo el mismo punto de verificación mientras cambio el modelo.

A continuación se presentan tres formas de mantener la compatibilidad de los puntos de verificación, por orden de flexibilidad creciente:

  1. El modelo tiene los mismos nombres de variables que antes.

  2. El modelo tiene diferentes nombres de variables, y mantiene un mapa de asignación que esquematiza los nombres de las variables en el punto de verificación a los nuevos nombres.

  3. El modelo tiene diferentes nombres de variables y conserva un objeto Checkpoint TF2 que almacena todas las variables.

Cuando los nombres de las variables coinciden

Título largo: Cómo reutilizar los puntos de verificación cuando los nombres de las variables coinciden.

Respuesta corta: Puede cargar directamente el punto de verificación preexistente con tf1.train.Saver o tf.train.Checkpoint.


Si está usando tf.compat.v1.keras.utils.track_tf1_style_variables, entonces se asegurará de que los nombres de las variables de su modelo son los mismos que antes. También puede asegurarse manualmente de que los nombres de las variables coinciden.

Cuando los nombres de las variables coinciden en los modelos migrados, puede usar directamente tf.train.Checkpoint o tf.compat.v1.train.Saver para cargar el punto de verificación. Ambas API son compatibles con eager mode y modo grafo, por lo que puede usarlas en cualquier fase de la migración.

Nota: Puede usar tf.train.Checkpoint para cargar puntos de verificación TF1, pero no puede usar tf.compat.v1.Saver para cargar puntos de verificación TF2 sin una complicada coincidencia de nombres.

A continuación se muestran ejemplos de cómo usar el mismo punto de verificación con diferentes modelos. En primer lugar, guarde un punto de verificación TF1 con tf1.train.Saver:

with tf.Graph().as_default() as g: a = tf1.get_variable('a', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) b = tf1.get_variable('b', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) c = tf1.get_variable('scoped/c', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) with tf1.Session() as sess: saver = tf1.train.Saver() sess.run(a.assign(1)) sess.run(b.assign(2)) sess.run(c.assign(3)) save_path = saver.save(sess, 'tf1-ckpt') print_checkpoint(save_path)

El ejemplo siguiente usa tf.compat.v1.Saver para cargar el punto de verificación mientras está en eager mode:

a = tf.Variable(0.0, name='a') b = tf.Variable(0.0, name='b') with tf.name_scope('scoped'): c = tf.Variable(0.0, name='c') # With the removal of collections in TF2, you must pass in the list of variables # to the Saver object: saver = tf1.train.Saver(var_list=[a, b, c]) saver.restore(sess=None, save_path=save_path) print(f"loaded values of [a, b, c]: [{a.numpy()}, {b.numpy()}, {c.numpy()}]") # Saving also works in eager (sess must be None). path = saver.save(sess=None, save_path='tf1-ckpt-saved-in-eager') print_checkpoint(path)

El siguiente recorte de código carga el punto de verificación usando la APItf.train.Checkpoint de TF2:

a = tf.Variable(0.0, name='a') b = tf.Variable(0.0, name='b') with tf.name_scope('scoped'): c = tf.Variable(0.0, name='c') # Without the name_scope, name="scoped/c" works too: c_2 = tf.Variable(0.0, name='scoped/c') print("Variable names: ") print(f" a.name = {a.name}") print(f" b.name = {b.name}") print(f" c.name = {c.name}") print(f" c_2.name = {c_2.name}") # Restore the values with tf.train.Checkpoint ckpt = tf.train.Checkpoint(variables=[a, b, c, c_2]) ckpt.restore(save_path) print(f"loaded values of [a, b, c, c_2]: [{a.numpy()}, {b.numpy()}, {c.numpy()}, {c_2.numpy()}]")

Nombres de variables en TF2

  • Las variables siguen teniendo todas un argumento name que puede configurar.

  • Los modelos Keras también toman un argumento name que configuran como prefijo para sus variables.

  • La función v1.name_scope puede usarse para configurar los prefijos de los nombres de las variables. Esto es muy diferente de tf.variable_scope. Sólo afecta a los nombres, y no hace un seguimiento de las variables y su reutilización.

El decorador tf.compat.v1.keras.utils.track_tf1_style_variables es un shim que le ayuda a conservar los nombres de las variables y la compatibilidad con el punto de verificación TF1, conservando sin cambios la semántica de denominación y reutilización de tf.variable_scope y tf.compat.v1.get_variable. Consulte la Guía para mapear modelos para saber más.

Nota 1: Si está usando el shim, use las API del TF2 para cargar sus puntos de verificación (incluso cuando use puntos de verificación del TF1 preentrenados).

Consulte la sección Keras de punto de verificación.

Nota 2: Al migrar a tf.Variable desde get_variable:

Si su capa o módulo decorado con shim consta de algunas variables (o capas/modelos Keras) que usan tf.Variable en lugar de tf.compat.v1.get_variable y se anexan como propiedades/seguimiento según la orientación a objetos, pueden tener una semántica de nomenclatura de variables diferente en los grafos/sesiones TF1.x versus durante la ejecución eager.

En resumen, los nombres pueden no ser lo que usted espera que sean cuando se ejecuta en TF2.

Advertencia: Las variables pueden tener nombres duplicados en ejecución eager, lo que puede causar problemas si es necesario mapear varias variables del punto de verificación basado en nombres con el mismo nombre. Puede ajustar explícitamente la capa y los nombres de las variables usando tf.name_scope y el constructor de capa o los argumentos name de tf.Variable para ajustar los nombres de las variables y asegurarse de que no hay duplicados.

Actualizar los mapas de asignación

Los mapas de asignación se suelen usar para transferir ponderaciones entre modelos TF1, y también se pueden usar durante la migración de su modelo si cambian los nombres de las variables.

Puede usar estos mapas con tf.compat.v1.train.init_from_checkpoint, tf.compat.v1.train.Saver, y tf.train.load_checkpoint para cargar ponderaciones en modelos en los que los nombres de las variables o el ámbito pueden haber cambiado.

Los ejemplos de esta sección usarán un punto de verificación previamente guardado:

print_checkpoint('tf1-ckpt')

Carga con init_from_checkpoint

tf1.train.init_from_checkpoint debe llamarse mientras se está en un grafo/sesión, porque coloca los valores en los inicializadores de variables en lugar de crear una op de asignación.

Puede usar el argumento assignment_map para configurar cómo se cargan las variables. De la documentación:

El mapa de asignación admite la siguiente sintaxis:

  • 'checkpoint_scope_name/': 'scope_name/': cargará todas las variables del actual scope_name desde checkpoint_scope_name con nombres de tensor coincidentes.

  • 'checkpoint_scope_name/some_other_variable': 'scope_name/variable_name': inicializará la variable scope_name/variable_name de checkpoint_scope_name/some_other_variable.

  • 'scope_variable_name': variable: inicializará el objeto tf.Variable dado con el tensor 'scope_variable_name' del punto de verificación.

  • 'scope_variable_name': list(variable): inicializará la lista de variables particionadas con el tensor 'scope_variable_name' desde el punto de verificación.

  • '/': 'scope_name/': cargará todas las variables del scope_name actual desde la raíz del punto de verificación (por ejemplo, sin ámbito).

# Restoring with tf1.train.init_from_checkpoint: # A new model with a different scope for the variables. with tf.Graph().as_default() as g: with tf1.variable_scope('new_scope'): a = tf1.get_variable('a', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) b = tf1.get_variable('b', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) c = tf1.get_variable('scoped/c', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) with tf1.Session() as sess: # The assignment map will remap all variables in the checkpoint to the # new scope: tf1.train.init_from_checkpoint( 'tf1-ckpt', assignment_map={'/': 'new_scope/'}) # `init_from_checkpoint` adds the initializers to these variables. # Use `sess.run` to run these initializers. sess.run(tf1.global_variables_initializer()) print("Restored [a, b, c]: ", sess.run([a, b, c]))

Carga con tf1.train.Saver

A diferencia de init_from_checkpoint, tf.compat.v1.train.Saver se ejecuta tanto en modo grafo como en eager mode. El argumento var_list acepta opcionalmente un diccionario, con la salvedad de que debe mapear los nombres de las variables al objeto tf.Variable.

# Restoring with tf1.train.Saver (works in both graph and eager): # A new model with a different scope for the variables. with tf1.variable_scope('new_scope'): a = tf1.get_variable('a', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) b = tf1.get_variable('b', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) c = tf1.get_variable('scoped/c', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) # Initialize the saver with a dictionary with the original variable names: saver = tf1.train.Saver({'a': a, 'b': b, 'scoped/c': c}) saver.restore(sess=None, save_path='tf1-ckpt') print("Restored [a, b, c]: ", [a.numpy(), b.numpy(), c.numpy()])

Carga con tf.train.load_checkpoint

Esta opción es para usted si necesita un control preciso sobre los valores de las variables. Nuevamente, esto funciona tanto en modo grafo como en eager mode.

# Restoring with tf.train.load_checkpoint (works in both graph and eager): # A new model with a different scope for the variables. with tf.Graph().as_default() as g: with tf1.variable_scope('new_scope'): a = tf1.get_variable('a', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) b = tf1.get_variable('b', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) c = tf1.get_variable('scoped/c', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) with tf1.Session() as sess: # It may be easier writing a loop if your model has a lot of variables. reader = tf.train.load_checkpoint('tf1-ckpt') sess.run(a.assign(reader.get_tensor('a'))) sess.run(b.assign(reader.get_tensor('b'))) sess.run(c.assign(reader.get_tensor('scoped/c'))) print("Restored [a, b, c]: ", sess.run([a, b, c]))

Actualizar un objeto de punto de verificación de TF2

Si los nombres de las variables y del ámbito pueden cambiar mucho durante la migración, entonces usa tf.train.Checkpoint y puntos de verificación TF2. TF2 usa la estructura de objetos en lugar de nombres de variables (más información en Cambios de TF1 a TF2).

En resumen, cuando crees un tf.train.Checkpoint para guardar o restaurar puntos de verificación, asegúrate de que usa el mismo ordenamiento (para listas) y claves (para diccionarios y argumentos de palabras clave para el inicializador Checkpoint). Algunos ejemplos de compatibilidad de puntos de verificación:

ckpt = tf.train.Checkpoint(foo=[var_a, var_b]) # compatible with ckpt tf.train.Checkpoint(foo=[var_a, var_b]) # not compatible with ckpt tf.train.Checkpoint(foo=[var_b, var_a]) tf.train.Checkpoint(bar=[var_a, var_b])

Las muestras de código que aparecen a continuación muestran cómo usar el "mismo" tf.train.Checkpoint para cargar variables con nombres diferentes. Primero, guarda un punto de verificación TF2:

with tf.Graph().as_default() as g: a = tf1.get_variable('a', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(1)) b = tf1.get_variable('b', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(2)) with tf1.variable_scope('scoped'): c = tf1.get_variable('c', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(3)) with tf1.Session() as sess: sess.run(tf1.global_variables_initializer()) print("[a, b, c]: ", sess.run([a, b, c])) # Save a TF2 checkpoint ckpt = tf.train.Checkpoint(unscoped=[a, b], scoped=[c]) tf2_ckpt_path = ckpt.save('tf2-ckpt') print_checkpoint(tf2_ckpt_path)

Puede conservar el uso de tf.train.Checkpoint aunque cambien los nombres de las variables/ámbitos:

with tf.Graph().as_default() as g: a = tf1.get_variable('a_different_name', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) b = tf1.get_variable('b_different_name', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) with tf1.variable_scope('different_scope'): c = tf1.get_variable('c', shape=[], dtype=tf.float32, initializer=tf1.zeros_initializer()) with tf1.Session() as sess: sess.run(tf1.global_variables_initializer()) print("Initialized [a, b, c]: ", sess.run([a, b, c])) ckpt = tf.train.Checkpoint(unscoped=[a, b], scoped=[c]) # `assert_consumed` validates that all checkpoint objects are restored from # the checkpoint. `run_restore_ops` is required when running in a TF1 # session. ckpt.restore(tf2_ckpt_path).assert_consumed().run_restore_ops() # Removing `assert_consumed` is fine if you want to skip the validation. # ckpt.restore(tf2_ckpt_path).run_restore_ops() print("Restored [a, b, c]: ", sess.run([a, b, c]))

Y en eager mode:

a = tf.Variable(0.) b = tf.Variable(0.) c = tf.Variable(0.) print("Initialized [a, b, c]: ", [a.numpy(), b.numpy(), c.numpy()]) # The keys "scoped" and "unscoped" are no longer relevant, but are used to # maintain compatibility with the saved checkpoints. ckpt = tf.train.Checkpoint(unscoped=[a, b], scoped=[c]) ckpt.restore(tf2_ckpt_path).assert_consumed().run_restore_ops() print("Restored [a, b, c]: ", [a.numpy(), b.numpy(), c.numpy()])

Puntos de verificación de TF2 en Estimator

Las secciones anteriores describen cómo mantener la compatibilidad de los puntos de verificación mientras migra su modelo. Estos conceptos también se aplican a los modelos Estimator, aunque la forma en que se guarda/carga el punto de verificación es ligeramente diferente. Al migrar su modelo Estimator para usar las API TF2, es posible que desee cambiar los puntos de verificación {nbsp}de TF1 a TF2 mientras el modelo sigue usando Estimator. Esta sección muestra cómo hacerlo.

tf.estimator.Estimator y MonitoredSession tienen un mecanismo de guardado llamado scaffold, un objeto tf.compat.v1.train.Scaffold. El Scaffold puede contener un tf1.train.Saver o tf.train.Checkpoint, que permite a Estimator y MonitoredSession guardar puntos de verificación del estilo TF1 o TF2.

# A model_fn that saves a TF1 checkpoint def model_fn_tf1_ckpt(features, labels, mode): # This model adds 2 to the variable `v` in every train step. train_step = tf1.train.get_or_create_global_step() v = tf1.get_variable('var', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(0)) return tf.estimator.EstimatorSpec( mode, predictions=v, train_op=tf.group(v.assign_add(2), train_step.assign_add(1)), loss=tf.constant(1.), scaffold=None ) !rm -rf est-tf1 est = tf.estimator.Estimator(model_fn_tf1_ckpt, 'est-tf1') def train_fn(): return tf.data.Dataset.from_tensor_slices(([1,2,3], [4,5,6])) est.train(train_fn, steps=1) latest_checkpoint = tf.train.latest_checkpoint('est-tf1') print_checkpoint(latest_checkpoint)
# A model_fn that saves a TF2 checkpoint def model_fn_tf2_ckpt(features, labels, mode): # This model adds 2 to the variable `v` in every train step. train_step = tf1.train.get_or_create_global_step() v = tf1.get_variable('var', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(0)) ckpt = tf.train.Checkpoint(var_list={'var': v}, step=train_step) return tf.estimator.EstimatorSpec( mode, predictions=v, train_op=tf.group(v.assign_add(2), train_step.assign_add(1)), loss=tf.constant(1.), scaffold=tf1.train.Scaffold(saver=ckpt) ) !rm -rf est-tf2 est = tf.estimator.Estimator(model_fn_tf2_ckpt, 'est-tf2', warm_start_from='est-tf1') def train_fn(): return tf.data.Dataset.from_tensor_slices(([1,2,3], [4,5,6])) est.train(train_fn, steps=1) latest_checkpoint = tf.train.latest_checkpoint('est-tf2') print_checkpoint(latest_checkpoint) assert est.get_variable_value('var_list/var/.ATTRIBUTES/VARIABLE_VALUE') == 4

El valor final de v debería ser 16, después de haber sido templado desde est-tf1, y luego entrenado durante 5 pasos adicionales. El valor del paso de entrenamiento no se arrastra desde el punto de verificación warm_start.

Usar puntos de verificación de Keras

Los modelos creados con Keras siguen usando tf1.train.Saver y tf.train.Checkpoint para cargar las ponderaciones preexistentes. Cuando tu modelo esté totalmente migrado, pasa a usar model.save_weights y model.load_weights, especialmente si estás usando la retrollamada ModelCheckpoint durante el entrenamiento.

Algunas cosas que debes saber sobre los puntos de verificación y Keras:

Inicialización vs Construcción

Los modelos Keras y las capas deben pasar por dos pasos antes de crearse por completo. El primero es la inicialización del objeto Python: layer = tf.keras.capas.Dense(x). El segundo es el paso build, en el que se crean realmente la mayoría de las ponderaciones: layer.build(input_shape). También puede construir un modelo llamándolo o ejecutando un único paso train, eval o predict (sólo la primera vez).

Si encuentras que model.load_weights(path).assert_consumed() produce un error, es probable que el modelo/las capas no se hayan construido.

Keras usa los puntos de verificación de TF2

tf.train.Checkpoint(model).write es equivalente a model.save_weights. Lo mismo ocurre con tf.train.Checkpoint(model).read y model.load_weights. Ten en cuenta que Checkpoint(model) != Checkpoint(model=model).

Los puntos de verificación TF2 funcionan con el paso build() de Keras

tf.train.Checkpoint.restore tiene un mecanismo llamado restauración diferida que permite a tf.Module y a los objetos Keras almacenar valores de variables si éstas aún no se han creado. Esto permite a los modelos inicializados cargar ponderaciones y construir después.

m = YourKerasModel() status = m.load_weights(path) # This call builds the model. The variables are created with the restored # values. m.predict(inputs) status.assert_consumed()

Debido a este mecanismo, te recomendamos encarecidamente que uses las API de carga de puntos de verificación TF2 con modelos Keras (incluso al restaurar puntos de verificación TF1 preexistentes en las shims de mapeo de modelos). Más información en la guía de puntos de verificación.

Recortes de código

Los recortes siguientes muestran la compatibilidad de las versiones TF1/TF2 en las API de guardado de puntos de verificación.

Guardar un punto de verificación de TF1 en TF2

a = tf.Variable(1.0, name='a') b = tf.Variable(2.0, name='b') with tf.name_scope('scoped'): c = tf.Variable(3.0, name='c') saver = tf1.train.Saver(var_list=[a, b, c]) path = saver.save(sess=None, save_path='tf1-ckpt-saved-in-eager') print_checkpoint(path)

Cargar un punto de verificación de TF1 en TF2

a = tf.Variable(0., name='a') b = tf.Variable(0., name='b') with tf.name_scope('scoped'): c = tf.Variable(0., name='c') print("Initialized [a, b, c]: ", [a.numpy(), b.numpy(), c.numpy()]) saver = tf1.train.Saver(var_list=[a, b, c]) saver.restore(sess=None, save_path='tf1-ckpt-saved-in-eager') print("Restored [a, b, c]: ", [a.numpy(), b.numpy(), c.numpy()])

Guardar un punto de verificación de TF2 en TF1

with tf.Graph().as_default() as g: a = tf1.get_variable('a', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(1)) b = tf1.get_variable('b', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(2)) with tf1.variable_scope('scoped'): c = tf1.get_variable('c', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(3)) with tf1.Session() as sess: sess.run(tf1.global_variables_initializer()) ckpt = tf.train.Checkpoint( var_list={v.name.split(':')[0]: v for v in tf1.global_variables()}) tf2_in_tf1_path = ckpt.save('tf2-ckpt-saved-in-session') print_checkpoint(tf2_in_tf1_path)

Cargar un punto de verificación de TF2 en TF1

with tf.Graph().as_default() as g: a = tf1.get_variable('a', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(0)) b = tf1.get_variable('b', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(0)) with tf1.variable_scope('scoped'): c = tf1.get_variable('c', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(0)) with tf1.Session() as sess: sess.run(tf1.global_variables_initializer()) print("Initialized [a, b, c]: ", sess.run([a, b, c])) ckpt = tf.train.Checkpoint( var_list={v.name.split(':')[0]: v for v in tf1.global_variables()}) ckpt.restore('tf2-ckpt-saved-in-session-1').run_restore_ops() print("Restored [a, b, c]: ", sess.run([a, b, c]))

Conversión de puntos de verificación

Puede convertir los puntos de verificación entre TF1 y TF2 cargándolos y volviéndolos a guardar. Una alternativa es tf.train.load_checkpoint, que se muestra en el código siguiente.

Convertir el punto de verificación TF1 a TF2

def convert_tf1_to_tf2(checkpoint_path, output_prefix): """Converts a TF1 checkpoint to TF2. To load the converted checkpoint, you must build a dictionary that maps variable names to variable objects. ``` ckpt = tf.train.Checkpoint(vars={name: variable}) ckpt.restore(converted_ckpt_path) ``` Args: checkpoint_path: Path to the TF1 checkpoint. output_prefix: Path prefix to the converted checkpoint. Returns: Path to the converted checkpoint. """ vars = {} reader = tf.train.load_checkpoint(checkpoint_path) dtypes = reader.get_variable_to_dtype_map() for key in dtypes.keys(): vars[key] = tf.Variable(reader.get_tensor(key)) return tf.train.Checkpoint(vars=vars).save(output_prefix)

Convierta el punto de verificación guardado en el recorte Save a TF1 checkpoint in TF2:

# Make sure to run the snippet in `Save a TF1 checkpoint in TF2`. print_checkpoint('tf1-ckpt-saved-in-eager') converted_path = convert_tf1_to_tf2('tf1-ckpt-saved-in-eager', 'converted-tf1-to-tf2') print("\n[Converted]") print_checkpoint(converted_path) # Try loading the converted checkpoint. a = tf.Variable(0.) b = tf.Variable(0.) c = tf.Variable(0.) ckpt = tf.train.Checkpoint(vars={'a': a, 'b': b, 'scoped/c': c}) ckpt.restore(converted_path).assert_consumed() print("\nRestored [a, b, c]: ", [a.numpy(), b.numpy(), c.numpy()])

Convertir el punto de verificación TF2 a TF1

def convert_tf2_to_tf1(checkpoint_path, output_prefix): """Converts a TF2 checkpoint to TF1. The checkpoint must be saved using a `tf.train.Checkpoint(var_list={name: variable})` To load the converted checkpoint with `tf.compat.v1.Saver`: ``` saver = tf.compat.v1.train.Saver(var_list={name: variable}) # An alternative, if the variable names match the keys: saver = tf.compat.v1.train.Saver(var_list=[variables]) saver.restore(sess, output_path) ``` """ vars = {} reader = tf.train.load_checkpoint(checkpoint_path) dtypes = reader.get_variable_to_dtype_map() for key in dtypes.keys(): # Get the "name" from the if key.startswith('var_list/'): var_name = key.split('/')[1] # TF2 checkpoint keys use '/', so if they appear in the user-defined name, # they are escaped to '.S'. var_name = var_name.replace('.S', '/') vars[var_name] = tf.Variable(reader.get_tensor(key)) return tf1.train.Saver(var_list=vars).save(sess=None, save_path=output_prefix)

Convierta el punto de verificación guardado en el recorte Save a TF2 checkpoint in TF1:

# Make sure to run the snippet in `Save a TF2 checkpoint in TF1`. print_checkpoint('tf2-ckpt-saved-in-session-1') converted_path = convert_tf2_to_tf1('tf2-ckpt-saved-in-session-1', 'converted-tf2-to-tf1') print("\n[Converted]") print_checkpoint(converted_path) # Try loading the converted checkpoint. with tf.Graph().as_default() as g: a = tf1.get_variable('a', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(0)) b = tf1.get_variable('b', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(0)) with tf1.variable_scope('scoped'): c = tf1.get_variable('c', shape=[], dtype=tf.float32, initializer=tf1.constant_initializer(0)) with tf1.Session() as sess: saver = tf1.train.Saver([a, b, c]) saver.restore(sess, converted_path) print("\nRestored [a, b, c]: ", sess.run([a, b, c]))

Guías relacionadas