Modelos guardados reutilizables

Introducción

TensorFlow Hub aloja SavedModels para TensorFlow 2, entre otros activos. Se pueden volver a cargar en un programa Python con obj = hub.load(url) [ obtenga más información ]. El obj devuelto es el resultado de tf.saved_model.load() (consulte la guía SavedModel de TensorFlow). Este objeto puede tener atributos arbitrarios que son tf.functions, tf.Variables (inicializados a partir de sus valores previamente entrenados), otros recursos y, de forma recursiva, más objetos similares.

Esta página describe una interfaz que el obj cargado implementará para poder reutilizarla en un programa TensorFlow Python. Los modelos guardados que se ajustan a esta interfaz se denominan modelos guardados reutilizables .

Reutilizar significa construir un modelo más grande alrededor obj , incluida la capacidad de ajustarlo. El ajuste fino significa un entrenamiento adicional de los pesos en el obj cargado como parte del modelo circundante. La función de pérdida y el optimizador están determinados por el modelo circundante; obj solo define el mapeo de activaciones de entrada a salida (el "pase directo"), posiblemente incluyendo técnicas como abandono o normalización por lotes.

El equipo de TensorFlow Hub recomienda implementar la interfaz Reutilizable SavedModel en todos los SavedModels que deben reutilizarse en el sentido anterior. Muchas utilidades de la biblioteca tensorflow_hub , en particular hub.KerasLayer , requieren SavedModels para implementarla.

Relación con SignatureDefs

Esta interfaz en términos de tf.functions y otras características de TF2 está separada de las firmas de SavedModel, que han estado disponibles desde TF1 y continúan usándose en TF2 para inferencia (como implementar SavedModels en TF Serving o TF Lite). Las firmas para inferencia no son lo suficientemente expresivas para admitir ajustes finos, y tf.function proporciona una API de Python más natural y expresiva para el modelo reutilizado.

Relación con las bibliotecas de construcción de modelos

Un modelo guardado reutilizable utiliza solo primitivas de TensorFlow 2, independientemente de cualquier biblioteca de creación de modelos en particular, como Keras o Sonnet. Esto facilita la reutilización en bibliotecas de creación de modelos, sin dependencias del código de creación de modelos original.

Se necesitará cierta adaptación para cargar modelos guardados reutilizables o guardarlos en cualquier biblioteca de creación de modelos. Para Keras, hub.KerasLayer proporciona la carga, y el guardado integrado de Keras en el formato SavedModel se ha rediseñado para TF2 con el objetivo de proporcionar un superconjunto de esta interfaz (consulte el RFC de mayo de 2019).

Relación con las "API de modelos guardados comunes" específicas de tareas

La definición de interfaz en esta página permite cualquier número y tipo de entradas y salidas. Las API comunes de SavedModel para TF Hub refinan esta interfaz general con convenciones de uso para tareas específicas para hacer que los modelos sean fácilmente intercambiables.

Definición de interfaz

Atributos

Un SavedModel reutilizable es un SavedModel de TensorFlow 2 tal que obj = tf.saved_model.load(...) devuelve un objeto que tiene los siguientes atributos

  • __call__ . Requerido. Una función tf.que implementa el cálculo del modelo (el "pase directo") sujeto a la siguiente especificación.

  • variables : una lista de objetos tf.Variable, que enumera todas las variables utilizadas por cualquier posible invocación de __call__ , incluidas las que se pueden entrenar y las que no se pueden entrenar.

    Esta lista se puede omitir si está vacía.

  • trainable_variables : una lista de objetos tf.Variable tales que v.trainable es verdadero para todos los elementos. Estas variables deben ser un subconjunto de variables . Estas son las variables que se entrenarán al ajustar el objeto. El creador de SavedModel puede optar por omitir aquí algunas variables que originalmente se podían entrenar para indicar que no deben modificarse durante el ajuste fino.

    Esta lista se puede omitir si está vacía, en particular, si SavedModel no admite ajustes finos.

  • regularization_losses : una lista de tf.functions, cada una de las cuales toma cero entradas y devuelve un único tensor flotante escalar. Para realizar ajustes, se recomienda al usuario de SavedModel que los incluya como términos de regularización adicionales en la pérdida (en el caso más simple, sin mayor escala). Normalmente, se utilizan para representar regularizadores de peso. (Por falta de entradas, estas tf.functions no pueden expresar regularizadores de actividad).

    Esta lista se puede omitir si está vacía, en particular, si SavedModel no admite ajustes finos o no desea prescribir la regularización del peso.

