Modelos salvos reutilizáveis

Mantenha tudo organizado com as coleções Salve e categorize o conteúdo com base nas suas preferências.

Introdução

O TensorFlow Hub hospeda SavedModels para TensorFlow 2, entre outros ativos. 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 SavedModel do TensorFlow ). Este objeto pode ter atributos arbitrários que são tf.functions, tf.Variables (inicializados 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 ser reutilizado em um programa TensorFlow Python. SavedModels 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. O ajuste fino significa treinamento adicional dos pesos no obj carregado como parte do modelo circundante. A função de perda e o otimizador são determinados pelo modelo circundante; O obj define apenas o mapeamento de ativações de entrada para saída (o "forward pass"), possivelmente incluindo técnicas como dropout ou normalização em lote.

A equipe do TensorFlow Hub recomenda implementar a interface SavedModel reutilizável em todos os SavedModels que devem ser reutilizados no sentido acima. Muitos utilitários da biblioteca tensorflow_hub , principalmente hub.KerasLayer , requerem SavedModels para implementá-lo.

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 a ser usadas no TF2 para inferência (como implantar SavedModels no TF Serving ou TF Lite). 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 primitivos do TensorFlow 2, independentemente de qualquer biblioteca de construção de modelo específica, como Keras ou Sonnet. Isso facilita a reutilização em bibliotecas de construção de modelo, livre de dependências no código de construção de modelo original.

Alguma quantidade de adaptação será necessária para carregar SavedModels reutilizáveis ​​ou salvá-los de qualquer biblioteca de construção de modelo. Para Keras, hub.KerasLayer fornece o carregamento, e o salvamento interno do Keras no formato SavedModel foi redesenhado para TF2 com o objetivo de fornecer um superconjunto dessa interface (consulte o RFC de maio de 2019).

Relação com "APIs SavedModel comuns" específicas da tarefa

A definição de interface nesta página permite qualquer número e tipo de entradas e saídas. As APIs de SavedModel comuns para TF Hub refinam essa interface geral com convenções de uso para tarefas específicas para tornar 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 tem os seguintes atributos

  • __call__ . Requerido. Uma função tf.implementando a computação do modelo (o "passe direto") sujeito à especificação abaixo.

  • variables : Uma lista de objetos tf.Variable, listando todas as variáveis ​​usadas por qualquer invocação possível de __call__ , incluindo treináveis ​​e não treináveis.

    Esta lista pode ser omitida se estiver vazia.

  • trainable_variables : Uma lista de objetos tf.Variable de forma que v.trainable seja verdadeiro para todos os elementos. Essas variáveis ​​devem ser um subconjunto de variables . Essas são as variáveis ​​a serem treinadas ao ajustar o objeto. O criador do SavedModel pode optar por omitir algumas variáveis ​​aqui que foram 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 ajuste fino.

  • regularization_losses : Uma lista de tf.functions, cada uma recebendo zero entradas e retornando um único tensor escalar float. Para ajuste fino, o usuário SavedModel é aconselhado a incluí-los como termos de regularização adicionais na perda (no caso mais simples, sem escala adicional). Normalmente, eles são usados ​​para representar regularizadores de peso. (Por falta de entradas, essas tf.functions não podem expressar 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 a regularização de peso.

A função __call__

Um obj SavedModel restaurado tem um atributo obj.__call__ que é um tf.function restaurado e permite que obj seja chamado da seguinte maneira.

Sinopse (pseudo-código):

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

Argumentos

Os argumentos são os seguintes.

  • Há um argumento posicional obrigatório com um lote de ativações de entrada do SavedModel. Seu tipo é um dos

    • um único tensor para uma única entrada,
    • uma lista de tensores para uma sequência ordenada de entradas sem nome,
    • um dict de tensores codificados por um conjunto específico de nomes de entrada.

    (Revisões futuras desta interface podem permitir aninhamentos mais gerais.) O criador do SavedModel escolhe um deles e as formas e dtypes do tensor. Quando útil, algumas dimensões da forma devem ser indefinidas (principalmente o tamanho do lote).

  • Pode haver um training de argumento de palavra-chave opcional que aceite um booleano do Python, True ou False . 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 argumento de training com valor de tensor. Cabe ao chamador usar tf.cond() se necessário para despachar entre eles.

  • O criador do SavedModel pode optar por aceitar mais kwargs opcionais de nomes específicos.

    • Para argumentos com valor de tensor, o criador de SavedModel define seus dtypes e formas permitidos. tf.function aceita um valor padrão do Python em um argumento que é rastreado com uma entrada tf.TensorSpec. Tais argumentos podem ser usados ​​para permitir a personalização de hiperparâmetros numéricos envolvidos em __call__ (por exemplo, taxa de abandono).

    • Para argumentos com valor de Python, o criador de SavedModel define seus valores permitidos. Tais argumentos podem ser usados ​​como sinalizadores para fazer escolhas discretas na função rastreada (mas lembre-se da explosão combinatória de traços).

A função __call__ restaurada deve fornecer rastreamentos para todas as combinações permitidas de argumentos. Inverter training entre True e False não deve alterar a permissibilidade dos argumentos.

Resultado

As 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 dict de tensores codificados por um conjunto específico de nomes de saída.

(Revisões futuras desta interface podem permitir aninhamentos mais gerais.) O tipo de retorno pode variar dependendo dos kwargs valorizados em Python. Isso permite que os sinalizadores produzam saídas extras. O criador do SavedModel define os tipos e formas de saída e sua dependência nas entradas.

Chamadas nomeadas

Um SavedModel reutilizável pode fornecer várias peças de 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 para aquela peça do modelo. Para o exemplo acima, haveria obj.foo.__call__ , obj.foo.variables e assim por diante.

Observe que esta interface não cobre a abordagem de adicionar um tf.function simples 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 podem permitir um aninhamento mais profundo e podem dispensar o requisito de que o próprio objeto de nível superior possa ser chamado.)

Observações finais

Relação com APIs em processo

Este documento descreve uma interface de uma classe Python que consiste em primitivas como tf.function e tf.Variable que sobrevivem a uma viagem de ida e volta através da serialização via tf.saved_model.save() e tf.saved_model.load() . No entanto, a interface já estava presente no objeto original que foi passado para tf.saved_model.save() . A adaptação a essa interface permite a troca de peças de modelo entre APIs de construção de modelo em um único programa TensorFlow.