Introdução
O TensorFlow Hub hospeda SavedModels para TensorFlow 2, entre outros recursos. Eles podem ser carregados de volta em um programa Python com obj = hub.load(url) [ saiba mais ]. O obj retornado é o resultado de tf.saved_model.load() (consulte o guia de SavedModel do TensorFlow). Este objeto pode ter atributos arbitrários, como `tf.functions`, `tf.Variables` (inicializadas a partir de seus valores pré-treinados), outros recursos e, recursivamente, mais objetos desse tipo.
Esta página descreve uma interface a ser implementada pelo obj carregado para que possa ser reutilizada em um programa TensorFlow em Python. Os SavedModels que estão em conformidade com essa interface são chamados de SavedModels Reutilizáveis .
Reutilizar significa construir um modelo maior em torno de obj , incluindo a capacidade de ajustá-lo. Ajustar significa treinar ainda mais os pesos no obj carregado como parte do modelo circundante. A função de perda e o otimizador são determinados pelo modelo circundante; obj define apenas o mapeamento das ativações de entrada para saída (a "passagem direta"), possivelmente incluindo técnicas como dropout ou normalização em lote.
A equipe do TensorFlow Hub recomenda a implementação da interface `Reusable SavedModel` em todos os `SavedModels` que se destinam a ser reutilizados no sentido acima. Muitas utilidades da biblioteca tensorflow_hub , notavelmente hub.KerasLayer , exigem que os `SavedModels` a implementem.
Relação com SignatureDefs
Essa interface, em termos de tf.functions e outros recursos do TF2, é separada das assinaturas do SavedModel, que estão disponíveis desde o TF1 e continuam sendo usadas no TF2 para inferência (como a implantação de SavedModels no TF Serving ou TF Lite). As assinaturas para inferência não são expressivas o suficiente para suportar ajustes finos, e tf.function fornece uma API Python mais natural e expressiva para o modelo reutilizado.
Relação com bibliotecas de construção de modelos
Um SavedModel reutilizável usa apenas primitivas do TensorFlow 2, independentemente de qualquer biblioteca de modelagem específica, como Keras ou Sonnet. Isso facilita a reutilização em diferentes bibliotecas de modelagem, sem dependências do código original de modelagem.
Será necessário algum grau de adaptação para carregar ou salvar SavedModels reutilizáveis em qualquer biblioteca de modelagem. Para o Keras, o hub.KerasLayer fornece o carregamento, e o recurso de salvamento integrado do Keras no formato SavedModel foi redesenhado para o TF2 com o objetivo de fornecer um superconjunto dessa interface (consulte o RFC de maio de 2019).
Relação com as "APIs de modelo salvo comuns" específicas da tarefa
A definição da interface nesta página permite qualquer número e tipo de entradas e saídas. As APIs Common SavedModel para TF Hub refinam essa interface geral com convenções de uso para tarefas específicas, tornando os modelos facilmente intercambiáveis.
Definição de interface
Atributos
Um SavedModel reutilizável é um SavedModel do TensorFlow 2 tal que obj = tf.saved_model.load(...) retorna um objeto que possui os seguintes atributos.
__call__. Obrigatório. Uma função tf.function que implementa o cálculo do modelo (a "passagem direta") sujeito à especificação abaixo.variables: Uma lista de objetos tf.Variable, listando todas as variáveis usadas por qualquer possível invocação de__call__, incluindo variáveis treináveis e não treináveis.Esta lista pode ser omitida se estiver vazia.
trainable_variables: Uma lista de objetos `tf.Variable` ondev.trainableé verdadeiro para todos os elementos. Essas variáveis devem ser um subconjunto devariables. Essas são as variáveis a serem treinadas durante o ajuste fino do objeto. O criador do `SavedModel` pode optar por omitir algumas variáveis que eram originalmente treináveis para indicar que elas não devem ser modificadas durante o ajuste fino.Esta lista pode ser omitida se estiver vazia, em particular, se o SavedModel não suportar ajustes finos.
regularization_losses: Uma lista de funções do TensorFlow (tf.functions), cada uma recebendo zero entradas e retornando um único tensor escalar do tipo float. Para ajustes finos, recomenda-se que o usuário do SavedModel inclua esses termos como regularizadores adicionais na função de perda (no caso mais simples, sem escalonamento adicional). Normalmente, esses termos são usados para representar regularizadores de peso. (Por falta de entradas, essas funções do TensorFlow não podem representar regularizadores de atividade.)Esta lista pode ser omitida se estiver vazia, em particular, se o SavedModel não suportar ajuste fino ou não desejar prescrever regularização de pesos.
A função __call__
Um obj SavedModel restaurado possui um atributo obj.__call__ que é uma função tf.function restaurada e permite que obj seja chamado da seguinte forma.
Sinopse (pseudocódigo):
outputs = obj(inputs, trainable=..., **kwargs)
Argumentos
Os argumentos são os seguintes.
Existe um argumento posicional obrigatório com um lote de ativações de entrada do SavedModel. Seu tipo é um dos seguintes:
- Um único tensor para uma única entrada,
- Uma lista de tensores para uma sequência ordenada de entradas sem nome.
- Um dicionário de tensores indexados por um conjunto específico de nomes de entrada.
(Revisões futuras desta interface poderão permitir aninhamentos mais gerais.) O criador do SavedModel escolhe um desses, bem como os formatos e tipos de dados do tensor. Quando útil, algumas dimensões do formato devem ser indefinidas (principalmente o tamanho do lote).
Pode haver um argumento de palavra-chave opcional, `
training, que aceita um valor booleano em Python,TrueouFalse. O padrão éFalse. Se o modelo suporta ajuste fino e se seu cálculo difere entre os dois (por exemplo, como em dropout e normalização em lote), essa distinção é implementada com este argumento. Caso contrário, este argumento pode estar ausente.Não é necessário que
__call__aceite um argumentotrainingdo tipo Tensor. Cabe ao chamador usartf.cond()se necessário para despachar entre eles.O criador do SavedModel pode optar por aceitar mais
kwargsopcionais com nomes específicos.Para argumentos com valores de tensores, o criador do SavedModel define os tipos de dados e formatos permitidos.
tf.functionaceita um valor padrão do Python para um argumento que é rastreado com uma entrada tf.TensorSpec. Esses argumentos podem ser usados para permitir a personalização de hiperparâmetros numéricos envolvidos em__call__(por exemplo, taxa de dropout).Para argumentos com valores em Python, o criador do SavedModel define os valores permitidos. Esses argumentos podem ser usados como indicadores para fazer escolhas discretas na função rastreada (mas cuidado com a explosão combinatória dos rastreamentos).
A função __call__ restaurada deve fornecer registros para todas as combinações permitidas de argumentos. A inversão do training entre True e False não deve alterar a permissibilidade dos argumentos.
Resultado
Os outputs da chamada obj podem ser
- Um único tensor para uma única saída.
- Uma lista de tensores para uma sequência ordenada de saídas sem nome.
- Um dicionário de tensores indexados por um conjunto específico de nomes de saída.
(Revisões futuras desta interface poderão permitir aninhamentos mais gerais.) O tipo de retorno pode variar dependendo dos argumentos nomeados (kwargs) com valores em Python. Isso permite que flags produzam saídas adicionais. O criador do SavedModel define os tipos de dados (dtypes) e formatos de saída, bem como sua dependência das entradas.
Funções invocáveis nomeadas
Um SavedModel reutilizável pode fornecer várias partes do modelo da maneira descrita acima, colocando-as em subobjetos nomeados, por exemplo, obj.foo , obj.bar e assim por diante. Cada subobjeto fornece um método __call__ e atributos de suporte sobre as variáveis etc. específicas daquela parte do modelo. Para o exemplo acima, haveria obj.foo.__call__ , obj.foo.variables e assim por diante.
Note que esta interface não abrange a abordagem de adicionar uma tf.function diretamente como tf.foo .
Espera-se que os usuários de SavedModels reutilizáveis lidem apenas com um nível de aninhamento ( obj.bar , mas não obj.bar.baz ). (Revisões futuras desta interface poderão permitir aninhamentos mais profundos e poderão dispensar a exigência de que o objeto de nível superior seja invocável.)
Considerações finais
Relação com APIs em processo
Este documento descreve uma interface de uma classe Python que consiste em tipos primitivos como `tf.function` e `tf.Variable`, os quais sobrevivem à serialização realizada por meio de tf.saved_model.save() e tf.saved_model.load() . No entanto, a interface já estava presente no objeto original passado para tf.saved_model.save() . A adaptação dessa interface permite a troca de partes do modelo entre APIs de construção de modelos dentro de um único programa TensorFlow.