Solução de problemas e perguntas frequentes

Este guia apresenta soluções de problemas para os usuários que querem executar os próprios modelos do TensorFlow na Cloud TPU. Para ver um guia mais geral sobre como dar os primeiros passos com a Cloud TPU, consulte o guia de início rápido ou o tutorial do MNIST.

Visão geral

A estratégia recomendada para executar os modelos do TensorFlow na Cloud TPU é usar a API TPUEstimator. Se você já usa a API Estimator do TensorFlow, geralmente é necessário alterar apenas algumas linhas de código para trocar para a TPUEstimator. A maneira recomendada de carregar dados na TPUEstimator é com a API Dataset. Consulte o tutorial do ResNet para ver um exemplo real de como usar Dataset e TPUEstimator.

Depois de converter o modelo para TPUEstimator, verifique se ela funciona com a sinalização use_tpu=False. Com ela, o TensorFlow retorna à API Estimator comum e não usa nenhum código relacionado à TPU. Portanto, quaisquer problemas encontrados na execução de modelos quando use_tpu=False não estão relacionados à TPU nem incluídos no escopo deste guia. Para encontrar ajuda geral sobre o TensorFlow, consulte a documentação dele.

Quando é possível executar um modelo com a TPUEstimator e use_tpu=False, o ideal é que executá-lo na TPU seja apenas uma questão de definir use_tpu=True e apontar master para um URL de servidor de TPU, geralmente usando um resolvedor de cluster. No entanto, como os modelos do TensorFlow podem ser muito complexos, e a TPU usa um mecanismo de execução totalmente novo, é possível que ocorram problemas específicos da TPU. Eles estão incluídos nas cinco amplas categorias a seguir, com links para a seção relevante neste guia:

  1. Não é possível conectar o script de treinamento ao servidor da TPU de nenhuma maneira.

  2. Ocorre um erro na TPU ao tentar executar o modelo.

  3. O modelo não cabe na memória da TPU.

  4. O modelo é executado na TPU, mas a velocidade de treinamento não é tão rápida quanto esperado.

  5. O modelo é executado na TPU, mas a precisão do modelo treinado pela TPU é pior do que uma linha de base treinada pela CPU/GPU.

Além disso, você encontra neste guia perguntas frequentes sobre a funcionalidade geral disponível nas TPUs.

Para encontrar mais ajuda especializada sobre a portabilidade de tipos específicos de redes neurais para a TPU, consulte os tutoriais da Cloud TPU.

Problema ao se conectar ao servidor da TPU

Ao executar um modelo na TPU, é necessário transmitir um URL remoto do servidor da TPU para o parâmetro master em RunConfig. Em segundo plano, o TensorFlow cria uma tf.Session remota com esse servidor. Essa seção fornece soluções de problemas para quando o TensorFlow trava ou exibe um erro ao se conectar ao servidor da TPU. A etapa de compilação do gráfico da TPU pode levar muito tempo nos modelos grandes. Portanto, execute o script por pelo menos 5 minutos antes de confirmar que ele travou.

A primeira etapa é verificar se o problema está no próprio servidor ou no canal de treinamento do TensorFlow. Para isso, execute o tutorial do MNIST usando o URL de servidor da TPU e verifique se funciona corretamente. Se o tutorial do MNIST não conectar, isso confirma que o problema é no servidor da TPU. Nesse caso, siga as seguintes etapas:

  1. Execute o comando a seguir para listar as TPUs disponíveis:

    (vm)$ gcloud compute tpus list
    

    Talvez também seja necessário definir zone e project, conforme mostrado no tutorial do MNIST. Isso exibe um resultado como este:

    NAME       ZONE           ACCELERATOR_TYPE  NETWORK_ENDPOINT   NETWORK  RANGE          STATUS
    demo-tpu   us-central1-b  v2-8              10.240.1.2:8470    default  10.240.1.0/29  READY

  2. Verifique se você está transmitindo o valor correto para --tpu_name (demo-tpu no exemplo acima), e se essa TPU está listada como READY. Garanta também que zone e project tenham sido definidos com:

    (vm)$ gcloud config set project your-project-name
    
    (vm)$ gcloud config set compute/zone us-central1-b
    

  3. Se a TPU não estiver listada como READY, ou se você ainda estiver com problemas de conexão, reinicie manualmente o servidor com gcloud compute tpus reset $TPU_NAME. No exemplo acima, $TPU_NAME é demo-tpu. Isso pode levar alguns minutos.

  4. Execute novamente o comando ... tpus list acima e espere a TPU entrar no estado READY. Isso pode levar alguns minutos.

  5. Tente executar o tutorial do MNIST novamente.

  6. Se ainda estiver com problemas para executar o tutorial do MNIST, peça ajuda ao suporte da TPU.

Se o exemplo do MNIST for executado corretamente, mas o modelo continuar travando, é provável que o problema seja com o canal de treinamento. Primeiro, verifique se você usa a API TPUEstimator no modelo, já que ela lida com o canal de processamento complexo e possibilita a troca simples entre a execução de TPU e não TPU com a sinalização use_tpu. Consulte os tutoriais da TPU para ver vários exemplos de como usar a TPUEstimator. Depois que começar a usar a API TPUEstimator no modelo, verifique se ele é executado corretamente quando use_tpu=False está definido. Se a execução falhar mesmo com use_tpu=False definido, o problema não está relacionado à TPU.

