Guia de desempenho

O desempenho do TensorFlow Serving depende muito do aplicativo que ele executa, do ambiente em que é implantado e de outros softwares com os quais compartilha acesso aos recursos de hardware subjacentes. Como tal, ajustar seu desempenho depende um pouco do caso e existem muito poucas regras universais que garantam o desempenho ideal em todas as configurações. Dito isso, este documento visa capturar alguns princípios gerais e práticas recomendadas para executar o TensorFlow Serving.

Use o guia Solicitações de inferência de perfil com TensorBoard para entender o comportamento subjacente da computação do seu modelo em solicitações de inferência e use este guia para melhorar iterativamente seu desempenho.

Dicas rápidas

  • A latência da primeira solicitação é muito alta? Habilite o aquecimento do modelo .
  • Interessado em maior utilização de recursos ou rendimento? Configurar lote

Ajuste de desempenho: objetivos e parâmetros

Ao ajustar o desempenho do TensorFlow Serving, geralmente há dois tipos de objetivos que você pode ter e três grupos de parâmetros a serem ajustados para melhorar esses objetivos.

Objetivos

TensorFlow Serving é um sistema de atendimento on-line para modelos aprendidos por máquina. Tal como acontece com muitos outros sistemas de serviço on-line, seu principal objetivo de desempenho é maximizar o rendimento e, ao mesmo tempo, manter a latência final abaixo de determinados limites . Dependendo dos detalhes e da maturidade do seu aplicativo, você pode se preocupar mais com a latência média do que com a latência final , mas alguma noção de latência e taxa de transferência geralmente são as métricas em relação às quais você define objetivos de desempenho. Observe que não discutimos a disponibilidade neste guia, pois isso é mais uma função do ambiente de implantação.

Parâmetros

Podemos pensar aproximadamente em 3 grupos de parâmetros cuja configuração determina o desempenho observado: 1) o modelo TensorFlow 2) as solicitações de inferência e 3) o servidor (hardware e binário).

1) O modelo TensorFlow

O modelo define o cálculo que o TensorFlow Serving realizará ao receber cada solicitação recebida.

Nos bastidores, o TensorFlow Serving usa o tempo de execução do TensorFlow para fazer a inferência real em suas solicitações. Isso significa que a latência média de atendimento de uma solicitação com o TensorFlow Serving geralmente é pelo menos a de fazer inferência diretamente com o TensorFlow. Isso significa que se em uma determinada máquina, a inferência em um único exemplo leva 2 segundos e você tem uma meta de latência inferior a um segundo, você precisa traçar o perfil das solicitações de inferência, entender quais operações do TensorFlow e subgráficos do seu modelo contribuem mais para essa latência e redesenhe seu modelo tendo em mente a latência de inferência como uma restrição de design.

Observe que, embora a latência média de execução de inferência com o TensorFlow Serving geralmente não seja menor do que usar o TensorFlow diretamente, o destaque do TensorFlow Serving é manter a latência final baixa para muitos clientes que consultam muitos modelos diferentes, ao mesmo tempo em que utiliza com eficiência o hardware subjacente para maximizar a taxa de transferência. .

2) Os pedidos de inferência

Superfícies de API

O TensorFlow Serving tem duas superfícies de API (HTTP e gRPC), ambas implementando a API PredictionService (com exceção do servidor HTTP que não expõe um endpoint MultiInference ). Ambas as superfícies de API são altamente ajustadas e adicionam latência mínima, mas, na prática, observa-se que a superfície gRPC tem um desempenho um pouco melhor.

Métodos de API

Em geral, é aconselhável usar os endpoints Classify e Regress, pois eles aceitam tf.Example , que é uma abstração de nível superior; no entanto, em casos raros de solicitações estruturadas grandes (O(Mb)), usuários experientes podem achar que usar PredictRequest e codificar diretamente suas mensagens Protobuf em um TensorProto e pular a serialização e desserialização de tf.Example é uma fonte de ligeiro ganho de desempenho.

Tamanho do batch

Existem duas maneiras principais pelas quais o lote pode ajudar no seu desempenho. Você pode configurar seus clientes para enviar solicitações em lote para o TensorFlow Serving ou pode enviar solicitações individuais e configurar o TensorFlow Serving para aguardar um período de tempo predeterminado e realizar inferência em todas as solicitações que chegam nesse período em um lote. A configuração do último tipo de lote permite que você atinja o TensorFlow Serving com QPS extremamente altos, ao mesmo tempo que permite dimensionar sublinearmente os recursos de computação necessários para acompanhar. Isso é discutido mais detalhadamente no guia de configuração e no README de lote .

