Prepare um modelo com o PyTorch, o Ray e o Google Kubernetes Engine (GKE) em GPUs

Este guia demonstra como preparar um modelo no Google Kubernetes Engine (GKE) usando o Ray, o PyTorch e o suplemento do operador Ray.

Acerca do Ray

O Ray é uma framework de computação escalável de código aberto para aplicações de IA/AA. O Ray Train é um componente no Ray concebido para a preparação e o ajuste fino de modelos distribuídos. Pode usar a API Ray Train para dimensionar a preparação em várias máquinas e integrar com bibliotecas de aprendizagem automática, como o PyTorch.

Pode implementar tarefas de preparação do Ray através do recurso RayCluster ou RayJob. Deve usar um recurso RayJob quando implementar tarefas do Ray em produção pelos seguintes motivos:

  • O recurso RayJob cria um cluster Ray efémero que pode ser eliminado automaticamente quando uma tarefa é concluída.
  • O recurso RayJob suporta políticas de repetição para a execução resiliente de tarefas.
  • Pode gerir tarefas do Ray através de padrões da API Kubernetes familiares.

Prepare o seu ambiente

Para preparar o seu ambiente, siga estes passos:

  1. Inicie uma sessão do Cloud Shell a partir da Google Cloud consola, clicando em Ícone de ativação do Cloud Shell Ativar Cloud Shell na Google Cloud consola. Esta ação inicia uma sessão no painel inferior da Google Cloud consola.

  2. Defina variáveis de ambiente:

    export PROJECT_ID=PROJECT_ID
    export CLUSTER_NAME=ray-cluster
    export COMPUTE_REGION=us-central1
    export COMPUTE_ZONE=us-central1-c
    export CLUSTER_VERSION=CLUSTER_VERSION
    export TUTORIAL_HOME=`pwd`
    

    Substitua o seguinte:

    • PROJECT_ID: o seu Google Cloud ID do projeto.
    • CLUSTER_VERSION: a versão do GKE a usar. Tem de ser 1.30.1 ou posterior.
  3. Clone o repositório do GitHub:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  4. Mude para o diretório de trabalho:

    cd kubernetes-engine-samples/ai-ml/gke-ray/raytrain/pytorch-mnist
    
  5. Crie um ambiente virtual do Python:

    python -m venv myenv && \
    source myenv/bin/activate
    
  6. Instale o Ray.

Crie um cluster do GKE

Crie um cluster do GKE Autopilot ou Standard:

Piloto automático

Crie um cluster do Autopilot:

gcloud container clusters create-auto ${CLUSTER_NAME}  \
    --enable-ray-operator \
    --cluster-version=${CLUSTER_VERSION} \
    --location=${COMPUTE_REGION}

Standard

Criar um cluster padrão:

gcloud container clusters create ${CLUSTER_NAME} \
    --addons=RayOperator \
    --cluster-version=${CLUSTER_VERSION}  \
    --machine-type=e2-standard-8 \
    --location=${COMPUTE_ZONE} \
    --num-nodes=4

Implemente um recurso RayCluster

Implemente um recurso RayCluster no seu cluster:

  1. Reveja o seguinte manifesto:

    apiVersion: ray.io/v1
    kind: RayCluster
    metadata:
      name: pytorch-mnist-cluster
    spec:
      rayVersion: '2.37.0'
      headGroupSpec:
        rayStartParams:
          dashboard-host: '0.0.0.0'
        template:
          metadata:
          spec:
            containers:
            - name: ray-head
              image: rayproject/ray:2.37.0
              ports:
              - containerPort: 6379
                name: gcs
              - containerPort: 8265
                name: dashboard
              - containerPort: 10001
                name: client
              resources:
                limits:
                  cpu: "2"
                  ephemeral-storage: "9Gi"
                  memory: "4Gi"
                requests:
                  cpu: "2"
                  ephemeral-storage: "9Gi"
                  memory: "4Gi"
      workerGroupSpecs:
      - replicas: 4
        minReplicas: 1
        maxReplicas: 5
        groupName: worker-group
        rayStartParams: {}
        template:
          spec:
            containers:
            - name: ray-worker
              image: rayproject/ray:2.37.0
              resources:
                limits:
                  cpu: "4"
                  ephemeral-storage: "9Gi"
                  memory: "8Gi"
                requests:
                  cpu: "4"
                  ephemeral-storage: "9Gi"
                  memory: "8Gi"

    Este manifesto descreve um recurso personalizado RayCluster.

  2. Aplique o manifesto ao seu cluster do GKE:

    kubectl apply -f ray-cluster.yaml
    
  3. Verifique se o recurso RayCluster está pronto:

    kubectl get raycluster
    

    O resultado é semelhante ao seguinte:

    NAME                    DESIRED WORKERS   AVAILABLE WORKERS   CPUS   MEMORY   GPUS   STATUS   AGE
    pytorch-mnist-cluster   2                 2                   6      20Gi     0      ready    63s
    

    Neste resultado, ready na coluna STATUS indica que o recurso RayCluster está pronto.

