Usando compilação AOT
O que é tfcompile?
O tfcompile é uma ferramenta autônoma que compila grafos do TensorFlow antecipadamente (AOT) em código executável. Ele pode reduzir o tamanho binário total e também evitar algumas sobrecargas de tempo de execução. Um caso de uso típico de tfcompile é compilar um grafo de inferência em código executável para dispositivos móveis.
O grafo do TensorFlow normalmente é executado pelo runtime do TensorFlow. Isso incorre em alguma sobrecarga de tempo de execução para a execução de cada nó do grafo. Isso também leva a um tamanho total maior de código binário, já que o código do runtime do TensorFlow precisa estar disponível, além do próprio grafo. O código executável produzido por tfcompile não usa o runtime do TensorFlow e só possui dependências de kernels que são realmente usados na computação.
O compilador é construído sobre o framework XLA. O código que liga o TensorFlow ao framework XLA reside em tensorflow/compiler.
O que o tfcompile faz?
O tfcompile pega um subgrafo, identificado pelos conceitos de feeds e fetches do TensorFlow, e gera uma função que implementa esse subgrafo. Os feeds são argumentos de entrada da função e os fetches são os argumentos de saída da função. Todas as entradas devem ser totalmente especificadas pelos feeds; o subgrafo removido resultante não pode conter nós Placeholder ou Variable. É comum especificar todos os espaços reservados e variáveis como feeds, o que garante que o subgrafo resultante não contenha mais esses nós. A função gerada é empacotada como cc_library, com um arquivo de cabeçalho exportando a assinatura da função e um arquivo objeto contendo a implementação. O usuário escreve código para chamar a função gerada conforme apropriado.
Usando tfcompile
Esta seção detalha passos de alto nível para gerar um binário executável com tfcompile a partir de um subgrafo do TensorFlow. Os passos são:
Passo 1: configure o subgrafo para compilar
Passo 2: use a macro de build
tf_librarypara compilar o subgrafoPasso 3: escreva o código para chamar o subgrafo
Passo 4: crie o binário final
Passo 1: configure o subgrafo para compilar
Identifique os feeds e fetches que correspondem aos argumentos de entrada e saída da função gerada. Em seguida, configure os feeds e fetches em um proto tensorflow.tf2xla.Config.
Passo 2: use a macro de build tf_library para compilar o subgrafo
Este passo converte o grafo numa cc_library usando a macro de build tf_library. A cc_library consiste num arquivo objeto contendo o código gerado a partir do grafo, junto com um arquivo de cabeçalho que dá acesso ao código gerado. tf_library utiliza tfcompile para compilar o grafo do TensorFlow em código executável.
Para gerar o proto GraphDef (test_graph_tfmatmul.pb) para este exemplo, execute make_test_graphs.py e especifique o local de saída com o sinalizador --out_dir.
Grafos típicos contêm Variables que representam os pesos que são aprendidos por meio de treinamento, mas tfcompile não pode compilar um subgrafo que contenha Variables. A ferramenta freeze_graph.py converte variáveis em constantes, usando valores armazenados em um arquivo de checkpoint. Por conveniência, a macro tf_library suporta o argumento freeze_checkpoint, que executa a ferramenta. Para mais exemplos, consulte tensorflow/compiler/aot/tests/BUILD .
As constantes que aparecem no subgrafo compilado são compiladas diretamente no código gerado. Para passar as constantes para a função gerada, em vez de compilá-las, simplesmente passe-as como feeds.
Para detalhes sobre a macro de build tf_library, veja tfcompile.bzl.
Para detalhes sobre a ferramenta tfcompile nativa, veja tfcompile_main.cc.
Passo 3: escreva o código para chamar o subgrafo
Este passo usa o arquivo de cabeçalho (test_graph_tfmatmul.h) gerado pela macro de build tf_library no passo anterior para chamar o código gerado. O arquivo de cabeçalho está localizado no diretório bazel-bin correspondente ao pacote de build e é nomeado com base no atributo name definido na macro de build tf_library. Por exemplo, o cabeçalho gerado para test_graph_tfmatmul seria test_graph_tfmatmul.h. Abaixo está uma versão abreviada do que é gerado. O arquivo gerado, em bazel-bin, contém comentários úteis adicionais.
A classe C++ gerada é chamada MatMulComp no namespace foo::bar, porque essa era a cpp_class especificada na macro tf_library. Todas as classes geradas possuem uma API semelhante, com a única diferença sendo os métodos para lidar com buffers de argumentos e resultados. Esses métodos diferem com base no número e nos tipos de buffers, que foram especificados pelos argumentos feed e fetch para a macro tf_library.
Há três tipos de buffers gerenciados na classe gerada: args representando as entradas, results representando as saídas e temps representando buffers temporários usados internamente para realizar o cálculo. Por padrão, cada instância da classe gerada aloca e gerencia todos esses buffers para você. O argumento do construtor AllocMode pode ser usado para alterar esse comportamento. Todos os buffers estão alinhados aos limites de 64 bytes.
A classe C++ gerada é apenas um wrapper em torno do código de baixo nível gerado pelo XLA.
Exemplo de chamada da função gerada com base em tfcompile_test.cc:
Passo 4: crie o binário final
Este passo combina a biblioteca gerada por tf_library no passo 2 e o código escrito no passo 3 para criar um arquivo binário final. Abaixo está um exemplo de arquivo BUILD do bazel.