Executar cargas de trabalho de inferência do TensorFlow com o TensorRT5 e a GPU NVIDIA T4

Este tutorial aborda como executar inferências de aprendizagem profunda em cargas de trabalho de grande escala usando GPUs NVIDIA TensorRT5 executadas no Compute Engine.

Antes de começar, seguem-se alguns aspetos essenciais:

  • A inferência de aprendizagem avançada é a fase do processo de aprendizagem automática em que um modelo preparado é usado para reconhecer, processar e classificar resultados.
  • O NVIDIA TensorRT é uma plataforma otimizada para executar cargas de trabalho de aprendizagem profunda.
  • As GPUs são usadas para acelerar cargas de trabalho com grande volume de dados, como a aprendizagem automática e o tratamento de dados. Estão disponíveis várias GPUs NVIDIA no Compute Engine. Este tutorial usa GPUs T4, uma vez que as GPUs T4 foram concebidas especificamente para cargas de trabalho de inferência de aprendizagem profunda.

Objetivos

Neste tutorial, são abordados os seguintes procedimentos:

  • Preparar um modelo com um gráfico pré-preparado.
  • Testar a velocidade de inferência de um modelo com diferentes modos de otimização.
  • Converter um modelo personalizado para TensorRT.
  • Configurar um cluster de várias zonas. Este cluster de várias zonas está configurado da seguinte forma:
    • Criado com base nas Deep Learning VM Images. Estas imagens estão pré-instaladas com o TensorFlow, o TensorFlow serving e o TensorRT5.
    • O ajuste de escala automático está ativado. A criação de uma escala automática neste tutorial baseia-se na utilização da GPU.
    • O balanceamento de carga está ativado.
    • Firewall ativada.
  • Executar uma carga de trabalho de inferência no cluster de várias zonas.

Vista geral da arquitetura de alto nível da configuração do tutorial.

Custos

O custo da execução deste tutorial varia consoante a secção.

Pode calcular o custo através da calculadora de preços.

Para estimar o custo de preparação do modelo e testar as velocidades de inferência a diferentes velocidades de otimização, use as seguintes especificações:

  • 1 instância de VM: n1-standard-8 (vCPUs: 8, RAM: 30 GB)
  • 1 GPU NVIDIA T4

Para estimar o custo de configuração do cluster de várias zonas, use as seguintes especificações:

  • 2 instâncias de VM: n1-standard-16 (vCPUs: 16, RAM 60 GB)
  • 4 GPUs NVIDIA T4 para cada instância de VM
  • 100 GB de SSD para cada instância de VM
  • 1 regra de encaminhamento

Antes de começar

Configuração do projeto

  1. In the Trusted Cloud console, on the project selector page, select or create a Trusted Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  2. Verify that billing is enabled for your Trusted Cloud project.

  3. Enable the Compute Engine and Cloud Machine Learning APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  4. Configuração de ferramentas

    Para usar a CLI do Google Cloud neste tutorial:

    1. Instale ou atualize para a versão mais recente da CLI do Google Cloud.
    2. (Opcional) Defina uma região e uma zona predefinidas.

A preparar o modelo

Esta secção aborda a criação de uma instância de máquina virtual (VM) que é usada para executar o modelo. Esta secção também aborda como transferir um modelo do catálogo de modelos oficiais do TensorFlow

  1. Crie a instância de VM. Este tutorial foi criado com o tf-ent-2-10-cu113. Para ver as versões de imagens mais recentes, consulte o artigo Escolher um sistema operativo na documentação de imagens de VMs de aprendizagem profunda.

    export IMAGE_FAMILY="tf-ent-2-10-cu113"
    export ZONE="us-central1-b"
    export INSTANCE_NAME="model-prep"
    gcloud compute instances create $INSTANCE_NAME \
       --zone=$ZONE \
       --image-family=$IMAGE_FAMILY \
       --machine-type=n1-standard-8 \
       --image-project=deeplearning-platform-release \
       --maintenance-policy=TERMINATE \
       --accelerator="type=nvidia-tesla-t4,count=1" \
       --metadata="install-nvidia-driver=True"
    
  2. Selecione um modelo. Este tutorial usa o modelo ResNet. Este modelo ResNet é preparado no conjunto de dados ImageNet que está no TensorFlow.

    Para transferir o modelo ResNet para a sua instância de VM, execute o seguinte comando:

    wget -q http://download.tensorflow.org/models/official/resnetv2_imagenet_frozen_graph.pb

    Guarde a localização do seu modelo ResNet na variável $WORKDIR. Substitua MODEL_LOCATION pelo diretório de trabalho que contém o modelo transferido.

    export WORKDIR=MODEL_LOCATION