La función __call__

Un obj Restored SavedModel tiene un atributo obj.__call__ que es una función tf.function restaurada y permite llamar a obj de la siguiente manera.

Sinopsis (pseudocódigo):

outputs = obj(inputs, trainable=..., **kwargs)

Argumentos

Los argumentos son los siguientes.

  • Hay un argumento posicional requerido con un lote de activaciones de entrada del SavedModel. Su tipo es uno de

    • un solo tensor para una sola entrada,
    • una lista de tensores para una secuencia ordenada de entradas sin nombre,
    • un dictado de tensores codificados por un conjunto particular de nombres de entrada.

    (Las revisiones futuras de esta interfaz pueden permitir nidos más generales). El creador de SavedModel elige uno de ellos y las formas y tipos de tensor. Cuando sea útil, algunas dimensiones de la forma no deben estar definidas (en particular, el tamaño del lote).

  • Puede haber un training de argumentos de palabras clave opcional que acepte un booleano de Python, True o False . El valor predeterminado es False . Si el modelo admite el ajuste fino y si su cálculo difiere entre los dos (por ejemplo, como en el abandono y la normalización por lotes), esa distinción se implementa con este argumento. De lo contrario, este argumento puede estar ausente.

    No es necesario que __call__ acepte un argumento training con valor de tensor. Corresponde a la persona que llama usar tf.cond() si es necesario para realizar el envío entre ellos.

  • El creador de SavedModel puede optar por aceptar más kwargs opcionales de nombres particulares.

    • Para los argumentos con valores de tensor, el creador de SavedModel define sus tipos y formas permitidos. tf.function acepta un valor predeterminado de Python en un argumento que se rastrea con una entrada tf.TensorSpec. Estos argumentos se pueden utilizar para permitir la personalización de hiperparámetros numéricos involucrados en __call__ (por ejemplo, tasa de abandono).

    • Para los argumentos valorados en Python, el creador de SavedModel define sus valores permitidos. Estos argumentos se pueden utilizar como indicadores para realizar elecciones discretas en la función trazada (pero tenga en cuenta la explosión combinatoria de trazas).

La función __call__ restaurada debe proporcionar seguimientos para todas las combinaciones permitidas de argumentos. Cambiar training entre True y False no debe cambiar la permisibilidad de los argumentos.

Resultado

Los outputs de llamar obj pueden ser

  • un solo tensor para una sola salida,
  • una lista de tensores para una secuencia ordenada de salidas sin nombre,
  • un dictado de tensores codificados por un conjunto particular de nombres de salida.

(Las revisiones futuras de esta interfaz pueden permitir anidamientos más generales). El tipo de retorno puede variar dependiendo de los kwargs valorados en Python. Esto permite que las banderas produzcan resultados adicionales. El creador de SavedModel define los tipos y formas de salida y su dependencia de las entradas.

invocables con nombre

Un modelo guardado reutilizable puede proporcionar múltiples piezas de modelo de la forma descrita anteriormente colocándolas en subobjetos con nombre, por ejemplo, obj.foo , obj.bar , etc. Cada subobjeto proporciona un método __call__ y atributos de soporte sobre las variables, etc., específicos de esa pieza del modelo. Para el ejemplo anterior, habría obj.foo.__call__ , obj.foo.variables , etc.

Tenga en cuenta que esta interfaz no cubre el enfoque de agregar una función tf.function directamente como tf.foo .

Se espera que los usuarios de modelos guardados reutilizables solo manejen un nivel de anidamiento ( obj.bar pero no obj.bar.baz ). (Las revisiones futuras de esta interfaz pueden permitir un anidamiento más profundo y pueden eliminar el requisito de que el objeto de nivel superior sea invocable).

Comentarios finales

Relación con las API en proceso

Este documento describe una interfaz de una clase de Python que consta de primitivas como tf.function y tf.Variable que sobreviven a un viaje de ida y vuelta a través de la serialización a través de tf.saved_model.save() y tf.saved_model.load() . Sin embargo, la interfaz ya estaba presente en el objeto original que se pasó a tf.saved_model.save() . La adaptación a esa interfaz permite el intercambio de piezas de modelo entre API de creación de modelos dentro de un único programa TensorFlow.