Preparação distribuída

Esta página descreve como executar tarefas de preparação distribuídas no Vertex AI.

Requisitos de código

Use uma estrutura de ML que suporte a preparação distribuída. No código de preparação, pode usar as variáveis de ambiente CLUSTER_SPEC ou TF_CONFIG para fazer referência a partes específicas do cluster de preparação.

Estrutura do cluster de formação

Se executar uma tarefa de preparação distribuída com o Vertex AI, especifica várias máquinas (nós) num cluster de preparação. O serviço de preparação afeta os recursos aos tipos de máquinas que especificar. A tarefa em execução num determinado nó é denominada réplica. Um grupo de réplicas com a mesma configuração chama-se conjunto de trabalhadores.

Cada réplica no cluster de preparação recebe uma única função ou tarefa na preparação distribuída. Por exemplo:

  • Réplica principal: exatamente uma réplica é designada como a réplica principal. Esta tarefa gere as outras e comunica o estado do trabalho como um todo.

  • Trabalhadores: uma ou mais réplicas podem ser designadas como trabalhadores. Estas réplicas fazem a sua parte do trabalho conforme designado na configuração da tarefa.

  • Servidores de parâmetros: se forem suportados pela sua framework de ML, uma ou mais réplicas podem ser designadas como servidores de parâmetros. Estas réplicas armazenam os parâmetros do modelo e coordenam o estado do modelo partilhado entre os trabalhadores.

  • Avaliadores: se suportado pela sua framework de ML, uma ou mais réplicas podem ser designadas como avaliadores. Estas réplicas podem ser usadas para avaliar o seu modelo. Se estiver a usar o TensorFlow, tenha em atenção que este geralmente espera que use não mais do que um avaliador.

Configure uma tarefa de preparação distribuída

Pode configurar qualquer tarefa de treino personalizada como uma tarefa de treino distribuído definindo vários conjuntos de trabalhadores. Também pode executar o treino distribuído num pipeline de treino ou num trabalho de otimização de hiperparâmetros.

Para configurar uma tarefa de preparação distribuída, defina a sua lista de conjuntos de trabalhadores (workerPoolSpecs[]), designando um WorkerPoolSpec para cada tipo de tarefa:

Posição em workerPoolSpecs[] Tarefa realizada no cluster
Primeiro (workerPoolSpecs[0]) Principal, chefe, programador ou "mestre"
Segundo (workerPoolSpecs[1]) Secundário, réplicas, trabalhadores
Terceiro (workerPoolSpecs[2]) Servidores de parâmetros, servidor de redução
Quarto (workerPoolSpecs[3]) Avaliadores

Tem de especificar uma réplica principal, que coordena o trabalho realizado por todas as outras réplicas. Use a primeira especificação do pool de trabalhadores apenas para a réplica principal e defina o respetivo replicaCount como 1:

{
  "workerPoolSpecs": [
     // `WorkerPoolSpec` for worker pool 0, primary replica, required
     {
       "machineSpec": {...},
       "replicaCount": 1,
       "diskSpec": {...},
       ...
     },
     // `WorkerPoolSpec` for worker pool 1, optional
     {},
     // `WorkerPoolSpec` for worker pool 2, optional
     {},
     // `WorkerPoolSpec` for worker pool 3, optional
     {}
   ]
   ...
}

Especifique grupos de trabalhadores adicionais

Consoante a sua framework de ML, pode especificar pools de trabalhadores adicionais para outros fins. Por exemplo, se estiver a usar o TensorFlow, pode especificar pools de trabalhadores para configurar réplicas de trabalhadores, réplicas de servidores de parâmetros e réplicas de avaliadores.

A ordem dos grupos de trabalhadores que especificar na lista workerPoolSpecs[] determina o tipo de grupo de trabalhadores. Defina valores vazios para os conjuntos de trabalhadores que não quer usar, para que os possa ignorar na lista workerPoolSpecs[] de modo a especificar os conjuntos de trabalhadores que quer usar. Por exemplo:

Se quiser especificar um trabalho que tenha apenas uma réplica principal e um conjunto de trabalhadores do servidor de parâmetros, tem de definir um valor vazio para o conjunto de trabalhadores 1:

