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

Para usar TensorFlow para aprendizaje automático, es probable que deba definir, guardar y restaurar un modelo.

Un modelo es, de forma abstracta:

  • Una función que calcula algo con tensores (un siguiente paso)

  • Algunas variables que pueden actualizarse según el entrenamiento.

En esta guía, aprenderá sobre Keras en profundidad para ver cómo se definen los modelos de TensorFlow. Veremos cómo TensorFlow recopila variables y modelos, y también cómo se guardan y restauran.

Nota: Si quiere empezar con Keras directamente, consulte la colección de guías de Keras.

Preparación

import tensorflow as tf from datetime import datetime %load_ext tensorboard

Módulos de TensorFlow

La mayoría de los modelos tienen capas. Las capas son funciones con una estructura matemática que puede reutilizarse y tiene variables entrenables. En TensorFlow, las implementaciones de nivel superior de capas y modelos, como Keras o Sonnet, están construidas en la misma clase fundacional: tf.Module.

Construir módulos

Aquí tiene un ejemplo de un tf.Module muy simple que opera en un tensor escalar:

class SimpleModule(tf.Module): def __init__(self, name=None): super().__init__(name=name) self.a_variable = tf.Variable(5.0, name="train_me") self.non_trainable_variable = tf.Variable(5.0, trainable=False, name="do_not_train_me") def __call__(self, x): return self.a_variable * x + self.non_trainable_variable simple_module = SimpleModule(name="simple") simple_module(tf.constant(5.0))

Los módulos y, por extensión, las capas son terminología de aprendizaje automático para "objetos": tienen un estado interno y métodos que usan ese estado.

Los __call__ no tienen nada en especial, excepto comportarse como un invocable de Python; puede llamar sus modelos con cualquier función.

Puede activar o desactivar la entrenabilidad de las variables por cualquier motivo, incluso puede congelar capas y variables durante los ajustes.

Nota: tf.Module es la clase base de tf.keras.layers.Layer y tf.keras.Model, por eso todo lo que se menciona aquí aplica a Keras. Por motivos de compatibilidad histórica, las capas de Keras no recopilan variables de los módulos, así que sus modelos deberían usar solo módulos o solo capas de Keras. Sin embargo, los métodos que se muestran a continuación para inspeccionar variables son los mismos en cualquiera de los casos.

Al subclasificar tf.Module, cualquier instancia de tf.Variable o tf.Module que se asigne a las propiedades de este objeto se recopilan automáticamente. Esto le permite ahorrar y cargar variables, así como también crear colecciones de tf.Module.

# All trainable variables print("trainable variables:", simple_module.trainable_variables) # Every variable print("all variables:", simple_module.variables)

Este es un ejemplo de un modelo líneal de dos capas hecho de módulos.

Primero una capa densa (lineal):

class Dense(tf.Module): def __init__(self, in_features, out_features, name=None): super().__init__(name=name) self.w = tf.Variable( tf.random.normal([in_features, out_features]), name='w') self.b = tf.Variable(tf.zeros([out_features]), name='b') def __call__(self, x): y = tf.matmul(x, self.w) + self.b return tf.nn.relu(y)

Y luego se completa el modelo, que hace instancias de dos capas y las aplica:

class SequentialModule(tf.Module): def __init__(self, name=None): super().__init__(name=name) self.dense_1 = Dense(in_features=3, out_features=3) self.dense_2 = Dense(in_features=3, out_features=2) def __call__(self, x): x = self.dense_1(x) return self.dense_2(x) # You have made a model! my_model = SequentialModule(name="the_model") # Call it, with random results print("Model results:", my_model(tf.constant([[2.0, 2.0, 2.0]])))

Las instancias tf.Module recopilarán automáticamente, de forma recursiva, cualquier instancia de tf.Variable o tf.Module asignada. Esto le permite gestionar las colecciones de los tf.Module con una instancia de modelo simple y guardar y cargar modelos completos.

print("Submodules:", my_model.submodules)
for var in my_model.variables: print(var, "\n")

Esperar para crear variables

Tal vez se dió cuenta que aquí se deben definir los tamaños de entrada y de salida en la capa. Esto es para que la variable w tenga una forma reconocida y que pueda ser asignada.

Al aplazar la creación de la variable a la primera vez, se llama al módulo con una forma de entrada específica, no hace falta especificar el tamaño de la entrada desde el principio.

