Compatibilidade de versão do TensorFlow

Este documento é destinado a usuários que precisam de compatibilidade retroativa entre diferentes versões do TensorFlow (seja para código ou dados) e para desenvolvedores que desejam modificar o TensorFlow preservando a compatibilidade.

Versionamento semântico 2.0

O TensorFlow segue o Semantic Versioning 2.0 ( semver ) para sua API pública. Cada versão de lançamento do TensorFlow tem o formato MAJOR.MINOR.PATCH . Por exemplo, o TensorFlow versão 1.2.3 tem MAJOR versão 1, MINOR versão 2 e PATCH versão 3. As alterações em cada número têm o seguinte significado:

  • PRINCIPAL : Alterações potencialmente incompatíveis com versões anteriores. O código e os dados que funcionaram com uma versão principal anterior não funcionarão necessariamente com a nova versão. No entanto, em alguns casos, os gráficos e pontos de verificação existentes do TensorFlow podem ser migráveis ​​para a versão mais recente; consulte Compatibilidade de gráficos e pontos de verificação para obter detalhes sobre compatibilidade de dados.

  • MENOR : Recursos compatíveis com versões anteriores, melhorias de velocidade, etc. Código e dados que funcionaram com uma versão secundária anterior e que dependem apenas da API pública não experimental continuarão a funcionar inalterados. Para obter detalhes sobre o que é ou não a API pública, consulte O que é coberto .

  • PATCH : Correções de bugs compatíveis com versões anteriores.

Por exemplo, a versão 1.0.0 introduziu alterações incompatíveis com versões anteriores da versão 0.12.1. No entanto, a versão 1.1.1 era compatível com versões anteriores da versão 1.0.0.

O que está coberto

Somente as APIs públicas do TensorFlow são compatíveis com versões anteriores e versões secundárias e de patch. As APIs públicas consistem em

  • Todas as funções e classes Python documentadas no módulo tensorflow e seus submódulos, exceto

    • Símbolos privados: qualquer função, classe, etc., cujo nome comece com _
    • Símbolos experimentais e tf.contrib , veja abaixo para detalhes.

    Observe que o código nos diretórios examples/ e tools/ não pode ser acessado por meio do módulo tensorflow Python e, portanto, não é coberto pela garantia de compatibilidade.

    Se um símbolo estiver disponível por meio do módulo tensorflow Python ou de seus submódulos, mas não estiver documentado, ele não será considerado parte da API pública.

  • A API de compatibilidade (em Python, o módulo tf.compat ). Nas versões principais, podemos lançar utilitários e endpoints adicionais para ajudar os usuários na transição para uma nova versão principal. Esses símbolos de API estão obsoletos e não são suportados (ou seja, não adicionaremos nenhum recurso e não corrigiremos bugs além de corrigir vulnerabilidades), mas eles se enquadram em nossas garantias de compatibilidade.

  • A API C do TensorFlow:

  • Os seguintes arquivos de buffer de protocolo:

Número de versão separado para TensorFlow Lite

Atualmente o TensorFlow Lite é distribuído como parte do TensorFlow. No entanto, reservamo-nos o direito de, no futuro, lançar alterações nas APIs do TensorFlow Lite em uma programação diferente das outras APIs do TensorFlow, ou até mesmo mover o TensorFlow Lite para uma distribuição de origem separada e/ou um repositório de origem separado do TensorFlow.

Por causa disso, usamos um número de versão diferente para TensorFlow Lite ( TFLITE_VERSION_STRING em tensorflow/lite/version.h e TfLiteVersion() em tensorflow/lite/c/c_api.h ) do que para TensorFlow ( TF_VERSION_STRING em tensorflow/core/public/version.h e TF_Version() em tensorflow/c/c_api.h ). Atualmente, esses dois números de versão têm o mesmo valor. Mas no futuro poderão divergir; por exemplo, podemos incrementar o número da versão principal do TensorFlow Lite sem incrementar o número da versão principal do TensorFlow ou vice-versa.

A superfície da API coberta pelo número de versão do TensorFlow Lite é composta pelas seguintes APIs públicas:

Os símbolos experimentais não são abrangidos; veja abaixo para obter detalhes.

Número de versão separado para APIs de extensão do TensorFlow Lite