{
  "workerPoolSpecs": [
     // `WorkerPoolSpec` for worker pool 0, required
     {
       "machineSpec": {...},
       "replicaCount": 1,
       "diskSpec": {...},
       ...
     },
     // `WorkerPoolSpec` for worker pool 1, optional
     {},
     // `WorkerPoolSpec` for worker pool 2, optional
     {
       "machineSpec": {...},
       "replicaCount": 1,
       "diskSpec": {...},
       ...
     },
     // `WorkerPoolSpec` for worker pool 3, optional
     {}
   ]
   ...
}

Reduza o tempo de formação com o servidor de redução

Quando treina um modelo de AA grande com vários nós, a comunicação de gradientes entre nós pode contribuir para uma latência significativa. O servidor de redução é um algoritmo de redução total que pode aumentar o débito e reduzir a latência para a preparação distribuída. O Vertex AI disponibiliza o servidor de redução numa imagem de contentor Docker que pode usar para um dos seus conjuntos de trabalhadores durante a preparação distribuída.

Para saber como funciona o servidor de redução, consulte o artigo Formação de GPUs distribuídas mais rápida com o servidor de redução na Vertex AI.

Pré-requisitos

Pode usar o servidor de redução se cumprir os seguintes requisitos:

  • Está a realizar a formação distribuída com trabalhadores de GPU.

  • O seu código de preparação usa o TensorFlow ou o PyTorch e está configurado para a preparação paralela de dados com vários anfitriões com GPUs usando a função NCCL all-reduce. (Também pode usar outras frameworks de ML que usam a NCCL.)

  • Os contentores executados no nó principal (workerPoolSpecs[0]) e nos trabalhadores (workerPoolSpecs[1]) suportam o servidor de redução. Especificamente, cada contentor é um dos seguintes:

    • Um contentor de preparação do TensorFlow pré-criado, versão 2.3 ou posterior.

    • Um contentor de preparação do Pytorch pré-criado, versão 1.4 ou posterior.

    • Um contentor personalizado com o NCCL 2.7 ou posterior e o pacote google-reduction-server instalado. Pode instalar este pacote numa imagem de contentor personalizada adicionando a seguinte linha ao seu Dockerfile:

      RUN echo "deb https://packages.cloud.google.com/apt google-fast-socket main" | tee /etc/apt/sources.list.d/google-fast-socket.list && \
          curl -s -L https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
          apt update && apt install -y google-reduction-server
      

Faça a preparação com o servidor de redução

Para usar o servidor de redução, faça o seguinte quando criar um recurso de preparação personalizado:

  1. Especifique um dos seguintes URIs no containerSpec.imageUri campo do terceiro conjunto de trabalhadores (workerPoolSpecs[2]):

    • us-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest
    • europe-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest
    • asia-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest

    A escolha da região múltipla mais próxima do local onde está a realizar o treino personalizado pode reduzir a latência.

  2. Quando selecionar o tipo de máquina e o número de nós para o terceiro conjunto de trabalhadores, certifique-se de que a largura de banda total da rede do terceiro conjunto de trabalhadores corresponde ou excede a largura de banda total da rede do primeiro e do segundo conjunto de trabalhadores.

    Para saber mais sobre a largura de banda máxima disponível de cada nó no segundo conjunto de trabalhadores, consulte Largura de banda da rede e GPUs.

    Não usa GPUs para os nós do servidor de redução. Para saber mais sobre a largura de banda máxima disponível de cada nó no terceiro conjunto de trabalhadores, consulte as colunas "Largura de banda de saída máxima (Gbps)" na família de máquinas de uso geral.

    Por exemplo, se configurar o primeiro e o segundo conjunto de trabalhadores para usar 5 n1-highmem-96 nós, cada um com 8 NVIDIA_TESLA_V100 GPUs, cada nó tem uma largura de banda máxima disponível de 100 Gbps, para uma largura de banda total de 500 Gbps. Para igualar esta largura de banda no terceiro conjunto de trabalhadores, pode usar 16 nós n1-highcpu-16, cada um com uma largura de banda máxima de 32 Gbps, para uma largura de banda total de 512 Gbps.

    Recomendamos que use o tipo de máquina n1-highcpu-16 para nós do servidor de redução, porque este tipo de máquina oferece uma largura de banda relativamente elevada para os respetivos recursos.

O comando seguinte fornece um exemplo de como criar um recurso que usa o servidor de redução:CustomJob