class FlexibleDenseModule(tf.Module): # Note: No need for `in_features` def __init__(self, out_features, name=None): super().__init__(name=name) self.is_built = False self.out_features = out_features def __call__(self, x): # Create variables on first call. if not self.is_built: self.w = tf.Variable( tf.random.normal([x.shape[-1], self.out_features]), name='w') self.b = tf.Variable(tf.zeros([self.out_features]), name='b') self.is_built = True y = tf.matmul(x, self.w) + self.b return tf.nn.relu(y)
# Used in a module class MySequentialModule(tf.Module): def __init__(self, name=None): super().__init__(name=name) self.dense_1 = FlexibleDenseModule(out_features=3) self.dense_2 = FlexibleDenseModule(out_features=2) def __call__(self, x): x = self.dense_1(x) return self.dense_2(x) my_model = MySequentialModule(name="the_model") print("Model results:", my_model(tf.constant([[2.0, 2.0, 2.0]])))

Esta flexibilidad es lo que hace que las capas de TensorFlow solo necesitan que se especifique la forma de sus salidas, así como en tf.keras.layers.Dense, en vez de tener que definir el tamaño de entrada y de salida.

Guardar pesos

Puede guardar un tf.Module de las dos formas, como punto de verificación y como SavedModel.

Los puntos de verificación son los pesos (es decir, los valores del conjunto de variables en el módulo y sus submódulos):

chkp_path = "my_checkpoint" checkpoint = tf.train.Checkpoint(model=my_model) checkpoint.write(chkp_path)

Los puntos de verificación consisten en dos tipos de archivos: los datos en sí y un archivo de índice para los metadatos. El archivo de índice hace el seguimiento de lo que se guarda en realidad y enumera los puntos de verificación Los datos del punto de verificación contienen los valores de la variable y sus rutas de acceso de búsqueda de atributo.

!ls my_checkpoint*

Puede revisar el punto de verificación para asegurarse de que se guarde toda la colección de variables, ordenadas según el objeto de Python que las contiene.

tf.train.list_variables(chkp_path)

Durante el entrenamiento distribuido (de varios modelos) pueden particionarse, es por eso que se enumeran (e.g., '00000-oe-00001'). Pero en este caso, solo hay una partición.

Cuando vuelve a cargar modelos, se sobrescriben los valores en su objeto de Python.

new_model = MySequentialModule() new_checkpoint = tf.train.Checkpoint(model=new_model) new_checkpoint.restore("my_checkpoint") # Should be the same result as above new_model(tf.constant([[2.0, 2.0, 2.0]]))

Nota: Ya que los puntos de verificación son el centro de los flujos de entrenamiento largos, tf.checkpoint.CheckpointManager es una clase de ayuda que hace que sea más fácil gestionar los puntos de verificación. Consulte la Guía de entrenamiento de puntos de verificación para obtener más detalles.

Guardar funciones

TensorFlow puede ejecutar modelos sin los objetos originales de Python, como se muestra en TensorFlow Serving y TensorFlow Lite, incluso cuando se descarga un modelo entrenado desde TensorFlow Hub.

TensorFlow necesita saber cómo hacer los cálculos descritos en Python, pero sin el código original. Para eso, puede hacer un gráfico, que se explica en la guía de Introducción a gráficos y funciones.

Este gráfico contiene operaciones, o ops, que implementan la función.

Puede definir un gráfico en el modelo anterior al agregar el decorador @tf.function para indicar que el código debe ejecutarse como un gráfico.

class MySequentialModule(tf.Module): def __init__(self, name=None): super().__init__(name=name) self.dense_1 = Dense(in_features=3, out_features=3) self.dense_2 = Dense(in_features=3, out_features=2) @tf.function def __call__(self, x): x = self.dense_1(x) return self.dense_2(x) # You have made a model with a graph! my_model = MySequentialModule(name="the_model")

El módulo que creó funciona exactamente de la misma forma que antes. Cada signatura única que se pasa en la función crea un gráfico diferente. Échele un vistazo a la guía de Introducción a gráficos y funciones para obtener más detalles.

print(my_model([[2.0, 2.0, 2.0]])) print(my_model([[[2.0, 2.0, 2.0], [2.0, 2.0, 2.0]]]))

Puede visualizar el gráfico al trazarlo en el resúmen de TensorBoard.

# Set up logging. stamp = datetime.now().strftime("%Y%m%d-%H%M%S") logdir = "logs/func/%s" % stamp writer = tf.summary.create_file_writer(logdir) # Create a new model to get a fresh trace # Otherwise the summary will not see the graph. new_model = MySequentialModule() # Bracket the function call with # tf.summary.trace_on() and tf.summary.trace_export(). tf.summary.trace_on(graph=True) tf.profiler.experimental.start(logdir) # Call only one tf.function when tracing. z = print(new_model(tf.constant([[2.0, 2.0, 2.0]]))) with writer.as_default(): tf.summary.trace_export( name="my_func_trace", step=0, profiler_outdir=logdir)

Inicie TensorBoard para ver el trazado resultante:

#docs_infra: no_execute %tensorboard --logdir logs/func

Una captura de pantalla del gráfico en TensorBoard