O TensorFlow Lite fornece APIs C para estender o interpretador do TensorFlow Lite com "operações personalizadas", que fornecem operações definidas pelo usuário em um gráfico, ou "delegados", que permitem delegar a computação de um gráfico (ou de um subconjunto de um gráfico) para um back-end personalizado. Essas APIs, que chamamos coletivamente de "APIs de extensão do TensorFlow Lite", exigem dependências mais íntimas de alguns detalhes da implementação do TensorFlow Lite.

Reservamo-nos o direito de lançar alterações nessas APIs no futuro, incluindo potencialmente alterações não compatíveis com versões anteriores, em uma programação diferente das outras APIs do TensorFlow Lite. Portanto, usamos um número de versão diferente para as APIs de extensão do TensorFlow Lite do que os números de versão do TensorFlow Lite ou TensorFlow (que foram descritos na seção anterior). Estamos introduzindo algumas novas APIs no TensorFlow Lite versão 2.15 para obter a versão das APIs de extensão do TensorFlow Lite ( TFLITE_EXTENSION_APIS_VERSION_STRING em tensorflow/lite/version.h e TfLiteExtensionApisVersion() em tensorflow/lite/c/c_api.h ). O número da versão das APIs de extensão do TensorFlow Lite é atualmente igual ao número da versão do TensorFlow e do TensorFlow Lite. Mas no futuro poderão divergir; por exemplo, podemos incrementar o número da versão principal para as APIs de extensão do TensorFlow Lite sem incrementar o número da versão principal do TensorFlow Lite ou vice-versa.

A superfície da API coberta pelo número de versão das APIs de extensão do TensorFlow Lite é composta pelas seguintes APIs públicas:

Novamente, os símbolos experimentais não são abrangidos; veja abaixo para obter detalhes.

O que não está coberto

Algumas partes do TensorFlow podem mudar de maneira incompatível com versões anteriores a qualquer momento. Esses incluem:

  • APIs experimentais : Para facilitar o desenvolvimento, isentamos alguns símbolos de API claramente marcados como experimentais das garantias de compatibilidade. Em particular, não estão cobertos por quaisquer garantias de compatibilidade:

    • qualquer símbolo no módulo tf.contrib ou em seus submódulos;
    • qualquer símbolo (módulo, função, argumento, propriedade, classe, constante, tipo, pacote, etc.) cujo nome contenha experimental ou Experimental ; ou
    • qualquer símbolo cujo nome totalmente qualificado inclua um módulo ou classe ou pacote que seja experimental. Isso inclui campos e submensagens de qualquer buffer de protocolo chamado experimental .
  • Outras linguagens : APIs do TensorFlow em linguagens diferentes de Python e C, como:

    e APIs TensorFlow Lite em linguagens diferentes de Java/Kotlin, C, Objective-C e Swift, em particular

  • Detalhes de operações compostas: muitas funções públicas em Python se expandem para várias operações primitivas no gráfico, e esses detalhes farão parte de quaisquer gráficos salvos no disco como GraphDef s. Esses detalhes podem mudar para lançamentos menores. Em particular, os testes de regressão que verificam a correspondência exata entre os gráficos provavelmente serão interrompidos em versões menores, mesmo que o comportamento do gráfico deva permanecer inalterado e os pontos de verificação existentes ainda funcionem.

  • Detalhes numéricos de ponto flutuante: os valores específicos de ponto flutuante calculados pelas operações podem mudar a qualquer momento. Os usuários devem confiar apenas na precisão aproximada e na estabilidade numérica, e não nos bits específicos computados. As alterações nas fórmulas numéricas em versões secundárias e de patch devem resultar em precisão comparável ou melhorada, com a ressalva de que, no aprendizado de máquina, a precisão aprimorada de fórmulas específicas pode resultar em menor precisão para o sistema geral.

  • Números aleatórios: Os números aleatórios específicos calculados podem mudar a qualquer momento. Os usuários devem confiar apenas em distribuições aproximadamente corretas e força estatística, e não nos bits específicos computados. Consulte o guia de geração de números aleatórios para obter detalhes.

  • Distorção de versão no Tensorflow distribuído: a execução de duas versões diferentes do TensorFlow em um único cluster não é compatível. Não há garantias sobre a compatibilidade retroativa do protocolo wire.

  • Bugs: Reservamo-nos o direito de fazer alterações de comportamento incompatível com versões anteriores (embora não de API) se a implementação atual estiver claramente quebrada, ou seja, se contradizer a documentação ou se um comportamento pretendido bem conhecido e bem definido não for implementado corretamente devido para um bug. Por exemplo, se um otimizador afirma implementar um algoritmo de otimização bem conhecido, mas não corresponde a esse algoritmo devido a um bug, então corrigiremos o otimizador. Nossa correção pode quebrar o código dependendo do comportamento errado para convergência. Notaremos essas mudanças nas notas de lançamento.

  • API não utilizada: reservamo-nos o direito de fazer alterações incompatíveis com versões anteriores em APIs para as quais não encontramos usos documentados (realizando auditoria do uso do TensorFlow por meio da pesquisa no GitHub). Antes de fazer qualquer alteração, anunciaremos nossa intenção de fazer a alteração na lista de e-mail anuncia@ , fornecendo instruções sobre como resolver quaisquer quebras (se aplicável) e aguardaremos duas semanas para dar à nossa comunidade a chance de compartilhar seus comentários. .

  • Comportamento de erro: podemos substituir erros por comportamento sem erro. Por exemplo, podemos alterar uma função para calcular um resultado em vez de gerar um erro, mesmo que esse erro esteja documentado. Também nos reservamos o direito de alterar o texto das mensagens de erro. Além disso, o tipo de erro pode mudar, a menos que o tipo de exceção para uma condição de erro específica seja especificado na documentação.