gcloud ai custom-jobs create \
  --region=LOCATION \
  --display-name=JOB_NAME \
  --worker-pool-spec=machine-type=n1-highmem-96,replica-count=1,accelerator-type=NVIDIA_TESLA_V100,accelerator-count=8,container-image-uri=CUSTOM_CONTAINER_IMAGE_URI \
  --worker-pool-spec=machine-type=n1-highmem-96,replica-count=4,accelerator-type=NVIDIA_TESLA_V100,accelerator-count=8,container-image-uri=CUSTOM_CONTAINER_IMAGE_URI \
  --worker-pool-spec=machine-type=n1-highcpu-16,replica-count=16,container-image-uri=us-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest

Para mais contexto, consulte o guia de criação de um CustomJob.

Práticas recomendadas para a preparação com o servidor de redução

Tipo de máquina e quantidade

Na preparação do servidor de redução, cada trabalhador tem de se ligar a todos os anfitriões de redução. Para minimizar o número de ligações no anfitrião do trabalhador, use um tipo de máquina com a largura de banda da rede mais elevada para o anfitrião do redutor.

Uma boa escolha para anfitriões de redutores é uma VM N1/N2 de uso geral com, pelo menos, 16 vCPUs que ofereça 32 Gbps de largura de banda de saída, como n1-highcpu-16 e n2-highcpu-16. A largura de banda da VM de nível 1 para VMs N1/N2 aumenta a largura de banda de saída máxima, que varia entre 50 Gbps e 100 Gbps, o que as torna uma boa escolha para nós de VMs redutoras.

A largura de banda de saída total dos trabalhadores e dos redutores deve ser a mesma. Por exemplo, se usar 8 VMs a2-megagpu-16g como trabalhadores, deve usar, pelo menos, 25 VMs n1-highcpu-16 como redutores.

`(8 worker VMs * 100 Gbps) / 32 Gbps egress = 25 reducer VMs`.

Agrupe mensagens pequenas

O servidor de redução funciona melhor se as mensagens a agregar forem suficientemente grandes. A maioria das estruturas de ML já fornece técnicas sob terminologia diferente para agrupar pequenos tensores de gradiente antes de executar a redução total.

Horovod

O Horovod suporta a Tensor Fusion para processar em lote pequenos tensores para a redução total. Os tensores são preenchidos num buffer de fusão até que o buffer esteja totalmente preenchido e a operação all-reduce no buffer seja executada. Pode ajustar o tamanho da memória intermédia de fusão definindo a variável de ambiente HOROVOD_FUSION_THRESHOLD.

O valor recomendado para a variável de ambiente HOROVOD_FUSION_THRESHOLD é, pelo menos, 128 MB. Neste caso, defina a variável de HOROVOD_FUSION_THRESHOLDambiente como 134217728 (128 * 1024 * 1024).

PyTorch

O PyTorch DistributedDataParallel suporta mensagens em lote como "gradient bucketing". Defina o parâmetro bucket_cap_mb no construtor DistributedDataParallel para controlar o tamanho dos seus contentores de lotes. O tamanho predefinido é de 25 MB.

PRÁTICA RECOMENDADA: o valor recomendado de bucket_cap_mb é 64 (64 MB).

Variáveis de ambiente para o seu cluster

O Vertex AI preenche uma variável de ambiente, CLUSTER_SPEC, em cada réplica para descrever como o cluster geral está configurado. Tal como o TensorFlowTF_CONFIG, o CLUSTER_SPEC descreve todas as réplicas no cluster, incluindo o respetivo índice e função (réplica principal, trabalhador, servidor de parâmetros ou avaliador).

Quando executa a preparação distribuída com o TensorFlow, TF_CONFIG é analisado para criar tf.train.ClusterSpec. Da mesma forma, quando executa a preparação distribuída com outras frameworks de ML, tem de analisar CLUSTER_SPEC para preencher quaisquer variáveis de ambiente ou definições necessárias pela framework.

O formato de CLUSTER_SPEC

A variável de ambiente CLUSTER_SPEC é uma string JSON com o seguinte formato:

Chave Descrição
"cluster"

A descrição do cluster para o seu contentor personalizado. Tal como com TF_CONFIG, este objeto está formatado como uma especificação do cluster do TensorFlow e pode ser transmitido ao construtor de tf.train.ClusterSpec.

A descrição do cluster contém uma lista de nomes de réplicas para cada grupo de trabalhadores que especificar.