Crear un SavedModel

Lo que se recomienda para compartir modelos entrenados es usar SavedModel. SavedModel contiene una colección de funciones y una colección de pesos.

Puede guardar el modelo que acaba de entrenar de la siguiente manera:

tf.saved_model.save(my_model, "the_saved_model")
# Inspect the SavedModel in the directory !ls -l the_saved_model
# The variables/ directory contains a checkpoint of the variables !ls -l the_saved_model/variables

El archivo saved_model.pb es un búfer de protocolo que describe un tf.Graph funcional.

Se pueden cargar los modelos y las capas desde esta representación sin realmente hacer un instancia de la clase que lo creó. Esto es ideal en situaciones donde se tiene (o quiere) un intérprete de Python, como servir a escala o en un dispositivo perimetral o en situaciones donde el código de Python original no esté disponible o no se pueda usar.

Puede cargar un modelo como un objeto nuevo:

new_model = tf.saved_model.load("the_saved_model")

new_model, creado desde un modelo guardado, es un objeto de usuario interno de TensorFlow sin el conocimiento de la clase. No es un tipo SequentialModule.

isinstance(new_model, SequentialModule)

Este modelo nuevo funciona en signaturas de entrada que ya están definidas. No se puede agregar signaturas a modelos restaurados como este.

print(my_model([[2.0, 2.0, 2.0]])) print(my_model([[[2.0, 2.0, 2.0], [2.0, 2.0, 2.0]]]))

Por lo tanto, al usar SavedModel, podrá guardar los pesos y gráficos de TensorFlow con tf.Module, y luego cargarlos de nuevo.

Modelos y capas de Keras

Note cómo no mencionamos Keras todavía. Puede construir su propio API de nivel superior además del tf.Module, y la gente lo ha hecho.

En esta sección, examinaremos cómo es que Keras usa tf.Module. Puede encontrar la guía de usuario completa de los modelos de Keras en la guía de Keras.

Las capas y modelo de Keras tienen muchas más características, entre ellas:

  • Pérdidas opcionales

  • Soporte para métricas

  • Soporte integrado para un argumento de training opcional para diferenciar entre el uso de entrenamiento y de inferencia

  • Guardar y restaurar objetos de Python en vez desolo funciones de caja negra

  • Los métodos get_config y from_config que le permiten guardar configuraciones con precisión para permitir la clonación de modelos en Python.

Estas características permiten modelos mucho más complejos mediante la subclasificación, tales como los modelos GAN y el Autocodificador variacional (VAE, por sus siglas en inglés). Puede leer más sobre estos modelos en la guía completa para personalizar capas y modelos

Los modelos de Keras también tienen una funcionalidad adicional que facilita el entrenamiento, la evaluación, la carga, el almacenamiento e incluso el entrenamiento de varios modelos.

Capas de Keras

La clase tf.keras.layers.Layer es la clase fundamental de todas las capas de Keras y hereda de tf.Module.

Puede convertir un módulo en una capa de Keras con tan solo intercambiar el elemento primario y luego cambiar __call__ a call:

class MyDense(tf.keras.layers.Layer): # Adding **kwargs to support base Keras layer arguments def __init__(self, in_features, out_features, **kwargs): super().__init__(**kwargs) # This will soon move to the build step; see below self.w = tf.Variable( tf.random.normal([in_features, out_features]), name='w') self.b = tf.Variable(tf.zeros([out_features]), name='b') def call(self, x): y = tf.matmul(x, self.w) + self.b return tf.nn.relu(y) simple_layer = MyDense(name="simple", in_features=3, out_features=3)

Las capas de Keras tienen su propio __call__ que realiza parte de la contabilización que se describe en la siguiente sección y luego llama a call(). No se debería notar ningún cambio en la funcionalidad.

simple_layer([[2.0, 2.0, 2.0]])

El paso build

Como ya mencionamos, en muchos casos es conveniente esperar a crear las variables hasta saber la forma de la entrada.

Las capas de Keras vienen con un paso de ciclo de vida adicional que permite más flexibilidad al definir sus capas. Esto se define en la función build.

Se llama a la función build exactamente una vez y se la llama con la forma de la entrada. Suele usarse para crear variables (pesos).

Puede reescribir la capa MyDense anterior para ser flexible con respecto al tamaño de las entradas.

class FlexibleDense(tf.keras.layers.Layer): # Note the added `**kwargs`, as Keras supports many arguments def __init__(self, out_features, **kwargs): super().__init__(**kwargs) self.out_features = out_features def build(self, input_shape): # Create the state of the layer (weights) self.w = tf.Variable( tf.random.normal([input_shape[-1], self.out_features]), name='w') self.b = tf.Variable(tf.zeros([self.out_features]), name='b') def call(self, inputs): # Defines the computation from inputs to outputs return tf.matmul(inputs, self.w) + self.b # Create the instance of the layer flexible_dense = FlexibleDense(out_features=3)