Compatibilidade de SavedModels, gráficos e pontos de verificação

SavedModel é o formato de serialização preferido para usar em programas TensorFlow. SavedModels contém duas partes: um ou mais gráficos codificados como GraphDefs e um Checkpoint. Os gráficos descrevem o fluxo de dados das operações a serem executadas e os pontos de verificação contêm os valores tensores salvos das variáveis ​​em um gráfico.

Muitos usuários do TensorFlow criam SavedModels e os carregam e executam com uma versão posterior do TensorFlow. Em conformidade com semver , SavedModels escritos com uma versão do TensorFlow podem ser carregados e avaliados com uma versão posterior do TensorFlow com a mesma versão principal.

Oferecemos garantias adicionais para SavedModels suportados . Chamamos um SavedModel que foi criado usando apenas APIs não obsoletas, não experimentais e sem compatibilidade na versão principal N do TensorFlow como SavedModel compatível com a versão N . Qualquer SavedModel compatível com a versão principal N do TensorFlow pode ser carregado e executado com a versão principal N+1 do TensorFlow. No entanto, a funcionalidade necessária para construir ou modificar tal modelo pode não estar mais disponível, portanto esta garantia se aplica apenas ao SavedModel não modificado.

Faremos o possível para preservar a compatibilidade com versões anteriores pelo maior tempo possível, para que os arquivos serializados possam ser usados ​​por longos períodos de tempo.

Compatibilidade com GraphDef

Os gráficos são serializados por meio do buffer do protocolo GraphDef . Para facilitar alterações incompatíveis com versões anteriores em gráficos, cada GraphDef tem um número de versão separado da versão do TensorFlow. Por exemplo, GraphDef versão 17 descontinuou o inv op em favor do reciprocal . A semântica é:

  • Cada versão do TensorFlow oferece suporte a um intervalo de versões GraphDef . Esse intervalo será constante entre versões de patch e só aumentará em versões secundárias. A eliminação do suporte para uma versão GraphDef ocorrerá apenas para uma versão principal do TensorFlow (e apenas alinhada com o suporte de versão garantido para SavedModels).

  • Os gráficos recém-criados recebem o número de versão mais recente GraphDef .

  • Se uma determinada versão do TensorFlow oferecer suporte à versão GraphDef de um gráfico, ele carregará e avaliará com o mesmo comportamento da versão do TensorFlow usada para gerá-lo (exceto para detalhes numéricos de ponto flutuante e números aleatórios conforme descrito acima), independentemente do principal versão do TensorFlow. Em particular, um GraphDef compatível com um arquivo de ponto de verificação em uma versão do TensorFlow (como é o caso de um SavedModel) permanecerá compatível com esse ponto de verificação em versões subsequentes, desde que o GraphDef seja compatível.

    Observe que isso se aplica apenas a gráficos serializados em GraphDefs (e SavedModels): o código que lê um ponto de verificação pode não ser capaz de ler pontos de verificação gerados pelo mesmo código executando uma versão diferente do TensorFlow.

  • Se o limite superior GraphDef for aumentado para X em uma versão (menor), levará pelo menos seis meses antes que o limite inferior seja aumentado para X. Por exemplo (estamos usando números de versão hipotéticos aqui):

    • O TensorFlow 1.2 pode oferecer suporte GraphDef versões 4 a 7.
    • O TensorFlow 1.3 pode adicionar GraphDef versão 8 e oferecer suporte às versões 4 a 8.
    • Pelo menos seis meses depois, o TensorFlow 2.0.0 pode abandonar o suporte para as versões 4 a 7, deixando apenas a versão 8.

    Observe que, como as versões principais do TensorFlow geralmente são publicadas com mais de 6 meses de intervalo, as garantias para SavedModels suportados detalhadas acima são muito mais fortes do que a garantia de 6 meses para GraphDefs.

