En su lanzamiento en 2018, TensorFlow Hub ofrecía un único tipo de activo: el formato TF1 Hub para importar a programas TensorFlow 1.
Esta página explica cómo usar el formato TF1 Hub en TF1 (o el modo de compatibilidad TF1 de TF2) con la clase hub.Module
y las API asociadas. (El uso típico es construir un tf.Graph
, posiblemente dentro de un TF1 Estimator
, combinando uno o más modelos en formato TF1 Hub con tf.compat.layers
o tf.layers
).
Los usuarios de TensorFlow 2 (fuera del modo de compatibilidad TF1) deben usar la nueva API con hub.load()
o hub.KerasLayer
. La nueva API carga el nuevo tipo de activo TF2 SavedModel, pero también tiene soporte limitado para cargar el formato TF1 Hub en TF2 .
Usando un modelo en formato TF1 Hub
Creación de instancias de un modelo en formato TF1 Hub
Un modelo en formato TF1 Hub se importa a un programa TensorFlow creando un objeto hub.Module
a partir de una cadena con su URL o ruta del sistema de archivos, como por ejemplo:
m = hub.Module("path/to/a/module_dir")
Nota: Consulte más información sobre otros tipos de identificadores válidos aquí .
Esto agrega las variables del módulo al gráfico actual de TensorFlow. Al ejecutar sus inicializadores se leerán sus valores previamente entrenados del disco. Asimismo, se agregan tablas y otros estados al gráfico.
Módulos de almacenamiento en caché
Al crear un módulo a partir de una URL, el contenido del módulo se descarga y se almacena en caché en el directorio temporal del sistema local. La ubicación donde se almacenan en caché los módulos se puede anular utilizando la variable de entorno TFHUB_CACHE_DIR
. Para obtener más información, consulte Almacenamiento en caché .
Aplicar un módulo
Una vez creado una instancia, un módulo m
se puede llamar cero o más veces como una función de Python desde entradas tensoriales hasta salidas tensoriales:
y = m(x)
Cada una de estas llamadas agrega operaciones al gráfico actual de TensorFlow para calcular y
a partir de x
. Si esto involucra variables con pesos entrenados, estos se comparten entre todas las aplicaciones.
Los módulos pueden definir múltiples firmas con nombre para permitir su aplicación en más de una forma (similar a cómo los objetos Python tienen métodos ). La documentación de un módulo debe describir las firmas disponibles. La llamada anterior aplica la firma denominada "default"
. Se puede seleccionar cualquier firma pasando su nombre al argumento opcional signature=
.
Si una firma tiene varias entradas, se deben pasar como un dict, con las claves definidas por la firma. Del mismo modo, si una firma tiene múltiples salidas, estas se pueden recuperar como un dict pasando as_dict=True
, bajo las claves definidas por la firma (la clave "default"
es para la única salida devuelta si as_dict=False
). Entonces, la forma más general de aplicar un módulo es la siguiente:
outputs = m(dict(apples=x1, oranges=x2), signature="fruit_to_pet", as_dict=True)
y1 = outputs["cats"]
y2 = outputs["dogs"]
Una persona que llama debe proporcionar todas las entradas definidas por una firma, pero no es necesario utilizar todas las salidas de un módulo. TensorFlow ejecutará solo aquellas partes del módulo que terminen como dependencias de un objetivo en tf.Session.run()
. De hecho, los editores de módulos pueden optar por proporcionar varias salidas para usos avanzados (como activaciones de capas intermedias) junto con las salidas principales. Los consumidores de módulos deben manejar las salidas adicionales con elegancia.
Probar módulos alternativos
Siempre que haya varios módulos para la misma tarea, TensorFlow Hub recomienda equiparlos con firmas (interfaces) compatibles, de modo que probar diferentes sea tan fácil como variar el identificador del módulo como un hiperparámetro con valor de cadena.
Con este fin, mantenemos una colección de firmas comunes recomendadas para tareas populares.
Creando un nuevo módulo
Nota de compatibilidad
El formato TF1 Hub está orientado a TensorFlow 1. TF Hub solo lo admite parcialmente en TensorFlow 2. Considere publicar en el nuevo formato TF2 SavedModel .
El formato TF1 Hub es similar al formato SavedModel de TensorFlow 1 en un nivel sintáctico (los mismos nombres de archivo y mensajes de protocolo), pero semánticamente diferente para permitir la reutilización, composición y reentrenamiento del módulo (por ejemplo, almacenamiento diferente de inicializadores de recursos, etiquetado diferente convenciones para metagrafías). La forma más sencilla de diferenciarlos en el disco es la presencia o ausencia del archivo tfhub_module.pb
.
Enfoque general
Para definir un nuevo módulo, un editor llama a hub.create_module_spec()
con una función module_fn
. Esta función construye un gráfico que representa la estructura interna del módulo, utilizando tf.placeholder()
para las entradas que debe proporcionar la persona que llama. Luego define firmas llamando hub.add_signature(name, inputs, outputs)
una o más veces.
Por ejemplo:
def module_fn():
inputs = tf.placeholder(dtype=tf.float32, shape=[None, 50])
layer1 = tf.layers.dense(inputs, 200)
layer2 = tf.layers.dense(layer1, 100)
outputs = dict(default=layer2, hidden_activations=layer1)
# Add default signature.
hub.add_signature(inputs=inputs, outputs=outputs)
...
spec = hub.create_module_spec(module_fn)
El resultado de hub.create_module_spec()
se puede usar, en lugar de una ruta, para crear una instancia de un objeto de módulo dentro de un gráfico de TensorFlow particular. En tal caso, no hay ningún punto de control y la instancia del módulo utilizará los inicializadores de variables en su lugar.
Cualquier instancia de módulo se puede serializar en el disco mediante su método export(path, session)
. Al exportar un módulo, se serializa su definición junto con el estado actual de sus variables en la session
en la ruta pasada. Esto se puede utilizar al exportar un módulo por primera vez, así como al exportar un módulo ajustado.
Para compatibilidad con los estimadores de TensorFlow, hub.LatestModuleExporter
exporta módulos desde el último punto de control, al igual que tf.estimator.LatestExporter
exporta el modelo completo desde el último punto de control.
Los editores de módulos deben implementar una firma común cuando sea posible, para que los consumidores puedan intercambiar módulos fácilmente y encontrar el mejor para su problema.
ejemplo real
Eche un vistazo a nuestro exportador de módulos de incrustación de texto para ver un ejemplo real de cómo crear un módulo a partir de un formato de incrustación de texto común.
Sintonia FINA
Entrenar las variables de un módulo importado junto con las del modelo que lo rodea se llama ajuste fino . Un ajuste fino puede dar lugar a una mejor calidad, pero añade nuevas complicaciones. Aconsejamos a los consumidores que consideren realizar ajustes solo después de explorar ajustes de calidad más simples y solo si el editor del módulo lo recomienda.
Para los consumidores
Para habilitar el ajuste fino, cree una instancia del módulo con hub.Module(..., trainable=True)
para que sus variables sean entrenables e importe REGULARIZATION_LOSSES
de TensorFlow. Si el módulo tiene varias variantes de gráficos, asegúrese de elegir la adecuada para la capacitación. Por lo general, ese es el que tiene etiquetas {"train"}
.
Elija un régimen de entrenamiento que no arruine los pesos previamente entrenados, por ejemplo, una tasa de aprendizaje más baja que para entrenar desde cero.
Para editores
Para facilitar el ajuste a los consumidores, tenga en cuenta lo siguiente:
El ajuste necesita regularización. Su módulo se exporta con la colección
REGULARIZATION_LOSSES
, que es lo que coloca su elección detf.layers.dense(..., kernel_regularizer=...)
etc. en lo que el consumidor obtiene detf.losses.get_regularization_losses()
. Prefiero esta forma de definir las pérdidas de regularización L1/L2.En el modelo de editor, evite definir la regularización L1/L2 mediante los parámetros
l1_
yl2_regularization_strength
detf.train.FtrlOptimizer
,tf.train.ProximalGradientDescentOptimizer
y otros optimizadores proximales. Estos no se exportan junto con el módulo y establecer niveles de regularización globalmente puede no ser apropiado para el consumidor. Excepto por la regularización L1 en modelos amplios (es decir, lineales dispersos) o amplios y profundos, debería ser posible utilizar pérdidas de regularización individuales en su lugar.Si utiliza abandono, normalización por lotes o técnicas de entrenamiento similares, establezca sus hiperparámetros en valores que tengan sentido en muchos usos esperados. Es posible que sea necesario ajustar la tasa de abandono a la propensión del problema objetivo al sobreajuste. En la normalización por lotes, el impulso (también conocido como coeficiente de caída) debe ser lo suficientemente pequeño como para permitir un ajuste fino con conjuntos de datos pequeños y/o lotes grandes. Para los consumidores avanzados, considere agregar una firma que exponga el control sobre los hiperparámetros críticos.