Hasta este punto, el modelo todavía no está construido por lo tanto no hay variables:

flexible_dense.variables

Cuando se llama a la función se asignan las variables con el tamaño adecuado:

# Call it, with predictably random results print("Model results:", flexible_dense(tf.constant([[2.0, 2.0, 2.0], [3.0, 3.0, 3.0]])))
flexible_dense.variables

Dado que build solo se llama una vez, se rechazarán las entradas si el tamaño no es compatible con las variables de la capa:

try: print("Model results:", flexible_dense(tf.constant([[2.0, 2.0, 2.0, 2.0]]))) except tf.errors.InvalidArgumentError as e: print("Failed:", e)

Modelos de Keras

Puede definir su modelo como capas de Keras anidadas.

Sin embargo, Keras también proporciona una clase de modelo con todas las características llamado tf.keras.Model. Este hereda de tf.keras.layers.Layer, por eso se puede usar y anidar un modelo de Keras de la misma forma que las capas de Keras. Los modelos de Keras vienen con una funcionalidad adicional que facilita el entrenamiento, la evaluación, la carga, el almacenamiento e incluso el entrenamiento de varios modelos.

Puede definir el SequentialModule de arriba con un código casi idéntico, volver a convertir __call__ a call() y cambiar el elemento primario:

class MySequentialModel(tf.keras.Model): def __init__(self, name=None, **kwargs): super().__init__(**kwargs) self.dense_1 = FlexibleDense(out_features=3) self.dense_2 = FlexibleDense(out_features=2) def call(self, x): x = self.dense_1(x) return self.dense_2(x) # You have made a Keras model! my_sequential_model = MySequentialModel(name="the_model") # Call it on a tensor, with random results print("Model results:", my_sequential_model(tf.constant([[2.0, 2.0, 2.0]])))

Todas las mismas características están disponibles, incluso el seguimiento de variables y de submodelos.

Nota: las variables de un tf.Module sin procesar, anidado dentro de la capa o modelo de Keras no sé recopilarán para entrenamiento ni almacenamiento. Mejor anide las capas de Keras dentro de las capas de Keras.

my_sequential_model.variables
my_sequential_model.submodules

Reemplazar tf.keras.Model es un enfoque típico de Python para construir modelos de TensorFlow. Si migra modelos desde otros frameworks, esto puede ser muy simple.

Si construye modelos que son simplemente agrupaciones de capas y entradas existentes, puede ahorrar tiempo y espacio con la API funcional, que viene con características adicionales sobre la reconstrucción y arquitectura del modelo .

Este es el mismo modelo con la API funcional:

inputs = tf.keras.Input(shape=[3,]) x = FlexibleDense(3)(inputs) x = FlexibleDense(2)(x) my_functional_model = tf.keras.Model(inputs=inputs, outputs=x) my_functional_model.summary()
my_functional_model(tf.constant([[2.0, 2.0, 2.0]]))

La diferencia más importante es que la forma de entrada se especifica desde el inicio como parte del proceso de construcción funcional. En este caso, no hace falta especificar el argumento input_shape; puede marcar algunas dimensiones como None.

Nota: No hace falta especificar la input_shape o la InputLayer en un modelo subclasificado; los argumentos y las capas serán ignorados.

Guardar los modelos de Keras

Los modelos de Keras tienen su propio formato de guardado especializado de archivo ZIP, que se marca con la extensión .keras. Al llamar tf.keras.Model.save, agregue la extensión .keras en el nombre de archivo. Por ejemplo:

my_sequential_model.save("exname_of_file.keras")

Y así de fácil, también se pueden volver a cargar:

reconstructed_model = tf.keras.models.load_model("exname_of_file.keras")

Los archivos archivados en ZIP de Keras, .keras, guardan los estados de las métricas, de las pérdidas y de los optimizadores.

Se puede usar este modelo reconstruido, y producirá el mismo resultado al llamarlo con los mismos datos:

reconstructed_model(tf.constant([[2.0, 2.0, 2.0]]))

Guardar puntos de verificación de los modelos de Keras

También se pueden guardar los puntos de verificación de los modelos de Keras y se vería igual que un tf.Module.

Hay más cosas para aprender sobre el guardado y la serialización de los modelos de Keras, por ejemplo proporcionar métodos de configuración para capas personalizadas que sean compatibles con funciones. Échele un vistazo a la guía de guardado y serialización.

Siguientes pasos

Si quiere obtener más detalles sobre Keras, puede ver las guías actuales de Keras aquí.

Otro ejemplo de una API de nivel superior construida en tf.module es Sonnet de DeepMind, que se explica en su sitio web.