Finalmente, quando o suporte para uma versão GraphDef for abandonado, tentaremos fornecer ferramentas para converter gráficos automaticamente para uma versão mais recente GraphDef suportada.

Compatibilidade de gráfico e ponto de verificação ao estender o TensorFlow

Esta seção é relevante apenas ao fazer alterações incompatíveis no formato GraphDef , como ao adicionar operações, remover operações ou alterar a funcionalidade de operações existentes. A seção anterior deve ser suficiente para a maioria dos usuários.

Compatibilidade retroativa e parcial

Nosso esquema de versionamento tem três requisitos:

  • Compatibilidade com versões anteriores para oferecer suporte ao carregamento de gráficos e pontos de verificação criados com versões mais antigas do TensorFlow.
  • Compatibilidade futura para oferecer suporte a cenários em que o produtor de um gráfico ou ponto de verificação é atualizado para uma versão mais recente do TensorFlow antes do consumidor.
  • Habilite a evolução do TensorFlow de maneiras incompatíveis. Por exemplo, remover operações, adicionar atributos e remover atributos.

Observe que, embora o mecanismo de versão GraphDef seja separado da versão do TensorFlow, as alterações incompatíveis com versões anteriores no formato GraphDef ainda são restritas pelo controle de versão semântico. Isso significa que a funcionalidade só pode ser removida ou alterada entre versões MAJOR do TensorFlow (como 1.7 a 2.0 ). Além disso, a compatibilidade futura é imposta nas versões de patch ( 1.x.1 a 1.x.2 por exemplo).

Para obter compatibilidade retroativa e futura e saber quando impor alterações nos formatos, os gráficos e pontos de verificação possuem metadados que descrevem quando foram produzidos. As seções abaixo detalham a implementação do TensorFlow e as diretrizes para a evolução das versões GraphDef .

Esquemas de versão de dados independentes

Existem diferentes versões de dados para gráficos e pontos de verificação. Os dois formatos de dados evoluem em taxas diferentes um do outro e também em taxas diferentes do TensorFlow. Ambos os sistemas de versionamento são definidos em core/public/version.h . Sempre que uma nova versão é adicionada, uma nota é adicionada ao cabeçalho detalhando o que mudou e a data.

Dados, produtores e consumidores

Distinguimos entre os seguintes tipos de informações de versão de dados:

  • produtores : binários que produzem dados. Os produtores têm uma versão ( producer ) e uma versão mínima do consumidor com a qual são compatíveis ( min_consumer ).
  • consumidores : binários que consomem dados. Os consumidores têm uma versão ( consumer ) e uma versão mínima do produtor com a qual são compatíveis ( min_producer ).

Cada parte dos dados versionados possui um campo de VersionDef versions que registra o producer que criou os dados, o min_consumer com o qual é compatível e uma lista de versões bad_consumers que não são permitidas.

Por padrão, quando um produtor cria alguns dados, os dados herdam as versões do producer e min_consumer do produtor. bad_consumers pode ser definido se versões específicas do consumidor contêm bugs e devem ser evitadas. Um consumidor pode aceitar um dado se o seguinte for verdadeiro:

  • consumer >= min_consumer dos dados
  • producer de dados >= min_producer do consumidor
  • consumer não está nos dados bad_consumers

