Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/es-419/guide/keras/save_and_serialize.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.

Guardar y cargar modelos de Keras

Introducción

Un modelo de Keras consiste en múltiples componentes:

  • La arquitectura, o configuración, que especifica qué capas contiene el modelo y cómo están conectadas.

  • Un conjunto de valores de ponderaciones (el "estado del modelo").

  • Un optimizador (definido al compilar el modelo).

  • Un conjunto de pérdidas y métricas (definidas al compilar el modelo o llamar a add_loss() o add_metric()).

La API de Keras permite guardar todas estas piezas en el disco a la vez, o guardar solo algunas de ellas de forma selectiva:

  • Guardar todo en un único archivo en el formato TensorFlow SavedModel (o en el antiguo formato Keras H5). Esta es la práctica estándar.

  • Guardar solo la arquitectura / configuración, normalmente como un archivo JSON.

  • Guardar solo los valores de las ponderaciones. Esto se utiliza generalmente cuando se entrena el modelo.

Veamos cada una de estas opciones. ¿Cuándo utilizarías una u otra y cómo funcionan?

Cómo guardar y cargar un modelo

Si solo dispone de 10 segundos para leer esta guía, esto es lo que necesita saber.

Guardar un modelo de Keras:

model = ... # Get model (Sequential, Functional Model, or Model subclass) model.save('path/to/location')

Cargando el modelo de nuevo:

from tensorflow import keras model = keras.models.load_model('path/to/location')

Ahora, veamos los detalles.

Preparación

import numpy as np import tensorflow as tf from tensorflow import keras

Guardar y cargar modelos completos

Puede guardar un modelo completo en un solo artefacto. Esto incluirá:

  • La arquitectura/configuración del modelo

  • Los valores de ponderación del modelo (aprendidos durante el entrenamiento)

  • La información de compilación del modelo (si se llamó a compile()).

  • El optimizador y su estado, según corresponda (esto le permite reiniciar el entrenamiento donde lo dejó)

APIs

  • model.save() o tf.keras.models.save_model()

  • tf.keras.models.load_model()

Hay dos formatos que puede utilizar para guardar un modelo completo en el disco: el formato SavedModel de TensorFlow, y el formato más antiguo de Keras H5. El formato recomendado es SavedModel. Es el predeterminado cuando se utiliza model.save().

Puede cambiar al formato H5:

  • Pasar save_format='h5' a save().

  • Pasar un nombre de archivo que termine en .h5 o .keras a save().

Formato SavedModel

SavedModel es el formato de almacenamiento más completo que guarda la arquitectura del modelo, las ponderaciones y los subgrafos de Tensorflow rastreadas de las funciones de llamada. Esto permite que Keras restaure tanto las capas incorporadas como los objetos personalizados.

Ejemplo:

def get_model(): # Create a simple model. inputs = keras.Input(shape=(32,)) outputs = keras.layers.Dense(1)(inputs) model = keras.Model(inputs, outputs) model.compile(optimizer="adam", loss="mean_squared_error") return model model = get_model() # Train the model. test_input = np.random.random((128, 32)) test_target = np.random.random((128, 1)) model.fit(test_input, test_target) # Calling `save('my_model')` creates a SavedModel folder `my_model`. model.save("my_model") # It can be used to reconstruct the model identically. reconstructed_model = keras.models.load_model("my_model") # Let's check: np.testing.assert_allclose( model.predict(test_input), reconstructed_model.predict(test_input) ) # The reconstructed model is already compiled and has retained the optimizer # state, so training can resume: reconstructed_model.fit(test_input, test_target)

¿Qué contiene el SavedModel?

Al llamar a model.save('my_model') se crea una carpeta llamada my_model, que contiene lo siguiente:

!ls my_model

La arquitectura del modelo y la configuración de entrenamiento (incluyendo el optimizador, las pérdidas y las métricas) se guardan en saved_model.pb. Las ponderaciones se guardan en el directorio variables/.

Para obtener información detallada sobre el formato SavedModel, consulte la guía SavedModel (El formato SavedModel en el disco).

Cómo administra SavedModel los objetos personalizados