Estabeleça ligação ao recurso RayCluster

Estabeleça ligação ao recurso RayCluster para enviar uma tarefa do Ray.

  1. Verifique se o GKE criou o serviço RayCluster:

    kubectl get svc pytorch-mnist-cluster-head-svc
    

    O resultado é semelhante ao seguinte:

    NAME                             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                                AGE
    pytorch-mnist-cluster-head-svc   ClusterIP   34.118.238.247   <none>        10001/TCP,8265/TCP,6379/TCP,8080/TCP   109s
    
  2. Estabeleça uma sessão de encaminhamento de porta para o dispositivo Ray:

    kubectl port-forward svc/pytorch-mnist-cluster-head-svc 8265:8265 2>&1 >/dev/null &
    
  3. Verifique se o cliente do Ray consegue estabelecer ligação ao cluster do Ray através de localhost:

    ray list nodes --address http://localhost:8265
    

    O resultado é semelhante ao seguinte:

    Stats:
    ------------------------------
    Total: 3
    
    Table:
    ------------------------------
        NODE_ID                                                   NODE_IP     IS_HEAD_NODE    STATE    NODE_NAME    RESOURCES_TOTAL                 LABELS
    0  1d07447d7d124db641052a3443ed882f913510dbe866719ac36667d2  10.28.1.21  False           ALIVE    10.28.1.21   CPU: 2.0                        ray.io/node_id: 1d07447d7d124db641052a3443ed882f913510dbe866719ac36667d2
    # Several lines of output omitted
    

Prepare um modelo

Prepare um modelo do PyTorch com o conjunto de dados Fashion MNIST:

  1. Envie uma tarefa do Ray e aguarde pela conclusão da tarefa:

    ray job submit --submission-id pytorch-mnist-job --working-dir . --runtime-env-json='{"pip": ["torch", "torchvision"], "excludes": ["myenv"]}' --address http://localhost:8265 -- python train.py
    

    O resultado é semelhante ao seguinte:

    Job submission server address: http://localhost:8265
    
    --------------------------------------------
    Job 'pytorch-mnist-job' submitted successfully
    --------------------------------------------
    
    Next steps
      Query the logs of the job:
        ray job logs pytorch-mnist-job
      Query the status of the job:
        ray job status pytorch-mnist-job
      Request the job to be stopped:
        ray job stop pytorch-mnist-job
    
    Handling connection for 8265
    Tailing logs until the job exits (disable with --no-wait):
    ...
    ...
    
  2. Valide o estado da tarefa:

    ray job status pytorch-mnist
    

    O resultado é semelhante ao seguinte:

    Job submission server address: http://localhost:8265
    Status for job 'pytorch-mnist-job': RUNNING
    Status message: Job is currently running.
    

    Aguarde até que o Status for job esteja COMPLETE. Este processo pode demorar 15 minutos ou mais.

  3. Veja os registos de tarefas do Ray:

    ray job logs pytorch-mnist
    

    O resultado é semelhante ao seguinte:

    Training started with configuration:
    ╭─────────────────────────────────────────────────╮
    │ Training config                                  │
    ├──────────────────────────────────────────────────┤
    │ train_loop_config/batch_size_per_worker       8  │
    │ train_loop_config/epochs                     10  │
    │ train_loop_config/lr                      0.001  │
    ╰─────────────────────────────────────────────────╯
    
    # Several lines omitted
    
    Training finished iteration 10 at 2024-06-19 08:29:36. Total running time: 9min 18s
    ╭───────────────────────────────╮
    │ Training result                │
    ├────────────────────────────────┤
    │ checkpoint_dir_name            │
    │ time_this_iter_s      25.7394  │
    │ time_total_s          351.233  │
    │ training_iteration         10  │
    │ accuracy               0.8656  │
    │ loss                  0.37827  │
    ╰───────────────────────────────╯
    
    # Several lines omitted
    -------------------------------
    Job 'pytorch-mnist' succeeded
    -------------------------------
    