"workerpool0" Todas as tarefas de preparação distribuídas têm uma réplica principal no primeiro conjunto de trabalhadores.
"workerpool1" Este grupo de trabalhadores contém réplicas de trabalhadores, se as tiver especificado quando criou a tarefa.
"workerpool2" Este conjunto de trabalhadores contém servidores de parâmetros, se os tiver especificado quando criou a tarefa.
"workerpool3" Este conjunto de trabalhadores contém avaliadores, se os tiver especificado quando criou a sua tarefa.
"environment" A string cloud.
"task" Descreve a tarefa do nó específico no qual o seu código está a ser executado. Pode usar estas informações para escrever código para trabalhadores específicos num trabalho distribuído. Esta entrada é um dicionário com as seguintes chaves:
"type" O tipo de conjunto de trabalhadores no qual esta tarefa está a ser executada. Por exemplo, "workerpool0" refere-se à réplica principal.
"index"

O índice baseado em zero da tarefa. Por exemplo, se a sua tarefa de preparação incluir dois trabalhadores, este valor é definido como 0 num deles e 1 no outro.

"trial" O identificador da avaliação do aperfeiçoamento de hiperparâmetros em execução. Quando configura o ajuste de hiperparâmetros para a sua tarefa, define um número de testes para fazer o treino. Este valor permite-lhe diferenciar no seu código entre os testes em execução. O identificador é um valor de string que contém o número de tentativa, começando em 1.
job

O CustomJobSpec que forneceu para criar a tarefa de preparação atual, representado como um dicionário.

CLUSTER_SPEC exemplo

Segue-se um valor de exemplo:


{
   "cluster":{
      "workerpool0":[
         "cmle-training-workerpool0-ab-0:2222"
      ],
      "workerpool1":[
         "cmle-training-workerpool1-ab-0:2222",
         "cmle-training-workerpool1-ab-1:2222"
      ],
      "workerpool2":[
         "cmle-training-workerpool2-ab-0:2222",
         "cmle-training-workerpool2-ab-1:2222"
      ],
      "workerpool3":[
         "cmle-training-workerpool3-ab-0:2222",
         "cmle-training-workerpool3-ab-1:2222",
         "cmle-training-workerpool3-ab-2:2222"
      ]
   },
   "environment":"cloud",
   "task":{
      "type":"workerpool0",
      "index":0,
      "trial":"TRIAL_ID"
   },
   "job": {
      ...
   }
}

O formato de TF_CONFIG

Além disso, o Vertex AI define a variável de ambiente TF_CONFIG em cada réplica de todas as tarefas de preparação distribuída.CLUSTER_SPEC O Vertex AI não define TF_CONFIG para tarefas de preparação de réplica única.

CLUSTER_SPEC e TF_CONFIG partilham alguns valores, mas têm formatos diferentes. Ambas as variáveis de ambiente incluem campos adicionais além do que o TensorFlow requer.

A preparação distribuída com o TensorFlow funciona da mesma forma quando usa contentores personalizados e quando usa um contentor pré-criado.

A variável de ambiente TF_CONFIG é uma string JSON com o seguinte formato:

TF_CONFIG campos
cluster

A descrição do cluster do TensorFlow. Um dicionário que mapeia um ou mais nomes de tarefas (chief, worker, ps ou master) para listas de endereços de rede onde estas tarefas estão a ser executadas. Para uma determinada tarefa de preparação, este dicionário é o mesmo em todas as VMs.

Este é um primeiro argumento válido para o construtor tf.train.ClusterSpec. Tenha em atenção que este dicionário nunca contém evaluator como chave, uma vez que os avaliadores não são considerados parte do cluster de preparação, mesmo que os use para o seu trabalho.

task

A descrição da tarefa da VM onde esta variável de ambiente está definida. Para uma determinada tarefa de preparação, este dicionário é diferente em cada VM. Pode usar estas informações para personalizar o código que é executado em cada MV num trabalho de preparação distribuída. Também pode usá-lo para alterar o comportamento do código de preparação para diferentes testes de uma otimização de hiperparâmetros tarefa.

Este dicionário inclui os seguintes pares de chave-valor:

task campos
type

O tipo de tarefa que esta VM está a realizar. Este valor é definido como worker nos trabalhadores, ps nos servidores de parâmetros e evaluator nos avaliadores. No worker principal da tarefa, o valor é definido como chief ou master.