Al guardar el modelo y sus capas, el formato SavedModel almacena el nombre de la clase, la función de llamada, las pérdidas y las ponderaciones (y la configuración, si está implementada). La función de llamada define el grafo de cálculo del modelo/ la capa.

En ausencia de la configuración del modelo/capa, la función de llamada se utiliza para crear un modelo que existe como el modelo original que puede ser entrenado, evaluado y utilizado para hacer inferencias.

No obstante, siempre es una práctica recomendable definir los métodos get_config y from_config al escribir un modelo personalizado o una clase de capa. Esto le permite actualizar fácilmente el cálculo más tarde si es necesario. Consulte la sección sobre Objetos personalizados para obtener más información.

Ejemplo:

class CustomModel(keras.Model): def __init__(self, hidden_units): super(CustomModel, self).__init__() self.hidden_units = hidden_units self.dense_layers = [keras.layers.Dense(u) for u in hidden_units] def call(self, inputs): x = inputs for layer in self.dense_layers: x = layer(x) return x def get_config(self): return {"hidden_units": self.hidden_units} @classmethod def from_config(cls, config): return cls(**config) model = CustomModel([16, 16, 10]) # Build the model by calling it input_arr = tf.random.uniform((1, 5)) outputs = model(input_arr) model.save("my_model") # Option 1: Load with the custom_object argument. loaded_1 = keras.models.load_model( "my_model", custom_objects={"CustomModel": CustomModel} ) # Option 2: Load without the CustomModel class. # Delete the custom-defined model class to ensure that the loader does not have # access to it. del CustomModel loaded_2 = keras.models.load_model("my_model") np.testing.assert_allclose(loaded_1(input_arr), outputs) np.testing.assert_allclose(loaded_2(input_arr), outputs) print("Original model:", model) print("Model Loaded with custom objects:", loaded_1) print("Model loaded without the custom object class:", loaded_2)

El primer modelo cargado se hace mediante la clase config y CustomModel. El segundo modelo se carga creando de forma dinámica la clase model que actúa como el modelo original.

Cómo configurar el SavedModel

Nuevo en TensoFlow 2.4 Se agregó el argumento save_traces a model.save, el cual permite activar el rastreo de funciones de SavedModel. Las funciones se guardan para permitir a Keras volver a cargar objetos personalizados sin las definiciones de clase originales, por lo que cuando save_traces=False, todos los objetos personalizados deben tener métodos get_config/from_config definidos. Al cargar, los objetos personalizados deben pasarse al argumento custom_objects. save_traces=False reduce el espacio en disco utilizado por el SavedModel y el tiempo de ahorro.

Formato Keras H5

Keras también permite guardar un solo archivo HDF5 que contiene la arquitectura del modelo, los valores de las ponderaciones y la información compile(). Es una alternativa ligera a SavedModel.

Ejemplo:

model = get_model() # Train the model. test_input = np.random.random((128, 32)) test_target = np.random.random((128, 1)) model.fit(test_input, test_target) # Calling `save('my_model.h5')` creates a h5 file `my_model.h5`. model.save("my_h5_model.h5") # It can be used to reconstruct the model identically. reconstructed_model = keras.models.load_model("my_h5_model.h5") # Let's check: np.testing.assert_allclose( model.predict(test_input), reconstructed_model.predict(test_input) ) # The reconstructed model is already compiled and has retained the optimizer # state, so training can resume: reconstructed_model.fit(test_input, test_target)

Limitaciones

En comparación con el formato SavedModel, hay dos cosas que no se incluyen en el archivo H5:

  • Las pérdidas y métricas externas agregadas mediante model.add_loss() & model.add_metric() no se guardan (a diferencia de SavedModel). Si tiene dichas pérdidas y métricas en su modelo y desea reanudar el entrenamiento, deberá volver a agregarlas usted mismo después de cargar el modelo. Tenga en cuenta que esto no se aplica a las pérdidas/métricas creadas dentro de las capas mediante self.add_loss() & self.add_metric(). Mientras la capa esté cargada, estas pérdidas y métricas se mantienen, ya que forman parte del método call de la capa.

  • El grafo del cálculo de los objetos personalizados, como las capas personalizadas, no se incluye en el archivo guardado. En el momento de la carga, Keras necesitará acceder a las clases/funciones de Python de estos objetos para reconstruir el modelo. Ver Objetos personalizados.