Implemente um RayJob

O recurso personalizado RayJob gere o ciclo de vida de um recurso RayCluster durante a execução de uma única tarefa do Ray.

  1. Reveja o seguinte manifesto:

    apiVersion: ray.io/v1
    kind: RayJob
    metadata:
      name: pytorch-mnist-job
    spec:
      shutdownAfterJobFinishes: true
      entrypoint: python ai-ml/gke-ray/raytrain/pytorch-mnist/train.py
      runtimeEnvYAML: |
        pip:
          - torch
          - torchvision
        working_dir: "https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/archive/main.zip"
        env_vars:
          NUM_WORKERS: "4"
          CPUS_PER_WORKER: "2"
      rayClusterSpec:
        rayVersion: '2.37.0'
        headGroupSpec:
          rayStartParams: {}
          template:
            spec:
              containers:
                - name: ray-head
                  image: rayproject/ray:2.37.0
                  ports:
                    - containerPort: 6379
                      name: gcs-server
                    - containerPort: 8265
                      name: dashboard
                    - containerPort: 10001
                      name: client
                  resources:
                    limits:
                      cpu: "2"
                      ephemeral-storage: "9Gi"
                      memory: "4Gi"
                    requests:
                      cpu: "2"
                      ephemeral-storage: "9Gi"
                      memory: "4Gi"
        workerGroupSpecs:
          - replicas: 4
            minReplicas: 1
            maxReplicas: 5
            groupName: small-group
            rayStartParams: {}
            template:
              spec:
                containers:
                  - name: ray-worker
                    image: rayproject/ray:2.37.0
                    resources:
                      limits:
                        cpu: "4"
                        ephemeral-storage: "9Gi"
                        memory: "8Gi"
                      requests:
                        cpu: "4"
                        ephemeral-storage: "9Gi"
                        memory: "8Gi"

    Este manifesto descreve um recurso personalizado RayJob.

  2. Aplique o manifesto ao seu cluster do GKE:

    kubectl apply -f ray-job.yaml
    
  3. Verifique se o recurso RayJob está em execução:

    kubectl get rayjob
    

    O resultado é semelhante ao seguinte:

    NAME                JOB STATUS   DEPLOYMENT STATUS   START TIME             END TIME   AGE
    pytorch-mnist-job   RUNNING      Running             2024-06-19T15:43:32Z              2m29s
    

    Nesta saída, a coluna DEPLOYMENT STATUS indica que o recurso RayJob é Running.

  4. Veja o estado do recurso RayJob:

    kubectl logs -f -l job-name=pytorch-mnist-job
    

    O resultado é semelhante ao seguinte:

    Training started with configuration:
    ╭─────────────────────────────────────────────────╮
    │ Training config                                  │
    ├──────────────────────────────────────────────────┤
    │ train_loop_config/batch_size_per_worker       8  │
    │ train_loop_config/epochs                     10  │
    │ train_loop_config/lr                      0.001  │
    ╰─────────────────────────────────────────────────╯
    
    # Several lines omitted
    
    Training finished iteration 10 at 2024-06-19 08:29:36. Total running time: 9min 18s
    ╭───────────────────────────────╮
    │ Training result                │
    ├────────────────────────────────┤
    │ checkpoint_dir_name            │
    │ time_this_iter_s      25.7394  │
    │ time_total_s          351.233  │
    │ training_iteration         10  │
    │ accuracy               0.8656  │
    │ loss                  0.37827  │
    ╰───────────────────────────────╯
    
    # Several lines omitted
    -------------------------------
    Job 'pytorch-mnist' succeeded
    -------------------------------
    
  5. Verifique se o trabalho do Ray está concluído:

    kubectl get rayjob
    

    O resultado é semelhante ao seguinte:

    NAME                JOB STATUS   DEPLOYMENT STATUS   START TIME             END TIME               AGE
    pytorch-mnist-job   SUCCEEDED    Complete            2024-06-19T15:43:32Z   2024-06-19T15:51:12Z   9m6s
    

    Nesta saída, a coluna DEPLOYMENT STATUS indica que o recurso RayJob é Complete.