Introducción
TensorFlow Hub aloja SavedModels para TensorFlow 2, entre otros recursos. Estos se pueden cargar en un programa Python con obj = hub.load(url) [ más información ]. El obj devuelto es el resultado de tf.saved_model.load() (consulte la guía de SavedModel de TensorFlow). Este objeto puede tener atributos arbitrarios que son tf.functions, tf.Variables (inicializadas a partir de sus valores preentrenados), otros recursos y, recursivamente, más objetos de este tipo.
Esta página describe una interfaz que debe implementar el obj cargado para poder reutilizarlo en un programa de TensorFlow Python. Los SavedModels que cumplen con esta interfaz se denominan SavedModels reutilizables .
Reutilizar implica construir un modelo más grande alrededor de obj , incluyendo la capacidad de ajustarlo. El ajuste fino consiste en entrenar aún más los pesos del obj cargado como parte del modelo circundante. La función de pérdida y el optimizador vienen determinados por el modelo circundante; obj solo define la asignación de activaciones de entrada a salida (el "paso hacia adelante"), que puede incluir técnicas como dropout o normalización por lotes.
El equipo de TensorFlow Hub recomienda implementar la interfaz Reusable SavedModel en todos los SavedModels que se vayan a reutilizar en el sentido mencionado anteriormente. Muchas utilidades de la biblioteca tensorflow_hub , en particular hub.KerasLayer , requieren que los SavedModels la implementen.
Relación con SignatureDefs
Esta interfaz, en lo que respecta a tf.functions y otras características de TF2, es independiente de las firmas de SavedModel, que están disponibles desde TF1 y se siguen utilizando en TF2 para la inferencia (como al implementar SavedModels en TF Serving o TF Lite). Las firmas para la inferencia no son lo suficientemente expresivas como para permitir el ajuste fino, 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 SavedModel reutilizable utiliza únicamente primitivas de TensorFlow 2, independientemente de cualquier biblioteca de creación de modelos específica como Keras o Sonnet. Esto facilita su reutilización en diferentes bibliotecas de creación de modelos, sin depender del código original.
Será necesario realizar algunas adaptaciones para cargar o guardar modelos guardados reutilizables en cualquier biblioteca de creación de modelos. En Keras, hub.KerasLayer se encarga de la carga, y la función de guardado integrada de Keras en formato SavedModel se ha rediseñado para TF2 con el objetivo de proporcionar un superconjunto de esta interfaz (véase la RFC de mayo de 2019).
Relación con las API de "Modelos guardados comunes" específicas de cada tarea.
La definición de interfaz en esta página permite cualquier número y tipo de entradas y salidas. Las API de Common SavedModel para TF Hub perfeccionan esta interfaz general con convenciones de uso para tareas específicas, lo que facilita el intercambio de modelos.
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__. Obligatorio. Una función tf.function que implementa el cálculo del modelo (el "paso hacia adelante") sujeto a la especificación que se indica a continuación.variables: Una lista de objetos tf.Variable, que enumera todas las variables utilizadas por cualquier posible invocación de__call__, incluidas tanto las entrenables como las no entrenables.Esta lista puede omitirse si está vacía.
trainable_variables: Una lista de objetos tf.Variable tales quev.trainablesea verdadero para todos los elementos. Estas variables deben ser un subconjunto devariables. Estas son las variables que se entrenarán al ajustar el objeto. El creador de SavedModel puede optar por omitir algunas variables que originalmente eran entrenables para indicar que no deben modificarse durante el ajuste.Esta lista puede omitirse si está vacía, en particular, si el SavedModel no admite ajustes finos.
regularization_losses: Una lista de funciones tf.functions, cada una sin entrada y que devuelve un tensor escalar de tipo float. Para un ajuste fino, se recomienda al usuario de SavedModel incluirlas como términos de regularización adicionales en la función de pérdida (en el caso más simple, sin escalado adicional). Normalmente, se utilizan para representar regularizadores de peso. (Debido a la falta de entradas, estas funciones tf.functions no pueden expresar regularizadores de actividad).Esta lista puede omitirse si está vacía, en particular, si el SavedModel no admite el ajuste fino o no desea prescribir la regularización de pesos.
La función __call__
Un obj SavedModel restaurado tiene un atributo obj.__call__ que es una función tf.function restaurada y permite llamar obj de la siguiente manera.
Sinopsis (pseudocódigo):
outputs = obj(inputs, trainable=..., **kwargs)
Argumentos
Los argumentos son los siguientes.
Hay un argumento posicional y obligatorio con un lote de activaciones de entrada del SavedModel. Su tipo es uno de
- un único tensor para una única entrada,
- una lista de tensores para una secuencia ordenada de entradas sin nombre,
- un diccionario de tensores indexados por un conjunto particular de nombres de entrada.
(Las futuras revisiones de esta interfaz podrían permitir anidamientos más generales). El creador del SavedModel elige uno de ellos, así como las formas y los tipos de datos del tensor. Cuando sea útil, algunas dimensiones de la forma deberían quedar sin definir (en particular, el tamaño del lote).
Puede existir un argumento de palabra clave opcional, `
training, que acepta un valor booleano de Python,TrueoFalse. El valor predeterminado esFalse. Si el modelo admite ajuste fino y su cálculo difiere entre ambos (por ejemplo, en el caso de `dropout` y la normalización por lotes), esta distinción se implementa con este argumento. De lo contrario, este argumento puede estar ausente.No es necesario que
__call__acepte un argumentotrainingcon valor Tensor. Corresponde a quien realiza la llamada usartf.cond()si es necesario para alternar entre ellos.El creador del SavedModel puede optar por aceptar más
kwargscon nombre opcionales.Para los argumentos con valor Tensor, el creador de SavedModel define sus tipos de datos y formas permitidas.
tf.functionacepta un valor predeterminado de Python en un argumento que se rastrea con una entrada tf.TensorSpec. Dichos argumentos se pueden usar para permitir la personalización de los hiperparámetros numéricos involucrados en__call__(por ejemplo, tasa de abandono).Para los argumentos con valores de Python, el creador del SavedModel define sus valores permitidos. Dichos argumentos pueden usarse como indicadores para tomar decisiones específicas en la función rastreada (pero tenga en cuenta la explosión combinatoria de rastreos).
La función __call__ restaurada debe proporcionar trazas para todas las combinaciones de argumentos permitidas. Cambiar el estado training entre True y False no debe modificar la permisibilidad de los argumentos.
Resultado
Las outputs de la llamada obj pueden ser
- un único tensor para una única salida,
- una lista de tensores para una secuencia ordenada de salidas sin nombre,
- un diccionario de tensores indexados por un conjunto particular de nombres de salida.
(Las futuras revisiones de esta interfaz podrían permitir anidamientos más generales). El tipo de retorno puede variar según los argumentos con nombre de Python. Esto permite que las banderas generen salidas adicionales. El creador de SavedModel define los tipos de datos y las formas de salida, así como su dependencia de las entradas.
Invocables con nombre
Un SavedModel reutilizable puede proporcionar múltiples componentes de modelo como se describió anteriormente, agrupándolos 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íficas de ese componente del modelo. En 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 simple tf.function directamente como tf.foo .
Se espera que los usuarios de modelos guardados reutilizables solo gestionen un nivel de anidamiento ( obj.bar , pero no obj.bar.baz ). (Las futuras revisiones de esta interfaz podrían permitir un anidamiento más profundo y podrían eliminar el requisito de que el objeto de nivel superior sea invocable).
Observaciones finales
Relación con las API en proceso
Este documento describe la interfaz de una clase de Python que consta de primitivas como tf.function y tf.Variable, las cuales se conservan tras un proceso de serialización mediante 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 dicha interfaz permite el intercambio de componentes del modelo entre las API de creación de modelos dentro de un mismo programa de TensorFlow.