Guardar la arquitectura

La configuración (o arquitectura) del modelo especifica qué capas contiene el modelo y cómo están conectadas estas capas*. Si tiene la configuración de un modelo, entonces el modelo se puede crear con un estado recién inicializado para las ponderaciones y sin información de compilación.

*Note que esto solo se aplica a modelos definidos usando las Apis functional o Sequential y no a modelos subclasificados.

Configuración de un modelo de la API Sequential o Functional

Este tipo de modelos son grafos explícitos de capas: su configuración siempre está disponible de forma estructurada.

APIs

  • get_config() y from_config()

  • tf.keras.models.model_to_json() y tf.keras.models.model_from_json()

get_config() y from_config()

Llamar config = model.get_config() devolverá un dict Python que contiene la configuración del modelo. El mismo modelo puede reconstruirse mediante Sequential.from_config(config) (para un modelo Sequential) o Model.from_config(config) (para un modelo Functional de API).

El mismo flujo de trabajo también funciona para cualquier capa serializable.

Ejemplo de capa:

layer = keras.layers.Dense(3, activation="relu") layer_config = layer.get_config() new_layer = keras.layers.Dense.from_config(layer_config)

Ejemplo de modelo Sequential:

model = keras.Sequential([keras.Input((32,)), keras.layers.Dense(1)]) config = model.get_config() new_model = keras.Sequential.from_config(config)

Ejemplo de modelo Functional:

inputs = keras.Input((32,)) outputs = keras.layers.Dense(1)(inputs) model = keras.Model(inputs, outputs) config = model.get_config() new_model = keras.Model.from_config(config)

to_json() y tf.keras.models.model_from_json()

Esto es similar a get_config / from_config, excepto que convierte el modelo en una cadena JSON, que luego se puede cargar sin la clase del modelo original. También es específico para los modelos, que no está hecho para las capas.

Ejemplo:

model = keras.Sequential([keras.Input((32,)), keras.layers.Dense(1)]) json_config = model.to_json() new_model = keras.models.model_from_json(json_config)

Objetos personalizados

Modelos y capas

La arquitectura de los modelos y capas subclase se definen en los métodos __init__ y call. Se consideran bytecode de Python, que no se pueden serializar en una configuración compatible con JSON -- podría intentar serializar el bytecode (por ejemplo, mediante pickle), pero es completamente inseguro y esto significaría que su modelo no se podría cargar en un sistema diferente.

Para guardar/cargar un modelo con capas definidas por el usuario, o un modelo de subclase, debe sobrescribir los métodos get_config y de forma opcional from_config. Además, debe registrar el objeto personalizado para que Keras sea consciente de ello.

Funciones personalizadas

Las funciones definidas por el usuario (por ejemplo, pérdida de activación o inicialización) no necesitan un método get_config. El nombre de la función es suficiente para cargarla siempre que esté registrada como objeto personalizado.

Cargar solo el grafo de TensorFlow

Es posible cargar la gráfica de TensorFlow generada por Keras. Si lo hace, no necesitará proporcionar ningún custom_objects. Puede hacerlo de la siguiente manera:

model.save("my_model") tensorflow_graph = tf.saved_model.load("my_model") x = np.random.uniform(size=(4, 32)).astype(np.float32) predicted = tensorflow_graph(x).numpy()

Tenga en cuenta que este método tiene varios inconvenientes:

  • Por razones de rastreabilidad, siempre debe tener acceso a los objetos personalizados que se utilizaron. No querrá poner en producción un modelo que no podrá volver a crear.

  • El objeto que devuelve tf.saved_model.load no es un modelo de Keras. Así que no es tan fácil de usar. Por ejemplo, no tendrá acceso a .predict() o .fit().

Aunque se desaconseja su uso, puede ser útil si se encuentra en un aprieto, por ejemplo, si perdió el código de sus objetos personalizados o tiene problemas para cargar el modelo con tf.keras.models.load_model().