index

O índice baseado em zero da tarefa. Por exemplo, se a sua tarefa de preparação incluir dois trabalhadores, este valor é definido como 0 num deles e 1 no outro.

trial

O ID da tentativa de aperfeiçoamento de hiperparâmetros em execução atualmente nesta VM. Este campo só é definido se a tarefa de preparação atual for uma tarefa de ajuste de hiperparâmetros.

Para tarefas de ajuste de hiperparâmetros, o Vertex AI executa o seu código de preparação repetidamente em várias tentativas com hiperparâmetros diferentes de cada vez. Este campo contém o número da avaliação atual, começando em 1 para a primeira avaliação.

cloud

Um ID usado internamente pelo Vertex AI. Pode ignorar este campo.

job

O CustomJobSpec que forneceu para criar a tarefa de preparação atual, representado como um dicionário.

environment

A string cloud.

TF_CONFIG exemplo

O exemplo de código seguinte imprime a variável de ambiente TF_CONFIGnos registos de preparação:

import json
import os

tf_config_str = os.environ.get('TF_CONFIG')
tf_config_dict  = json.loads(tf_config_str)

# Convert back to string just for pretty printing
print(json.dumps(tf_config_dict, indent=2))

Num trabalho de otimização de hiperparâmetros executado na versão de tempo de execução 2.1 ou posterior e que usa um trabalhador principal, dois trabalhadores e um servidor de parâmetros, este código produz o seguinte registo para um dos trabalhadores durante a primeira tentativa de otimização de hiperparâmetros. O resultado do exemplo oculta o campo job para maior concisão e substitui alguns IDs por valores genéricos.

{
  "cluster": {
    "chief": [
      "training-workerpool0-[ID_STRING_1]-0:2222"
    ],
    "ps": [
      "training-workerpool2-[ID_STRING_1]-0:2222"
    ],
    "worker": [
      "training-workerpool1-[ID_STRING_1]-0:2222",
      "training-workerpool1-[ID_STRING_1]-1:2222"
    ]
  },
  "environment": "cloud",
  "job": {
    ...
  },
  "task": {
    "cloud": "[ID_STRING_2]",
    "index": 0,
    "trial": "1",
    "type": "worker"
  }
}

Quando usar o TF_CONFIG

O TF_CONFIG só está definido para tarefas de preparação distribuída.

Provavelmente, não precisa de interagir diretamente com a variável de ambiente TF_CONFIG no código de preparação. Aceda apenas à variável de ambiente TF_CONFIG se as estratégias de distribuição do TensorFlow e o fluxo de trabalho de ajuste de hiperparâmetros padrão do Vertex AI, ambos descritos nas secções seguintes, não funcionarem para o seu trabalho.

Preparação distribuída

O Vertex AI define a variável de ambiente TF_CONFIG para expandir as especificações que o TensorFlow requer para a preparação distribuída.

Para realizar a preparação distribuída com o TensorFlow, use a tf.distribute.Strategy API. Em particular, recomendamos que use a API Keras juntamente com o MultiWorkerMirroredStrategy ou, se especificar servidores de parâmetros para a sua tarefa, o ParameterServerStrategy. No entanto, tenha em atenção que o TensorFlow só oferece suporte experimental para estas estratégias.

Estas estratégias de distribuição usam a variável de ambiente TF_CONFIG para atribuir funções a cada VM na tarefa de preparação e para facilitar a comunicação entre as VMs. Não precisa de aceder diretamente à variável de ambiente TF_CONFIG no seu código de preparação, porque o TensorFlow processa-a por si.

Analise apenas a variável de ambiente TF_CONFIG diretamente se quiser personalizar o comportamento das diferentes VMs que executam a tarefa de preparação.

Aperfeiçoamento de hiperparâmetros

Quando executa uma tarefa de ajuste de hiperparâmetros, o Vertex AI fornece argumentos diferentes ao seu código de preparação para cada tentativa. O código de preparação não tem necessariamente de saber que avaliação está a ser executada atualmente. Além disso, pode monitorizar o progresso das tarefas de aperfeiçoamento de hiperparâmetros na Google Cloud consola.

Se necessário, o seu código pode ler o número de tentativas atual do campo trial do campo task da variável de ambiente TF_CONFIG.

O que se segue?