Como produtores e consumidores vêm da mesma base de código do TensorFlow, core/public/version.h contém uma versão de dados principal que é tratada como producer ou consumer dependendo do contexto e min_consumer e min_producer (necessários para produtores e consumidores, respectivamente) . Especificamente,

  • Para versões GraphDef , temos TF_GRAPH_DEF_VERSION , TF_GRAPH_DEF_VERSION_MIN_CONSUMER e TF_GRAPH_DEF_VERSION_MIN_PRODUCER .
  • Para versões de checkpoint, temos TF_CHECKPOINT_VERSION , TF_CHECKPOINT_VERSION_MIN_CONSUMER e TF_CHECKPOINT_VERSION_MIN_PRODUCER .

Adicione um novo atributo padrão a uma operação existente

Seguir as orientações abaixo oferece compatibilidade futura somente se o conjunto de operações não tiver sido alterado:

  1. Se a compatibilidade futura for desejada, defina strip_default_attrs como True ao exportar o modelo usando os métodos tf.saved_model.SavedModelBuilder.add_meta_graph_and_variables e tf.saved_model.SavedModelBuilder.add_meta_graph da classe SavedModelBuilder ou tf.estimator.Estimator.export_saved_model
  2. Isso elimina os atributos com valor padrão no momento da produção/exportação dos modelos. Isso garante que o tf.MetaGraphDef exportado não contenha o novo atributo operacional quando o valor padrão for usado.
  3. Ter esse controle poderia permitir que consumidores desatualizados (por exemplo, servindo binários que ficam atrás dos binários de treinamento) continuassem carregando os modelos e evitassem interrupções no atendimento do modelo.

Versões em evolução do GraphDef

Esta seção explica como usar esse mecanismo de controle de versão para fazer diferentes tipos de alterações no formato GraphDef .

Adicionar uma operação

Adicione a nova operação aos consumidores e produtores ao mesmo tempo e não altere nenhuma versão GraphDef . Esse tipo de alteração é automaticamente compatível com versões anteriores e não afeta o plano de compatibilidade futura, uma vez que os scripts de produtor existentes não usarão repentinamente a nova funcionalidade.

Adicione uma operação e troque os wrappers Python existentes para usá-la

  1. Implemente novas funcionalidades de consumidor e incremente a versão GraphDef .
  2. Se for possível fazer com que os wrappers utilizem a nova funcionalidade apenas em casos que não funcionavam antes, os wrappers poderão ser atualizados agora.
  3. Altere os wrappers do Python para usar a nova funcionalidade. Não incremente min_consumer , pois modelos que não utilizam esta operação não devem quebrar.

Remover ou restringir a funcionalidade de uma operação

  1. Corrija todos os scripts do produtor (não o próprio TensorFlow) para não usar a operação ou funcionalidade banida.
  2. Aumente a versão GraphDef e implemente uma nova funcionalidade de consumidor que proíba a operação ou funcionalidade removida para GraphDefs na nova versão e superior. Se possível, faça o TensorFlow parar de produzir GraphDefs com a funcionalidade banida. Para fazer isso, adicione o REGISTER_OP(...).Deprecated(deprecated_at_version, message) .
  3. Aguarde um lançamento principal para fins de compatibilidade com versões anteriores.
  4. Aumente min_producer para a versão GraphDef de (2) e remova totalmente a funcionalidade.

Alterar a funcionalidade de uma operação

  1. Adicione uma nova operação semelhante chamada SomethingV2 ou similar e passe pelo processo de adicioná-la e trocar os wrappers Python existentes para usá-la. Para garantir a compatibilidade futura, use as verificações sugeridas em compat.py ao alterar os wrappers do Python.
  2. Remova a operação antiga (só pode ocorrer com uma alteração importante de versão devido à compatibilidade com versões anteriores).
  3. Aumente min_consumer para descartar consumidores com a operação antiga, adicione novamente a operação antiga como um alias para SomethingV2 e siga o processo para trocar os wrappers Python existentes para usá-lo.
  4. Siga o processo para remover SomethingV2 .

Banir uma única versão insegura para o consumidor

  1. Altere a versão GraphDef e adicione a versão incorreta a bad_consumers para todos os novos GraphDefs. Se possível, adicione bad_consumers apenas para GraphDefs que contenham uma determinada operação ou similar.
  2. Se os consumidores existentes tiverem a versão ruim, elimine-os o mais rápido possível.