Puede encontrar más información en la página sobre tf.saved_model.load

Cómo definir los métodos de configuración

Especificaciones:

  • get_config debería devolver un diccionario serializable en JSON para ser compatible con las APIs de ahorro de arquitectura y modelos de Keras.

  • from_config(config) (classmethod) debe devolver una nueva capa u objeto del modelo que se crea a partir de la configuración. La implementación predeterminada devuelve cls(**config).

Ejemplo:

class CustomLayer(keras.layers.Layer): def __init__(self, a): self.var = tf.Variable(a, name="var_a") def call(self, inputs, training=False): if training: return inputs * self.var else: return inputs def get_config(self): return {"a": self.var.numpy()} # There's actually no need to define `from_config` here, since returning # `cls(**config)` is the default behavior. @classmethod def from_config(cls, config): return cls(**config) layer = CustomLayer(5) layer.var.assign(2) serialized_layer = keras.layers.serialize(layer) new_layer = keras.layers.deserialize( serialized_layer, custom_objects={"CustomLayer": CustomLayer} )

Registro del objeto personalizado

Keras mantiene una nota de qué clase generó la configuración. En el ejemplo anterior, tf.keras.layers.serialize genera una forma serializada de la capa personalizada:

{'class_name': 'CustomLayer', 'config': {'a': 2}}

Keras mantiene una lista maestra de todas las clases incorporadas de capas, modelos, optimizadores y métricas, que se utiliza para encontrar la clase correcta para llamar a from_config. Si no se puede encontrar la clase, se producirá un error (Value Error: Unknown layer). Hay varias formas de registrar clases personalizadas en esta lista:

  1. Establecer el argumento custom_objects en la función de carga. (consulte el ejemplo en la sección anterior "Definición de los métodos de configuración")

  2. tf.keras.utils.custom_object_scope o tf.keras.utils.CustomObjectScope

  3. tf.keras.utils.register_keras_serializable

Ejemplo de función y capa personalizada

class CustomLayer(keras.layers.Layer): def __init__(self, units=32, **kwargs): super(CustomLayer, self).__init__(**kwargs) self.units = units def build(self, input_shape): self.w = self.add_weight( shape=(input_shape[-1], self.units), initializer="random_normal", trainable=True, ) self.b = self.add_weight( shape=(self.units,), initializer="random_normal", trainable=True ) def call(self, inputs): return tf.matmul(inputs, self.w) + self.b def get_config(self): config = super(CustomLayer, self).get_config() config.update({"units": self.units}) return config def custom_activation(x): return tf.nn.tanh(x) ** 2 # Make a model with the CustomLayer and custom_activation inputs = keras.Input((32,)) x = CustomLayer(32)(inputs) outputs = keras.layers.Activation(custom_activation)(x) model = keras.Model(inputs, outputs) # Retrieve the config config = model.get_config() # At loading time, register the custom objects with a `custom_object_scope`: custom_objects = {"CustomLayer": CustomLayer, "custom_activation": custom_activation} with keras.utils.custom_object_scope(custom_objects): new_model = keras.Model.from_config(config)

Clonación de modelos en la memoria

También se puede clonar un modelo en memoria mediante tf.keras.models.clone_model(). Esto es equivalente a obtener la configuración y después recrear el modelo a partir de su configuración (por lo que no conserva la información de compilación ni los valores de las ponderaciones de las capas).

Ejemplo:

with keras.utils.custom_object_scope(custom_objects): new_model = keras.models.clone_model(model)

Cómo guardar y cargar solo los valores de las ponderaciones del modelo

Puede elegir guardar y cargar solo las ponderaciones de un modelo. Esto puede ser útil si:

  • Solo necesita el modelo para la inferencia: en este caso no necesitará reiniciar el entrenamiento, por lo que no necesita la información de compilación ni el estado del optimizador.

  • Está realizando aprendizaje por transferencia: en este caso estará entrenando un nuevo modelo reutilizando el estado de un modelo anterior, por lo que no necesita la información de compilación del modelo anterior.

API para transferencia de ponderación en la memoria

