Treine um modelo com o Ray e o PyTorch no Google Kubernetes Engine (GKE)

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.

Objetivos

Este guia destina-se a clientes de IA generativa, utilizadores novos ou existentes do GKE, engenheiros de ML, engenheiros de MLOps (DevOps) ou administradores de plataformas interessados em usar capacidades de orquestração de contentores do Kubernetes para publicar modelos com o Ray.

  • Crie um cluster do GKE.
  • Crie um cluster do Ray com o recurso personalizado RayCluster.
  • Prepare um modelo com uma tarefa do Ray.
  • Implemente uma tarefa do Ray com o recurso personalizado RayJob.

Custos

Neste documento, usa os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custos com base na sua utilização projetada, use a calculadora de preços.

Os novos Google Cloud utilizadores podem ser elegíveis para uma avaliação gratuita.

Quando terminar as tarefas descritas neste documento, pode evitar a faturação contínua eliminando os recursos que criou. Para mais informações, consulte o artigo Limpe.

Antes de começar

O Cloud Shell está pré-instalado com o software necessário para este tutorial, incluindo o kubectl e a CLI gcloud. Se não usar o Cloud Shell, tem de instalar a CLI gcloud.

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.

  3. Se estiver a usar um fornecedor de identidade (IdP) externo, tem primeiro de iniciar sessão na CLI gcloud com a sua identidade federada.

  4. Para inicializar a CLI gcloud, execute o seguinte comando:

    gcloud init
  5. Create or select a Google 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.
    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the GKE API:

    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.

    gcloud services enable container.googleapis.com
  8. Install the Google Cloud CLI.

  9. Se estiver a usar um fornecedor de identidade (IdP) externo, tem primeiro de iniciar sessão na CLI gcloud com a sua identidade federada.

  10. Para inicializar a CLI gcloud, execute o seguinte comando:

    gcloud init
  11. Create or select a Google 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.
    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  12. Verify that billing is enabled for your Google Cloud project.

  13. Enable the GKE API:

    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.

    gcloud services enable container.googleapis.com
  14. Grant roles to your user account. Run the following command once for each of the following IAM roles: roles/container.clusterAdmin, roles/container.admin

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE

    Replace the following:

    • PROJECT_ID: Your project ID.
    • USER_IDENTIFIER: The identifier for your user account. For example, myemail@example.com.
    • ROLE: The IAM role that you grant to your user account.
  15. 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 a tarefa do Ray está concluída:

      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.

    Limpar

    Elimine o projeto

      Delete a Google Cloud project:

      gcloud projects delete PROJECT_ID

    Elimine recursos individuais

    Se usou um projeto existente e não o quer eliminar, pode eliminar os recursos individuais. Para eliminar o cluster, escreva:

    gcloud container clusters delete ${CLUSTER_NAME}
    

    O que se segue?