Como depurar erros comuns

Não é possível usar o sistema de arquivos local

Mensagem de erro

InvalidArgumentError: Unimplemented: File system scheme '[local]' not implemented

Detalhes

É necessário usar um caminho de intervalo do Cloud Storage (gs://bucket-name/...) em todos os arquivos de entrada e no diretório do modelo. Esse intervalo precisa ser acessível a partir do servidor da TPU. Todo o processamento de dados e a criação de pontos de verificação do modelo são executados no servidor da TPU, e não na máquina local. Para ver informações sobre como configurar corretamente o Cloud Storage para usá-lo com a TPU, consulte o guia Como conectar-se a intervalos do Cloud Storage.

Tipo de dados incompatível

Mensagem de erro

TypeError: DataType is not a supported TPU infeed type.

Detalhes

No momento, apenas os tipos de dados tf.float32, tf.int32, tf.bfloat16 e tf.bool são compatíveis com a TPU. É necessário converter outros tipos comuns como tf.uint8, tf.string e tf.int64 para um dos tipos compatíveis durante o pré-processamento de dados, ou seja, no input_fn da TPUEstimator. Consulte o tutorial do MNIST para ver outro exemplo. Como exemplo, este snippet de código do MNIST converte um tensor image armazenado como uma sequência de bytes tf.uint8 para um tf.float32:

image = tf.decode_raw(image, tf.uint8)
image = tf.cast(image, tf.float32)
image = tf.reshape(image, [784])

Este snippet converte um tensor label armazenado como tf.int64 para um tf.int32:

label = tf.cast(label, tf.int32)

Formas dinâmicas incompatíveis

Mensagem de erro

ValueError: shape [Shape] must have a fixed size for dimension d that is known at graph construction time.

Detalhes

Para executar um modelo na TPU, o TensorFlow o compila usando a biblioteca XLA. Essa etapa de compilação aumenta bastante a velocidade de treinamento e o uso de memória. No entanto, as formas ou tamanhos de dimensão de todos os tensores no gráfico precisam ser estáticos. Isso significa que seus valores precisam ser conhecidos no momento da compilação do gráfico. Se não for possível determinar formas nesse momento, a compilação da TPU falhará com um erro como o acima.

Uma operação comum que retorna uma forma dinâmica é dataset.batch(batch_size), já que o número de amostras restantes em um fluxo pode ser menor que o tamanho do lote. Portanto, ao realizar treinamentos na TPU, use tf.contrib.data.batch_and_drop_remainder(batch_size). Isso possivelmente elimina as últimas amostras de um arquivo para garantir que cada lote tenha a forma estática de batch_size. Por exemplo:

dataset = ...
dataset = dataset.apply(tf.contrib.data.batch_and_drop_remainder(batch_size))

Operação do TensorFlow indisponível

Mensagem de erro

NotFoundError: No registered 'OpName' OpKernel for XLA_TPU_JIT devices compatible with node

Detalhes

O modelo usa uma operação do TensorFlow que não está atualmente disponível na TPU.

Para ver uma lista de operações disponíveis na TPU, juntamente com planos para compatibilidade futura e sugestões de soluções alternativas, consulte o guia sobre operações disponíveis do TensorFlow.

Mensagem de erro de falta de memória

Mensagem de erro

ResourceExhaustedError: Ran out of memory in memory space hbm; used: YYY; limit: 7.48G.

Detalhes

Cada Cloud TPU é formada por oito núcleos, todos com 8 GB de RAM (ou HBM, memória de alta largura de banda, na sigla em inglês). Essa memória é usada para armazenar os tensores de peso (variáveis), bem como os de resultados intermediários necessários para o cálculo do gradiente. Se o modelo for muito grande para caber na RAM da TPU, a inicialização falhará, e a mensagem de erro acima será exibida. Consulte a seção sobre como reduzir o uso de memória para encontrar mais ajuda.

CrossShardOptimizer não está em uso

Mensagem de erro

ValueError: CrossShardOptimizer must be used for model training on TPUs.

Detalhes

Ao definir um modelo usando a API TensorFlow de Python, a grande maioria do código escrito pelo usuário não precisa ser especializada para a TPU. A exceção mais significativa é o otimizador, que precisa ser encapsulado em tf.contrib.tpu.CrossShardOptimizer() como mostrado abaixo:

optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
if FLAGS.use_tpu:
  optimizer = tf.contrib.tpu.CrossShardOptimizer(optimizer)
train_op=optimizer.minimize(loss, tf.train.get_global_step())

Cada Cloud TPU é formada por 8 núcleos, que são unidades de processamento independentes. Em cada etapa de treinamento ou atualização de peso, todos esses núcleos calculam os valores de saída e fazem a computação do gradiente em um pequeno lote independente de dados. Em seguida, eles trocam gradientes entre si. Na maioria dos casos, isso é matematicamente equivalente a calcular os gradientes em um lote grande, mesmo havendo algumas ressalvas explicadas em Noções básicas sobre a fragmentação de dados.

CrossShardOptimizer é a operação responsável por essa troca de gradientes. Por padrão, o CrossShardOptimizer calcula os gradientes da perda média nos núcleos. No entanto, é possível configurá-lo para calcular a perda somada transmitindo reduction=losses.Reduction.SUM.

Não é possível se conectar ao servidor da TPU

Mensagem de erro

An error was raised while a session was being created. This may be due to a preemption of a connected worker or parameter server. A new session is created.

Detalhes

Esse erro é exibido quando o TensorFlow não consegue se conectar ao URL do servidor da TPU, que é transmitido para o master. Para encontrar ajuda, consulte a seção sobre problemas ao se conectar ao servidor da TPU.

Erros no meio do treinamento

Todos os erros relacionados à falha na execução do modelo na TPU foram projetados para serem descobertos durante a inicialização. Portanto, é raro que um modelo falhe no meio do treinamento. Se isso acontecer, a causa mais provável é um problema na função de pré-processamento de dados. Por exemplo, ao usar a API Dataset, você normalmente precisa chamar dataset = dataset.repeat(). Caso contrário, o treinamento falhará após a primeira transmissão pelos dados. As operações de execução dinâmicas como tf.while_loop() também só falham de um jeito que é dependente dos dados de entrada. Há também a rara possibilidade de hardware falso ou falhas de rede.

Problemas que interrompem a execução

Quando há erro no TensorFlow durante a execução da TPU, o script costuma travar em vez de sair para o shell. Se isso acontecer, pressione CTRL+\ no teclado para acionar SIGQUIT, o que encerra o Python de imediato.

Da mesma forma, pressionar CTRL+C durante a execução da TPU não encerra o TensorFlow imediatamente. Em vez disso, ele aguarda o fim do ciclo de iteração atual para se encerrar corretamente. Pressionar CTRL+\ encerra o Python de imediato.

Se tiver algum problema para se reconectar ao servidor da TPU após encerrar dessa maneira, redefina manualmente o servidor com o comando gcloud compute tpus reset $TPU_SERVER_NAME, em que $TPU_SERVER_NAME é retirado da primeira coluna do comando gcloud compute tpus list.

Como reduzir o uso da memória

Se ocorrer um erro de falta de memória ao executar o modelo na TPU, você precisará reduzir o uso da memória. Nesta seção, descrevemos várias causas principais dos problemas de memória e fornecemos diretrizes para solucioná-los.

Grande número de pesos de modelo

Possível causa do problema de memória

Cada peso de modelo float32 requer 4 bytes. Eles são replicados em cada núcleo da TPU. Portanto, um modelo com centenas de milhões de pesos provavelmente será grande demais para caber na TPU.

Como reduzir o uso de memória

  1. Alguns otimizadores exigem memória adicional por peso para armazenar estatísticas de atualização. Especialmente, AdamOptimizer e AdadeltaOptimizer requerem 8 bytes extras por peso. Já AdagradOptimizer e MomentumOptimizer exigem 4. O GradientDescentOptimizer padrão não requer armazenamento extra. No entanto, ele pode não ter o mesmo desempenho de outros otimizadores em termos de precisão final do modelo. O AdafactorOptimizer experimental exige quase nenhuma memória. Ele tem o mesmo desempenho do otimizador Adam de linha de base ao treinar modelos Transformer.
  2. Se a maioria dos pesos for incorporações de palavras, técnicas como o WordPiece reduzem bastante o tamanho do vocabulário e aumentam a precisão em várias tarefas.
  3. Uma próxima versão do TensorFlow oferecerá compatibilidade experimental com pesos e gradientes de ponto flutuante de 16 bits, o que reduzirá pela metade os requisitos de memória.

Preenchimento excessivo do tensor

Possível causa do problema de memória

Os tensores na memória da TPU são preenchidos. Isso significa que a TPU arredonda os tamanhos dos tensores armazenados na memória para executar cálculos com mais eficiência. O preenchimento acontece de modo evidente no nível do hardware e não afeta os resultados. No entanto, em alguns casos, o preenchimento aumenta bastante o uso de memória e o tempo de execução.

Como reduzir o uso de memória

O software da TPU exibe os tensores na memória para aumentar a eficiência computacional e minimizar o preenchimento. Esse processo de exibição da memória é complexo. No entanto, para conseguir os melhores resultados, o modelo precisa cumprir a regra geral a seguir. Para reduzir a sobrecarga de memória e aumentar a eficiência computacional, é necessário que:

  • o tamanho total do lote seja múltiplo de 64 (8 por núcleo de TPU), e as dimensões do recurso sejam múltiplo de 128;

    ou

  • o tamanho total do lote seja múltiplo de 1024 (128 por núcleo de TPU), e as dimensões do recurso sejam múltiplo de 8.

Ao usar um tamanho de lote de 1024 e dimensões de recurso que são múltiplo de 128, você garante a melhor eficiência, mesmo que isso não seja possível em todos os modelos. Para maior clareza, a "dimensão de recurso" se refere ao tamanho oculto de uma camada totalmente conectada ou ao número de canais de saída em uma convolução. Nem todas as camadas seguem essa regra, especialmente a primeira e a última da rede. Isso não é um problema, e é esperado que a maioria dos modelos exija uma certa quantidade de preenchimento.

Tamanho de lote muito grande

Possível causa do problema de memória

Ao treinar uma rede neural em uma CPU, GPU ou TPU, o uso da memória é proveniente do:

  1. armazenamento dos pesos, gradientes de peso e estatísticas específicas do otimizador, como momentum. O uso da memória é diretamente proporcional ao número de pesos no modelo, mas não ao tamanho do lote;
  2. armazenamento de ativações intermediárias do passe para frente necessário para calcular o passe para trás. O uso da memória é diretamente proporcional aos tamanhos do lote e da camada e ao número de camadas.

Portanto, a memória exigida por um modelo é muito dependente do tamanho do lote.

Como reduzir o uso de memória

Reduza lentamente o tamanho do lote até que ele caiba na memória. Verifique se ele é múltiplo de 64. O tamanho do lote por núcleo precisa ser múltiplo de 8. Lembre-se de que tamanhos de lote maiores são mais eficientes na TPU. O tamanho total de 1024 (128 por núcleo) costuma ser um bom ponto de partida.

Modelo muito grande

Possível causa do problema de memória

A memória exigida por um modelo é muito dependente do número de operadores no gráfico, ou seja, das camadas na rede. Esse requisito é separado do número de pesos. Por exemplo, calcular o gradiente de um operador como tf.nn.conv2d() aumenta o uso da memória, além de qualquer memória usada para armazenar pesos.

O mecanismo da TPU recalcula estrategicamente determinados operadores para ajustar o modelo na memória. Isso é chamado de rematerialização e é similar ao ponto de verificação do gradiente. No entanto, o mecanismo nem sempre é capaz de fazer isso.

Como reduzir o uso de memória

Se não for possível executar o modelo na TPU mesmo com um tamanho de lote pequeno (por exemplo, 64), reduza o número de camadas ou os tamanhos delas. Uma próxima versão do TensorFlow será compatível com o "paralelismo de modelos" na TPU. Isso possibilita que modelos muito maiores sejam executados na Cloud TPU ao colocar diferentes partes dele em funcionamento em diferentes núcleos da TPU.

Como melhorar a velocidade do treinamento

Nesta seção, descrevemos várias possíveis maneiras de melhorar a velocidade do treinamento se você conseguir executar o modelo na TPU, mas a velocidade será mais lenta que o esperado.

Todos os núcleos da TPU não estão em uso

Descrição do problema de desempenho

Cada Cloud TPU contém 8 núcleos de TPU separados, que funcionam como unidades de processamento independentes. A TPU não é totalmente utilizada a menos que todos os 8 núcleos sejam.

Como saber se o modelo foi afetado

Se o modelo não especifica explicitamente o parâmetro num_shards de TPUConfig como 8, o TensorFlow não utiliza todos os núcleos da TPU.

Como mitigar

Ao executar um treinamento de TPU completo, sempre defina num_shards como 8. Consulte o tutorial do MNIST ou o snippet de código abaixo para ver um exemplo:

tf.flags.DEFINE_integer("num_shards", 8, "Number of shards (TPU chips).")

run_config = tf.contrib.tpu.RunConfig(
  tpu_config=tf.contrib.tpu.TPUConfig(num_shards=FLAGS.num_shards, ...

estimator = tf.contrib.tpu.TPUEstimator(
    config=run_config, ...

Às vezes, definir num_shards como 1 pode ser útil para depurar diferenças na precisão do modelo. Portanto, recomendamos o uso de uma sinalização de linha de comando com o valor padrão de 8.

Muito poucas iterações por ciclo

Descrição do problema de desempenho

O parâmetro iterations_per_loop para TPUConfig controla quantos lotes de dados são enviados à TPU em um único "ciclo de treinamento". Cada um deles requer bastante comunicação entre a máquina local e o servidor da TPU. Portanto, se iterations_per_loop for muito pequeno, o treinamento poderá ser muito lento.

Como saber se o modelo foi afetado

Se a mensagem de registro Enqueue next (X) batch(es) of data to infeed for exibida com muita frequência (por exemplo, a cada 3 segundos), é provável que o treinamento tenha uma grande sobrecarga proveniente do ciclo.

Como mitigar

Defina iterations_per_loop como um valor maior. No tutorial do MNIST, isso é controlado pela sinalização --iterations. Contanto que a mensagem Enqueue next (X) batch(es) of data to infeed não seja exibida mais do que algumas vezes por minuto, o valor atual será suficiente. É possível definir iterations_per_loop como um valor muito grande. A única desvantagem é que as mensagens de registro e o ponto de verificação só podem ocorrer no final de um ciclo.

Gargalo de processamento de entrada

Descrição do problema de desempenho

Enquanto a TPU realiza o treinamento em um determinado bloco de dados, a função de processamento de entrada prepara o próximo bloco na CPU. Assim, se a função de entrada leva menos tempo que a do modelo, o custo do processamento de entrada é efetivamente zero. No entanto, uma função de entrada que leva mais tempo que a função do modelo cria um gargalo.

Como saber se o modelo foi afetado

Siga as instruções em Ferramentas da Cloud TPU: analisador do canal de entrada para ver a respectiva análise no TensorBoard:

imagem

A página de análise do canal de entrada exibe um resumo claro que mostra se o modelo tem gargalo do processamento de entrada. Ela também exibe o tempo de execução por operação para identificar as operações problemáticas.

Como mitigar

Há várias mitigações possíveis ao carregar dados com a API Dataset:

  1. Armazene os dados como uma coleção de estruturas tf.train.Example em arquivos TFRecord e os carregue com TFRecordDataset. Consulte o tutorial da API Dataset ou o do ResNet para ver exemplos.
  2. Use dataset.cache() e/ou dataset.prefetch() para armazenar em buffer os dados de entrada. Isso evita que lentidões esporádicas no acesso aos arquivos criem um gargalo.
  3. Especifique o parâmetro num_parallel_calls da função dataset.map() para ativar operações map() com várias threads.
  4. Realize o caro pré-processamento de dados off-line como um custo único em vez de gerá-lo em todas as épocas de cada treinamento.

Todo o processamento de entrada é executado em CPUs localizadas no servidor da TPU, e não na máquina local. Portanto, a velocidade da máquina local não é um fator.

Muitas operações de multiplicação não matricial

Descrição do problema de desempenho

A Cloud TPU realiza convoluções e multiplicações de matrizes a velocidades incrivelmente altas. A maioria das outras operações do TensorFlow conta com implementações eficientes na TPU. No entanto, essa não é a principal qualidade da TPU em relação a outros hardwares. Portanto, é necessário que as convoluções ou multiplicações de matrizes sejam predominantes no modelo para aproveitar ao máximo a TPU.

Como saber se o modelo foi afetado

No guia Ferramentas da Cloud TPU: perfil das operações, descrevemos como gerar um perfil de desempenho para o modelo de acordo com o tipo de operação. Em geral, as convoluções e multiplicações de matrizes são predominantes na grande maioria das arquiteturas modernas de rede neural.

Como mitigar

Se a falta de multiplicações de matrizes no modelo for motivada principalmente por problemas na velocidade do treinamento em outro hardware, recomendamos que você faça novamente a comparação desses modelos na TPU para melhorar a velocidade. Se isso for uma propriedade fundamental do modelo, a TPU não é a melhor opção de hardware.

Preenchimento excessivo do tensor

Descrição do problema de desempenho

A TPU preenche os tensores na memória para poder usar as unidades computacionais com eficiência. O preenchimento pode aumentar o uso da memória e da largura de banda dela. Consulte a seção sobre preenchimento de tensor para entender e solucionar os problemas relacionados.

Tamanho do lote muito pequeno

Descrição do problema de desempenho

Como regra geral, o uso de lotes maiores aumenta a velocidade de treinamento na TPU em termos de amostras/segundo.

Como saber se o modelo foi afetado

O tamanho do lote de qualquer modelo precisa sempre ser pelo menos 64 (8 por núcleo de TPU), já que a TPU preenche os tensores nesse tamanho. O tamanho ideal ao treinar na TPU é de 1024 (128 por núcleo de TPU). Isso elimina as ineficiências relacionadas à transferência de memória e preenchimento.

Como mitigar

Recomendamos que você use o maior tamanho de lote que se encaixe na memória e seja múltiplo de 64. Para isso, o jeito mais fácil é começar com 1024. Se ocorrer um erro de falta de memória, reduza o tamanho do lote até que o modelo seja executado com êxito. Alterar o tamanho do lote de um modelo requer o ajuste de outros hiperparâmetros para conseguir a mesma precisão, como a taxa de aprendizado. No entanto, isso precisa ser avaliado de acordo com o caso.

Tamanhos de camada muito pequenos

Descrição do problema de desempenho

Mesmo quando as convoluções e multiplicações de matrizes são predominantes no modelo, a TPU pode não funcionar com eficiência total se os tensores de entrada forem pequenos. Em comparação a outros hardwares, a TPU é executada com mais eficiência quando o tamanho do lote e os da camada são grandes. Por exemplo, dimensão ≥ 512.

Como saber se o modelo foi afetado

Como regra geral, os tamanhos de camada menores que 128 geram baixa eficiência na TPU. Isso acontece porque 128 é a dimensão nativa da unidade de multiplicação de matriz da TPU. Nas camadas totalmente conectadas, o tamanho mínimo oculto de 512 é recomendado para gerar alta eficiência. As camadas convolucionais normalmente não precisam ser tão grandes quanto as totalmente conectadas para atingir o mesmo nível de eficiência. Por exemplo, uma convolução 3 × 3 de tamanho 256 atinge eficiência similar (alta) em comparação com uma camada totalmente conectada de tamanho 2048, já que 3 × 3 × 256 = 2304.

Como mitigar

Se os tamanhos pequenos de camada no modelo forem motivados principalmente pela velocidade do treinamento, recomendamos que você faça novamente a comparação dos modelos com camadas maiores na TPU. Por exemplo, dobrar o tamanho da saída de uma camada de 256 para 512 só aumenta o tempo de treinamento em 20%, mesmo que o modelo execute duas vezes a computação.

Perfil de modelo no nível operacional

Geralmente, é bom medir o uso de memória e tempo de execução no nível operacional para identificar gargalos de desempenho. Para ver instruções sobre como fazer isso, consulte o guia Ferramentas da Cloud TPU: visualizador de rastreamento.

Como depurar quedas na precisão do modelo

Um dos objetivos do ecossistema da Cloud TPU é que qualquer modelo treinado atualmente em uma CPU ou GPU atinja uma precisão muito semelhante no treinamento na TPU, com pequenos ajustes nos hiperparâmetros como o tamanho do lote e a taxa de aprendizado. No entanto, os usuários às vezes observam uma queda na precisão ao treinar modelos na TPU. A depuração desses problemas pode ser muito frustrante devido à natureza aleatória do treinamento da rede neural. Nesta seção, fornecemos orientações sobre como identificar a principal causa de qualquer queda na precisão ao portar um modelo para a TPU.

Noções básicas sobre fragmentação de dados (paralelismo)

Um dos principais objetivos do TensorFlow é que cada operação produza resultados quase idênticos, seja a execução na CPU, GPU ou TPU. Há certas exceções, como as operações aleatórias. Em geral, se você encontrar qualquer diferença significativa entre o resultado de operações não aleatórias na TPU e CPU, denuncie como um bug para o suporte da TPU.

No entanto, no canal de treinamento como um todo, há uma grande diferença entre o treinamento na CPU/GPU e na TPU. Ao usar TPUEstimator e use_tpu=False, o TensorFlow retorna ao mecanismo de execução padrão. Ele treina um lote por etapa. Porém, ao treinar na TPU verdadeira, o TensorFlow faz a fragmentação de dados, também conhecida como "paralelismo de dados com SGD síncrono". Isso acontece porque cada Cloud TPU é formada por 8 núcleos que funcionam como unidades de processamento independentes. Portanto, em cada etapa do treinamento, todos os núcleos da TPU recebem um lote de dados, calculam os gradientes de peso, trocam esses gradientes entre si e então calculam a atualização de peso. Por padrão, a média de perda é calculada nos núcleos, mas é possível somá-la alterando o parâmetro de CrossShardOptimizer.

Se for possível calcular a perda total do modelo como a média ou soma de perdas independentes por amostra, este procedimento será matematicamente similar ao treinamento em um único lote grande. A operação mais comum que não é independente por amostra é a normalização de lote, que é executada em cada lote por núcleo separadamente. Por exemplo, se o tamanho total do lote for 128, o tamanho por núcleo será 16. Cada um dos 8 núcleos executará a normalização de lote nas 16 amostras. Em alguns casos, há queda na precisão ao executar a normalização em lotes pequenos. Por exemplo, menos de 32. No cenário ideal, o tamanho total do lote ao realizar treinamentos na TPU pode ser grande. Por exemplo, de 256 a 1024. Portanto, lotes desse tamanho não são um grande problema. No entanto, se esse tamanho for muito grande para caber na memória, será necessário avaliar o efeito da fragmentação de acordo com o caso.

Por conta das complexidades geradas pela fragmentação, a primeira etapa para depurar quedas na precisão do modelo é executar um treinamento de TPU determinista e de núcleo único. Depois, basta compará-lo a um modelo treinado na CPU/GPU. Geralmente, isso é feito rapidamente porque não requer o treinamento de um modelo para convergência.

Treinamento determinista

Um motivo da dificuldade em depurar diferenças na precisão do modelo é que o TensorFlow usa inicialização de peso e embaralhamento de dados diferentes sempre que um modelo é treinado. É bom modificar o procedimento de treinamento para ser determinista. Assim, várias execuções produzem modelos quase idênticos. Nesta seção, você aprende a executar o tutorial do MNIST com determinismo:

  1. Gere um arquivo de ponto de verificação inicial ao executar uma única etapa na CPU. Ela é usada para conseguir a inicialização de peso determinista. Também é possível sugerir os inicializadores de variáveis, mas isso é mais difícil.
# Run training for 1 step to create an initial checkpoint.
python mnist_tpu.py \
  --use_tpu=False \
  --data_dir=${STORAGE_BUCKET}/data/ \
  --model_dir=${STORAGE_BUCKET}/init_output \
  --random_seed=12345 \
  --iterations=1
  --train_steps=1
  1. Modifique as funções de embaralhamento de dados na função de entrada para usar uma sugestão aleatória. Você já fez isso no tutorial do MNIST. É algo que funciona para as operações de processamento de dados de entrada porque elas são sempre executadas na CPU. As operações aleatórias na função do modelo podem não ser deterministas entre a TPU e a CPU. Por exemplo:
# In the flag definitions
tf.flags.DEFINE_integer("batch_size", None, "Random seed for training")

# In the input_fn
if FLAGS.random_seed is not None:
dataset = dataset.shuffle(seed=FLAGS.random_seed)
  1. Execute o mesmo modelo duas vezes na CPU para verificar se o treinamento é determinista. É necessário executá-lo em um número razoável de etapas. Por exemplo, 1000. No entanto, ele não precisa ser executado para convergência, já que isso é muito lento na CPU.

    Como o treinamento na CPU é parecido com um treinamento de núcleo único na TPU, use um tamanho de lote que caiba em um único núcleo de TPU. Normalmente, é o tamanho total do lote dividido por 8. O TensorFlow não garante o determinismo bit a bit entre as execuções, mas a perda será muito parecida:
# Copy the initial weights
gsutil mkdir ${STORAGE_BUCKET}/cpu_output_1
gsutil cp -f ${STORAGE_BUCKET}/init_output/* ${STORAGE_BUCKET}/cpu_output_1
gsutil mkdir ${STORAGE_BUCKET}/cpu_output_2
gsutil cp -f ${STORAGE_BUCKET}/init_output/* ${STORAGE_BUCKET}/cpu_output_2

# Run 1
python mnist_tpu.py \
  --use_tpu=False \
  --data_dir=${STORAGE_BUCKET}/data/ \
  --model_dir=${STORAGE_BUCKET}/cpu_output_1 \
  --batch_size=128 \
  --random_seed=12345 \
  --train_steps=2000 \
  --eval_steps=10

# Output 1
accuracy = 0.9910644, global_step = 1000, loss = 0.025323588

# Run 2
python mnist_tpu.py \
  --use_tpu=False \
  --data_dir=${STORAGE_BUCKET}/data/ \
  --model_dir=${STORAGE_BUCKET}/cpu_output_1 \
  --batch_size=128 \
  --random_seed=12345 \
  --train_steps=2000 \
  --eval_steps=10

# Output 2
accuracy = 0.9910644, global_step = 1000, loss = 0.025323414

Treinamento de núcleo único na TPU

Depois que for possível executar o tutorial do MNIST com determinismo, a próxima etapa é replicar os resultados treinados pela CPU na TPU. Você usa um único núcleo de TPU para identificar se o problema está relacionado à fragmentação de dados ou ao próprio mecanismo de execução da TPU.

Veja como executar uma avaliação e treinamento de núcleo único no tutorial do MNIST:

# Use the same weight initialization as the CPU
gsutil cp -f ${STORAGE_BUCKET}/init_output/* ${STORAGE_BUCKET}/tpu_output

# Run training for 1000 steps
python mnist.py \
    --use_tpu=True \
    --master=$GRPC_SERVER \
    --train_file=${STORAGE_BUCKET}/data/train.tfrecords \
    --model_dir=${STORAGE_BUCKET}/tpu_output \
    --random_seed=12345 \
    --batch_size=128 \
    --num_shards=1 \
    --train_steps=1000 \
    --eval_steps=10

  accuracy = 0.9910644, global_step = 1000, loss = 0.02514153

A perda não corresponderá exatamente ao modelo treinado pela CPU, mas será parecida. Caso contrário, isso indica que você encontrou um bug no mecanismo de execução da TPU. Antes de enviar um relatório de bug ao suporte da TPU, verifique o seguinte:

  1. Se você está transmitindo num_shards=1 para TPUConfig.

  2. Se você não tem operações aleatórias na função do modelo, e se qualquer operação aleatória na função de entrada está sendo sugerida corretamente.

  3. Se você está usando o mesmo arquivo de ponto de verificação inicial no treinamento da CPU e da TPU.

Como depurar o treinamento de vários núcleos na TPU

Se o modelo tiver a mesma perda na CPU e na TPU de núcleo único, o problema é provavelmente um dos seguintes:

(a) A degradação é por conta da variância aleatória natural ao treinar modelos neurais com diferentes inicializações.

(b) A degradação é por conta de um problema relacionado à fragmentação de dados na TPU.

Para determinar se (a) é o problema, treine novamente o modelo completo na CPU/GPU e na TPU de vários núcleos usando a mesma inicialização de peso, como mostrado acima.

Se você tiver certeza de que a queda na precisão tem significância estatística, estes são os problemas mais prováveis relacionados à fragmentação de dados:

  1. Se o modelo calcula a perda como a soma dos erros por amostra, transmita reduction=losses.Reduction.SUM para CrossShardOptimizer. Por padrão, CrossShardOptimizer calcula a média das perdas, em vez da soma.
  2. Se o modelo usa a normalização de lote, um tamanho total menor que 256 (por exemplo, menos de 32 por núcleo) poderá reduzir a precisão.
  3. Se o modelo tem uma função de perda por lote, ela é afetada pela fragmentação. Essas funções costumam ser muito especializadas. Por exemplo, Karras et al.(2017) usa um discriminador de lotes ao treinar uma rede adversária generativa.

Perguntas frequentes sobre a funcionalidade disponível

Posso usar a TPU para inferência?

Sim, é possível usá-la para treinamento e inferência. Por exemplo, no tutorial do ResNet, você realiza avaliações periódicas durante o ciclo de treinamento. Para o fornecimento de modelo, há algumas ressalvas a serem observadas. O principal é que a pilha de software da TPU é otimizada atualmente para capacidade, e não latência. No momento, executar a inferência em um único lote de entrada e aguardar o resultado tem uma sobrecarga de pelo menos 10 ms, o que pode ser um problema no fornecimento de baixa latência.

Essa sobrecarga será muito reduzida nas próximas versões do TensorFlow.

Há alguma operação integrada do TensorFlow que não está disponível na TPU?

No momento, há uma pequena quantidade de operações integradas do TensorFlow que não está disponível na TPU. Consulte o guia sobre as operações disponíveis do TensorFlow, que mostra detalhes das soluções alternativas atuais.

Como escrever uma operação personalizada para a TPU?

As operações do TensorFlow executadas na TPU são implementadas no HLO do XLA. Essa é uma linguagem para definir operações detalhadas de tensor por meio de um pequeno conjunto de funções de nível baixo. O XLA está incluído na versão de código aberto do TensorFlow. Portanto, é tecnicamente possível escrever a operação no HLO. Você encontra a maioria das implementações existentes no diretório tf2xla. No entanto, isso possibilita apenas a execução de um conjunto limitado de operações de tensor na TPU, não C++ arbitrário ou código Python. A maioria das operações de tensor comuns que você pode implementar no HLO já foi escrita. Uma próxima versão do TensorFlow será compatível com a execução eficiente de operações padrão da CPU durante o treinamento/inferência da TPU.

Posso usar marcadores e dicionários de feed com uma TPU?

Esse padrão de uso está tecnicamente disponível na TPU, mas é altamente recomendável não usá-lo. Ele utiliza apenas um único núcleo de TPU, o que gera muita sobrecarga. Na verdade, para criar um canal de treinamento, use as APIs TPUEstimator e Dataset. Consulte o tutorial do ResNet para ver um exemplo de como criar um ciclo de treinamento simples com TPUEstimator e Dataset.

Posso treinar um modelo de aprendizado por reforço (RL, na sigla em inglês) com uma TPU?

O aprendizado por reforço inclui uma ampla variedade de técnicas. No momento, algumas delas não são compatíveis com as abstrações de software nas TPUs. Certas configurações do aprendizado por reforço exigem a execução de um "ambiente de simulação" de caixa preta usando uma CPU como parte do ciclo de treinamento. Ele não consegue acompanhar a TPU e gera ineficiências significativas. As próximas versões do TensorFlow incluirão abstrações para facilitar o aprendizado por reforço que "dispensa políticas".

Posso usar incorporações de palavras com uma TPU?

Sim, a TPU é compatível com tf.nn.embedding_lookup(), já que é apenas um wrapper em torno de tf.gather(), que tem uma implementação na TPU. No entanto, a TPU não é compatível com tf.nn.embedding_lookup_sparse(). O tensor de código de entrada em tf.embedding_lookup() precisa ter uma forma estática durante o treinamento. Ou seja, o tamanho do lote e o comprimento da sequência precisam ser iguais em cada lote. Essa é uma restrição mais geral em todos os tensores ao usar a TPU.

Posso usar sequências de comprimento variável com uma TPU?

Há vários métodos para representar sequências de comprimento variável no TensorFlow, incluindo preenchimento, tf.while_loop(), dimensões do tensor inferidas e intervalos. Infelizmente, o mecanismo atual de execução da TPU é compatível apenas com um subconjunto deles. É necessário implementar sequências de comprimento variável usando concatenação de sequência, preenchimento, intervalos, tf.dynamic_rnn() e tf.while_loop().

Posso treinar uma rede neural recorrente (RNN, na sigla em inglês) em uma TPU?

Em certas configurações, tf.static_rnn() e tf.dynamic_rnn() são compatíveis com o mecanismo atual de execução da TPU. Mais geralmente, a TPU é compatível com tf.while_loop() e TensorArray, que são usados para implementar tf.dynamic_rnn(). Kits de ferramentas especializados como o CuDNN não são compatíveis com a TPU porque contêm códigos específicos da GPU. Usar tf.while_loop() na TPU requer a especificação de um limite superior no número de iterações de ciclo para que o mecanismo de execução determine estaticamente o uso de memória.

Posso treinar uma rede adversária generativa (GAN, na sigla em inglês) com uma TPU?

Com as GANs, é frequente alternar entre treinar o gerador e treinar o discriminador. O mecanismo de execução atual da TPU é compatível apenas com um único gráfico de execução. A alternância entre os gráficos requer uma recompilação completa, que pode levar 30 segundos ou mais. Essa limitação será diminuída em uma próxima versão do TensorFlow.

Uma possível solução alternativa é sempre calcular a soma das perdas do gerador e do discriminador. No entanto, multiplique essas perdas por dois tensores de entrada g_w e d_w. Nos lotes em que o gerador e o discriminador precisam ser treinados, transmita g_w=1.0 e d_w=0.0 e vice-versa.

Posso treinar um modelo de aprendizado de várias tarefas com uma TPU?

Se for possível representar as tarefas como um gráfico grande com uma função de perda agregada, não será necessário suporte especial para o aprendizado de várias tarefas. No entanto, o mecanismo de execução da TPU é compatível atualmente apenas com um único gráfico de execução. Portanto, não é possível alternar rapidamente entre vários gráficos de execução que compartilham variáveis, mas têm estruturas diferentes. Alterar os gráficos de execução requer a repetição da etapa de compilação do gráfico, que pode levar 30 segundos ou mais.

A TPU é compatível com o modo adiantado?

Não, o modo adiantado usa um novo mecanismo de execução dinâmico. Já a TPU utiliza o XLA, que executa a compilação estática do gráfico de execução.

A TPU é compatível com o paralelismo de modelos?

O paralelismo de modelos é a execução de programas de TPU não idênticos em vários núcleos dentro de um único dispositivo de TPU. No momento, ele não é compatível com a TPU, mas será em uma próxima versão do TensorFlow.

Como inspeciono o valor real dos tensores intermediários na TPU, como em tf.Print ou tfdbg?

No momento, esse recurso não é compatível com a TPU. O padrão sugerido para desenvolvimento na TPU é implementar o modelo usando a biblioteca TPUEstimator. Ela possibilita a transição simples entre a TPU e a CPU/GPU com a sinalização use_tpu. Recomendamos que você depure os modelos na CPU/GPU usando as ferramentas padrão do TensorFlow. Em seguida, alterne para a TPU quando o modelo estiver pronto para um treinamento em grande escala.

Meu esquema de treinamento é muito complexo ou especializado para a API TPUEstimator. Há uma API de nível mais baixo que eu possa usar?

TPUEstimator é a biblioteca principal para o treinamento de TPU em uma Cloud TPU. No entanto, a TPUEstimator encapsula a API tpu, que é parte do TensorFlow de código aberto. Portanto, é tecnicamente possível (mas não compatível) usar diretamente a API tpu de nível baixo. Se o canal de treinamento exigir comunicação frequente entre a TPU e a CPU ou a alteração constante do gráfico de execução, o cálculo não será executado com eficiência na TPU. As próximas versões do TensorFlow vão aprimorar ambos os recursos.

Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…