Las ponderaciones pueden copiarse entre diferentes objetos utilizando get_weights y set_weights:

  • tf.keras.layers.Layer.get_weights(): Devuelve una lista de matrices numpy.

  • tf.keras.layers.Layer.set_weights(): Establece las ponderaciones del modelo con los valores del argumento weights.

A continuación, algunos ejemplos.

Transferencia de ponderaciones de una capa a otra, en la memoria

def create_layer(): layer = keras.layers.Dense(64, activation="relu", name="dense_2") layer.build((None, 784)) return layer layer_1 = create_layer() layer_2 = create_layer() # Copy weights from layer 1 to layer 2 layer_2.set_weights(layer_1.get_weights())

Transferencia de ponderaciones de un modelo a otro de arquitectura compatible, en la memoria

# Create a simple functional model inputs = keras.Input(shape=(784,), name="digits") x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs) x = keras.layers.Dense(64, activation="relu", name="dense_2")(x) outputs = keras.layers.Dense(10, name="predictions")(x) functional_model = keras.Model(inputs=inputs, outputs=outputs, name="3_layer_mlp") # Define a subclassed model with the same architecture class SubclassedModel(keras.Model): def __init__(self, output_dim, name=None): super(SubclassedModel, self).__init__(name=name) self.output_dim = output_dim self.dense_1 = keras.layers.Dense(64, activation="relu", name="dense_1") self.dense_2 = keras.layers.Dense(64, activation="relu", name="dense_2") self.dense_3 = keras.layers.Dense(output_dim, name="predictions") def call(self, inputs): x = self.dense_1(inputs) x = self.dense_2(x) x = self.dense_3(x) return x def get_config(self): return {"output_dim": self.output_dim, "name": self.name} subclassed_model = SubclassedModel(10) # Call the subclassed model once to create the weights. subclassed_model(tf.ones((1, 784))) # Copy weights from functional_model to subclassed_model. subclassed_model.set_weights(functional_model.get_weights()) assert len(functional_model.weights) == len(subclassed_model.weights) for a, b in zip(functional_model.weights, subclassed_model.weights): np.testing.assert_allclose(a.numpy(), b.numpy())

El caso de las capas sin estado

Como las capas sin estado no cambian el orden ni el número de ponderaciones, los modelos pueden tener arquitecturas compatibles aunque haya capas sin estado adicionales/faltantes.

inputs = keras.Input(shape=(784,), name="digits") x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs) x = keras.layers.Dense(64, activation="relu", name="dense_2")(x) outputs = keras.layers.Dense(10, name="predictions")(x) functional_model = keras.Model(inputs=inputs, outputs=outputs, name="3_layer_mlp") inputs = keras.Input(shape=(784,), name="digits") x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs) x = keras.layers.Dense(64, activation="relu", name="dense_2")(x) # Add a dropout layer, which does not contain any weights. x = keras.layers.Dropout(0.5)(x) outputs = keras.layers.Dense(10, name="predictions")(x) functional_model_with_dropout = keras.Model( inputs=inputs, outputs=outputs, name="3_layer_mlp" ) functional_model_with_dropout.set_weights(functional_model.get_weights())

API para guardar ponderaciones en el disco y volver a cargarlas

Las ponderaciones pueden guardarse en el disco llamando a model.save_weights en los siguientes formatos:

  • Punto de verificación de TensorFlow

  • HDF5

El formato predeterminado para model.save_weights es el punto de verificación de TensorFlow. Hay dos formas de especificar el formato de guardado:

  1. save_format argumento: Establezca el valor en save_format="tf" o save_format="h5".

  2. argumento path: Si la ruta termina con .h5 o .hdf5, entonces se utiliza el formato HDF5. Otros sufijos resultarán en un punto de verificación de TensorFlow a menos que save_format esté configurado.

También está la opción de recuperar ponderaciones como matrices numpy en la memoria. Cada API tiene sus pros y sus contras que se detallan a continuación.

Formato de los puntos de verificación de TF

Ejemplo:

# Runnable example sequential_model = keras.Sequential( [ keras.Input(shape=(784,), name="digits"), keras.layers.Dense(64, activation="relu", name="dense_1"), keras.layers.Dense(64, activation="relu", name="dense_2"), keras.layers.Dense(10, name="predictions"), ] ) sequential_model.save_weights("ckpt") load_status = sequential_model.load_weights("ckpt") # `assert_consumed` can be used as validation that all variable values have been # restored from the checkpoint. See `tf.train.Checkpoint.restore` for other # methods in the Status object. load_status.assert_consumed()

Detalles del formato

El formato del punto de verificación de TensorFlow guarda y restaura las ponderaciones usando nombres de atributos de objetos. Por ejemplo, considere la capa tf.keras.layers.Dense. La capa contiene dos ponderaciones: dense.kernel y dense.bias. Cuando la capa se guarda en el formato tf, el punto de control resultante contiene las claves "kernel" y "bias" y sus correspondientes valores de ponderaciones. Para obtener más información, consulte "Mecánica de carga" en la guía del punto de verificación de TF.

Tenga en cuenta que el atributo/borde del grafo se nombra con el nombre utilizado en el objeto padre, no con el nombre de la variable. Considere CustomLayer en el siguiente ejemplo. La variable CustomLayer.var se guarda con "var" como parte de la clave, no con "var_a".

class CustomLayer(keras.layers.Layer): def __init__(self, a): self.var = tf.Variable(a, name="var_a") layer = CustomLayer(5) layer_ckpt = tf.train.Checkpoint(layer=layer).save("custom_layer") ckpt_reader = tf.train.load_checkpoint(layer_ckpt) ckpt_reader.get_variable_to_dtype_map()

Ejemplo de transferencia de aprendizaje

Básicamente, mientras dos modelos tengan la misma arquitectura, podrán compartir el mismo punto de control.

Ejemplo:

inputs = keras.Input(shape=(784,), name="digits") x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs) x = keras.layers.Dense(64, activation="relu", name="dense_2")(x) outputs = keras.layers.Dense(10, name="predictions")(x) functional_model = keras.Model(inputs=inputs, outputs=outputs, name="3_layer_mlp") # Extract a portion of the functional model defined in the Setup section. # The following lines produce a new model that excludes the final output # layer of the functional model. pretrained = keras.Model( functional_model.inputs, functional_model.layers[-1].input, name="pretrained_model" ) # Randomly assign "trained" weights. for w in pretrained.weights: w.assign(tf.random.normal(w.shape)) pretrained.save_weights("pretrained_ckpt") pretrained.summary() # Assume this is a separate program where only 'pretrained_ckpt' exists. # Create a new functional model with a different output dimension. inputs = keras.Input(shape=(784,), name="digits") x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs) x = keras.layers.Dense(64, activation="relu", name="dense_2")(x) outputs = keras.layers.Dense(5, name="predictions")(x) model = keras.Model(inputs=inputs, outputs=outputs, name="new_model") # Load the weights from pretrained_ckpt into model. model.load_weights("pretrained_ckpt") # Check that all of the pretrained weights have been loaded. for a, b in zip(pretrained.weights, model.weights): np.testing.assert_allclose(a.numpy(), b.numpy()) print("\n", "-" * 50) model.summary() # Example 2: Sequential model # Recreate the pretrained model, and load the saved weights. inputs = keras.Input(shape=(784,), name="digits") x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs) x = keras.layers.Dense(64, activation="relu", name="dense_2")(x) pretrained_model = keras.Model(inputs=inputs, outputs=x, name="pretrained") # Sequential example: model = keras.Sequential([pretrained_model, keras.layers.Dense(5, name="predictions")]) model.summary() pretrained_model.load_weights("pretrained_ckpt") # Warning! Calling `model.load_weights('pretrained_ckpt')` won't throw an error, # but will *not* work as expected. If you inspect the weights, you'll see that # none of the weights will have loaded. `pretrained_model.load_weights()` is the # correct method to call.

Generalmente se recomienda utilizar la misma API para construir modelos. Si cambia entre Sequential y Functional, o Functional y subclassed, etc., reconstruya siempre el modelo entrenado previamente y cargue las ponderaciones entrenadas previamente en ese modelo.