3) O Servidor (Hardware e Binário)

O binário do TensorFlow Serving faz uma contabilidade bastante precisa do hardware no qual é executado. Como tal, você deve evitar executar outros aplicativos com uso intensivo de memória ou computação na mesma máquina, especialmente aqueles com uso dinâmico de recursos.

Tal como acontece com muitos outros tipos de cargas de trabalho, o TensorFlow Serving é mais eficiente quando implantado em menos máquinas maiores (mais CPU e RAM) (ou seja, uma Deployment com menos replicas em termos de Kubernetes). Isso se deve a um melhor potencial de implantação multilocatário para utilizar o hardware e a custos fixos mais baixos (servidor RPC, tempo de execução do TensorFlow, etc.).

Aceleradores

Se seu host tiver acesso a um acelerador, certifique-se de ter implementado seu modelo para colocar cálculos densos no acelerador - isso deve ser feito automaticamente se você usou APIs TensorFlow de alto nível, mas se você criou gráficos personalizados ou deseja fixar partes específicas de gráficos em aceleradores específicos, pode ser necessário colocar manualmente certos subgráficos em aceleradores (ou seja, usando with tf.device('/device:GPU:0'): ... ).

CPUs modernas

CPUs modernas têm estendido continuamente a arquitetura do conjunto de instruções x86 para melhorar o suporte para SIMD (Single Instruction Multiple Data) e outros recursos críticos para cálculos densos (por exemplo, multiplicação e adição em um ciclo de clock). No entanto, para funcionar em máquinas um pouco mais antigas, o TensorFlow e o TensorFlow Serving são criados com a modesta suposição de que o mais novo desses recursos não é compatível com a CPU do host.

Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA

Se você vir esta entrada de log (possivelmente extensões diferentes das 2 listadas) na inicialização do TensorFlow Serving, significa que você pode reconstruir o TensorFlow Serving e direcionar a plataforma do seu host específico e desfrutar de melhor desempenho. Criar o TensorFlow Serving a partir do código-fonte é relativamente fácil usando o Docker e está documentado aqui .

Configuração Binária

O TensorFlow Serving oferece vários botões de configuração que controlam seu comportamento em tempo de execução, principalmente definidos por meio de sinalizadores de linha de comando . Alguns deles (mais notavelmente tensorflow_intra_op_parallelism e tensorflow_inter_op_parallelism ) são transmitidos para configurar o tempo de execução do TensorFlow e são configurados automaticamente, que usuários experientes podem substituir fazendo muitos experimentos e encontrando a configuração correta para sua carga de trabalho e ambiente específicos.

Vida útil de uma solicitação de inferência do TensorFlow Serving

Vamos examinar brevemente a vida de um exemplo prototípico de uma solicitação de inferência do TensorFlow Serving para ver a jornada que uma solicitação típica percorre. Para nosso exemplo, vamos nos aprofundar em uma solicitação de previsão recebida pela superfície da API gRPC do TensorFlow Serving 2.0.0.

Vamos primeiro examinar um diagrama de sequência em nível de componente e depois passar para o código que implementa essa série de interações.

Diagrama de sequência

Diagrama de sequência de previsão

Observe que Client é um componente de propriedade do usuário, Prediction Service, Servables e Server Core são de propriedade do TensorFlow Serving e o TensorFlow Runtime é de propriedade do Core TensorFlow .

Detalhes da sequência

  1. PredictionServiceImpl::Predict recebe o PredictRequest
  2. Invocamos o TensorflowPredictor::Predict , propagando o prazo da solicitação a partir da solicitação gRPC (se alguma tiver sido definida).
  3. Dentro de TensorflowPredictor::Predict , procuramos o Servable (modelo) no qual a solicitação está procurando realizar inferência, do qual recuperamos informações sobre o SavedModel e, mais importante, um identificador para o objeto Session no qual o gráfico do modelo está (possivelmente parcialmente) carregado. Este objeto Servable foi criado e confirmado na memória quando o modelo foi carregado pelo TensorFlow Serving. Em seguida, invocamos internal::RunPredict para realizar a previsão.
  4. Em internal::RunPredict , após validar e pré-processar a solicitação, usamos o objeto Session para realizar a inferência usando uma chamada de bloqueio para Session::Run , ponto em que entramos na base de código principal do TensorFlow. Após o retorno de Session::Run e nossos tensores outputs terem sido preenchidos, convertemos as saídas em PredictionResponse e retornamos o resultado na pilha de chamadas.