Executar o teste de velocidade de inferência

Esta secção abrange os seguintes procedimentos:

  • Configurar o modelo ResNet.
  • Executar testes de inferência em diferentes modos de otimização.
  • Rever os resultados dos testes de inferência.

Vista geral do processo de teste

O TensorRT pode melhorar a velocidade de desempenho para cargas de trabalho de inferência. No entanto, a melhoria mais significativa resulta do processo de quantização.

A quantização de modelos é o processo pelo qual reduz a precisão das ponderações de um modelo. Por exemplo, se o peso inicial de um modelo for FP32, pode reduzir a precisão para FP16, INT8 ou até INT4. É importante escolher o compromisso certo entre a velocidade (precisão dos pesos) e a precisão de um modelo. Felizmente, o TensorFlow inclui funcionalidades que fazem exatamente isto, medindo a precisão em comparação com a velocidade ou outras métricas, como o débito, a latência, as taxas de conversão de nós e o tempo total de preparação.

Procedimento

  1. Configure o modelo ResNet. Para configurar o modelo, execute os seguintes comandos:

    git clone https://github.com/tensorflow/models.git
    cd models
    git checkout f0e10716160cd048618ccdd4b6e18336223a172f
    touch research/__init__.py
    touch research/tensorrt/__init__.py
    cp research/tensorrt/labellist.json .
    cp research/tensorrt/image.jpg ..
    
  2. Execute o teste. Este comando demora algum tempo a terminar.

    python -m research.tensorrt.tensorrt \
       --frozen_graph=$WORKDIR/resnetv2_imagenet_frozen_graph.pb \
       --image_file=$WORKDIR/image.jpg \
       --native --fp32 --fp16 --int8 \
       --output_dir=$WORKDIR
    

    Onde:

    • $WORKDIR é o diretório no qual transferiu o modelo ResNet.
    • Os argumentos --native são os diferentes modos de quantização a testar.
  3. Reveja os resultados. Quando o teste estiver concluído, pode fazer uma comparação dos resultados da inferência para cada modo de otimização.

    Predictions:
    Precision:  native [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty',     u'lakeside, lakeshore', u'grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus']
    Precision:  FP32 [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty', u'lakeside,   lakeshore', u'sandbar, sand bar']
    Precision:  FP16 [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty', u'lakeside,   lakeshore', u'sandbar, sand bar']
    Precision:  INT8 [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty', u'grey         whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus', u'lakeside, lakeshore']
    

    Para ver os resultados completos, execute o seguinte comando:

    cat $WORKDIR/log.txt

    Resultados de desempenho.

    A partir dos resultados, pode ver que o FP32 e o FP16 são idênticos. Isto significa que, se se sentir confortável a trabalhar com o TensorRT, pode começar a usar o FP16 imediatamente. INT8, mostra resultados ligeiramente piores.

    Além disso, pode ver que a execução do modelo com o TensorRT5 mostra os seguintes resultados:

    • A utilização da otimização FP32 melhora o débito em 40%, de 314 fps para 440 fps. Ao mesmo tempo, a latência diminui aproximadamente 30%, passando de 0,40 ms para 0,28 ms.
    • A utilização da otimização FP16, em vez do gráfico nativo do TensorFlow, aumenta a velocidade em 214%, de 314 para 988 fps. Ao mesmo tempo, a latência diminui 0,12 ms, quase uma diminuição de 3 vezes.
    • Com o INT8, pode observar um aumento de velocidade de 385% de 314 fps para 1524 fps, com a latência a diminuir para 0,08 ms.

Converter um modelo personalizado para TensorRT

Para esta conversão, pode usar um modelo INT8.

  1. Transfira o modelo. Para converter um modelo personalizado num gráfico TensorRT, precisa de um modelo guardado. Para obter um modelo ResNet INT8 guardado, execute o seguinte comando:

    wget http://download.tensorflow.org/models/official/20181001_resnet/savedmodels/resnet_v2_fp32_savedmodel_NCHW.tar.gz
    tar -xzvf resnet_v2_fp32_savedmodel_NCHW.tar.gz
  2. Converta o modelo no gráfico TensorRT através das TFTools. Para converter o modelo com as TFTools, execute o seguinte comando:

    git clone https://github.com/GoogleCloudPlatform/ml-on-gcp.git
    cd ml-on-gcp/dlvm/tools
    python ./convert_to_rt.py \
       --input_model_dir=$WORKDIR/resnet_v2_fp32_savedmodel_NCHW/1538687196 \
       --output_model_dir=$WORKDIR/resnet_v2_int8_NCHW/00001 \
       --batch_size=128 \
       --precision_mode="INT8"
    

    Agora, tem um modelo INT8 no diretório $WORKDIR/resnet_v2_int8_NCHW/00001.

    Para garantir que tudo está configurado corretamente, experimente executar um teste de inferência.

    tensorflow_model_server --model_base_path=$WORKDIR/resnet_v2_int8_NCHW/ --rest_api_port=8888
  3. Carregue o modelo para o Cloud Storage. Este passo é necessário para que o modelo possa ser usado a partir do cluster de várias zonas configurado na secção seguinte. Para carregar o modelo, conclua os seguintes passos:

    1. Arquive o modelo.

      tar -zcvf model.tar.gz ./resnet_v2_int8_NCHW/
    2. Carregue o arquivo. Substitua GCS_PATH pelo caminho para o seu contentor do Cloud Storage.

      export GCS_PATH=GCS_PATH
      gcloud storage cp model.tar.gz $GCS_PATH
      

      Se necessário, pode obter um gráfico congelado INT8 do armazenamento na nuvem neste URL:

      gs://cloud-samples-data/dlvm/t4/model.tar.gz

Configurar um cluster de várias zonas

Esta secção explica os passos que tem de seguir ao configurar um cluster de várias zonas.

Crie o cluster

Agora que tem um modelo na plataforma do Cloud Storage, pode criar um cluster.

  1. Crie um modelo de instância. Um modelo de instância é um recurso útil para criar novas instâncias. Consulte o artigo Modelos de instâncias. Substitua YOUR_PROJECT_NAME pelo ID do seu projeto.

    export INSTANCE_TEMPLATE_NAME="tf-inference-template"
    export IMAGE_FAMILY="tf-ent-2-10-cu113"
    export PROJECT_NAME=YOUR_PROJECT_NAME
    
    gcloud beta compute --project=$PROJECT_NAME instance-templates create $INSTANCE_TEMPLATE_NAME \
         --machine-type=n1-standard-16 \
         --maintenance-policy=TERMINATE \
         --accelerator=type=nvidia-tesla-t4,count=4 \
         --min-cpu-platform=Intel\ Skylake \
         --tags=http-server,https-server \
         --image-family=$IMAGE_FAMILY \
         --image-project=deeplearning-platform-release \
         --boot-disk-size=100GB \
         --boot-disk-type=pd-ssd \
         --boot-disk-device-name=$INSTANCE_TEMPLATE_NAME \
         --metadata startup-script-url=gs://cloud-samples-data/dlvm/t4/start_agent_and_inf_server_4.sh
    
    • Este modelo de instância inclui um script de arranque especificado pelo parâmetro de metadados.
      • Execute este script de arranque durante a criação de instâncias em todas as instâncias que usam este modelo.
      • Este script de arranque executa os seguintes passos:
        • Instala um agente de monitorização que monitoriza a utilização da GPU na instância.
        • Transfere o modelo.
        • Inicia o serviço de inferência.
      • No script de arranque, tf_serve.py contém a lógica de inferência. Este exemplo inclui um ficheiro Python muito pequeno baseado no pacote TFServe
      • Para ver o script de arranque, consulte startup_inf_script.sh.
  2. Crie um grupo de instâncias geridas (MIG). Este grupo de instâncias geridas é necessário para configurar várias instâncias em execução em zonas específicas. As instâncias são criadas com base no modelo de instância gerado no passo anterior.

    export INSTANCE_GROUP_NAME="deeplearning-instance-group"
    export INSTANCE_TEMPLATE_NAME="tf-inference-template"
    gcloud compute instance-groups managed create $INSTANCE_GROUP_NAME \
       --template $INSTANCE_TEMPLATE_NAME \
       --base-instance-name deeplearning-instances \
       --size 2 \
       --zones us-central1-a,us-central1-b
    
    • Pode criar esta instância em qualquer zona disponível que suporte GPUs T4. Certifique-se de que tem quotas de GPU disponíveis na zona.

    • A criação da instância demora algum tempo. Pode monitorizar o progresso executando os seguintes comandos:

      export INSTANCE_GROUP_NAME="deeplearning-instance-group"
      gcloud compute instance-groups managed list-instances $INSTANCE_GROUP_NAME --region us-central1

      Criação de instâncias.

    • Quando o grupo de instâncias gerido é criado, deve ver um resultado semelhante ao seguinte:

      A instância em execução.

  3. Confirme se as métricas estão disponíveis na Trusted Cloud by S3NS página do Cloud Monitoring.

    1. Na Trusted Cloud consola, aceda à página Monitorização.

      Aceder a Monitorização

    2. Se o Explorador de métricas for apresentado no painel de navegação, clique em Explorador de métricas. Caso contrário, selecione Recursos e, de seguida, selecione Explorador de métricas.

    3. Pesquise gpu_utilization.

      Início da monitorização.

    4. Se estiverem a ser recebidos dados, deve ver algo semelhante ao seguinte:

      A monitorização está em execução.

Ative o dimensionamento automático

  1. Ative o dimensionamento automático para o grupo de instâncias gerido.

    export INSTANCE_GROUP_NAME="deeplearning-instance-group"
    
    gcloud compute instance-groups managed set-autoscaling $INSTANCE_GROUP_NAME \
       --custom-metric-utilization metric=custom.googleapis.com/gpu_utilization,utilization-target-type=GAUGE,utilization-target=85 \
       --max-num-replicas 4 \
       --cool-down-period 360 \
       --region us-central1
    

    O custom.googleapis.com/gpu_utilization é o caminho completo para a nossa métrica. O exemplo especifica o nível 85, o que significa que sempre que a utilização da GPU atinge 85, a plataforma cria uma nova instância no nosso grupo.

  2. Teste o ajuste de escala automático. Para testar o ajuste de escala automático, tem de realizar os seguintes passos:

    1. SSH para a instância. Consulte o artigo Ligar a instâncias.
    2. Use a ferramenta gpu-burn para carregar a GPU até 100% de utilização durante 600 segundos:

      git clone https://github.com/GoogleCloudPlatform/ml-on-gcp.git
      cd ml-on-gcp/third_party/gpu-burn
      git checkout c0b072aa09c360c17a065368294159a6cef59ddf
      make
      ./gpu_burn 600 > /dev/null &
      
    3. Veja a página do Cloud Monitoring. Observe a escala automática. O cluster é dimensionado adicionando mais uma instância.

      Escala automática no cluster.

    4. Na Trusted Cloud consola, aceda à página Grupos de instâncias.

      Aceda a Grupos de instâncias

    5. Clique no deeplearning-instance-group grupo de instâncias geridas.

    6. Clique no separador Monitorização.

      Neste ponto, a lógica de escalamento automático deve estar a tentar criar o maior número possível de instâncias para reduzir a carga, sem sucesso:

      Instâncias adicionais.

      Neste ponto, pode parar de gerar instâncias e observar como o sistema é reduzido.

Configure um balanceador de carga

Vamos rever o que tem até agora:

  • Um modelo preparado, otimizado com o TensorRT5 (INT8)
  • Um grupo gerido de instâncias. Estas instâncias têm a escala automática ativada com base na utilização da GPU ativada

Agora, pode criar um equilibrador de carga à frente das instâncias.

  1. Crie verificações de funcionamento. As verificações de funcionamento são usadas para determinar se um anfitrião específico no nosso back-end pode servir o tráfego.

    export HEALTH_CHECK_NAME="http-basic-check"
    
    gcloud compute health-checks create http $HEALTH_CHECK_NAME \
       --request-path /v1/models/default \
       --port 8888
    
  2. Crie um serviço de back-end que inclua um grupo de instâncias e uma verificação de funcionamento.

    1. Crie a verificação de funcionamento.

      export HEALTH_CHECK_NAME="http-basic-check"
      export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
      
      gcloud compute backend-services create $WEB_BACKED_SERVICE_NAME \
         --protocol HTTP \
         --health-checks $HEALTH_CHECK_NAME \
         --global
      
    2. Adicione o grupo de instâncias ao novo serviço de back-end.

      export INSTANCE_GROUP_NAME="deeplearning-instance-group"
      export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
      
      gcloud compute backend-services add-backend $WEB_BACKED_SERVICE_NAME \
         --balancing-mode UTILIZATION \
         --max-utilization 0.8 \
         --capacity-scaler 1 \
         --instance-group $INSTANCE_GROUP_NAME \
         --instance-group-region us-central1 \
         --global
      
  3. Configure o URL de encaminhamento. O balanceador de carga tem de saber que URL pode ser encaminhado para os serviços de back-end.

    export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
    export WEB_MAP_NAME="map-all"
    
    gcloud compute url-maps create $WEB_MAP_NAME \
       --default-service $WEB_BACKED_SERVICE_NAME
    
  4. Crie o balanceador de carga.

    export WEB_MAP_NAME="map-all"
    export LB_NAME="tf-lb"
    
    gcloud compute target-http-proxies create $LB_NAME \
       --url-map $WEB_MAP_NAME
    
  5. Adicione um endereço IP externo ao balanceador de carga.

    export IP4_NAME="lb-ip4"
    
    gcloud compute addresses create $IP4_NAME \
       --ip-version=IPV4 \
       --network-tier=PREMIUM \
       --global
    
  6. Encontre o endereço IP atribuído.

    gcloud compute addresses list
  7. Configure a regra de encaminhamento que indica Trusted Cloud para encaminhar todos os pedidos do endereço IP público para o balanceador de carga.

    export IP=$(gcloud compute addresses list | grep ${IP4_NAME} | awk '{print $2}')
    export LB_NAME="tf-lb"
    export FORWARDING_RULE="lb-fwd-rule"
    
    gcloud compute forwarding-rules create $FORWARDING_RULE \
       --address $IP \
       --global \
       --load-balancing-scheme=EXTERNAL \
       --network-tier=PREMIUM \
       --target-http-proxy $LB_NAME \
       --ports 80
    

    Depois de criar as regras de encaminhamento globais, a propagação da configuração pode demorar vários minutos.

Ative a firewall

  1. Verifique se tem regras de firewall que permitam ligações de origens externas às suas instâncias de VM.

    gcloud compute firewall-rules list
  2. Se não tiver regras de firewall para permitir estas ligações, tem de as criar. Para criar regras de firewall, execute os seguintes comandos:

    gcloud compute firewall-rules create www-firewall-80 \
       --target-tags http-server --allow tcp:80
    
    gcloud compute firewall-rules create www-firewall-8888 \
       --target-tags http-server --allow tcp:8888
    

Executar uma inferência

  1. Pode usar o seguinte script Python para converter imagens num formato que pode ser carregado para o servidor.

    from PIL import Image
    import numpy as np
    import json
    import codecs
    
    img = Image.open("image.jpg").resize((240, 240)) img_array=np.array(img) result = { "instances":[img_array.tolist()] } file_path="/tmp/out.json" print(json.dump(result, codecs.open(file_path, 'w', encoding='utf-8'), separators=(',', ':'), sort_keys=True, indent=4))
  2. Execute a inferência.

    curl -X POST $IP/v1/models/default:predict -d @/tmp/out.json

Limpar

Para evitar incorrer em custos na sua conta do Google Cloud pelos recursos usados neste tutorial, elimine o projeto que contém os recursos ou mantenha o projeto e elimine os recursos individuais.

  1. Eliminar regras de encaminhamento.

    gcloud compute forwarding-rules delete $FORWARDING_RULE --global
  2. Elimine o endereço IPV4.

    gcloud compute addresses delete $IP4_NAME --global
  3. Elimine o balanceador de carga.

    gcloud compute target-http-proxies delete $LB_NAME
  4. Elimine o URL de encaminhamento.

    gcloud compute url-maps delete $WEB_MAP_NAME
  5. Elimine o serviço de back-end.

    gcloud compute backend-services delete $WEB_BACKED_SERVICE_NAME --global
  6. Elimine verificações de funcionamento.

    gcloud compute health-checks delete $HEALTH_CHECK_NAME
  7. Elimine o grupo de instâncias gerido.

    gcloud compute instance-groups managed delete $INSTANCE_GROUP_NAME --region us-central1
  8. Elimine o modelo de instância.

    gcloud beta compute --project=$PROJECT_NAME instance-templates delete $INSTANCE_TEMPLATE_NAME
  9. Elimine as regras de firewall.

    gcloud compute firewall-rules delete www-firewall-80
    gcloud compute firewall-rules delete www-firewall-8888