La siguiente pregunta es, ¿cómo se pueden guardar y cargar las ponderaciones en diferentes modelos si las arquitecturas de los modelos son bastante diferentes? La solución es utilizar tf.train.Checkpoint para guardar y restaurar las capas/variables exactas.

Ejemplo:

# Create a subclassed model that essentially uses functional_model's first # and last layers. # First, save the weights of functional_model's first and last dense layers. first_dense = functional_model.layers[1] last_dense = functional_model.layers[-1] ckpt_path = tf.train.Checkpoint( dense=first_dense, kernel=last_dense.kernel, bias=last_dense.bias ).save("ckpt") # Define the subclassed model. class ContrivedModel(keras.Model): def __init__(self): super(ContrivedModel, self).__init__() self.first_dense = keras.layers.Dense(64) self.kernel = self.add_variable("kernel", shape=(64, 10)) self.bias = self.add_variable("bias", shape=(10,)) def call(self, inputs): x = self.first_dense(inputs) return tf.matmul(x, self.kernel) + self.bias model = ContrivedModel() # Call model on inputs to create the variables of the dense layer. _ = model(tf.ones((1, 784))) # Create a Checkpoint with the same structure as before, and load the weights. tf.train.Checkpoint( dense=model.first_dense, kernel=model.kernel, bias=model.bias ).restore(ckpt_path).assert_consumed()

Formato HDF5

El formato HDF5 contiene ponderaciones agrupadas por nombres de capa. Las ponderaciones son listas ordenadas por la concatenación de la lista de ponderaciones entrenables con la lista de ponderaciones no entrenables (igual que layer.weights). Por lo tanto, un modelo puede utilizar un punto de control hdf5 si tiene las mismas capas y estados entrenables que se guardaron en el punto de control.

Ejemplo:

# Runnable example sequential_model = keras.Sequential( [ keras.Input(shape=(784,), name="digits"), keras.layers.Dense(64, activation="relu", name="dense_1"), keras.layers.Dense(64, activation="relu", name="dense_2"), keras.layers.Dense(10, name="predictions"), ] ) sequential_model.save_weights("weights.h5") sequential_model.load_weights("weights.h5")

Tenga en cuenta que cambiar layer.trainable puede dar como resultado una ordenación diferente de layer.weights cuando el modelo contiene capas anidadas.

class NestedDenseLayer(keras.layers.Layer): def __init__(self, units, name=None): super(NestedDenseLayer, self).__init__(name=name) self.dense_1 = keras.layers.Dense(units, name="dense_1") self.dense_2 = keras.layers.Dense(units, name="dense_2") def call(self, inputs): return self.dense_2(self.dense_1(inputs)) nested_model = keras.Sequential([keras.Input((784,)), NestedDenseLayer(10, "nested")]) variable_names = [v.name for v in nested_model.weights] print("variables: {}".format(variable_names)) print("\nChanging trainable status of one of the nested layers...") nested_model.get_layer("nested").dense_1.trainable = False variable_names_2 = [v.name for v in nested_model.weights] print("\nvariables: {}".format(variable_names_2)) print("variable ordering changed:", variable_names != variable_names_2)

Ejemplo de transferencia de aprendizaje

Cuando se cargan las ponderaciones entrenadas previamente desde HDF5, se recomienda cargar las ponderaciones en el modelo de verificación original y, a continuación, extraer las ponderaciones/capas deseadas en un nuevo modelo.

Ejemplo:

def create_functional_model(): inputs = keras.Input(shape=(784,), name="digits") x = keras.layers.Dense(64, activation="relu", name="dense_1")(inputs) x = keras.layers.Dense(64, activation="relu", name="dense_2")(x) outputs = keras.layers.Dense(10, name="predictions")(x) return keras.Model(inputs=inputs, outputs=outputs, name="3_layer_mlp") functional_model = create_functional_model() functional_model.save_weights("pretrained_weights.h5") # In a separate program: pretrained_model = create_functional_model() pretrained_model.load_weights("pretrained_weights.h5") # Create a new model by extracting layers from the original model: extracted_layers = pretrained_model.layers[:-1] extracted_layers.append(keras.layers.Dense(5, name="dense_3")) model = keras.Sequential(extracted_layers) model.summary()